fix(automation): enforce durable alert closure
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m32s
CD Pipeline / build-and-deploy (push) Successful in 8m2s
CD Pipeline / post-deploy-checks (push) Successful in 2m22s

Restore D037 durable incident readback without weakening database failure semantics.

Fence Agent99 dispatch and terminal learning to canonical identities, durable leases, verifier receipts, and reconciler-owned checkpoints.

Drain backup and restore legacy receipts in bounded cohorts with strict transport, claim, projection, and no-false-green controls.

Keep SSH service refusal visible while separating it from broker network-policy reachability.
This commit is contained in:
ogt
2026-07-14 09:40:53 +08:00
parent 72a167a322
commit 6cf8429d17
56 changed files with 15100 additions and 227 deletions

View File

@@ -22,7 +22,7 @@ C-Suite 戰略會議決議 (2026-03-22):
from datetime import datetime, timezone
from enum import Enum
from typing import Literal
from typing import Literal, cast, get_args
from uuid import UUID, uuid4
from pydantic import BaseModel, Field, field_validator
@@ -70,6 +70,33 @@ class IncidentStatus(str, Enum):
ESCALATED = "escalated" # 已升級 - 需要人工介入
# Signal sources are a durable contract: values written by the host sensor and
# the public signal ingress can remain in PostgreSQL long after a producer is
# upgraded. Keep this list bounded, but include every repo-owned producer
# vocabulary instead of silently rewriting provenance during readback.
SignalSource = Literal[
"prometheus",
"signoz",
"alertmanager",
"manual",
"telegram",
"journal",
"node-exporter",
"sensor-probe",
"sensor-agent",
]
SIGNAL_SOURCE_VALUES: frozenset[str] = frozenset(get_args(SignalSource))
def parse_signal_source(value: object) -> SignalSource:
"""Return a canonical known source or reject an unowned durable value."""
normalized = str(value or "").strip().lower()
if normalized not in SIGNAL_SOURCE_VALUES:
raise ValueError("unsupported_signal_source")
return cast(SignalSource, normalized)
# =============================================================================
# Signal (原始告警)
# =============================================================================
@@ -89,9 +116,7 @@ class Signal(BaseModel):
)
alert_name: str = Field(..., description="告警名稱 (如 HighCPUUsage)")
severity: Severity = Field(..., description="告警嚴重度")
source: Literal["prometheus", "signoz", "alertmanager", "manual", "telegram"] = (
Field(..., description="告警來源")
)
source: SignalSource = Field(..., description="告警來源")
fired_at: datetime = Field(..., description="告警觸發時間")
resolved_at: datetime | None = Field(None, description="告警解除時間")
labels: dict[str, str] = Field(
@@ -107,9 +132,26 @@ class Signal(BaseModel):
description="告警指紋 Hash用於去重與聚合",
)
@field_validator("source", mode="before")
@classmethod
def validate_source(cls, value: object) -> SignalSource:
return parse_signal_source(value)
# [首席架構師] 移除 json_encoders (Pydantic v2 已 deprecated),原生序列化輸出格式與 .isoformat() 一致 v1.1 2026-04-01 Asia/Taipei
class IncidentReadDegradation(BaseModel):
"""Public-safe metadata for one durable row excluded from a response."""
incident_id: str
reason_code: Literal[
"incident_signal_source_unsupported",
"incident_signal_schema_invalid",
"incident_record_schema_invalid",
]
quarantined_from_response: bool = True
# =============================================================================
# AI Decision Chain (CISO 要求:可稽核性)
# =============================================================================