fix(iwooos): project strict runtime 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 2m36s
CD Pipeline / build-and-deploy (push) Successful in 15m32s
CD Pipeline / post-deploy-checks (push) Successful in 1m58s

This commit is contained in:
ogt
2026-07-15 14:15:36 +08:00
parent bdb97afc5b
commit 7f504ca52e
7 changed files with 493 additions and 19 deletions

View File

@@ -36,7 +36,7 @@ type Copy = {
assetTypes: string;
nist: string;
siem: string;
aiLoop: string;
strictRun: string;
verified: string;
functions: string;
framework: string;
@@ -70,6 +70,7 @@ type Copy = {
failedCollectors: string;
failedCollectorsUnavailable: string;
sameRunMissing: string;
sameRunVerified: string;
loading: string;
unavailable: string;
refresh: string;
@@ -87,7 +88,7 @@ const COPY: Record<"zh" | "en", Copy> = {
assetTypes: "資產類型",
nist: "NIST 控制",
siem: "SIEM 閉環",
aiLoop: "AI 閉環",
strictRun: "同 run 閉環",
verified: "24h 已驗證",
functions: "治理六功能",
framework: "完整資安框架",
@@ -121,6 +122,7 @@ const COPY: Record<"zh" | "en", Copy> = {
failedCollectors: "失敗 Collector",
failedCollectorsUnavailable: "失敗原因待安全分類",
sameRunMissing: "尚無同 run 閉環證據",
sameRunVerified: "18 段同 run 閉環已驗證",
loading: "正在載入資安控制平面",
unavailable: "Live readback 無法取得",
refresh: "重新整理資安控制平面",
@@ -136,7 +138,7 @@ const COPY: Record<"zh" | "en", Copy> = {
assetTypes: "Asset types",
nist: "NIST control",
siem: "SIEM closure",
aiLoop: "AI closure",
strictRun: "Same-run closure",
verified: "Verified 24h",
functions: "Six functions",
framework: "Security framework",
@@ -170,6 +172,7 @@ const COPY: Record<"zh" | "en", Copy> = {
failedCollectors: "Failed collectors",
failedCollectorsUnavailable: "Failure detail awaiting safe classification",
sameRunMissing: "No same-run closure evidence",
sameRunVerified: "18-stage same-run closure verified",
loading: "Loading security control plane",
unavailable: "Live readback unavailable",
refresh: "Refresh security control plane",
@@ -557,10 +560,10 @@ export function SecurityAssetControlPlaneCockpit({
icon={Radar}
/>
<MetricCell
label={copy.aiLoop}
label={copy.strictRun}
value={
payload
? `${payload.summary.ai_loop_observed_stage_count}/${payload.summary.ai_loop_stage_count}`
? `${payload.ai_automation.strict_runtime_completion.present_stage_count}/${payload.ai_automation.strict_runtime_completion.required_stage_count}`
: "--"
}
icon={Bot}
@@ -986,7 +989,15 @@ export function SecurityAssetControlPlaneCockpit({
/>
{copy.sameRunMissing}
</div>
) : null}
) : (
<div className="mt-3 flex items-center gap-1.5 border-t border-[#ebe8df] pt-2 text-[10px] font-medium text-[#17602a]">
<CheckCircle2
className="h-3.5 w-3.5 shrink-0"
aria-hidden="true"
/>
{copy.sameRunVerified}
</div>
)}
</div>
<div className="border border-[#d8d3c7] bg-white p-3">

View File

@@ -14,8 +14,8 @@ function payload(): SecurityAssetControlPlanePayload {
status: "ready",
source_status: "live_database_aggregate",
summary: {
source_count: 9,
ready_source_count: 9,
source_count: 10,
ready_source_count: 10,
unavailable_source_count: 0,
managed_asset_count: 24,
expected_asset_type_count: 28,
@@ -97,6 +97,24 @@ function payload(): SecurityAssetControlPlanePayload {
failed_operation_count: 0,
same_run_closed_loop_proven: false,
same_run_closed_loop_count: 0,
strict_runtime_completion: {
schema_version: "ai_agent_strict_runtime_completion_v2",
runtime_contract_schema_version:
"ai_automation_runtime_completion_contract_v2",
contract_compatible: true,
completion_percent: 0,
required_stage_count: 18,
present_stage_count: 17,
missing_stage_count: 1,
same_run_correlation: false,
full_trace_same_run_correlation_proven: false,
execution_loop_closed: false,
closed: false,
reason_code: "strict_runtime_receipts_incomplete",
cache_fallback_active: false,
raw_run_identity_returned: false,
raw_stage_receipts_returned: false,
},
},
security_audit: {
k8s_execution_audit_count_24h: 2,
@@ -222,6 +240,20 @@ describe("security asset control plane projection", () => {
expect(isSecurityAssetControlPlanePayload(unsafeCollectorIdentity)).toBe(
false,
);
const inconsistentStrictRuntime = {
...safe,
ai_automation: {
...safe.ai_automation,
strict_runtime_completion: {
...safe.ai_automation.strict_runtime_completion,
closed: true,
},
},
};
expect(isSecurityAssetControlPlanePayload(inconsistentStrictRuntime)).toBe(
false,
);
});
it("does not show healthy before same-run closure is proven", () => {

View File

@@ -119,6 +119,24 @@ export type SecurityControlPlaneCertificateInventory = {
private_key_material_read: false;
};
export type SecurityStrictRuntimeCompletion = {
schema_version: "ai_agent_strict_runtime_completion_v2";
runtime_contract_schema_version: "ai_automation_runtime_completion_contract_v2";
contract_compatible: boolean;
completion_percent: number;
required_stage_count: number;
present_stage_count: number;
missing_stage_count: number;
same_run_correlation: boolean;
full_trace_same_run_correlation_proven: boolean;
execution_loop_closed: boolean;
closed: boolean;
reason_code: string | null;
cache_fallback_active: boolean;
raw_run_identity_returned: false;
raw_stage_receipts_returned: false;
};
export type SecurityAssetControlPlanePayload = {
schema_version: "iwooos_security_asset_control_plane_v1";
generated_at: string;
@@ -181,6 +199,7 @@ export type SecurityAssetControlPlanePayload = {
failed_operation_count: number;
same_run_closed_loop_proven: boolean;
same_run_closed_loop_count: number;
strict_runtime_completion: SecurityStrictRuntimeCompletion;
};
security_audit: {
k8s_execution_audit_count_24h: number;
@@ -255,6 +274,44 @@ export function isSecurityAssetControlPlanePayload(
) {
return false;
}
const strictRuntime = value.ai_automation.strict_runtime_completion;
if (
!isRecord(strictRuntime) ||
strictRuntime.schema_version !== "ai_agent_strict_runtime_completion_v2" ||
strictRuntime.runtime_contract_schema_version !==
"ai_automation_runtime_completion_contract_v2" ||
typeof strictRuntime.contract_compatible !== "boolean" ||
typeof strictRuntime.completion_percent !== "number" ||
typeof strictRuntime.required_stage_count !== "number" ||
typeof strictRuntime.present_stage_count !== "number" ||
typeof strictRuntime.missing_stage_count !== "number" ||
typeof strictRuntime.same_run_correlation !== "boolean" ||
typeof strictRuntime.full_trace_same_run_correlation_proven !== "boolean" ||
typeof strictRuntime.execution_loop_closed !== "boolean" ||
typeof strictRuntime.closed !== "boolean" ||
typeof strictRuntime.cache_fallback_active !== "boolean" ||
!(
strictRuntime.reason_code === null ||
typeof strictRuntime.reason_code === "string"
) ||
strictRuntime.raw_run_identity_returned !== false ||
strictRuntime.raw_stage_receipts_returned !== false ||
strictRuntime.required_stage_count !== 18 ||
strictRuntime.present_stage_count < 0 ||
strictRuntime.present_stage_count > strictRuntime.required_stage_count ||
strictRuntime.missing_stage_count !==
strictRuntime.required_stage_count - strictRuntime.present_stage_count ||
value.ai_automation.same_run_closed_loop_proven !== strictRuntime.closed ||
(strictRuntime.closed &&
(!strictRuntime.contract_compatible ||
strictRuntime.completion_percent !== 100 ||
!strictRuntime.same_run_correlation ||
!strictRuntime.full_trace_same_run_correlation_proven ||
!strictRuntime.execution_loop_closed)) ||
(!strictRuntime.closed && strictRuntime.completion_percent !== 0)
) {
return false;
}
if (value.supply_chain !== undefined) {
if (!isRecord(value.supply_chain)) return false;
if (