fix(iwooos): close Wazuh SOC runtime slice
Some checks failed
CD Pipeline / select-latest-carrier (push) Successful in 48s
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 / revalidate-deploy-carrier (push) Successful in 36s
CD Pipeline / build-and-deploy (push) Has been cancelled
CD Pipeline / revalidate-post-deploy-carrier (push) Has been cancelled
CD Pipeline / post-deploy-checks (push) Has been cancelled
Some checks failed
CD Pipeline / select-latest-carrier (push) Successful in 48s
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 / revalidate-deploy-carrier (push) Successful in 36s
CD Pipeline / build-and-deploy (push) Has been cancelled
CD Pipeline / revalidate-post-deploy-carrier (push) Has been cancelled
CD Pipeline / post-deploy-checks (push) Has been cancelled
This commit is contained in:
@@ -57,6 +57,17 @@ type Copy = {
|
||||
forbiddenSources: string;
|
||||
imagePolicy: string;
|
||||
publicTls: string;
|
||||
wazuhSlice: string;
|
||||
protectedAssets: string;
|
||||
ownerTelemetry: string;
|
||||
identityLink: string;
|
||||
incident: string;
|
||||
verifier: string;
|
||||
recipientReceipt: string;
|
||||
remainingGaps: string;
|
||||
delivered: string;
|
||||
closed: string;
|
||||
open: string;
|
||||
certificates: string;
|
||||
tlsEvidence: string;
|
||||
tlsHealthy: string;
|
||||
@@ -113,6 +124,17 @@ const COPY: Record<"zh" | "en", Copy> = {
|
||||
forbiddenSources: "禁用來源",
|
||||
imagePolicy: "映像政策",
|
||||
publicTls: "Public TLS",
|
||||
wazuhSlice: "Wazuh AI SOC 同 run",
|
||||
protectedAssets: "受保護資產",
|
||||
ownerTelemetry: "Owner / 遙測",
|
||||
identityLink: "Identity 串接",
|
||||
incident: "事件處置",
|
||||
verifier: "獨立驗證",
|
||||
recipientReceipt: "Telegram 收據",
|
||||
remainingGaps: "剩餘缺口",
|
||||
delivered: "已送達",
|
||||
closed: "已閉環",
|
||||
open: "未閉環",
|
||||
certificates: "憑證資產",
|
||||
tlsEvidence: "Live 驗證",
|
||||
tlsHealthy: "健康憑證",
|
||||
@@ -167,6 +189,17 @@ const COPY: Record<"zh" | "en", Copy> = {
|
||||
forbiddenSources: "Forbidden sources",
|
||||
imagePolicy: "Image policy",
|
||||
publicTls: "Public TLS",
|
||||
wazuhSlice: "Wazuh AI SOC same run",
|
||||
protectedAssets: "Protected assets",
|
||||
ownerTelemetry: "Owner / telemetry",
|
||||
identityLink: "Identity link",
|
||||
incident: "Incident",
|
||||
verifier: "Independent verify",
|
||||
recipientReceipt: "Telegram receipt",
|
||||
remainingGaps: "Remaining gaps",
|
||||
delivered: "DELIVERED",
|
||||
closed: "CLOSED",
|
||||
open: "OPEN",
|
||||
certificates: "Certificates",
|
||||
tlsEvidence: "Live evidence",
|
||||
tlsHealthy: "Healthy certs",
|
||||
@@ -290,12 +323,14 @@ function TruthCell({
|
||||
icon: Icon,
|
||||
tone = "neutral",
|
||||
wideOnMobile = false,
|
||||
title,
|
||||
}: {
|
||||
label: string;
|
||||
value: string | number;
|
||||
icon: typeof ShieldCheck;
|
||||
tone?: "neutral" | "healthy" | "critical";
|
||||
wideOnMobile?: boolean;
|
||||
title?: string;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
@@ -303,6 +338,8 @@ function TruthCell({
|
||||
"flex min-w-0 items-center gap-2 bg-white px-3 py-2.5",
|
||||
wideOnMobile && "last:col-span-2 lg:last:col-span-1",
|
||||
)}
|
||||
title={title}
|
||||
aria-label={title}
|
||||
>
|
||||
<Icon
|
||||
className={cn(
|
||||
@@ -400,6 +437,128 @@ function CertificateTruthStrip({
|
||||
);
|
||||
}
|
||||
|
||||
function WazuhSocTruthStrip({
|
||||
copy,
|
||||
payload,
|
||||
}: {
|
||||
copy: Copy;
|
||||
payload: SecurityAssetControlPlanePayload | null;
|
||||
}) {
|
||||
const wazuh = payload?.wazuh_soc_slice;
|
||||
const assetCount = wazuh?.canonical_asset_count ?? 0;
|
||||
const ownerAndTelemetryReady = Boolean(
|
||||
wazuh &&
|
||||
wazuh.owner_verified_asset_count === assetCount &&
|
||||
wazuh.telemetry_covered_asset_count === assetCount &&
|
||||
assetCount > 0,
|
||||
);
|
||||
const identityReady = Boolean(
|
||||
wazuh && wazuh.identity_kind_count === wazuh.required_identity_kind_count,
|
||||
);
|
||||
const receiptVisible =
|
||||
wazuh?.recipient_receipt_status === "recipient_visible";
|
||||
const verifierRef = wazuh?.verifier_receipt_ref ?? "";
|
||||
const recipientMessageRef = wazuh?.recipient_provider_message_ref ?? "";
|
||||
|
||||
return (
|
||||
<div className="border-t border-[#d8d3c7] bg-[#f6f4ee] px-3 py-2">
|
||||
<div className="mb-1.5 flex min-w-0 flex-wrap items-center justify-between gap-x-3 gap-y-1 text-[10px] font-semibold text-[#4f4d47]">
|
||||
<div className="flex min-w-0 flex-wrap items-center gap-1.5">
|
||||
<Radar className="h-3.5 w-3.5 shrink-0" aria-hidden="true" />
|
||||
<span>{copy.wazuhSlice}</span>
|
||||
<span className="max-w-full break-all font-mono text-[#17602a]">
|
||||
{wazuh?.protected_asset_ref ?? wazuh?.canonical_asset_ref ?? "--"}
|
||||
</span>
|
||||
<span aria-hidden="true">→</span>
|
||||
<span className="max-w-full break-all font-mono text-[#17602a]">
|
||||
{wazuh?.incident_ref ?? "--"}
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
className="font-mono text-[#9f2f25]"
|
||||
title={wazuh?.remaining_gap_codes.join(", ")}
|
||||
>
|
||||
{copy.remainingGaps} {wazuh?.remaining_gap_codes.length ?? "--"}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="grid grid-cols-2 gap-px bg-[#d8d3c7] sm:grid-cols-3 lg:grid-cols-6"
|
||||
data-testid="security-wazuh-soc-truth"
|
||||
>
|
||||
<TruthCell
|
||||
label={copy.protectedAssets}
|
||||
value={wazuh ? `${wazuh.protected_asset_count}/${assetCount}` : "--"}
|
||||
icon={ShieldCheck}
|
||||
title={
|
||||
wazuh?.protected_asset_ref
|
||||
? `${copy.protectedAssets}: ${wazuh.protected_asset_ref}`
|
||||
: undefined
|
||||
}
|
||||
tone={
|
||||
(wazuh?.protected_asset_count ?? 0) > 0 ? "healthy" : "critical"
|
||||
}
|
||||
/>
|
||||
<TruthCell
|
||||
label={copy.ownerTelemetry}
|
||||
value={
|
||||
wazuh
|
||||
? `${wazuh.owner_verified_asset_count}/${assetCount} · ${wazuh.telemetry_covered_asset_count}/${assetCount}`
|
||||
: "--"
|
||||
}
|
||||
icon={Activity}
|
||||
tone={ownerAndTelemetryReady ? "healthy" : "critical"}
|
||||
/>
|
||||
<TruthCell
|
||||
label={copy.identityLink}
|
||||
value={
|
||||
wazuh
|
||||
? `${wazuh.identity_kind_count}/${wazuh.required_identity_kind_count}`
|
||||
: "--"
|
||||
}
|
||||
icon={Boxes}
|
||||
tone={identityReady ? "healthy" : "critical"}
|
||||
/>
|
||||
<TruthCell
|
||||
label={copy.incident}
|
||||
value={
|
||||
wazuh
|
||||
? `${wazuh.same_run_closed ? copy.closed : copy.open} · ${wazuh.same_run_present_stage_count}/${wazuh.same_run_required_stage_count}`
|
||||
: "--"
|
||||
}
|
||||
icon={wazuh?.same_run_closed ? CheckCircle2 : TriangleAlert}
|
||||
tone={wazuh?.same_run_closed ? "healthy" : "critical"}
|
||||
/>
|
||||
<TruthCell
|
||||
label={copy.verifier}
|
||||
value={
|
||||
wazuh?.verifier_status === "passed"
|
||||
? `${copy.success} · ${verifierRef.slice(0, 8)}`
|
||||
: copy.failed
|
||||
}
|
||||
icon={CheckCircle2}
|
||||
tone={wazuh?.verifier_status === "passed" ? "healthy" : "critical"}
|
||||
title={verifierRef ? `${copy.verifier}: ${verifierRef}` : undefined}
|
||||
/>
|
||||
<TruthCell
|
||||
label={copy.recipientReceipt}
|
||||
value={
|
||||
receiptVisible
|
||||
? `${copy.delivered} · #${recipientMessageRef}`
|
||||
: copy.notEvidenced
|
||||
}
|
||||
icon={receiptVisible ? CheckCircle2 : ShieldAlert}
|
||||
tone={receiptVisible ? "healthy" : "critical"}
|
||||
title={
|
||||
receiptVisible
|
||||
? `${copy.recipientReceipt}: ${wazuh?.recipient_receipt_ref ?? "--"} / #${recipientMessageRef}`
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function StageStrip({
|
||||
title,
|
||||
stages,
|
||||
@@ -627,6 +786,10 @@ export function SecurityAssetControlPlaneCockpit({
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{view === "command" ? (
|
||||
<WazuhSocTruthStrip copy={copy} payload={payload} />
|
||||
) : null}
|
||||
|
||||
{view === "command" ? (
|
||||
<div
|
||||
className="grid grid-cols-3 gap-px border-t border-[#d8d3c7] bg-[#d8d3c7] lg:grid-cols-5"
|
||||
|
||||
@@ -14,8 +14,8 @@ function payload(): SecurityAssetControlPlanePayload {
|
||||
status: "ready",
|
||||
source_status: "live_database_aggregate",
|
||||
summary: {
|
||||
source_count: 10,
|
||||
ready_source_count: 10,
|
||||
source_count: 12,
|
||||
ready_source_count: 12,
|
||||
unavailable_source_count: 0,
|
||||
managed_asset_count: 24,
|
||||
expected_asset_type_count: 28,
|
||||
@@ -87,6 +87,43 @@ function payload(): SecurityAssetControlPlanePayload {
|
||||
},
|
||||
],
|
||||
},
|
||||
wazuh_soc_slice: {
|
||||
schema_version: "iwooos_wazuh_ai_soc_slice_v1",
|
||||
status: "same_run_closed_recipient_visible",
|
||||
canonical_asset_count: 1,
|
||||
canonical_asset_ref: "service:wazuh-manager",
|
||||
protected_asset_count: 1,
|
||||
protected_asset_ref: "service:wazuh-manager",
|
||||
asset_graph_joined: true,
|
||||
owner_resolved_asset_count: 1,
|
||||
owner_verified_asset_count: 1,
|
||||
telemetry_covered_asset_count: 1,
|
||||
identity_kind_count: 5,
|
||||
required_identity_kind_count: 5,
|
||||
identity_kinds: ["manager", "agent", "host", "service", "event"],
|
||||
incident_ref: "IWZ-POSTURE-2026072205",
|
||||
incident_status: "resolved",
|
||||
verifier_status: "passed",
|
||||
verifier_receipt_ref: "verifier-wazuh-2205",
|
||||
recipient_receipt_status: "recipient_visible",
|
||||
recipient_receipt_ref: "telegram-wazuh-2205",
|
||||
recipient_provider_message_ref: "2205",
|
||||
same_run_present_stage_count: 18,
|
||||
same_run_required_stage_count: 18,
|
||||
same_run_closed: true,
|
||||
critical_break_glass_required: true,
|
||||
remaining_gap_codes: [
|
||||
"wazuh_critical_ingress_break_glass_pending",
|
||||
"global_wazuh_asset_coverage_not_proven",
|
||||
],
|
||||
domain_controlled_percent: 70,
|
||||
domain_evidence_count: 7,
|
||||
domain_gap_code: "wazuh_bounded_slice_closed_global_coverage_open",
|
||||
coverage_overlay_applied_count: 2,
|
||||
raw_identity_returned: false,
|
||||
raw_event_payload_returned: false,
|
||||
secret_value_read: false,
|
||||
},
|
||||
siem: { pipeline: [] },
|
||||
ai_automation: {
|
||||
stages: [],
|
||||
@@ -184,6 +221,7 @@ function payload(): SecurityAssetControlPlanePayload {
|
||||
live_scan_triggered: false,
|
||||
runtime_action_triggered: false,
|
||||
completion_requires_same_run_receipts: true,
|
||||
wazuh_slice_is_global_coverage_claim: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -219,6 +257,15 @@ describe("security asset control plane projection", () => {
|
||||
false,
|
||||
);
|
||||
|
||||
const unsafeWazuhIdentity = {
|
||||
...safe,
|
||||
wazuh_soc_slice: {
|
||||
...safe.wazuh_soc_slice,
|
||||
raw_identity_returned: true,
|
||||
},
|
||||
};
|
||||
expect(isSecurityAssetControlPlanePayload(unsafeWazuhIdentity)).toBe(false);
|
||||
|
||||
const unsafeDiscovery = {
|
||||
...safe,
|
||||
discovery: {
|
||||
|
||||
@@ -121,6 +121,44 @@ export type SecurityControlPlaneCertificateInventory = {
|
||||
private_key_material_read: false;
|
||||
};
|
||||
|
||||
export type SecurityWazuhSocSlice = {
|
||||
schema_version: "iwooos_wazuh_ai_soc_slice_v1";
|
||||
status: "same_run_closed_recipient_visible" | "partial" | "not_evidenced";
|
||||
canonical_asset_count: number;
|
||||
canonical_asset_ref: "service:wazuh-manager" | null;
|
||||
protected_asset_count: number;
|
||||
protected_asset_ref: "service:wazuh-manager" | null;
|
||||
asset_graph_joined: boolean;
|
||||
owner_resolved_asset_count: number;
|
||||
owner_verified_asset_count: number;
|
||||
telemetry_covered_asset_count: number;
|
||||
identity_kind_count: number;
|
||||
required_identity_kind_count: number;
|
||||
identity_kinds: Array<"manager" | "agent" | "host" | "service" | "event">;
|
||||
incident_ref: string | null;
|
||||
incident_status: "resolved" | "open";
|
||||
verifier_status: "passed" | "missing";
|
||||
verifier_receipt_ref: string | null;
|
||||
recipient_receipt_status:
|
||||
| "recipient_visible"
|
||||
| "suppressed_unchanged"
|
||||
| "missing";
|
||||
recipient_receipt_ref: string | null;
|
||||
recipient_provider_message_ref: string | null;
|
||||
same_run_present_stage_count: number;
|
||||
same_run_required_stage_count: number;
|
||||
same_run_closed: boolean;
|
||||
critical_break_glass_required: boolean;
|
||||
remaining_gap_codes: string[];
|
||||
domain_controlled_percent: number;
|
||||
domain_evidence_count: number;
|
||||
domain_gap_code: string;
|
||||
coverage_overlay_applied_count: number;
|
||||
raw_identity_returned: false;
|
||||
raw_event_payload_returned: false;
|
||||
secret_value_read: false;
|
||||
};
|
||||
|
||||
export type SecurityStrictRuntimeCompletion = {
|
||||
schema_version: "ai_agent_strict_runtime_completion_v2";
|
||||
runtime_contract_schema_version: "ai_automation_runtime_completion_contract_v2";
|
||||
@@ -184,6 +222,7 @@ export type SecurityAssetControlPlanePayload = {
|
||||
completion_percent: number;
|
||||
}>;
|
||||
};
|
||||
wazuh_soc_slice: SecurityWazuhSocSlice;
|
||||
siem: {
|
||||
pipeline: SecurityControlPlaneStage[];
|
||||
incident_total_24h?: number;
|
||||
@@ -232,6 +271,7 @@ export type SecurityAssetControlPlanePayload = {
|
||||
live_scan_triggered: boolean;
|
||||
runtime_action_triggered: boolean;
|
||||
completion_requires_same_run_receipts: boolean;
|
||||
wazuh_slice_is_global_coverage_claim: false;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -270,6 +310,98 @@ export function isSecurityAssetControlPlanePayload(
|
||||
}
|
||||
if (!isRecord(value.siem) || !Array.isArray(value.siem.pipeline))
|
||||
return false;
|
||||
const wazuh = value.wazuh_soc_slice;
|
||||
const wazuhIdentityKinds = new Set([
|
||||
"manager",
|
||||
"agent",
|
||||
"host",
|
||||
"service",
|
||||
"event",
|
||||
]);
|
||||
if (
|
||||
!isRecord(wazuh) ||
|
||||
wazuh.schema_version !== "iwooos_wazuh_ai_soc_slice_v1" ||
|
||||
!["same_run_closed_recipient_visible", "partial", "not_evidenced"].includes(
|
||||
String(wazuh.status),
|
||||
) ||
|
||||
typeof wazuh.canonical_asset_count !== "number" ||
|
||||
!(
|
||||
wazuh.canonical_asset_ref === null ||
|
||||
wazuh.canonical_asset_ref === "service:wazuh-manager"
|
||||
) ||
|
||||
typeof wazuh.protected_asset_count !== "number" ||
|
||||
!(
|
||||
wazuh.protected_asset_ref === null ||
|
||||
wazuh.protected_asset_ref === "service:wazuh-manager"
|
||||
) ||
|
||||
typeof wazuh.asset_graph_joined !== "boolean" ||
|
||||
typeof wazuh.owner_resolved_asset_count !== "number" ||
|
||||
typeof wazuh.owner_verified_asset_count !== "number" ||
|
||||
typeof wazuh.telemetry_covered_asset_count !== "number" ||
|
||||
typeof wazuh.identity_kind_count !== "number" ||
|
||||
typeof wazuh.required_identity_kind_count !== "number" ||
|
||||
!Array.isArray(wazuh.identity_kinds) ||
|
||||
!wazuh.identity_kinds.every(
|
||||
(identityKind) =>
|
||||
typeof identityKind === "string" &&
|
||||
wazuhIdentityKinds.has(identityKind),
|
||||
) ||
|
||||
new Set(wazuh.identity_kinds).size !== wazuh.identity_kinds.length ||
|
||||
wazuh.identity_kind_count !== wazuh.identity_kinds.length ||
|
||||
wazuh.required_identity_kind_count !== 5 ||
|
||||
!(wazuh.incident_ref === null || typeof wazuh.incident_ref === "string") ||
|
||||
!["resolved", "open"].includes(String(wazuh.incident_status)) ||
|
||||
!["passed", "missing"].includes(String(wazuh.verifier_status)) ||
|
||||
!(
|
||||
wazuh.verifier_receipt_ref === null ||
|
||||
typeof wazuh.verifier_receipt_ref === "string"
|
||||
) ||
|
||||
!["recipient_visible", "suppressed_unchanged", "missing"].includes(
|
||||
String(wazuh.recipient_receipt_status),
|
||||
) ||
|
||||
!(
|
||||
wazuh.recipient_receipt_ref === null ||
|
||||
typeof wazuh.recipient_receipt_ref === "string"
|
||||
) ||
|
||||
!(
|
||||
wazuh.recipient_provider_message_ref === null ||
|
||||
typeof wazuh.recipient_provider_message_ref === "string"
|
||||
) ||
|
||||
typeof wazuh.same_run_present_stage_count !== "number" ||
|
||||
wazuh.same_run_required_stage_count !== 18 ||
|
||||
typeof wazuh.same_run_closed !== "boolean" ||
|
||||
typeof wazuh.critical_break_glass_required !== "boolean" ||
|
||||
!Array.isArray(wazuh.remaining_gap_codes) ||
|
||||
!wazuh.remaining_gap_codes.every(
|
||||
(gapCode) => typeof gapCode === "string",
|
||||
) ||
|
||||
typeof wazuh.domain_controlled_percent !== "number" ||
|
||||
wazuh.domain_controlled_percent < 0 ||
|
||||
wazuh.domain_controlled_percent > 70 ||
|
||||
typeof wazuh.domain_evidence_count !== "number" ||
|
||||
typeof wazuh.domain_gap_code !== "string" ||
|
||||
typeof wazuh.coverage_overlay_applied_count !== "number" ||
|
||||
wazuh.raw_identity_returned !== false ||
|
||||
wazuh.raw_event_payload_returned !== false ||
|
||||
wazuh.secret_value_read !== false ||
|
||||
wazuh.protected_asset_count > wazuh.canonical_asset_count ||
|
||||
(wazuh.asset_graph_joined &&
|
||||
wazuh.canonical_asset_ref !== "service:wazuh-manager") ||
|
||||
(wazuh.protected_asset_count === 1 &&
|
||||
wazuh.protected_asset_ref !== wazuh.canonical_asset_ref) ||
|
||||
(wazuh.status === "same_run_closed_recipient_visible" &&
|
||||
(!wazuh.same_run_closed ||
|
||||
!wazuh.asset_graph_joined ||
|
||||
wazuh.same_run_present_stage_count !== 18 ||
|
||||
wazuh.incident_status !== "resolved" ||
|
||||
wazuh.verifier_status !== "passed" ||
|
||||
!wazuh.verifier_receipt_ref ||
|
||||
wazuh.recipient_receipt_status !== "recipient_visible" ||
|
||||
!wazuh.recipient_receipt_ref ||
|
||||
!wazuh.recipient_provider_message_ref))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
!isRecord(value.ai_automation) ||
|
||||
!Array.isArray(value.ai_automation.stages)
|
||||
@@ -371,7 +503,8 @@ export function isSecurityAssetControlPlanePayload(
|
||||
value.boundaries.raw_discovery_error_returned === false &&
|
||||
value.boundaries.secret_value_collection_allowed === false &&
|
||||
value.boundaries.live_scan_triggered === false &&
|
||||
value.boundaries.runtime_action_triggered === false
|
||||
value.boundaries.runtime_action_triggered === false &&
|
||||
value.boundaries.wazuh_slice_is_global_coverage_claim === false
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user