feat(security): verify public tls asset health
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
||||
Boxes,
|
||||
CheckCircle2,
|
||||
Database,
|
||||
LockKeyhole,
|
||||
RefreshCw,
|
||||
Radar,
|
||||
ShieldAlert,
|
||||
@@ -48,6 +49,11 @@ type Copy = {
|
||||
digestPinned: string;
|
||||
forbiddenSources: string;
|
||||
imagePolicy: string;
|
||||
publicTls: string;
|
||||
certificates: string;
|
||||
tlsEvidence: string;
|
||||
tlsHealthy: string;
|
||||
tlsPolicy: string;
|
||||
compliant: string;
|
||||
repair: string;
|
||||
notEvidenced: string;
|
||||
@@ -88,6 +94,11 @@ const COPY: Record<"zh" | "en", Copy> = {
|
||||
digestPinned: "Digest 鎖定",
|
||||
forbiddenSources: "禁用來源",
|
||||
imagePolicy: "映像政策",
|
||||
publicTls: "Public TLS",
|
||||
certificates: "憑證資產",
|
||||
tlsEvidence: "Live 驗證",
|
||||
tlsHealthy: "健康憑證",
|
||||
tlsPolicy: "TLS 政策",
|
||||
compliant: "符合",
|
||||
repair: "需修復",
|
||||
notEvidenced: "未盤點",
|
||||
@@ -126,6 +137,11 @@ const COPY: Record<"zh" | "en", Copy> = {
|
||||
digestPinned: "Digest pinned",
|
||||
forbiddenSources: "Forbidden sources",
|
||||
imagePolicy: "Image policy",
|
||||
publicTls: "Public TLS",
|
||||
certificates: "Certificates",
|
||||
tlsEvidence: "Live evidence",
|
||||
tlsHealthy: "Healthy certs",
|
||||
tlsPolicy: "TLS policy",
|
||||
compliant: "PASS",
|
||||
repair: "REPAIR",
|
||||
notEvidenced: "NO DATA",
|
||||
@@ -247,6 +263,69 @@ function TruthCell({
|
||||
);
|
||||
}
|
||||
|
||||
function CertificateTruthStrip({
|
||||
copy,
|
||||
payload,
|
||||
}: {
|
||||
copy: Copy;
|
||||
payload: SecurityAssetControlPlanePayload | null;
|
||||
}) {
|
||||
const certificate = payload?.certificate_inventory;
|
||||
const assetCount = certificate?.certificate_asset_count ?? 0;
|
||||
const evidencedCount =
|
||||
certificate?.live_tls_evidenced_count ?? certificate?.live_tls_verified_count;
|
||||
const healthyCount = certificate?.live_tls_healthy_count;
|
||||
const healthProven = certificate?.live_tls_health_proven === true;
|
||||
|
||||
return (
|
||||
<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]">
|
||||
<LockKeyhole className="h-3.5 w-3.5" aria-hidden="true" />
|
||||
{copy.publicTls}
|
||||
</div>
|
||||
<div
|
||||
className="grid grid-cols-2 gap-px bg-[#d8d3c7] sm:grid-cols-4"
|
||||
data-testid="security-public-tls-truth"
|
||||
>
|
||||
<TruthCell
|
||||
label={copy.certificates}
|
||||
value={certificate?.certificate_asset_count ?? "--"}
|
||||
icon={LockKeyhole}
|
||||
tone={assetCount > 0 ? "healthy" : "critical"}
|
||||
/>
|
||||
<TruthCell
|
||||
label={copy.tlsEvidence}
|
||||
value={certificate ? `${evidencedCount ?? "--"}/${assetCount}` : "--"}
|
||||
icon={Radar}
|
||||
tone={
|
||||
certificate && certificate.live_tls_unverified_count === 0
|
||||
? "healthy"
|
||||
: "critical"
|
||||
}
|
||||
/>
|
||||
<TruthCell
|
||||
label={copy.tlsHealthy}
|
||||
value={certificate ? `${healthyCount ?? "--"}/${assetCount}` : "--"}
|
||||
icon={ShieldCheck}
|
||||
tone={healthProven ? "healthy" : "critical"}
|
||||
/>
|
||||
<TruthCell
|
||||
label={copy.tlsPolicy}
|
||||
value={
|
||||
!certificate
|
||||
? copy.notEvidenced
|
||||
: healthProven
|
||||
? copy.compliant
|
||||
: copy.repair
|
||||
}
|
||||
icon={healthProven ? ShieldCheck : TriangleAlert}
|
||||
tone={healthProven ? "healthy" : "critical"}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function StageStrip({
|
||||
title,
|
||||
stages,
|
||||
@@ -358,6 +437,8 @@ export function SecurityAssetControlPlaneCockpit({
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<CertificateTruthStrip copy={copy} payload={payload} />
|
||||
|
||||
<div className="grid grid-cols-2 gap-px bg-[#d8d3c7] sm:grid-cols-3 lg:grid-cols-6">
|
||||
<MetricCell
|
||||
label={copy.overall}
|
||||
|
||||
@@ -29,6 +29,8 @@ function payload(): SecurityAssetControlPlanePayload {
|
||||
relationship_count: 40,
|
||||
package_digest_unpinned_count: 0,
|
||||
forbidden_github_supply_chain_asset_count: 0,
|
||||
certificate_live_unverified_count: 0,
|
||||
certificate_live_unhealthy_count: 0,
|
||||
automation_coverage_green_percent: 85,
|
||||
automation_coverage_unknown_count: 0,
|
||||
compliance_violation_count: 0,
|
||||
@@ -113,6 +115,18 @@ function payload(): SecurityAssetControlPlanePayload {
|
||||
registry_api_called: false,
|
||||
github_api_used: false,
|
||||
},
|
||||
certificate_inventory: {
|
||||
certificate_asset_count: 10,
|
||||
live_tls_verified_count: 10,
|
||||
live_tls_evidenced_count: 10,
|
||||
live_tls_healthy_count: 10,
|
||||
live_tls_unverified_count: 0,
|
||||
live_tls_unhealthy_count: 0,
|
||||
live_tls_health_proven: true,
|
||||
raw_certificate_path_returned: false,
|
||||
certificate_material_read: false,
|
||||
private_key_material_read: false,
|
||||
},
|
||||
source_health: [
|
||||
{ source_id: "asset_inventory", status: "ready", reason_code: null },
|
||||
],
|
||||
@@ -167,6 +181,15 @@ describe("security asset control plane projection", () => {
|
||||
},
|
||||
};
|
||||
expect(isSecurityAssetControlPlanePayload(unsafeSupplyChain)).toBe(false);
|
||||
|
||||
const unsafeCertificateInventory = {
|
||||
...safe,
|
||||
certificate_inventory: {
|
||||
...safe.certificate_inventory,
|
||||
private_key_material_read: true,
|
||||
},
|
||||
};
|
||||
expect(isSecurityAssetControlPlanePayload(unsafeCertificateInventory)).toBe(false);
|
||||
});
|
||||
|
||||
it("does not show healthy before same-run closure is proven", () => {
|
||||
@@ -194,6 +217,20 @@ describe("security asset control plane projection", () => {
|
||||
expect(securityControlPlaneTone(value)).toBe("critical");
|
||||
});
|
||||
|
||||
it("keeps missing or unhealthy live TLS evidence critical", () => {
|
||||
const value = payload();
|
||||
value.ai_automation.same_run_closed_loop_proven = true;
|
||||
expect(securityControlPlaneTone(value)).toBe("healthy");
|
||||
|
||||
value.certificate_inventory!.live_tls_healthy_count = 9;
|
||||
value.certificate_inventory!.live_tls_unhealthy_count = 1;
|
||||
value.certificate_inventory!.live_tls_health_proven = false;
|
||||
expect(securityControlPlaneTone(value)).toBe("critical");
|
||||
|
||||
value.certificate_inventory = 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([
|
||||
|
||||
@@ -16,6 +16,8 @@ export type SecurityControlPlaneSummary = {
|
||||
relationship_count: number;
|
||||
package_digest_unpinned_count?: number;
|
||||
forbidden_github_supply_chain_asset_count?: number;
|
||||
certificate_live_unverified_count?: number;
|
||||
certificate_live_unhealthy_count?: number;
|
||||
automation_coverage_green_percent: number;
|
||||
automation_coverage_unknown_count: number;
|
||||
compliance_violation_count: number;
|
||||
@@ -84,6 +86,19 @@ export type SecurityControlPlaneSupplyChain = {
|
||||
github_api_used: false;
|
||||
};
|
||||
|
||||
export type SecurityControlPlaneCertificateInventory = {
|
||||
certificate_asset_count: number;
|
||||
live_tls_verified_count: number;
|
||||
live_tls_evidenced_count?: number;
|
||||
live_tls_healthy_count?: number;
|
||||
live_tls_unverified_count: number;
|
||||
live_tls_unhealthy_count?: number;
|
||||
live_tls_health_proven: boolean;
|
||||
raw_certificate_path_returned: false;
|
||||
certificate_material_read: false;
|
||||
private_key_material_read: false;
|
||||
};
|
||||
|
||||
export type SecurityAssetControlPlanePayload = {
|
||||
schema_version: "iwooos_security_asset_control_plane_v1";
|
||||
generated_at: string;
|
||||
@@ -156,6 +171,7 @@ export type SecurityAssetControlPlanePayload = {
|
||||
immutable_external_audit_store_evidenced: boolean;
|
||||
};
|
||||
supply_chain?: SecurityControlPlaneSupplyChain;
|
||||
certificate_inventory?: SecurityControlPlaneCertificateInventory;
|
||||
source_health: Array<{
|
||||
source_id: string;
|
||||
status: "ready" | "unavailable";
|
||||
@@ -212,6 +228,26 @@ export function isSecurityAssetControlPlanePayload(
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (value.certificate_inventory !== undefined) {
|
||||
if (!isRecord(value.certificate_inventory)) return false;
|
||||
if (
|
||||
typeof value.certificate_inventory.certificate_asset_count !== "number" ||
|
||||
typeof value.certificate_inventory.live_tls_verified_count !== "number" ||
|
||||
(value.certificate_inventory.live_tls_evidenced_count !== undefined &&
|
||||
typeof value.certificate_inventory.live_tls_evidenced_count !== "number") ||
|
||||
(value.certificate_inventory.live_tls_healthy_count !== undefined &&
|
||||
typeof value.certificate_inventory.live_tls_healthy_count !== "number") ||
|
||||
typeof value.certificate_inventory.live_tls_unverified_count !== "number" ||
|
||||
(value.certificate_inventory.live_tls_unhealthy_count !== undefined &&
|
||||
typeof value.certificate_inventory.live_tls_unhealthy_count !== "number") ||
|
||||
typeof value.certificate_inventory.live_tls_health_proven !== "boolean" ||
|
||||
value.certificate_inventory.raw_certificate_path_returned !== false ||
|
||||
value.certificate_inventory.certificate_material_read !== false ||
|
||||
value.certificate_inventory.private_key_material_read !== false
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return (
|
||||
typeof value.summary.managed_asset_count === "number" &&
|
||||
typeof value.summary.source_count === "number" &&
|
||||
@@ -245,6 +281,15 @@ export function securityControlPlaneTone(
|
||||
) {
|
||||
return "critical";
|
||||
}
|
||||
if (
|
||||
!payload.certificate_inventory ||
|
||||
payload.certificate_inventory.certificate_asset_count === 0 ||
|
||||
payload.certificate_inventory.live_tls_unverified_count > 0 ||
|
||||
(payload.certificate_inventory.live_tls_unhealthy_count ?? 0) > 0 ||
|
||||
!payload.certificate_inventory.live_tls_health_proven
|
||||
) {
|
||||
return "critical";
|
||||
}
|
||||
if (
|
||||
payload.summary.compliance_violation_count > 0 ||
|
||||
payload.summary.nist_controlled_percent < 50 ||
|
||||
|
||||
Reference in New Issue
Block a user