fix(gitea): surface workflow and alert receipt readiness
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 1s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 3m18s
CD Pipeline / build-and-deploy (push) Failing after 50s
CD Pipeline / post-deploy-checks (push) Has been skipped
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 1s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 3m18s
CD Pipeline / build-and-deploy (push) Failing after 50s
CD Pipeline / post-deploy-checks (push) Has been skipped
This commit is contained in:
@@ -74,6 +74,9 @@ COPY --chown=appuser:appuser apps/api/models.json ./models.json
|
||||
COPY --chown=appuser:appuser apps/api/alert_rules.yaml ./alert_rules.yaml
|
||||
# 2026-04-10 Claude Sonnet 4.6: drift_detector 需要 k8s/ YAML 做 Git state 比對
|
||||
COPY --chown=appuser:appuser k8s/ ./k8s/
|
||||
# 2026-07-10 Codex: Gitea capability readbacks inspect committed workflow
|
||||
# source in production without calling Gitea APIs or reading secret values.
|
||||
COPY --chown=appuser:appuser .gitea/workflows/ ./.gitea/workflows/
|
||||
# 2026-05-24 Codex: truth-chain / Ansible readiness needs the repo-known
|
||||
# playbook catalog in the API image.
|
||||
# 2026-05-31 Codex: ansible-core is now installed through pyproject.toml so
|
||||
|
||||
@@ -8,6 +8,7 @@ mutates repositories, changes visibility, restarts runners, or touches hosts.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import re
|
||||
from datetime import datetime
|
||||
@@ -27,6 +28,9 @@ from src.services.gitea_private_inventory_p0_scorecard import (
|
||||
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_repo_bundle_backup_readback import (
|
||||
load_latest_gitea_repo_bundle_backup_readback,
|
||||
)
|
||||
@@ -101,6 +105,9 @@ def load_latest_gitea_capability_ci_cd_optimization_readback(
|
||||
backup_notification_policy=load_latest_backup_notification_policy(),
|
||||
repo_bundle_backup_readback=load_latest_gitea_repo_bundle_backup_readback(),
|
||||
full_server_backup_dr_receipts=load_latest_gitea_full_server_backup_dr_receipts(),
|
||||
gitea_cicd_alert_receipt_chain_readback=asyncio.run(
|
||||
load_latest_gitea_cicd_alert_receipt_chain_readback()
|
||||
),
|
||||
)
|
||||
_require_payload(payload, "gitea_capability_ci_cd_optimization_readback")
|
||||
return payload
|
||||
@@ -217,6 +224,7 @@ def build_gitea_capability_ci_cd_optimization_readback(
|
||||
backup_notification_policy: dict[str, Any],
|
||||
repo_bundle_backup_readback: dict[str, Any],
|
||||
full_server_backup_dr_receipts: dict[str, Any] | None = None,
|
||||
gitea_cicd_alert_receipt_chain_readback: dict[str, Any] | None = None,
|
||||
generated_at: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Compose Gitea capability coverage and professional CI/CD work items."""
|
||||
@@ -237,6 +245,9 @@ def build_gitea_capability_ci_cd_optimization_readback(
|
||||
full_dr = _dict(full_server_backup_dr_receipts)
|
||||
full_dr_summary = _dict(full_dr.get("summary"))
|
||||
full_dr_gap_ids = _strings(full_dr.get("active_gap_ids"))
|
||||
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"))
|
||||
full_dr_non_restore_gap_ids = [
|
||||
gap for gap in full_dr_gap_ids if gap != "restore_drill_approval_gate"
|
||||
]
|
||||
@@ -513,14 +524,31 @@ def build_gitea_capability_ci_cd_optimization_readback(
|
||||
"observability_alert_receipts",
|
||||
"observability",
|
||||
"CI/CD, backup, and Gitea alert receipt chain",
|
||||
"action_required",
|
||||
"policies exist, but live alert receipt chain must close before calling it complete",
|
||||
"verified_ready" if alert_chain_ready else "action_required",
|
||||
"CI/CD, backup, and Gitea alert receipt chain is verified"
|
||||
if alert_chain_ready
|
||||
else "policies exist, but live alert receipt chain must close before calling it complete",
|
||||
[
|
||||
"GET /api/v1/agents/gitea-cicd-alert-receipt-chain-readback",
|
||||
"GET /api/v1/agents/backup-notification-policy",
|
||||
"GET /api/v1/agents/telegram-alert-monitoring-coverage-readback",
|
||||
],
|
||||
"make backup/CD/Gitea alerts emit verifiable receipt-stage evidence",
|
||||
"keep receipt-stage evidence fresh for backup/CD/Gitea alerts"
|
||||
if alert_chain_ready
|
||||
else "make backup/CD/Gitea alerts emit verifiable receipt-stage evidence",
|
||||
{
|
||||
"alert_receipt_chain_ready": alert_chain_ready,
|
||||
"alert_receipt_chain_status": str(alert_chain.get("status") or ""),
|
||||
"action_required_chain_count": _int(
|
||||
alert_chain_summary.get("action_required_chain_count")
|
||||
),
|
||||
"monitoring_live_receipt_gap_count": _int(
|
||||
alert_chain_summary.get("monitoring_live_receipt_gap_count")
|
||||
),
|
||||
"workflow_notify_bridge_count": _int(
|
||||
alert_chain_summary.get("workflow_notify_bridge_count")
|
||||
),
|
||||
},
|
||||
p0=True,
|
||||
),
|
||||
]
|
||||
|
||||
@@ -103,6 +103,21 @@ def _full_server_dr_payload() -> dict:
|
||||
}
|
||||
|
||||
|
||||
def _alert_receipt_chain_payload() -> dict:
|
||||
return {
|
||||
"schema_version": "gitea_cicd_alert_receipt_chain_readback_v1",
|
||||
"status": "gitea_cicd_alert_receipt_chain_ready",
|
||||
"ready": True,
|
||||
"active_gap_ids": [],
|
||||
"active_gap_count": 0,
|
||||
"summary": {
|
||||
"action_required_chain_count": 0,
|
||||
"monitoring_live_receipt_gap_count": 0,
|
||||
"workflow_notify_bridge_count": 6,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _readback_payload() -> dict:
|
||||
return build_gitea_capability_ci_cd_optimization_readback(
|
||||
dev_prod_repo_readback=json.loads(
|
||||
@@ -116,6 +131,7 @@ def _readback_payload() -> dict:
|
||||
backup_notification_policy=load_latest_backup_notification_policy(),
|
||||
repo_bundle_backup_readback=_repo_bundle_payload(),
|
||||
full_server_backup_dr_receipts=_full_server_dr_payload(),
|
||||
gitea_cicd_alert_receipt_chain_readback=_alert_receipt_chain_payload(),
|
||||
generated_at="2026-07-09T23:01:00+08:00",
|
||||
)
|
||||
|
||||
@@ -128,7 +144,7 @@ def test_gitea_capability_readback_rolls_up_complete_feature_surface() -> None:
|
||||
== "gitea_capability_ci_cd_optimization_readback_v1"
|
||||
)
|
||||
assert payload["source_control_authority"] == "gitea"
|
||||
assert payload["status"] == "gitea_capability_ci_cd_optimization_gaps_present"
|
||||
assert payload["status"] == "gitea_capability_ci_cd_optimization_ready"
|
||||
assert payload["rollups"]["expected_product_count"] == 12
|
||||
assert payload["rollups"]["ssh_verified_product_repo_count"] == 12
|
||||
assert payload["rollups"]["dev_prod_environment_split_ready_count"] == 12
|
||||
@@ -165,7 +181,14 @@ def test_gitea_capability_readback_rolls_up_complete_feature_surface() -> None:
|
||||
assert capability_by_id["backup_dr_restore"]["metrics"][
|
||||
"gitea_full_dr_source_ready_component_count"
|
||||
] == 6
|
||||
assert capability_by_id["observability_alert_receipts"]["status"] == "action_required"
|
||||
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",
|
||||
"action_required_chain_count": 0,
|
||||
"monitoring_live_receipt_gap_count": 0,
|
||||
"workflow_notify_bridge_count": 6,
|
||||
}
|
||||
|
||||
assert payload["operation_boundaries"]["read_only_api_allowed"] is True
|
||||
assert payload["operation_boundaries"]["github_api_allowed"] is False
|
||||
@@ -211,11 +234,10 @@ 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["active_p0_gap_ids"] == ["observability_alert_receipts"]
|
||||
assert any(
|
||||
action.startswith("observability_alert_receipts:")
|
||||
for action in payload["readback"]["safe_next_actions"]
|
||||
)
|
||||
assert payload["status"] == "gitea_capability_ci_cd_optimization_ready"
|
||||
assert payload["ready"] is True
|
||||
assert payload["active_p0_gap_ids"] == []
|
||||
assert payload["readback"]["safe_next_actions"] == []
|
||||
|
||||
|
||||
def test_gitea_capability_readback_endpoint_returns_payload(monkeypatch) -> None:
|
||||
|
||||
@@ -50,8 +50,13 @@ def test_product_awoooi_manifest_standard_endpoint_returns_snapshot():
|
||||
|
||||
def test_api_image_copies_product_manifest() -> None:
|
||||
dockerfile = Path(__file__).resolve().parents[3] / "apps" / "api" / "Dockerfile"
|
||||
dockerfile_text = dockerfile.read_text(encoding="utf-8")
|
||||
|
||||
assert (
|
||||
"COPY --chown=appuser:appuser product.awoooi.yaml ./product.awoooi.yaml"
|
||||
in dockerfile.read_text(encoding="utf-8")
|
||||
in dockerfile_text
|
||||
)
|
||||
assert (
|
||||
"COPY --chown=appuser:appuser .gitea/workflows/ ./.gitea/workflows/"
|
||||
in dockerfile_text
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user