feat(iwooos): surface runtime supply chain risk
This commit is contained in:
@@ -43,6 +43,14 @@ type Copy = {
|
||||
audit: string;
|
||||
aiTrace: string;
|
||||
sources: string;
|
||||
supplyChain: string;
|
||||
runtimeImages: string;
|
||||
digestPinned: string;
|
||||
forbiddenSources: string;
|
||||
imagePolicy: string;
|
||||
compliant: string;
|
||||
repair: string;
|
||||
notEvidenced: string;
|
||||
latestScan: string;
|
||||
freshness: string;
|
||||
runAssets: string;
|
||||
@@ -75,6 +83,14 @@ const COPY: Record<"zh" | "en", Copy> = {
|
||||
audit: "稽核軌跡",
|
||||
aiTrace: "AI 軌跡",
|
||||
sources: "資料源",
|
||||
supplyChain: "Runtime 供應鏈",
|
||||
runtimeImages: "Runtime 映像",
|
||||
digestPinned: "Digest 鎖定",
|
||||
forbiddenSources: "禁用來源",
|
||||
imagePolicy: "映像政策",
|
||||
compliant: "符合",
|
||||
repair: "需修復",
|
||||
notEvidenced: "未盤點",
|
||||
latestScan: "最新盤點",
|
||||
freshness: "新鮮度",
|
||||
runAssets: "本輪資產",
|
||||
@@ -105,6 +121,14 @@ const COPY: Record<"zh" | "en", Copy> = {
|
||||
audit: "Audit trail",
|
||||
aiTrace: "AI trace",
|
||||
sources: "Sources",
|
||||
supplyChain: "Runtime supply chain",
|
||||
runtimeImages: "Runtime images",
|
||||
digestPinned: "Digest pinned",
|
||||
forbiddenSources: "Forbidden sources",
|
||||
imagePolicy: "Image policy",
|
||||
compliant: "PASS",
|
||||
repair: "REPAIR",
|
||||
notEvidenced: "NO DATA",
|
||||
latestScan: "Latest scan",
|
||||
freshness: "Freshness",
|
||||
runAssets: "Run assets",
|
||||
@@ -178,14 +202,21 @@ function TruthCell({
|
||||
value,
|
||||
icon: Icon,
|
||||
tone = "neutral",
|
||||
wideOnMobile = false,
|
||||
}: {
|
||||
label: string;
|
||||
value: string | number;
|
||||
icon: typeof ShieldCheck;
|
||||
tone?: "neutral" | "healthy" | "critical";
|
||||
wideOnMobile?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<div className="flex min-w-0 items-center gap-2 bg-white px-3 py-2.5 last:col-span-2 sm:last:col-span-1">
|
||||
<div
|
||||
className={cn(
|
||||
"flex min-w-0 items-center gap-2 bg-white px-3 py-2.5",
|
||||
wideOnMobile && "last:col-span-2 sm:last:col-span-1"
|
||||
)}
|
||||
>
|
||||
<Icon
|
||||
className={cn(
|
||||
"h-3.5 w-3.5 shrink-0",
|
||||
@@ -398,9 +429,81 @@ export function SecurityAssetControlPlaneCockpit({
|
||||
value={payload?.summary.stale_asset_count ?? "--"}
|
||||
icon={TriangleAlert}
|
||||
tone={(payload?.summary.stale_asset_count ?? 0) > 0 ? "critical" : "healthy"}
|
||||
wideOnMobile
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="border-t border-[#d8d3c7] bg-[#f6f4ee] px-3 py-2">
|
||||
<div className="mb-1.5 flex items-center gap-1.5 text-[10px] font-semibold text-[#4f4d47]">
|
||||
<Boxes className="h-3.5 w-3.5" aria-hidden="true" />
|
||||
{copy.supplyChain}
|
||||
</div>
|
||||
<div
|
||||
className="grid grid-cols-2 gap-px bg-[#d8d3c7] sm:grid-cols-4"
|
||||
data-testid="security-supply-chain-truth"
|
||||
>
|
||||
<TruthCell
|
||||
label={copy.runtimeImages}
|
||||
value={payload?.supply_chain?.package_asset_count ?? "--"}
|
||||
icon={Boxes}
|
||||
tone={
|
||||
payload?.supply_chain?.package_inventory_evidenced
|
||||
? "healthy"
|
||||
: "critical"
|
||||
}
|
||||
/>
|
||||
<TruthCell
|
||||
label={copy.digestPinned}
|
||||
value={
|
||||
payload?.supply_chain
|
||||
? `${payload.supply_chain.package_digest_pinned_count}/${payload.supply_chain.package_asset_count}`
|
||||
: "--"
|
||||
}
|
||||
icon={CheckCircle2}
|
||||
tone={
|
||||
payload?.supply_chain?.package_inventory_evidenced &&
|
||||
payload.supply_chain.package_digest_unpinned_count === 0
|
||||
? "healthy"
|
||||
: "critical"
|
||||
}
|
||||
/>
|
||||
<TruthCell
|
||||
label={copy.forbiddenSources}
|
||||
value={
|
||||
payload?.supply_chain?.forbidden_github_supply_chain_asset_count ??
|
||||
"--"
|
||||
}
|
||||
icon={ShieldAlert}
|
||||
tone={
|
||||
payload?.supply_chain?.package_inventory_evidenced &&
|
||||
payload.supply_chain.forbidden_github_supply_chain_asset_count === 0
|
||||
? "healthy"
|
||||
: "critical"
|
||||
}
|
||||
/>
|
||||
<TruthCell
|
||||
label={copy.imagePolicy}
|
||||
value={
|
||||
!payload?.supply_chain?.package_inventory_evidenced
|
||||
? copy.notEvidenced
|
||||
: payload.supply_chain.runtime_image_policy_compliant
|
||||
? copy.compliant
|
||||
: copy.repair
|
||||
}
|
||||
icon={
|
||||
payload?.supply_chain?.runtime_image_policy_compliant
|
||||
? ShieldCheck
|
||||
: TriangleAlert
|
||||
}
|
||||
tone={
|
||||
payload?.supply_chain?.runtime_image_policy_compliant
|
||||
? "healthy"
|
||||
: "critical"
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{payload ? (
|
||||
<div className="grid gap-4 p-4 xl:grid-cols-[1.1fr_1.4fr]">
|
||||
<div className="min-w-0 space-y-4">
|
||||
|
||||
@@ -27,6 +27,8 @@ function payload(): SecurityAssetControlPlanePayload {
|
||||
stale_asset_count: 0,
|
||||
orphan_asset_count: 0,
|
||||
relationship_count: 40,
|
||||
package_digest_unpinned_count: 0,
|
||||
forbidden_github_supply_chain_asset_count: 0,
|
||||
automation_coverage_green_percent: 85,
|
||||
automation_coverage_unknown_count: 0,
|
||||
compliance_violation_count: 0,
|
||||
@@ -99,6 +101,18 @@ function payload(): SecurityAssetControlPlanePayload {
|
||||
accepted_ai_trace_count_24h: 2,
|
||||
immutable_external_audit_store_evidenced: false,
|
||||
},
|
||||
supply_chain: {
|
||||
package_asset_count: 12,
|
||||
package_inventory_evidenced: true,
|
||||
package_digest_pinned_count: 12,
|
||||
package_digest_unpinned_count: 0,
|
||||
forbidden_github_supply_chain_asset_count: 0,
|
||||
github_freeze_compliant: true,
|
||||
runtime_image_policy_compliant: true,
|
||||
raw_image_identity_returned: false,
|
||||
registry_api_called: false,
|
||||
github_api_used: false,
|
||||
},
|
||||
source_health: [
|
||||
{ source_id: "asset_inventory", status: "ready", reason_code: null },
|
||||
],
|
||||
@@ -144,6 +158,15 @@ describe("security asset control plane projection", () => {
|
||||
boundaries: { ...safe.boundaries, raw_asset_identity_returned: true },
|
||||
};
|
||||
expect(isSecurityAssetControlPlanePayload(unsafe)).toBe(false);
|
||||
|
||||
const unsafeSupplyChain = {
|
||||
...safe,
|
||||
supply_chain: {
|
||||
...safe.supply_chain,
|
||||
raw_image_identity_returned: true,
|
||||
},
|
||||
};
|
||||
expect(isSecurityAssetControlPlanePayload(unsafeSupplyChain)).toBe(false);
|
||||
});
|
||||
|
||||
it("does not show healthy before same-run closure is proven", () => {
|
||||
@@ -157,6 +180,20 @@ describe("security asset control plane projection", () => {
|
||||
expect(securityControlPlaneTone(value)).toBe("critical");
|
||||
});
|
||||
|
||||
it("keeps runtime image supply-chain gaps critical", () => {
|
||||
const value = payload();
|
||||
value.ai_automation.same_run_closed_loop_proven = true;
|
||||
expect(securityControlPlaneTone(value)).toBe("healthy");
|
||||
|
||||
value.supply_chain!.package_digest_pinned_count = 0;
|
||||
value.supply_chain!.package_digest_unpinned_count = 12;
|
||||
value.supply_chain!.runtime_image_policy_compliant = false;
|
||||
expect(securityControlPlaneTone(value)).toBe("critical");
|
||||
|
||||
value.supply_chain = undefined;
|
||||
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([
|
||||
|
||||
@@ -14,6 +14,8 @@ export type SecurityControlPlaneSummary = {
|
||||
stale_asset_count: number;
|
||||
orphan_asset_count: number;
|
||||
relationship_count: number;
|
||||
package_digest_unpinned_count?: number;
|
||||
forbidden_github_supply_chain_asset_count?: number;
|
||||
automation_coverage_green_percent: number;
|
||||
automation_coverage_unknown_count: number;
|
||||
compliance_violation_count: number;
|
||||
@@ -69,6 +71,19 @@ export type SecurityControlPlaneWorkItem = {
|
||||
next_action: string;
|
||||
};
|
||||
|
||||
export type SecurityControlPlaneSupplyChain = {
|
||||
package_asset_count: number;
|
||||
package_inventory_evidenced: boolean;
|
||||
package_digest_pinned_count: number;
|
||||
package_digest_unpinned_count: number;
|
||||
forbidden_github_supply_chain_asset_count: number;
|
||||
github_freeze_compliant: boolean;
|
||||
runtime_image_policy_compliant: boolean;
|
||||
raw_image_identity_returned: false;
|
||||
registry_api_called: false;
|
||||
github_api_used: false;
|
||||
};
|
||||
|
||||
export type SecurityAssetControlPlanePayload = {
|
||||
schema_version: "iwooos_security_asset_control_plane_v1";
|
||||
generated_at: string;
|
||||
@@ -140,6 +155,7 @@ export type SecurityAssetControlPlanePayload = {
|
||||
accepted_ai_trace_count_24h: number;
|
||||
immutable_external_audit_store_evidenced: boolean;
|
||||
};
|
||||
supply_chain?: SecurityControlPlaneSupplyChain;
|
||||
source_health: Array<{
|
||||
source_id: string;
|
||||
status: "ready" | "unavailable";
|
||||
@@ -178,6 +194,24 @@ export function isSecurityAssetControlPlanePayload(
|
||||
if (!isRecord(value.ai_automation) || !Array.isArray(value.ai_automation.stages)) {
|
||||
return false;
|
||||
}
|
||||
if (value.supply_chain !== undefined) {
|
||||
if (!isRecord(value.supply_chain)) return false;
|
||||
if (
|
||||
typeof value.supply_chain.package_asset_count !== "number" ||
|
||||
typeof value.supply_chain.package_inventory_evidenced !== "boolean" ||
|
||||
typeof value.supply_chain.package_digest_pinned_count !== "number" ||
|
||||
typeof value.supply_chain.package_digest_unpinned_count !== "number" ||
|
||||
typeof value.supply_chain.forbidden_github_supply_chain_asset_count !==
|
||||
"number" ||
|
||||
typeof value.supply_chain.github_freeze_compliant !== "boolean" ||
|
||||
typeof value.supply_chain.runtime_image_policy_compliant !== "boolean" ||
|
||||
value.supply_chain.raw_image_identity_returned !== false ||
|
||||
value.supply_chain.registry_api_called !== false ||
|
||||
value.supply_chain.github_api_used !== false
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return (
|
||||
typeof value.summary.managed_asset_count === "number" &&
|
||||
typeof value.summary.source_count === "number" &&
|
||||
@@ -202,6 +236,15 @@ export function securityControlPlaneTone(
|
||||
payload: SecurityAssetControlPlanePayload
|
||||
): SecurityControlPlaneTone {
|
||||
if (payload.status !== "ready" || !payload.discovery.fresh) return "critical";
|
||||
if (
|
||||
!payload.supply_chain ||
|
||||
!payload.supply_chain.package_inventory_evidenced ||
|
||||
payload.supply_chain.package_digest_unpinned_count > 0 ||
|
||||
payload.supply_chain.forbidden_github_supply_chain_asset_count > 0 ||
|
||||
!payload.supply_chain.runtime_image_policy_compliant
|
||||
) {
|
||||
return "critical";
|
||||
}
|
||||
if (
|
||||
payload.summary.compliance_violation_count > 0 ||
|
||||
payload.summary.nist_controlled_percent < 50 ||
|
||||
|
||||
Reference in New Issue
Block a user