feat(security): expand canonical asset coverage
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 4m3s
CD Pipeline / build-and-deploy (push) Failing after 10m5s
CD Pipeline / post-deploy-checks (push) Has been skipped

This commit is contained in:
ogt
2026-07-14 12:42:33 +08:00
parent 36778b35df
commit d734362768
7 changed files with 1134 additions and 130 deletions

View File

@@ -28,7 +28,7 @@ type Copy = {
title: string;
live: string;
degraded: string;
assets: string;
overall: string;
assetTypes: string;
nist: string;
siem: string;
@@ -60,7 +60,7 @@ const COPY: Record<"zh" | "en", Copy> = {
title: "AI 資安控制平面",
live: "LIVE",
degraded: "DEGRADED",
assets: "納管資產",
overall: "整體完成度",
assetTypes: "資產類型",
nist: "NIST 控制",
siem: "SIEM 閉環",
@@ -90,7 +90,7 @@ const COPY: Record<"zh" | "en", Copy> = {
title: "AI Security Control Plane",
live: "LIVE",
degraded: "DEGRADED",
assets: "Managed assets",
overall: "Overall completion",
assetTypes: "Asset types",
nist: "NIST control",
siem: "SIEM closure",
@@ -327,8 +327,12 @@ export function SecurityAssetControlPlaneCockpit({
</button>
</div>
<div className="grid gap-px bg-[#d8d3c7] sm:grid-cols-3 lg:grid-cols-6">
<MetricCell label={copy.assets} value={payload?.summary.managed_asset_count ?? "--"} icon={Boxes} />
<div className="grid grid-cols-2 gap-px bg-[#d8d3c7] sm:grid-cols-3 lg:grid-cols-6">
<MetricCell
label={copy.overall}
value={payload ? `${payload.summary.overall_security_completion_percent}%` : "--"}
icon={ShieldCheck}
/>
<MetricCell
label={copy.assetTypes}
value={payload ? `${payload.summary.asset_type_coverage_percent}%` : "--"}

View File

@@ -35,6 +35,7 @@ function payload(): SecurityAssetControlPlanePayload {
security_program_domain_count: 16,
security_program_controlled_domain_count: 9,
security_program_controlled_percent: 68,
overall_security_completion_percent: 70,
siem_stage_count: 8,
siem_observed_stage_count: 8,
siem_stage_coverage_percent: 100,
@@ -61,6 +62,20 @@ function payload(): SecurityAssetControlPlanePayload {
asset_scopes: [],
nist_csf_functions: [],
security_program_domains: [],
completion: {
method: "equal_weighted_runtime_conservative_v1",
dimension_count: 6,
overall_percent: 70,
strict_runtime_closure_percent: 0,
dimensions: [
{ dimension_id: "asset_scope", completion_percent: 71 },
{ dimension_id: "nist_control", completion_percent: 82 },
{ dimension_id: "security_program", completion_percent: 68 },
{ dimension_id: "siem_pipeline", completion_percent: 100 },
{ dimension_id: "ai_loop_stages", completion_percent: 100 },
{ dimension_id: "strict_same_run_runtime_closure", completion_percent: 0 },
],
},
siem: { pipeline: [] },
ai_automation: {
stages: [],

View File

@@ -22,6 +22,7 @@ export type SecurityControlPlaneSummary = {
security_program_domain_count: number;
security_program_controlled_domain_count: number;
security_program_controlled_percent: number;
overall_security_completion_percent: number;
siem_stage_count: number;
siem_observed_stage_count: number;
siem_stage_coverage_percent: number;
@@ -99,6 +100,16 @@ export type SecurityAssetControlPlanePayload = {
evidence_count: number;
gap_code: string | null;
}>;
completion: {
method: "equal_weighted_runtime_conservative_v1";
dimension_count: number;
overall_percent: number;
strict_runtime_closure_percent: number;
dimensions: Array<{
dimension_id: string;
completion_percent: number;
}>;
};
siem: {
pipeline: SecurityControlPlaneStage[];
incident_total_24h?: number;
@@ -172,6 +183,10 @@ export function isSecurityAssetControlPlanePayload(
typeof value.summary.source_count === "number" &&
Array.isArray(value.source_health) &&
typeof value.summary.nist_controlled_percent === "number" &&
typeof value.summary.overall_security_completion_percent === "number" &&
isRecord(value.completion) &&
value.completion.method === "equal_weighted_runtime_conservative_v1" &&
Array.isArray(value.completion.dimensions) &&
value.boundaries.aggregate_only === true &&
value.boundaries.raw_asset_identity_returned === false &&
value.boundaries.raw_event_payload_returned === false &&