80 lines
3.1 KiB
Bash
Executable File
80 lines
3.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||
ARTIFACT_SUMMARY_PATH="${ARTIFACT_SUMMARY_PATH:-$ROOT_DIR/artifacts/v3-governance-live/20260608_102323/99-summary.json}"
|
||
|
||
fail() {
|
||
echo "FAIL: $*" >&2
|
||
exit 1
|
||
}
|
||
|
||
log() {
|
||
echo "==> $*"
|
||
}
|
||
|
||
require_file() {
|
||
local path="$1"
|
||
[[ -f "$path" ]] || fail "missing required file: $path"
|
||
}
|
||
|
||
require_contains() {
|
||
local path="$1"
|
||
local needle="$2"
|
||
grep -F "$needle" "$path" >/dev/null || fail "missing expected text in $path: $needle"
|
||
}
|
||
|
||
log "checking V3-2 source-of-truth files"
|
||
require_file "$ROOT_DIR/docs/2026-06-04-SLO_AND_OBSERVABILITY.md"
|
||
require_file "$ROOT_DIR/docs/2026-06-04-KEY_ACCOUNT_GOVERNANCE.md"
|
||
require_file "$ROOT_DIR/docs/EXECUTION_BOARD.md"
|
||
require_file "$ROOT_DIR/deploy/monitoring/prometheus-rules.yml"
|
||
require_file "$ARTIFACT_SUMMARY_PATH"
|
||
|
||
log "checking metrics wiring truth"
|
||
require_contains "$ROOT_DIR/internal/metrics/metrics.go" 'Name: "user_key_operations_total"'
|
||
require_contains "$ROOT_DIR/internal/metrics/metrics.go" 'Name: "user_key_chat_requests_total"'
|
||
require_contains "$ROOT_DIR/internal/metrics/metrics.go" 'statusLabel := strconv.Itoa(status)'
|
||
require_contains "$ROOT_DIR/internal/app/route_resolve_api.go" 'decisionStatus = "failover"'
|
||
require_contains "$ROOT_DIR/internal/app/key_self_service_svc.go" 'recordUserKeyFailure("create", "resolve_host_error"'
|
||
require_contains "$ROOT_DIR/internal/app/key_self_service_svc.go" 'recordUserKeyFailure("delete", "get_key_error"'
|
||
|
||
log "checking alert rule alignment"
|
||
require_contains "$ROOT_DIR/deploy/monitoring/prometheus-rules.yml" 'user_key_chat_requests_total{result="ok"}'
|
||
require_contains "$ROOT_DIR/deploy/monitoring/prometheus-rules.yml" 'user_key_operations_total{operation="create",result!~"success|rate_limited"}'
|
||
require_contains "$ROOT_DIR/deploy/monitoring/prometheus-rules.yml" 'route_decisions_total{status="failover"}'
|
||
require_contains "$ROOT_DIR/deploy/monitoring/prometheus-rules.yml" 'http_requests_total{status=~"4..|5.."}'
|
||
|
||
log "checking live governance artifact"
|
||
python3 - "$ARTIFACT_SUMMARY_PATH" <<'PY'
|
||
import json, sys
|
||
from pathlib import Path
|
||
p = Path(sys.argv[1])
|
||
obj = json.loads(p.read_text())
|
||
checks = {
|
||
'create_http': 201,
|
||
'chat_before_http': 200,
|
||
'pause_http': 200,
|
||
'get_paused_http': 200,
|
||
'chat_paused_http': 403,
|
||
'resume_http': 200,
|
||
'get_resumed_http': 200,
|
||
'chat_resumed_http': 200,
|
||
'delete_http': 200,
|
||
}
|
||
for key, want in checks.items():
|
||
got = obj.get(key)
|
||
if got != want:
|
||
raise SystemExit(f'{key}={got!r}, want {want!r}')
|
||
paused_body = obj.get('chat_paused_body', '')
|
||
if 'key_paused' not in paused_body:
|
||
raise SystemExit('chat_paused_body missing key_paused evidence')
|
||
print(json.dumps({'artifact': str(p), 'checks': checks, 'paused_error': 'key_paused'}, ensure_ascii=False, indent=2))
|
||
PY
|
||
|
||
log "checking docs mention V3-2 closure state"
|
||
require_contains "$ROOT_DIR/docs/EXECUTION_BOARD.md" 'V3-2 SLO / 观测最小闭环(2026-06-08 首批)'
|
||
require_contains "$ROOT_DIR/docs/EXECUTION_BOARD.md" '失败路径细化、告警规则、发布门禁均已落地'
|
||
|
||
echo 'PASS: V3-2 SLO release gate verified'
|