feat(iwooos): add live security control plane
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 2m22s
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled
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 2m22s
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled
This commit is contained in:
135
apps/web/src/lib/__tests__/security-asset-control-plane.test.ts
Normal file
135
apps/web/src/lib/__tests__/security-asset-control-plane.test.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
isSecurityAssetControlPlanePayload,
|
||||
securityControlPlaneTone,
|
||||
topSecurityControlPlaneWorkItems,
|
||||
type SecurityAssetControlPlanePayload,
|
||||
} from "../security-asset-control-plane";
|
||||
|
||||
function payload(): SecurityAssetControlPlanePayload {
|
||||
return {
|
||||
schema_version: "iwooos_security_asset_control_plane_v1",
|
||||
generated_at: "2026-07-11T04:00:00+00:00",
|
||||
status: "ready",
|
||||
source_status: "live_database_aggregate",
|
||||
summary: {
|
||||
managed_asset_count: 24,
|
||||
expected_asset_type_count: 28,
|
||||
present_asset_type_count: 20,
|
||||
asset_type_coverage_percent: 71,
|
||||
scope_count: 6,
|
||||
controlled_scope_count: 3,
|
||||
unowned_asset_count: 0,
|
||||
stale_asset_count: 0,
|
||||
orphan_asset_count: 0,
|
||||
relationship_count: 40,
|
||||
automation_coverage_green_percent: 85,
|
||||
automation_coverage_unknown_count: 0,
|
||||
compliance_violation_count: 0,
|
||||
compliance_unknown_count: 0,
|
||||
nist_controlled_percent: 82,
|
||||
siem_stage_count: 8,
|
||||
siem_observed_stage_count: 8,
|
||||
siem_stage_coverage_percent: 100,
|
||||
ai_loop_stage_count: 7,
|
||||
ai_loop_observed_stage_count: 7,
|
||||
ai_loop_stage_coverage_percent: 100,
|
||||
verified_remediation_receipt_count_24h: 2,
|
||||
active_work_item_count: 2,
|
||||
},
|
||||
discovery: {
|
||||
latest_status: "success",
|
||||
latest_success_at: "2026-07-11T03:50:00+00:00",
|
||||
age_seconds: 600,
|
||||
freshness_slo_seconds: 7200,
|
||||
fresh: true,
|
||||
},
|
||||
asset_scopes: [],
|
||||
nist_csf_functions: [],
|
||||
siem: { pipeline: [] },
|
||||
ai_automation: {
|
||||
stages: [],
|
||||
aggregate_stage_coverage_percent: 100,
|
||||
accepted_ai_trace_count: 2,
|
||||
verified_remediation_receipt_count: 2,
|
||||
rollback_receipt_count: 0,
|
||||
failed_operation_count: 0,
|
||||
same_run_closed_loop_proven: false,
|
||||
same_run_closed_loop_count: 0,
|
||||
},
|
||||
security_audit: {
|
||||
k8s_execution_audit_count_24h: 2,
|
||||
k8s_execution_failure_count_24h: 0,
|
||||
mcp_tool_audit_count_24h: 4,
|
||||
mcp_tool_failure_count_24h: 0,
|
||||
asset_change_event_count_24h: 3,
|
||||
automation_operation_count_24h: 12,
|
||||
automation_failure_count_24h: 0,
|
||||
ai_trace_count_24h: 4,
|
||||
accepted_ai_trace_count_24h: 2,
|
||||
immutable_external_audit_store_evidenced: false,
|
||||
},
|
||||
work_items: [
|
||||
{
|
||||
work_item_id: "AIA-P1-001-01",
|
||||
priority: "P1",
|
||||
control_id: "audit",
|
||||
title: "audit",
|
||||
gap_count: 1,
|
||||
status: "open",
|
||||
next_action: "audit",
|
||||
},
|
||||
{
|
||||
work_item_id: "AIA-P0-007-01",
|
||||
priority: "P0",
|
||||
control_id: "siem",
|
||||
title: "siem",
|
||||
gap_count: 2,
|
||||
status: "open",
|
||||
next_action: "siem",
|
||||
},
|
||||
],
|
||||
boundaries: {
|
||||
aggregate_only: true,
|
||||
raw_asset_identity_returned: false,
|
||||
raw_event_payload_returned: false,
|
||||
secret_value_collection_allowed: false,
|
||||
live_scan_triggered: false,
|
||||
runtime_action_triggered: false,
|
||||
completion_requires_same_run_receipts: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe("security asset control plane projection", () => {
|
||||
it("accepts only the public-safe aggregate contract", () => {
|
||||
const safe = payload();
|
||||
expect(isSecurityAssetControlPlanePayload(safe)).toBe(true);
|
||||
|
||||
const unsafe = {
|
||||
...safe,
|
||||
boundaries: { ...safe.boundaries, raw_asset_identity_returned: true },
|
||||
};
|
||||
expect(isSecurityAssetControlPlanePayload(unsafe)).toBe(false);
|
||||
});
|
||||
|
||||
it("does not show healthy before same-run closure is proven", () => {
|
||||
const value = payload();
|
||||
expect(securityControlPlaneTone(value)).toBe("warning");
|
||||
|
||||
value.ai_automation.same_run_closed_loop_proven = true;
|
||||
expect(securityControlPlaneTone(value)).toBe("healthy");
|
||||
|
||||
value.discovery.fresh = false;
|
||||
expect(securityControlPlaneTone(value)).toBe("critical");
|
||||
});
|
||||
|
||||
it("keeps P0 work ahead of P1 regardless of API order", () => {
|
||||
const items = topSecurityControlPlaneWorkItems(payload(), 2);
|
||||
expect(items.map((item) => item.work_item_id)).toEqual([
|
||||
"AIA-P0-007-01",
|
||||
"AIA-P1-001-01",
|
||||
]);
|
||||
});
|
||||
});
|
||||
190
apps/web/src/lib/security-asset-control-plane.ts
Normal file
190
apps/web/src/lib/security-asset-control-plane.ts
Normal file
@@ -0,0 +1,190 @@
|
||||
export type SecurityControlStatus = "ready" | "degraded";
|
||||
|
||||
export type SecurityControlPlaneSummary = {
|
||||
managed_asset_count: number;
|
||||
expected_asset_type_count: number;
|
||||
present_asset_type_count: number;
|
||||
asset_type_coverage_percent: number;
|
||||
scope_count: number;
|
||||
controlled_scope_count: number;
|
||||
unowned_asset_count: number;
|
||||
stale_asset_count: number;
|
||||
orphan_asset_count: number;
|
||||
relationship_count: number;
|
||||
automation_coverage_green_percent: number;
|
||||
automation_coverage_unknown_count: number;
|
||||
compliance_violation_count: number;
|
||||
compliance_unknown_count: number;
|
||||
nist_controlled_percent: number;
|
||||
siem_stage_count: number;
|
||||
siem_observed_stage_count: number;
|
||||
siem_stage_coverage_percent: number;
|
||||
ai_loop_stage_count: number;
|
||||
ai_loop_observed_stage_count: number;
|
||||
ai_loop_stage_coverage_percent: number;
|
||||
verified_remediation_receipt_count_24h: number;
|
||||
active_work_item_count: number;
|
||||
};
|
||||
|
||||
export type SecurityControlPlaneFunction = {
|
||||
function_id: string;
|
||||
label: string;
|
||||
controlled_percent: number;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type SecurityControlPlaneStage = {
|
||||
stage_id: string;
|
||||
label: string;
|
||||
status: "observed" | "missing";
|
||||
evidence_count_24h?: number;
|
||||
receipt_count_24h?: number;
|
||||
};
|
||||
|
||||
export type SecurityControlPlaneScope = {
|
||||
scope_id: string;
|
||||
label: string;
|
||||
managed_asset_count: number;
|
||||
expected_type_count: number;
|
||||
present_type_count: number;
|
||||
missing_type_count: number;
|
||||
type_coverage_percent: number;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type SecurityControlPlaneWorkItem = {
|
||||
work_item_id: string;
|
||||
priority: string;
|
||||
control_id: string;
|
||||
title: string;
|
||||
gap_count: number;
|
||||
status: string;
|
||||
next_action: string;
|
||||
};
|
||||
|
||||
export type SecurityAssetControlPlanePayload = {
|
||||
schema_version: "iwooos_security_asset_control_plane_v1";
|
||||
generated_at: string;
|
||||
status: SecurityControlStatus;
|
||||
source_status: string;
|
||||
reason_code?: string;
|
||||
summary: SecurityControlPlaneSummary;
|
||||
discovery: {
|
||||
latest_status: string;
|
||||
latest_success_at: string | null;
|
||||
age_seconds: number | null;
|
||||
freshness_slo_seconds: number;
|
||||
fresh: boolean;
|
||||
};
|
||||
asset_scopes: SecurityControlPlaneScope[];
|
||||
nist_csf_functions: SecurityControlPlaneFunction[];
|
||||
siem: {
|
||||
pipeline: SecurityControlPlaneStage[];
|
||||
incident_total_24h?: number;
|
||||
open_incident_count_24h?: number;
|
||||
resolved_incident_count_24h?: number;
|
||||
noisy_rule_count?: number;
|
||||
mean_time_to_resolve_minutes_24h?: number | null;
|
||||
};
|
||||
ai_automation: {
|
||||
stages: SecurityControlPlaneStage[];
|
||||
aggregate_stage_coverage_percent: number;
|
||||
accepted_ai_trace_count: number;
|
||||
verified_remediation_receipt_count: number;
|
||||
rollback_receipt_count: number;
|
||||
failed_operation_count: number;
|
||||
same_run_closed_loop_proven: boolean;
|
||||
same_run_closed_loop_count: number;
|
||||
};
|
||||
security_audit: {
|
||||
k8s_execution_audit_count_24h: number;
|
||||
k8s_execution_failure_count_24h: number;
|
||||
mcp_tool_audit_count_24h: number;
|
||||
mcp_tool_failure_count_24h: number;
|
||||
asset_change_event_count_24h: number;
|
||||
automation_operation_count_24h: number;
|
||||
automation_failure_count_24h: number;
|
||||
ai_trace_count_24h: number;
|
||||
accepted_ai_trace_count_24h: number;
|
||||
immutable_external_audit_store_evidenced: boolean;
|
||||
};
|
||||
work_items: SecurityControlPlaneWorkItem[];
|
||||
boundaries: {
|
||||
aggregate_only: boolean;
|
||||
raw_asset_identity_returned: boolean;
|
||||
raw_event_payload_returned: boolean;
|
||||
secret_value_collection_allowed: boolean;
|
||||
live_scan_triggered: boolean;
|
||||
runtime_action_triggered: boolean;
|
||||
completion_requires_same_run_receipts: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === "object" && value !== null && !Array.isArray(value);
|
||||
}
|
||||
|
||||
export function isSecurityAssetControlPlanePayload(
|
||||
value: unknown
|
||||
): value is SecurityAssetControlPlanePayload {
|
||||
if (!isRecord(value)) return false;
|
||||
if (value.schema_version !== "iwooos_security_asset_control_plane_v1") return false;
|
||||
if (!isRecord(value.summary) || !isRecord(value.boundaries)) return false;
|
||||
if (!Array.isArray(value.asset_scopes) || !Array.isArray(value.nist_csf_functions)) {
|
||||
return false;
|
||||
}
|
||||
if (!isRecord(value.siem) || !Array.isArray(value.siem.pipeline)) return false;
|
||||
if (!isRecord(value.ai_automation) || !Array.isArray(value.ai_automation.stages)) {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
typeof value.summary.managed_asset_count === "number" &&
|
||||
typeof value.summary.nist_controlled_percent === "number" &&
|
||||
value.boundaries.aggregate_only === true &&
|
||||
value.boundaries.raw_asset_identity_returned === false &&
|
||||
value.boundaries.raw_event_payload_returned === false &&
|
||||
value.boundaries.secret_value_collection_allowed === false &&
|
||||
value.boundaries.live_scan_triggered === false &&
|
||||
value.boundaries.runtime_action_triggered === false
|
||||
);
|
||||
}
|
||||
|
||||
export type SecurityControlPlaneTone = "healthy" | "warning" | "critical";
|
||||
|
||||
export function securityControlPlaneTone(
|
||||
payload: SecurityAssetControlPlanePayload
|
||||
): SecurityControlPlaneTone {
|
||||
if (payload.status !== "ready" || !payload.discovery.fresh) return "critical";
|
||||
if (
|
||||
payload.summary.compliance_violation_count > 0 ||
|
||||
payload.summary.nist_controlled_percent < 50 ||
|
||||
payload.summary.siem_stage_coverage_percent < 50 ||
|
||||
payload.summary.ai_loop_stage_coverage_percent < 50
|
||||
) {
|
||||
return "critical";
|
||||
}
|
||||
if (
|
||||
payload.summary.unowned_asset_count > 0 ||
|
||||
payload.summary.orphan_asset_count > 0 ||
|
||||
payload.summary.automation_coverage_unknown_count > 0 ||
|
||||
payload.summary.compliance_unknown_count > 0 ||
|
||||
!payload.ai_automation.same_run_closed_loop_proven
|
||||
) {
|
||||
return "warning";
|
||||
}
|
||||
return "healthy";
|
||||
}
|
||||
|
||||
export function topSecurityControlPlaneWorkItems(
|
||||
payload: SecurityAssetControlPlanePayload,
|
||||
limit = 3
|
||||
): SecurityControlPlaneWorkItem[] {
|
||||
const rank: Record<string, number> = { P0: 0, P1: 1, P2: 2, P3: 3 };
|
||||
return [...payload.work_items]
|
||||
.sort(
|
||||
(left, right) =>
|
||||
(rank[left.priority] ?? 99) - (rank[right.priority] ?? 99) ||
|
||||
left.work_item_id.localeCompare(right.work_item_id)
|
||||
)
|
||||
.slice(0, Math.max(0, limit));
|
||||
}
|
||||
Reference in New Issue
Block a user