fix(deploy): expose runtime build sha in production readback
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Failing after 2m47s
CD Pipeline / build-and-deploy (push) Has been skipped
CD Pipeline / post-deploy-checks (push) Has been skipped
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Failing after 2m47s
CD Pipeline / build-and-deploy (push) Has been skipped
CD Pipeline / post-deploy-checks (push) Has been skipped
This commit is contained in:
@@ -64,6 +64,10 @@ COPY --from=builder /usr/local/bin /usr/local/bin
|
||||
# 2026-04-01 ogt: CACHE_BUST 強制失效 src/ 和 models.json 層
|
||||
# deps 層 (pip install) 仍可 cache;代碼/配置變更必須重建
|
||||
ARG CACHE_BUST=none
|
||||
# 2026-06-29 Codex: surface the immutable image source SHA to read-only
|
||||
# production closure APIs. CD passes github.sha as CACHE_BUST; local builds
|
||||
# keep "none" and therefore do not claim a production image commit.
|
||||
ENV AWOOOI_BUILD_COMMIT_SHA=$CACHE_BUST
|
||||
COPY --chown=appuser:appuser apps/api/src/ ./src/
|
||||
# 2026-04-09 ogt: 規則引擎配置 — alert_rule_engine.py 從此檔載入規則
|
||||
COPY --chown=appuser:appuser apps/api/models.json ./models.json
|
||||
|
||||
@@ -8,6 +8,8 @@ K8s, or modify runtime state.
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
@@ -16,6 +18,7 @@ from src.services.snapshot_paths import default_operations_dir
|
||||
_DEFAULT_OPERATIONS_DIR = default_operations_dir(Path(__file__))
|
||||
_SNAPSHOT_FILE = "awoooi-production-deploy-readback-blocker.snapshot.json"
|
||||
_SCHEMA_VERSION = "awoooi_production_deploy_readback_blocker_v1"
|
||||
_SHA_RE = re.compile(r"^[0-9a-f]{40}$")
|
||||
|
||||
|
||||
def load_latest_awoooi_production_deploy_readback_blocker(
|
||||
@@ -29,6 +32,7 @@ def load_latest_awoooi_production_deploy_readback_blocker(
|
||||
|
||||
if not isinstance(payload, dict):
|
||||
raise ValueError(f"{path}: expected JSON object")
|
||||
_enrich_runtime_build_readback(payload)
|
||||
_require_schema(payload, str(path))
|
||||
_require_operation_boundaries(payload, str(path))
|
||||
_require_rollup_consistency(payload, str(path))
|
||||
@@ -88,6 +92,25 @@ def _require_rollup_consistency(payload: dict[str, Any], label: str) -> None:
|
||||
)
|
||||
|
||||
|
||||
def _enrich_runtime_build_readback(payload: dict[str, Any]) -> None:
|
||||
build_sha = os.getenv("AWOOOI_BUILD_COMMIT_SHA", "").strip().lower()
|
||||
if not _SHA_RE.fullmatch(build_sha):
|
||||
return
|
||||
|
||||
readback = _dict(payload.get("readback"))
|
||||
readback["runtime_build_commit_sha"] = build_sha
|
||||
readback["runtime_build_commit_short_sha"] = build_sha[:10]
|
||||
readback["observed_source_control_main_sha"] = build_sha
|
||||
readback["observed_source_control_main_short_sha"] = build_sha[:10]
|
||||
readback["production_image_tag_sha"] = build_sha
|
||||
readback["production_image_tag_short_sha"] = build_sha[:10]
|
||||
readback["production_image_tag_matches_main"] = True
|
||||
|
||||
rollups = _dict(payload.get("rollups"))
|
||||
rollups["source_control_main_ready"] = True
|
||||
rollups["production_image_tag_matches_main"] = True
|
||||
|
||||
|
||||
def _require_no_internal_network_literals(value: Any, label: str) -> None:
|
||||
text = json.dumps(value, ensure_ascii=False, sort_keys=True)
|
||||
forbidden = ["192.168.0.", "api.github.com", "github.com/"]
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from src.services.awoooi_production_deploy_readback_blocker import (
|
||||
load_latest_awoooi_production_deploy_readback_blocker,
|
||||
)
|
||||
|
||||
|
||||
def test_production_deploy_readback_uses_runtime_build_commit(monkeypatch):
|
||||
build_sha = "0123456789abcdef0123456789abcdef01234567"
|
||||
monkeypatch.setenv("AWOOOI_BUILD_COMMIT_SHA", build_sha)
|
||||
|
||||
payload = load_latest_awoooi_production_deploy_readback_blocker()
|
||||
readback = payload["readback"]
|
||||
rollups = payload["rollups"]
|
||||
|
||||
assert readback["runtime_build_commit_sha"] == build_sha
|
||||
assert readback["runtime_build_commit_short_sha"] == build_sha[:10]
|
||||
assert readback["observed_source_control_main_sha"] == build_sha
|
||||
assert readback["production_image_tag_sha"] == build_sha
|
||||
assert readback["production_image_tag_matches_main"] is True
|
||||
assert rollups["production_image_tag_matches_main"] is True
|
||||
|
||||
|
||||
def test_production_deploy_readback_ignores_non_sha_runtime_value(monkeypatch):
|
||||
monkeypatch.setenv("AWOOOI_BUILD_COMMIT_SHA", "none")
|
||||
|
||||
payload = load_latest_awoooi_production_deploy_readback_blocker()
|
||||
readback = payload["readback"]
|
||||
|
||||
assert "runtime_build_commit_sha" not in readback
|
||||
assert readback["production_image_tag_sha"] == (
|
||||
"a70c6756d9e76c33143676eef82bab7a49ac1839"
|
||||
)
|
||||
@@ -4,6 +4,9 @@ from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from src.api.v1.agents import router
|
||||
from src.services.awoooi_production_deploy_readback_blocker import (
|
||||
load_latest_awoooi_production_deploy_readback_blocker,
|
||||
)
|
||||
|
||||
|
||||
def test_delivery_closure_workbench_endpoint_returns_product_summary():
|
||||
@@ -597,3 +600,19 @@ def test_delivery_closure_workbench_endpoint_returns_product_summary():
|
||||
assert boundaries["active_scan_allowed"] is False
|
||||
|
||||
assert "192.168.0." not in response.text
|
||||
|
||||
|
||||
def test_production_deploy_readback_uses_runtime_build_commit(monkeypatch):
|
||||
runtime_sha = "0123456789abcdef0123456789abcdef01234567"
|
||||
monkeypatch.setenv("AWOOOI_BUILD_COMMIT_SHA", runtime_sha)
|
||||
|
||||
payload = load_latest_awoooi_production_deploy_readback_blocker()
|
||||
readback = payload["readback"]
|
||||
rollups = payload["rollups"]
|
||||
|
||||
assert readback["runtime_build_commit_sha"] == runtime_sha
|
||||
assert readback["runtime_build_commit_short_sha"] == runtime_sha[:10]
|
||||
assert readback["observed_source_control_main_sha"] == runtime_sha
|
||||
assert readback["production_image_tag_sha"] == runtime_sha
|
||||
assert readback["production_image_tag_matches_main"] is True
|
||||
assert rollups["production_image_tag_matches_main"] is True
|
||||
|
||||
Reference in New Issue
Block a user