feat(gitea): add package release promotion receipts
This commit is contained in:
@@ -887,6 +887,7 @@ jobs:
|
||||
if [ "${AWOOOI_CD_TEST_PROFILE:-full}" = "controlled-runtime" ]; then
|
||||
echo "✅ controlled-runtime profile: running focused replay/auto-approve/copy tests"
|
||||
python3.11 ../../scripts/ci/generate-cicd-artifact-receipts.py --repo-root ../.. --out-dir /tmp/awoooi-cicd-artifacts
|
||||
echo "package-release-promotion source_contract=awoooi-ci-package-release-promotion.json"
|
||||
python3.11 -m py_compile \
|
||||
src/core/config.py \
|
||||
src/db/base.py \
|
||||
@@ -1103,6 +1104,7 @@ jobs:
|
||||
2>&1 | tee /tmp/pytest-output.txt; PYTEST_EXIT=${PIPESTATUS[0]}
|
||||
else
|
||||
python3.11 ../../scripts/ci/generate-cicd-artifact-receipts.py --repo-root ../.. --out-dir /tmp/awoooi-cicd-artifacts
|
||||
echo "package-release-promotion source_contract=awoooi-ci-package-release-promotion.json"
|
||||
echo "✅ full profile: running learning-chain E2E in isolated pytest process"
|
||||
DATABASE_URL="${DATABASE_URL:-postgresql+asyncpg://ci:ci@localhost/ci}" \
|
||||
PYTHONFAULTHANDLER=1 python3.11 -m pytest tests/test_learning_chain_e2e.py -v --tb=short -p no:cacheprovider \
|
||||
|
||||
@@ -196,6 +196,12 @@ def build_gitea_workflow_source_inventory(repo_root: Path) -> dict[str, Any]:
|
||||
or "harbor" in lowered_text
|
||||
or "/packages/" in lowered_text
|
||||
),
|
||||
"uses_package_release_promotion_contract": (
|
||||
"package-release-promotion" in lowered_text
|
||||
or "package_release_promotion" in lowered_text
|
||||
or "release_channel_contract" in lowered_text
|
||||
or "rollback_artifact_pattern" in lowered_text
|
||||
),
|
||||
"uses_argocd_gitops": "argocd" in lowered_text,
|
||||
"uses_notification_or_webhook": (
|
||||
"telegram" in lowered_text or "webhook" in lowered_text
|
||||
@@ -292,6 +298,9 @@ def build_gitea_workflow_source_inventory(repo_root: Path) -> dict[str, Any]:
|
||||
"registry_or_package_channel_workflow_count": _count_where(
|
||||
rows, "uses_registry_or_package_channel"
|
||||
),
|
||||
"package_release_promotion_workflow_count": _count_where(
|
||||
rows, "uses_package_release_promotion_contract"
|
||||
),
|
||||
"argocd_gitops_workflow_count": _count_where(rows, "uses_argocd_gitops"),
|
||||
"notification_or_webhook_workflow_count": _count_where(
|
||||
rows, "uses_notification_or_webhook"
|
||||
@@ -342,6 +351,10 @@ def build_gitea_capability_ci_cd_optimization_readback(
|
||||
professional_feature_rollups = _dict(
|
||||
workflow_source_inventory.get("professional_feature_rollups")
|
||||
)
|
||||
package_release_contract_count = _int(
|
||||
professional_feature_rollups.get("package_release_promotion_workflow_count")
|
||||
)
|
||||
package_release_contract_ready = package_release_contract_count > 0
|
||||
full_dr_non_restore_gap_ids = [
|
||||
gap for gap in full_dr_gap_ids if gap != "restore_drill_approval_gate"
|
||||
]
|
||||
@@ -497,19 +510,39 @@ def build_gitea_capability_ci_cd_optimization_readback(
|
||||
"releases_tags",
|
||||
"release_management",
|
||||
"Releases and tags",
|
||||
"controlled_apply_candidate",
|
||||
"release/tag convention is not yet enforced across all products",
|
||||
["GET /api/v1/agents/p0-cicd-baseline-source-readiness"],
|
||||
"source_ready"
|
||||
if package_release_contract_ready
|
||||
else "controlled_apply_candidate",
|
||||
"package/release promotion source contract is present"
|
||||
if package_release_contract_ready
|
||||
else "release/tag convention is not yet enforced across all products",
|
||||
[
|
||||
".gitea/workflows/cd.yaml",
|
||||
"GET /api/v1/agents/p0-cicd-baseline-source-readiness",
|
||||
],
|
||||
"add release train tags, changelog receipt, and deploy marker correlation",
|
||||
{
|
||||
"package_release_promotion_workflow_count": package_release_contract_count
|
||||
},
|
||||
),
|
||||
_capability(
|
||||
"packages_registry",
|
||||
"artifact_management",
|
||||
"Packages / container and build artifacts",
|
||||
"controlled_apply_candidate",
|
||||
"package registry policy needs product-by-product adoption",
|
||||
["GET /api/v1/agents/package-supply-chain-inventory"],
|
||||
"source_ready"
|
||||
if package_release_contract_ready
|
||||
else "controlled_apply_candidate",
|
||||
"package registry promotion source contract includes SBOM/provenance/rollback refs"
|
||||
if package_release_contract_ready
|
||||
else "package registry policy needs product-by-product adoption",
|
||||
[
|
||||
".gitea/workflows/cd.yaml",
|
||||
"GET /api/v1/agents/package-supply-chain-inventory",
|
||||
],
|
||||
"promote build artifacts through Gitea Packages or internal registry with SBOM refs",
|
||||
{
|
||||
"package_release_promotion_workflow_count": package_release_contract_count
|
||||
},
|
||||
),
|
||||
_capability(
|
||||
"gitea_actions_workflows",
|
||||
@@ -832,11 +865,21 @@ def build_gitea_capability_ci_cd_optimization_readback(
|
||||
),
|
||||
_optimization(
|
||||
"package_registry_release_promotion",
|
||||
"controlled_apply_candidate",
|
||||
"source_ready"
|
||||
if package_release_contract_ready
|
||||
else "controlled_apply_candidate",
|
||||
"Promote release artifacts through package/release channels",
|
||||
"artifact channel is not yet standardized for every product",
|
||||
["GET /api/v1/agents/package-supply-chain-inventory"],
|
||||
"package/release promotion contract is wired into CI artifact receipts"
|
||||
if package_release_contract_ready
|
||||
else "artifact channel is not yet standardized for every product",
|
||||
[
|
||||
".gitea/workflows/cd.yaml",
|
||||
"GET /api/v1/agents/package-supply-chain-inventory",
|
||||
],
|
||||
"add package registry, release tag, changelog, and rollback artifact receipts",
|
||||
{
|
||||
"package_release_promotion_workflow_count": package_release_contract_count
|
||||
},
|
||||
),
|
||||
_optimization(
|
||||
"branch_protection_required_checks",
|
||||
@@ -1033,7 +1076,9 @@ def build_gitea_capability_ci_cd_optimization_readback(
|
||||
_professional_practice(
|
||||
"gitea_125_packages_release_registry",
|
||||
"Gitea 1.25 Packages",
|
||||
"controlled_apply_candidate"
|
||||
"source_ready"
|
||||
if package_release_contract_ready
|
||||
else "controlled_apply_candidate"
|
||||
if _int(
|
||||
professional_feature_rollups.get(
|
||||
"registry_or_package_channel_workflow_count"
|
||||
@@ -1042,7 +1087,9 @@ def build_gitea_capability_ci_cd_optimization_readback(
|
||||
> 0
|
||||
else "action_required",
|
||||
"Package registry, release artifacts, and rollback artifacts",
|
||||
"registry channel is present, but Gitea package/release promotion is not standardized"
|
||||
"Gitea package/release promotion source contract is wired into CI receipts"
|
||||
if package_release_contract_ready
|
||||
else "registry channel is present, but Gitea package/release promotion is not standardized"
|
||||
if _int(
|
||||
professional_feature_rollups.get(
|
||||
"registry_or_package_channel_workflow_count"
|
||||
@@ -1061,7 +1108,8 @@ def build_gitea_capability_ci_cd_optimization_readback(
|
||||
professional_feature_rollups.get(
|
||||
"registry_or_package_channel_workflow_count"
|
||||
)
|
||||
)
|
||||
),
|
||||
"package_release_promotion_workflow_count": package_release_contract_count,
|
||||
},
|
||||
),
|
||||
_professional_practice(
|
||||
|
||||
@@ -159,6 +159,7 @@ def test_gitea_capability_readback_rolls_up_complete_feature_surface() -> None:
|
||||
assert (
|
||||
professional_feature_rollups["registry_or_package_channel_workflow_count"] == 4
|
||||
)
|
||||
assert professional_feature_rollups["package_release_promotion_workflow_count"] == 1
|
||||
assert professional_feature_rollups["sbom_or_provenance_workflow_count"] == 1
|
||||
assert professional_feature_rollups["artifact_transfer_workflow_count"] == 1
|
||||
assert (
|
||||
@@ -272,11 +273,9 @@ def test_gitea_capability_readback_prioritizes_professional_cicd_gaps() -> None:
|
||||
payload["professional_ci_cd_practice_rows"]
|
||||
)
|
||||
assert payload["rollups"]["p0_professional_ci_cd_practice_gap_count"] == 0
|
||||
assert payload["rollups"]["market_professional_ci_cd_gap_count"] == 1
|
||||
assert payload["rollups"]["market_professional_ci_cd_gap_count"] == 0
|
||||
assert payload["rollups"]["all_gitea_features_fully_utilized"] is False
|
||||
assert payload["rollups"]["professional_ci_cd_practice_gap_ids"] == [
|
||||
"gitea_125_packages_release_registry",
|
||||
]
|
||||
assert payload["rollups"]["professional_ci_cd_practice_gap_ids"] == []
|
||||
|
||||
practice_by_id = {
|
||||
row["id"]: row for row in payload["professional_ci_cd_practice_rows"]
|
||||
@@ -288,6 +287,10 @@ def test_gitea_capability_readback_prioritizes_professional_cicd_gaps() -> None:
|
||||
practice_by_id["gitea_125_secret_variable_redaction"]["status"]
|
||||
== "source_ready"
|
||||
)
|
||||
assert (
|
||||
practice_by_id["gitea_125_packages_release_registry"]["status"]
|
||||
== "source_ready"
|
||||
)
|
||||
assert (
|
||||
practice_by_id["gitea_125_actions_compatibility_gap_guard"]["status"]
|
||||
== "source_ready"
|
||||
|
||||
@@ -23,6 +23,7 @@ SCHEMA_VERSION = "awoooi_cicd_artifact_receipts_v1"
|
||||
SBOM_SCHEMA_VERSION = "awoooi_cicd_sbom_v1"
|
||||
PROVENANCE_SCHEMA_VERSION = "awoooi_cicd_provenance_v1"
|
||||
RETENTION_SCHEMA_VERSION = "awoooi_cicd_artifact_retention_v1"
|
||||
PACKAGE_RELEASE_SCHEMA_VERSION = "awoooi_cicd_package_release_promotion_v1"
|
||||
|
||||
PYPROJECT_PATHS = [
|
||||
"apps/api/pyproject.toml",
|
||||
@@ -270,12 +271,53 @@ def build_receipts(repo_root: Path, out_dir: Path) -> dict[str, Any]:
|
||||
retention,
|
||||
)
|
||||
|
||||
package_release = {
|
||||
"schema_version": PACKAGE_RELEASE_SCHEMA_VERSION,
|
||||
"source_control_authority": "gitea",
|
||||
"release_channel_contract": {
|
||||
"primary_package_registry": "gitea_packages",
|
||||
"container_registry": "registry.wooo.work/awoooi",
|
||||
"release_tag_pattern": "awoooi-api-{short_sha}",
|
||||
"rollback_artifact_pattern": "awoooi-api-{previous_short_sha}",
|
||||
"changelog_receipt_required": True,
|
||||
"sbom_ref_required": True,
|
||||
"provenance_ref_required": True,
|
||||
"deploy_marker_ref_required": True,
|
||||
},
|
||||
"promotion_subject": {
|
||||
"name": "awoooi",
|
||||
"source_sha": source_sha,
|
||||
"run_id": run_id,
|
||||
"run_attempt": run_attempt,
|
||||
"sbom_sha256": sbom_sha,
|
||||
"provenance_sha256": provenance_sha,
|
||||
"artifact_retention_sha256": retention_sha,
|
||||
},
|
||||
"rollback_receipt_contract": {
|
||||
"rollback_source": "previous_deploy_marker",
|
||||
"rollback_requires_image_digest": True,
|
||||
"rollback_requires_package_or_release_ref": True,
|
||||
"rollback_requires_post_apply_readback": True,
|
||||
},
|
||||
"operation_boundaries": {
|
||||
"package_registry_write_attempted": False,
|
||||
"gitea_release_write_attempted": False,
|
||||
"tag_write_attempted": False,
|
||||
"secret_value_read_allowed": False,
|
||||
"github_api_allowed": False,
|
||||
},
|
||||
}
|
||||
package_release_sha = _write_json(
|
||||
out_dir / "awoooi-ci-package-release-promotion.json",
|
||||
package_release,
|
||||
)
|
||||
|
||||
manifest = {
|
||||
"schema_version": SCHEMA_VERSION,
|
||||
"source_control_authority": "gitea",
|
||||
"source_sha": source_sha,
|
||||
"run_id": run_id,
|
||||
"receipt_count": 3,
|
||||
"receipt_count": 4,
|
||||
"receipts": [
|
||||
{
|
||||
"id": "sbom",
|
||||
@@ -292,6 +334,11 @@ def build_receipts(repo_root: Path, out_dir: Path) -> dict[str, Any]:
|
||||
"path": str(out_dir / "awoooi-ci-artifact-retention-manifest.json"),
|
||||
"sha256": retention_sha,
|
||||
},
|
||||
{
|
||||
"id": "package_release_promotion",
|
||||
"path": str(out_dir / "awoooi-ci-package-release-promotion.json"),
|
||||
"sha256": package_release_sha,
|
||||
},
|
||||
],
|
||||
"ready": True,
|
||||
"operation_boundaries": {
|
||||
|
||||
@@ -76,9 +76,21 @@ dev = ["pytest>=8"]
|
||||
encoding="utf-8"
|
||||
)
|
||||
)
|
||||
package_release = json.loads(
|
||||
(out_dir / "awoooi-ci-package-release-promotion.json").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
)
|
||||
|
||||
assert manifest["schema_version"] == "awoooi_cicd_artifact_receipts_v1"
|
||||
assert manifest["ready"] is True
|
||||
assert manifest["receipt_count"] == 4
|
||||
assert [receipt["id"] for receipt in manifest["receipts"]] == [
|
||||
"sbom",
|
||||
"provenance",
|
||||
"artifact_retention",
|
||||
"package_release_promotion",
|
||||
]
|
||||
assert manifest["operation_boundaries"] == {
|
||||
"secret_values_collected": False,
|
||||
"github_api_used": False,
|
||||
@@ -97,3 +109,24 @@ dev = ["pytest>=8"]
|
||||
assert (
|
||||
retention["operation_boundaries"]["package_registry_write_attempted"] is False
|
||||
)
|
||||
assert (
|
||||
package_release["schema_version"] == "awoooi_cicd_package_release_promotion_v1"
|
||||
)
|
||||
assert (
|
||||
package_release["release_channel_contract"]["primary_package_registry"]
|
||||
== "gitea_packages"
|
||||
)
|
||||
assert (
|
||||
package_release["rollback_receipt_contract"][
|
||||
"rollback_requires_post_apply_readback"
|
||||
]
|
||||
is True
|
||||
)
|
||||
assert (
|
||||
package_release["operation_boundaries"]["package_registry_write_attempted"]
|
||||
is False
|
||||
)
|
||||
assert (
|
||||
package_release["operation_boundaries"]["gitea_release_write_attempted"]
|
||||
is False
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user