feat(gitea): surface professional cicd practice gaps

This commit is contained in:
ogt
2026-07-10 10:48:04 +08:00
parent d97b114abd
commit 82ab3770ba
2 changed files with 565 additions and 52 deletions

View File

@@ -22,14 +22,14 @@ from src.services.backup_dr_readiness_matrix import (
from src.services.backup_notification_policy import (
load_latest_backup_notification_policy,
)
from src.services.gitea_private_inventory_p0_scorecard import (
load_latest_gitea_private_inventory_p0_scorecard,
from src.services.gitea_cicd_alert_receipt_chain_readback import (
load_latest_gitea_cicd_alert_receipt_chain_readback,
)
from src.services.gitea_full_server_backup_dr_receipts import (
load_latest_gitea_full_server_backup_dr_receipts,
)
from src.services.gitea_cicd_alert_receipt_chain_readback import (
load_latest_gitea_cicd_alert_receipt_chain_readback,
from src.services.gitea_private_inventory_p0_scorecard import (
load_latest_gitea_private_inventory_p0_scorecard,
)
from src.services.gitea_repo_bundle_backup_readback import (
load_latest_gitea_repo_bundle_backup_readback,
@@ -84,6 +84,19 @@ _REQUIRED_OPTIMIZATION_IDS = {
"dedupe_cancel_stale_run_guard",
}
_REQUIRED_PROFESSIONAL_CI_CD_PRACTICE_IDS = {
"gitea_125_actions_runner_trust",
"gitea_125_secret_variable_redaction",
"gitea_125_webhook_hmac_delivery",
"gitea_125_packages_release_registry",
"gitea_125_actions_compatibility_gap_guard",
"dora_delivery_metrics_receipts",
"slsa_build_provenance_isolation",
"gitops_argocd_automated_sync_contract",
"otel_cicd_pipeline_telemetry",
"artifact_cache_sbom_retention",
}
def load_latest_gitea_capability_ci_cd_optimization_readback(
*,
@@ -94,9 +107,7 @@ def load_latest_gitea_capability_ci_cd_optimization_readback(
root = repo_root or resolve_repo_root(Path(__file__))
operations = operations_dir or default_operations_dir(Path(__file__))
payload = build_gitea_capability_ci_cd_optimization_readback(
dev_prod_repo_readback=_load_json(
operations / _DEV_PROD_REPO_READBACK_FILE
),
dev_prod_repo_readback=_load_json(operations / _DEV_PROD_REPO_READBACK_FILE),
private_inventory=load_latest_gitea_private_inventory_p0_scorecard(),
workflow_runner_health=load_latest_gitea_workflow_runner_health(),
workflow_source_inventory=build_gitea_workflow_source_inventory(root),
@@ -128,6 +139,7 @@ def build_gitea_workflow_source_inventory(repo_root: Path) -> dict[str, Any]:
for path in workflow_files:
text = path.read_text(encoding="utf-8", errors="replace")
lowered_text = text.lower()
relative = path.relative_to(repo_root).as_posix()
secret_refs = sorted(set(re.findall(r"\bsecrets\.([A-Z0-9_]+)", text)))
vars_refs = sorted(set(re.findall(r"\bvars\.([A-Z0-9_]+)", text)))
@@ -149,10 +161,51 @@ def build_gitea_workflow_source_inventory(repo_root: Path) -> dict[str, Any]:
"vars_reference_count": vars_ref_count,
"referenced_variable_names": vars_refs,
"declared_runner_labels": _extract_runner_labels(text),
"declares_concurrency": _has_yaml_key(text, "concurrency"),
"declares_permissions": _has_yaml_key(text, "permissions"),
"declares_timeout_minutes": _has_yaml_key(text, "timeout-minutes"),
"declares_continue_on_error": _has_yaml_key(text, "continue-on-error"),
"declares_environment": _has_yaml_key(text, "environment"),
"uses_otel": "otel_" in lowered_text or "opentelemetry" in lowered_text,
"uses_artifact_transfer": (
"upload-artifact" in lowered_text
or "download-artifact" in lowered_text
),
"uses_cache_volume_or_action": (
"actions/cache" in lowered_text
or "venv-cache" in lowered_text
or "npm-cache" in lowered_text
or "pip-cache" in lowered_text
),
"uses_sbom_or_provenance": any(
marker in lowered_text
for marker in ("sbom", "provenance", "cosign", "syft", "trivy")
),
"uses_registry_or_package_channel": (
"registry.wooo.work" in text
or "harbor" in lowered_text
or "/packages/" in lowered_text
),
"uses_argocd_gitops": "argocd" in lowered_text,
"uses_notification_or_webhook": (
"telegram" in lowered_text or "webhook" in lowered_text
),
}
)
workflow_ids = sorted(row["workflow_id"] for row in rows)
gitea_ignored_syntax_keys = {
"declares_concurrency",
"declares_permissions",
"declares_timeout_minutes",
"declares_continue_on_error",
"declares_environment",
}
gitea_ignored_syntax_workflow_ids = sorted(
row["workflow_id"]
for row in rows
if any(row.get(key) is True for key in gitea_ignored_syntax_keys)
)
return {
"source_ref": ".gitea/workflows",
"source_present": workflow_dir.is_dir(),
@@ -210,6 +263,27 @@ def build_gitea_workflow_source_inventory(repo_root: Path) -> dict[str, Any]:
"has_agent_market_watch": "agent-market-watch" in workflow_ids,
"has_ai_technology_watch": "ai-technology-watch" in workflow_ids,
},
"professional_feature_rollups": {
"gitea_ignored_syntax_workflow_count": len(
gitea_ignored_syntax_workflow_ids
),
"gitea_ignored_syntax_workflow_ids": gitea_ignored_syntax_workflow_ids,
"otel_workflow_count": _count_where(rows, "uses_otel"),
"artifact_transfer_workflow_count": _count_where(
rows, "uses_artifact_transfer"
),
"cache_workflow_count": _count_where(rows, "uses_cache_volume_or_action"),
"sbom_or_provenance_workflow_count": _count_where(
rows, "uses_sbom_or_provenance"
),
"registry_or_package_channel_workflow_count": _count_where(
rows, "uses_registry_or_package_channel"
),
"argocd_gitops_workflow_count": _count_where(rows, "uses_argocd_gitops"),
"notification_or_webhook_workflow_count": _count_where(
rows, "uses_notification_or_webhook"
),
},
}
@@ -248,6 +322,9 @@ def build_gitea_capability_ci_cd_optimization_readback(
alert_chain = _dict(gitea_cicd_alert_receipt_chain_readback)
alert_chain_ready = alert_chain.get("ready") is True
alert_chain_summary = _dict(alert_chain.get("summary"))
professional_feature_rollups = _dict(
workflow_source_inventory.get("professional_feature_rollups")
)
full_dr_non_restore_gap_ids = [
gap for gap in full_dr_gap_ids if gap != "restore_drill_approval_gate"
]
@@ -257,7 +334,9 @@ def build_gitea_capability_ci_cd_optimization_readback(
)
full_dr_verified_ready = full_dr.get("ready") is True
all_repos_have_refs = dev_prod_summary.get("all_expected_product_repos_have_ssh_refs") is True
all_repos_have_refs = (
dev_prod_summary.get("all_expected_product_repos_have_ssh_refs") is True
)
all_repos_have_dev_main = (
dev_prod_summary.get("all_expected_product_repos_have_dev_and_main") is True
)
@@ -335,7 +414,9 @@ def build_gitea_capability_ci_cd_optimization_readback(
],
"preserve SSH/authenticated truth before creating or replacing repos",
{
"public_visible_count": _int(dev_prod_summary.get("public_visible_count")),
"public_visible_count": _int(
dev_prod_summary.get("public_visible_count")
),
"private_or_auth_only_count": _int(
dev_prod_summary.get("private_or_auth_only_count")
),
@@ -345,7 +426,9 @@ def build_gitea_capability_ci_cd_optimization_readback(
"pull_request_code_review",
"collaboration",
"Pull requests and code review",
"partially_ready" if known_workflows.get("has_code_review") else "action_required",
"partially_ready"
if known_workflows.get("has_code_review")
else "action_required",
"code-review workflow exists; repository PR policy still needs live inventory",
[
".gitea/workflows/code-review.yaml",
@@ -741,22 +824,294 @@ def build_gitea_capability_ci_cd_optimization_readback(
),
_optimization(
"dedupe_cancel_stale_run_guard",
"source_ready" if known_workflows.get("has_cd_pipeline") else "design_required",
"source_ready"
if known_workflows.get("has_cd_pipeline")
else "design_required",
"Implement Gitea-compatible stale-run dedupe guards",
"CD source includes stale-run guard; live receipt wiring is the remaining work"
if known_workflows.get("has_cd_pipeline")
else "Gitea Actions compatibility requires workflow/runner-side guards for some controls",
[".gitea/workflows/cd.yaml", "ops/runner/read-public-gitea-actions-queue.py"],
[
".gitea/workflows/cd.yaml",
"ops/runner/read-public-gitea-actions-queue.py",
],
"wire stale-run guard receipts into the Gitea capability readback"
if known_workflows.get("has_cd_pipeline")
else "add lease/marker based cancel-stale semantics instead of relying on unsupported syntax",
p0=True,
),
]
professional_practices = [
_professional_practice(
"gitea_125_actions_runner_trust",
"Gitea 1.25 Actions",
"verified_ready"
if workflow_source_count > 0 and not runner_action_ids
else "action_required",
"Trusted act runners, explicit labels, and non-110 isolation",
"workflow source and runner-label contracts are aligned"
if workflow_source_count > 0 and not runner_action_ids
else "runner trust and label ownership need closure before expansion",
[
".gitea/workflows",
"GET /api/v1/agents/gitea-workflow-runner-health",
"https://docs.gitea.com/1.25/usage/actions/overview",
"https://docs.gitea.com/1.25/usage/actions/act-runner",
],
"keep trusted labels and runner health fresh; evaluate ephemeral runners for broader shared-runner lanes",
{
"workflow_source_file_count": workflow_source_count,
"runner_contracts_requiring_action": runner_action_ids,
},
p0=True,
),
_professional_practice(
"gitea_125_secret_variable_redaction",
"Gitea 1.25 Actions",
"source_ready"
if _int(secret_rollups.get("secret_reference_count")) > 0
and secret_rollups.get("secret_values_collected") is False
else "authenticated_inventory_required",
"Secret and variable metadata inventory without value collection",
"workflow references are inventoried and secret values remain unread"
if _int(secret_rollups.get("secret_reference_count")) > 0
else "configured Gitea secret and variable names still need redacted inventory",
[
".gitea/workflows",
"GET /api/v1/agents/gitea-actions-secret-variable-name-inventory",
"https://docs.gitea.com/1.25/usage/actions/secrets",
"https://docs.gitea.com/1.25/usage/actions/actions-variables",
],
"verify presence and scope using redacted name-only metadata; never read secret values",
secret_rollups,
p0=True,
),
_professional_practice(
"gitea_125_webhook_hmac_delivery",
"Gitea 1.25 Repository",
"source_ready"
if quiet_notification_count > 0 and alert_chain_ready
else "action_required",
"Webhook HMAC delivery and notification receipt chain",
"notification policy and alert receipt chain are ready"
if quiet_notification_count > 0 and alert_chain_ready
else "webhook delivery receipts need live closure",
[
"GET /api/v1/agents/gitea-cicd-alert-receipt-chain-readback",
"GET /api/v1/agents/backup-notification-policy",
"https://docs.gitea.com/1.25/usage/repository/webhooks",
],
"bind Gitea webhook delivery ID, signature verification result, and Telegram/AwoooP receipt stage into one readback",
{
"quiet_notification_policy_count": quiet_notification_count,
"alert_receipt_chain_ready": alert_chain_ready,
},
),
_professional_practice(
"gitea_125_packages_release_registry",
"Gitea 1.25 Packages",
"controlled_apply_candidate"
if _int(
professional_feature_rollups.get(
"registry_or_package_channel_workflow_count"
)
)
> 0
else "action_required",
"Package registry, release artifacts, and rollback artifacts",
"registry channel is present, but Gitea package/release promotion is not standardized"
if _int(
professional_feature_rollups.get(
"registry_or_package_channel_workflow_count"
)
)
> 0
else "package and release artifact channel is missing from workflow source",
[
".gitea/workflows/cd.yaml",
"GET /api/v1/agents/package-supply-chain-inventory",
"https://docs.gitea.com/1.25/usage/packages/overview",
],
"standardize package/release promotion, rollback artifact naming, and package event receipts per product",
{
"registry_or_package_channel_workflow_count": _int(
professional_feature_rollups.get(
"registry_or_package_channel_workflow_count"
)
)
},
),
_professional_practice(
"gitea_125_actions_compatibility_gap_guard",
"Gitea 1.25 Actions",
"source_ready"
if known_workflows.get("has_cd_pipeline")
and _int(
professional_feature_rollups.get("gitea_ignored_syntax_workflow_count")
)
> 0
else "implemented",
"Gitea-compatible guards for ignored Actions syntax",
"workflow source detects ignored syntax and uses lease/marker/readback guards for critical CD semantics"
if _int(
professional_feature_rollups.get("gitea_ignored_syntax_workflow_count")
)
> 0
else "no ignored syntax detected in committed workflows",
[
".gitea/workflows/cd.yaml",
"ops/runner/read-public-gitea-actions-queue.py",
"https://docs.gitea.com/1.25/usage/actions/comparison",
],
"keep unsupported syntax detection visible and prefer Gitea-compatible receipt guards over copied YAML semantics",
{
"gitea_ignored_syntax_workflow_count": _int(
professional_feature_rollups.get(
"gitea_ignored_syntax_workflow_count"
)
),
"gitea_ignored_syntax_workflow_ids": _strings(
professional_feature_rollups.get(
"gitea_ignored_syntax_workflow_ids"
)
),
},
p0=True,
),
_professional_practice(
"dora_delivery_metrics_receipts",
"DORA",
"action_required",
"Five-metric delivery performance readback",
"deploy markers and alert receipts exist, but DORA trend metrics are not yet computed per product",
[
"GET /api/v1/agents/p0-cicd-baseline-source-readiness",
"GET /api/v1/agents/gitea-cicd-alert-receipt-chain-readback",
"https://dora.dev/guides/dora-metrics/",
],
"derive change lead time, deployment frequency, failed deployment recovery time, change fail rate, and deployment rework rate from Gitea/CD receipts",
),
_professional_practice(
"slsa_build_provenance_isolation",
"OpenSSF SLSA",
"action_required"
if _int(
professional_feature_rollups.get("sbom_or_provenance_workflow_count")
)
== 0
else "source_ready",
"Build provenance, digest identity, and isolated build controls",
"workflow source does not yet emit SLSA provenance/SBOM receipts"
if _int(
professional_feature_rollups.get("sbom_or_provenance_workflow_count")
)
== 0
else "workflow source contains provenance/SBOM markers",
[
"GET /api/v1/agents/package-supply-chain-inventory",
"https://slsa.dev/spec/v1.2/build-requirements",
],
"add digest-bound provenance/SBOM output and runner isolation evidence to build artifacts",
{
"sbom_or_provenance_workflow_count": _int(
professional_feature_rollups.get(
"sbom_or_provenance_workflow_count"
)
)
},
),
_professional_practice(
"gitops_argocd_automated_sync_contract",
"GitOps / Argo CD",
"source_ready"
if _int(professional_feature_rollups.get("argocd_gitops_workflow_count"))
> 0
else "action_required",
"Git commit driven deployment and Argo CD sync/readback",
"CD workflow uses ArgoCD GitOps and deploy-marker readback",
[
".gitea/workflows/cd.yaml",
"GET /api/v1/agents/p0-cicd-baseline-source-readiness",
"https://argo-cd.readthedocs.io/en/stable/user-guide/auto_sync/",
],
"keep Argo sync, health, revision, deploy marker, and smoke readback tied to the same commit",
{
"argocd_gitops_workflow_count": _int(
professional_feature_rollups.get("argocd_gitops_workflow_count")
)
},
p0=True,
),
_professional_practice(
"otel_cicd_pipeline_telemetry",
"OpenTelemetry",
"source_ready"
if _int(professional_feature_rollups.get("otel_workflow_count")) > 0
else "action_required",
"CI/CD pipeline telemetry and low-cardinality result tags",
"workflow source exports OTEL service/resource attributes for CD lanes",
[
".gitea/workflows/cd.yaml",
".gitea/workflows/cd-dev.yaml",
".gitea/workflows/e2e-health.yaml",
"https://opentelemetry.io/docs/specs/semconv/cicd/cicd-spans/",
],
"bind pipeline result, run id, commit, environment, and error type into CI/CD span/readback receipts",
{
"otel_workflow_count": _int(
professional_feature_rollups.get("otel_workflow_count")
)
},
),
_professional_practice(
"artifact_cache_sbom_retention",
"CI/CD Artifact Governance",
"action_required"
if _int(
professional_feature_rollups.get("artifact_transfer_workflow_count")
)
== 0
or _int(
professional_feature_rollups.get("sbom_or_provenance_workflow_count")
)
== 0
else "source_ready",
"Cache keys, artifact retention, SBOM, and receipt retention",
"workflow source still lacks unified artifact/SBOM retention receipts"
if _int(
professional_feature_rollups.get("artifact_transfer_workflow_count")
)
== 0
or _int(
professional_feature_rollups.get("sbom_or_provenance_workflow_count")
)
== 0
else "workflow source contains artifact and SBOM/provenance markers",
[
".gitea/workflows",
"GET /api/v1/agents/gitea-workflow-runner-health",
],
"standardize artifact upload, cache keys, SBOM/provenance naming, and retention windows across workflows",
{
"artifact_transfer_workflow_count": _int(
professional_feature_rollups.get("artifact_transfer_workflow_count")
),
"cache_workflow_count": _int(
professional_feature_rollups.get("cache_workflow_count")
),
"sbom_or_provenance_workflow_count": _int(
professional_feature_rollups.get(
"sbom_or_provenance_workflow_count"
)
),
},
),
]
rollups = _build_rollups(
capabilities=capabilities,
optimizations=optimizations,
professional_practices=professional_practices,
dev_prod_summary=dev_prod_summary,
workflow_source_count=workflow_source_count,
workflow_contract_count=workflow_contract_count,
@@ -820,17 +1175,26 @@ def build_gitea_capability_ci_cd_optimization_readback(
"official_gitea_feature_refs": [
"https://docs.gitea.com/1.25/usage/access-control/permissions",
"https://docs.gitea.com/1.25/usage/actions/overview",
"https://docs.gitea.com/1.25/usage/actions/act-runner",
"https://docs.gitea.com/1.25/usage/actions/comparison",
"https://docs.gitea.com/1.25/usage/actions/secrets",
"https://docs.gitea.com/1.25/usage/actions/actions-variables",
"https://docs.gitea.com/1.25/usage/packages/overview",
"https://docs.gitea.com/1.25/usage/repository/webhooks",
],
"market_practice_basis_refs": [
"https://dora.dev/guides/dora-metrics/",
"https://slsa.dev/spec/v1.2/build-requirements",
"https://argo-cd.readthedocs.io/en/stable/user-guide/auto_sync/",
"https://opentelemetry.io/docs/specs/semconv/cicd/cicd-spans/",
],
"safe_next_actions": _safe_next_actions(capabilities, optimizations),
},
"rollups": rollups,
"workflow_source_inventory": workflow_source_inventory,
"capability_rows": capabilities,
"ci_cd_optimization_rows": optimizations,
"professional_ci_cd_practice_rows": professional_practices,
}
_require_payload(payload, "gitea_capability_ci_cd_optimization_readback")
return payload
@@ -884,10 +1248,36 @@ def _optimization(
}
def _professional_practice(
practice_id: str,
framework: str,
status_value: str,
title: str,
usage_state: str,
evidence_refs: list[str],
next_action: str,
metrics: dict[str, Any] | None = None,
*,
p0: bool = False,
) -> dict[str, Any]:
return {
"id": practice_id,
"framework": framework,
"status": status_value,
"priority": "P0" if p0 else "P1",
"title": title,
"usage_state": usage_state,
"evidence_refs": evidence_refs,
"next_action": next_action,
"metrics": metrics or {},
}
def _build_rollups(
*,
capabilities: list[dict[str, Any]],
optimizations: list[dict[str, Any]],
professional_practices: list[dict[str, Any]],
dev_prod_summary: dict[str, Any],
workflow_source_count: int,
workflow_contract_count: int,
@@ -895,8 +1285,28 @@ def _build_rollups(
) -> dict[str, Any]:
capability_status = _count_by(capabilities, "status")
optimization_status = _count_by(optimizations, "status")
professional_status = _count_by(professional_practices, "status")
p0_capabilities = [row for row in capabilities if row.get("priority") == "P0"]
p0_optimizations = [row for row in optimizations if row.get("priority") == "P0"]
p0_professional_practices = [
row for row in professional_practices if row.get("priority") == "P0"
]
ready_statuses = {"verified_ready", "implemented", "source_ready"}
capability_gap_ids = [
str(row.get("id"))
for row in capabilities
if row.get("status") not in ready_statuses
]
optimization_gap_ids = [
str(row.get("id"))
for row in optimizations
if row.get("status") not in ready_statuses
]
professional_gap_ids = [
str(row.get("id"))
for row in professional_practices
if row.get("status") not in ready_statuses
]
return {
"capability_count": len(capabilities),
"capability_status_counts": capability_status,
@@ -917,6 +1327,21 @@ def _build_rollups(
),
"p0_optimization_count": len(p0_optimizations),
"p0_optimization_gap_count": _gap_count(p0_optimizations),
"professional_ci_cd_practice_count": len(professional_practices),
"professional_ci_cd_practice_status_counts": professional_status,
"professional_ci_cd_practice_gap_count": len(professional_gap_ids),
"professional_ci_cd_practice_gap_ids": professional_gap_ids,
"p0_professional_ci_cd_practice_count": len(p0_professional_practices),
"p0_professional_ci_cd_practice_gap_count": _gap_count(
p0_professional_practices
),
"market_professional_ci_cd_gap_count": len(professional_gap_ids),
"gitea_feature_utilization_gap_ids": sorted(
set(capability_gap_ids + optimization_gap_ids + professional_gap_ids)
),
"all_gitea_features_fully_utilized": not (
capability_gap_ids or optimization_gap_ids or professional_gap_ids
),
"expected_product_count": _int(dev_prod_summary.get("expected_product_count")),
"ssh_verified_product_repo_count": _int(
dev_prod_summary.get("ssh_repo_present_count")
@@ -939,13 +1364,9 @@ def _safe_next_actions(
row
for row in capabilities + optimizations
if row.get("priority") == "P0"
and row.get("status")
not in {"verified_ready", "implemented", "source_ready"}
]
return [
f"{row['id']}: {row['next_action']}"
for row in rows[:8]
and row.get("status") not in {"verified_ready", "implemented", "source_ready"}
]
return [f"{row['id']}: {row['next_action']}" for row in rows[:8]]
def _require_payload(payload: dict[str, Any], label: str) -> None:
@@ -973,26 +1394,45 @@ def _require_payload(payload: dict[str, Any], label: str) -> None:
flag for flag in blocked_true_flags if boundaries.get(flag) is not False
)
if unexpected:
raise ValueError(f"{label}: blocked operation flags must be false: {unexpected}")
raise ValueError(
f"{label}: blocked operation flags must be false: {unexpected}"
)
capabilities = _list(payload.get("capability_rows"))
optimizations = _list(payload.get("ci_cd_optimization_rows"))
capability_ids = {str(row.get("id") or "") for row in capabilities if isinstance(row, dict)}
professional_practices = _list(payload.get("professional_ci_cd_practice_rows"))
capability_ids = {
str(row.get("id") or "") for row in capabilities if isinstance(row, dict)
}
optimization_ids = {
str(row.get("id") or "") for row in optimizations if isinstance(row, dict)
}
professional_practice_ids = {
str(row.get("id") or "")
for row in professional_practices
if isinstance(row, dict)
}
missing_capabilities = sorted(_REQUIRED_CAPABILITY_IDS - capability_ids)
missing_optimizations = sorted(_REQUIRED_OPTIMIZATION_IDS - optimization_ids)
missing_professional_practices = sorted(
_REQUIRED_PROFESSIONAL_CI_CD_PRACTICE_IDS - professional_practice_ids
)
if missing_capabilities:
raise ValueError(f"{label}: missing capability rows: {missing_capabilities}")
if missing_optimizations:
raise ValueError(f"{label}: missing optimization rows: {missing_optimizations}")
if missing_professional_practices:
raise ValueError(
f"{label}: missing professional CI/CD practice rows: {missing_professional_practices}"
)
rollups = _dict(payload.get("rollups"))
if rollups.get("capability_count") != len(capabilities):
raise ValueError(f"{label}: capability_count mismatch")
if rollups.get("ci_cd_optimization_count") != len(optimizations):
raise ValueError(f"{label}: ci_cd_optimization_count mismatch")
if rollups.get("professional_ci_cd_practice_count") != len(professional_practices):
raise ValueError(f"{label}: professional_ci_cd_practice_count mismatch")
if rollups.get("capability_status_counts") != _count_by(capabilities, "status"):
raise ValueError(f"{label}: capability_status_counts mismatch")
if rollups.get("ci_cd_optimization_status_counts") != _count_by(
@@ -1000,6 +1440,11 @@ def _require_payload(payload: dict[str, Any], label: str) -> None:
"status",
):
raise ValueError(f"{label}: ci_cd_optimization_status_counts mismatch")
if rollups.get("professional_ci_cd_practice_status_counts") != _count_by(
professional_practices,
"status",
):
raise ValueError(f"{label}: professional_ci_cd_practice_status_counts mismatch")
_require_no_plaintext_secret_keys(payload, label)
@@ -1018,7 +1463,9 @@ def _require_no_plaintext_secret_keys(value: Any, label: str, path: str = "$") -
for key, child in value.items():
lowered = str(key).lower()
if lowered in forbidden or lowered.endswith("_secret_value"):
raise ValueError(f"{label}: forbidden plaintext-like key at {path}.{key}")
raise ValueError(
f"{label}: forbidden plaintext-like key at {path}.{key}"
)
_require_no_plaintext_secret_keys(child, label, f"{path}.{key}")
elif isinstance(value, list):
for index, child in enumerate(value):

View File

@@ -1,5 +1,6 @@
from __future__ import annotations
# ruff: noqa: E402
import json
import os
from pathlib import Path
@@ -140,8 +141,7 @@ def test_gitea_capability_readback_rolls_up_complete_feature_surface() -> None:
payload = _readback_payload()
assert (
payload["schema_version"]
== "gitea_capability_ci_cd_optimization_readback_v1"
payload["schema_version"] == "gitea_capability_ci_cd_optimization_readback_v1"
)
assert payload["source_control_authority"] == "gitea"
assert payload["status"] == "gitea_capability_ci_cd_optimization_ready"
@@ -149,12 +149,29 @@ def test_gitea_capability_readback_rolls_up_complete_feature_surface() -> None:
assert payload["rollups"]["ssh_verified_product_repo_count"] == 12
assert payload["rollups"]["dev_prod_environment_split_ready_count"] == 12
assert payload["workflow_source_inventory"]["workflow_file_count"] == 12
assert payload["workflow_source_inventory"]["secret_variable_rollups"][
"secret_values_collected"
] is False
assert payload["workflow_source_inventory"]["secret_variable_rollups"][
"secret_reference_count"
] > 0
professional_feature_rollups = payload["workflow_source_inventory"][
"professional_feature_rollups"
]
assert professional_feature_rollups["gitea_ignored_syntax_workflow_count"] == 9
assert professional_feature_rollups["otel_workflow_count"] == 3
assert professional_feature_rollups["argocd_gitops_workflow_count"] == 1
assert (
professional_feature_rollups["registry_or_package_channel_workflow_count"] == 4
)
assert professional_feature_rollups["sbom_or_provenance_workflow_count"] == 0
assert professional_feature_rollups["artifact_transfer_workflow_count"] == 0
assert (
payload["workflow_source_inventory"]["secret_variable_rollups"][
"secret_values_collected"
]
is False
)
assert (
payload["workflow_source_inventory"]["secret_variable_rollups"][
"secret_reference_count"
]
> 0
)
assert (
len(
payload["workflow_source_inventory"]["secret_variable_rollups"][
@@ -166,22 +183,27 @@ def test_gitea_capability_readback_rolls_up_complete_feature_surface() -> None:
capability_by_id = {row["id"]: row for row in payload["capability_rows"]}
assert capability_by_id["code_git_source_control"]["status"] == "verified_ready"
assert (
capability_by_id["dev_prod_environment_split"]["status"]
== "verified_ready"
)
assert capability_by_id["dev_prod_environment_split"]["status"] == "verified_ready"
assert capability_by_id["gitea_actions_workflows"]["status"] == "verified_ready"
assert capability_by_id["gitea_actions_workflows"]["metrics"] == {
"workflow_source_file_count": 12,
"workflow_contract_count": 12,
}
assert capability_by_id["gitea_actions_runners"]["status"] == "verified_ready"
assert capability_by_id["branch_protection_required_checks"]["status"] == "source_ready"
assert (
capability_by_id["branch_protection_required_checks"]["status"]
== "source_ready"
)
assert capability_by_id["backup_dr_restore"]["status"] == "source_ready"
assert capability_by_id["backup_dr_restore"]["metrics"][
"gitea_full_dr_source_ready_component_count"
] == 6
assert capability_by_id["observability_alert_receipts"]["status"] == "verified_ready"
assert (
capability_by_id["backup_dr_restore"]["metrics"][
"gitea_full_dr_source_ready_component_count"
]
== 6
)
assert (
capability_by_id["observability_alert_receipts"]["status"] == "verified_ready"
)
assert capability_by_id["observability_alert_receipts"]["metrics"] == {
"alert_receipt_chain_ready": True,
"alert_receipt_chain_status": "gitea_cicd_alert_receipt_chain_ready",
@@ -198,29 +220,22 @@ def test_gitea_capability_readback_rolls_up_complete_feature_surface() -> None:
def test_gitea_capability_readback_prioritizes_professional_cicd_gaps() -> None:
payload = _readback_payload()
optimization_by_id = {
row["id"]: row for row in payload["ci_cd_optimization_rows"]
}
optimization_by_id = {row["id"]: row for row in payload["ci_cd_optimization_rows"]}
assert (
optimization_by_id["gitea_actions_source_authority"]["status"]
== "implemented"
optimization_by_id["gitea_actions_source_authority"]["status"] == "implemented"
)
assert (
optimization_by_id["dev_prod_branch_promotion_contract"]["status"]
== "implemented"
)
assert (
optimization_by_id["workflow_contract_freshness"]["status"]
== "implemented"
)
assert optimization_by_id["workflow_contract_freshness"]["status"] == "implemented"
assert (
optimization_by_id["runner_label_isolation_attestation"]["status"]
== "implemented"
)
assert (
optimization_by_id["dedupe_cancel_stale_run_guard"]["status"]
== "source_ready"
optimization_by_id["dedupe_cancel_stale_run_guard"]["status"] == "source_ready"
)
assert (
optimization_by_id["branch_protection_required_checks"]["status"]
@@ -234,6 +249,56 @@ def test_gitea_capability_readback_prioritizes_professional_cicd_gaps() -> None:
payload["ci_cd_optimization_rows"]
)
assert payload["rollups"]["p0_optimization_gap_count"] == 0
assert payload["rollups"]["professional_ci_cd_practice_count"] == len(
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"] == 5
assert payload["rollups"]["all_gitea_features_fully_utilized"] is False
assert payload["rollups"]["professional_ci_cd_practice_gap_ids"] == [
"gitea_125_webhook_hmac_delivery",
"gitea_125_packages_release_registry",
"dora_delivery_metrics_receipts",
"slsa_build_provenance_isolation",
"artifact_cache_sbom_retention",
]
practice_by_id = {
row["id"]: row for row in payload["professional_ci_cd_practice_rows"]
}
assert (
practice_by_id["gitea_125_actions_runner_trust"]["status"] == "verified_ready"
)
assert (
practice_by_id["gitea_125_secret_variable_redaction"]["status"]
== "source_ready"
)
assert (
practice_by_id["gitea_125_actions_compatibility_gap_guard"]["status"]
== "source_ready"
)
assert (
practice_by_id["gitops_argocd_automated_sync_contract"]["status"]
== "source_ready"
)
assert practice_by_id["otel_cicd_pipeline_telemetry"]["status"] == "source_ready"
assert (
practice_by_id["dora_delivery_metrics_receipts"]["status"] == "action_required"
)
assert (
practice_by_id["slsa_build_provenance_isolation"]["status"] == "action_required"
)
assert (
practice_by_id["artifact_cache_sbom_retention"]["status"] == "action_required"
)
assert (
"https://dora.dev/guides/dora-metrics/"
in payload["readback"]["market_practice_basis_refs"]
)
assert (
"https://slsa.dev/spec/v1.2/build-requirements"
in payload["readback"]["market_practice_basis_refs"]
)
assert payload["status"] == "gitea_capability_ci_cd_optimization_ready"
assert payload["ready"] is True
assert payload["active_p0_gap_ids"] == []
@@ -250,12 +315,13 @@ def test_gitea_capability_readback_endpoint_returns_payload(monkeypatch) -> None
app.include_router(router, prefix="/api/v1")
client = TestClient(app)
response = client.get(
"/api/v1/agents/gitea-capability-ci-cd-optimization-readback"
)
response = client.get("/api/v1/agents/gitea-capability-ci-cd-optimization-readback")
assert response.status_code == 200
data = response.json()
assert data["schema_version"] == "gitea_capability_ci_cd_optimization_readback_v1"
assert data["rollups"]["capability_count"] == len(data["capability_rows"])
assert data["rollups"]["professional_ci_cd_practice_count"] == len(
data["professional_ci_cd_practice_rows"]
)
assert data["rollups"]["workflow_contract_fresh"] is True