feat(awooop): surface security mainline cockpit
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 1s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 1m13s
CD Pipeline / build-and-deploy (push) Successful in 5m8s
AWOOOI Harbor 110 Local Repair / workflow-shape (push) Successful in 0s
AWOOOI Harbor 110 Local Repair / harbor-110-local-repair (push) Successful in 38s
CD Pipeline / post-deploy-checks (push) Has been cancelled

This commit is contained in:
ogt
2026-07-09 19:14:56 +08:00
parent f156b17b3e
commit 1815925358

View File

@@ -21,6 +21,7 @@ import {
GitBranch,
GitPullRequest,
ListChecks,
Lock,
Network,
Radar,
RefreshCw,
@@ -1434,6 +1435,39 @@ type PriorityWorkOrderResponse = {
} | null;
};
type SecurityCockpitRuntimeReadback = {
status?: string | null;
summary?: {
control_plane_visibility_percent?: number | null;
actual_runtime_acceptance_percent?: number | null;
wazuh_manager_registry_accepted_count?: number | null;
wazuh_expected_host_scope_count?: number | null;
wazuh_owner_evidence_registry_export_accepted_count?: number | null;
wazuh_owner_evidence_reviewer_check_count?: number | null;
wazuh_runtime_apply_preflight_ready_count?: number | null;
wazuh_runtime_apply_check_mode_plan_count?: number | null;
wazuh_runtime_apply_rollback_plan_count?: number | null;
wazuh_runtime_apply_post_apply_verifier_count?: number | null;
runtime_gate_count?: number | null;
host_write_authorized_count?: number | null;
active_response_authorized_count?: number | null;
} | null;
};
type SecurityCockpitRegistryReadback = {
status?: string | null;
summary?: {
expected_scope_alias_count?: number | null;
manager_registry_accepted_count?: number | null;
owner_registry_export_accepted_count?: number | null;
reviewer_validation_passed_count?: number | null;
runtime_gate_count?: number | null;
host_write_authorized_count?: number | null;
active_response_authorized_count?: number | null;
secret_value_collection_allowed_count?: number | null;
} | null;
};
const COMMANDER_INSERTED_REQUIREMENT_FALLBACK: PriorityWorkOrderResponse = {
summary: {
active_p0_state: "blocked_reboot_auto_recovery_slo_not_ready",
@@ -9276,6 +9310,312 @@ function stockplatformManagerStateKey(value: string | null | undefined) {
return "review";
}
function SecurityMainlineCockpit({
priority,
loading,
locale,
}: {
priority: PriorityWorkOrderResponse | null;
loading: boolean;
locale: string;
}) {
const [runtime, setRuntime] = useState<SecurityCockpitRuntimeReadback | null>(null);
const [registry, setRegistry] = useState<SecurityCockpitRegistryReadback | null>(null);
const [liveLoading, setLiveLoading] = useState(true);
const isZh = locale === "zh-TW";
const copy = {
eyebrow: isZh ? "資安主線" : "Security mainline",
title: isZh ? "管理者作戰盤" : "Operator cockpit",
subtitle: isZh
? "正式環境讀回Wazuh manager registry、Windows99 locator、P0 blocker 與高風險動作邊界集中顯示。"
: "Production readback for Wazuh registry, Windows99 locator, P0 blockers, and high-risk guardrails.",
live: isZh ? "正式讀回" : "production",
loading: isZh ? "讀取中" : "loading",
p0: isZh ? "目前 P0" : "Current P0",
registry: isZh ? "Wazuh 納管" : "Wazuh registry",
locator: isZh ? "Windows99 locator" : "Windows99 locator",
guard: isZh ? "高風險邊界" : "Risk boundary",
next: isZh ? "下一步" : "Next action",
blockers: isZh ? "阻擋項" : "blockers",
readiness: isZh ? "準備度" : "readiness",
owner: isZh ? "owner export" : "owner export",
reviewer: isZh ? "review passed" : "review passed",
identity: isZh ? "單一身分候選" : "identity candidate",
confirmation: isZh ? "需確認" : "confirmation",
noRaw: isZh ? "不顯示 raw path" : "no raw path",
noWrite: isZh ? "未做主機寫入" : "no host write",
noPower: isZh ? "未改 VM power" : "no VM power change",
locked: isZh ? "runtime gate 鎖定" : "runtime gate locked",
deployLabel: isZh ? "部署" : "deploy",
locatorLabel: isZh ? "定位器" : "locator",
};
useEffect(() => {
let mounted = true;
async function loadSecurityReadback() {
setLiveLoading(true);
const [runtimePayload, registryPayload] = await Promise.all([
fetchJson<SecurityCockpitRuntimeReadback>(
`${API_BASE}/api/v1/iwooos/runtime-security-readback`,
12000
),
fetchJson<SecurityCockpitRegistryReadback>(
`${API_BASE}/api/v1/iwooos/wazuh-manager-registry-reviewer-validation`,
12000
),
]);
if (!mounted) return;
setRuntime(runtimePayload);
setRegistry(registryPayload);
setLiveLoading(false);
}
loadSecurityReadback();
return () => {
mounted = false;
};
}, []);
const summary = priority?.summary;
const activeItem = priority?.in_progress_or_blocked_in_priority_order?.[0] ?? null;
const evidence = activeItem?.evidence;
const runtimeSummary = runtime?.summary;
const registrySummary = registry?.summary;
const activeBlockers =
summary?.active_p0_live_active_blockers ??
evidence?.active_blockers ??
[];
const readiness = summary?.active_p0_readiness_percent ?? 0;
const registryAccepted =
registrySummary?.manager_registry_accepted_count ??
runtimeSummary?.wazuh_manager_registry_accepted_count ??
0;
const registryExpected =
registrySummary?.expected_scope_alias_count ??
runtimeSummary?.wazuh_expected_host_scope_count ??
0;
const ownerAccepted =
registrySummary?.owner_registry_export_accepted_count ??
runtimeSummary?.wazuh_owner_evidence_registry_export_accepted_count ??
0;
const reviewerPassed = registrySummary?.reviewer_validation_passed_count ?? 0;
const runtimeGateCount =
registrySummary?.runtime_gate_count ??
runtimeSummary?.runtime_gate_count ??
0;
const hostWriteCount =
registrySummary?.host_write_authorized_count ??
runtimeSummary?.host_write_authorized_count ??
0;
const activeResponseCount =
registrySummary?.active_response_authorized_count ??
runtimeSummary?.active_response_authorized_count ??
0;
const secretValueAllowedCount =
registrySummary?.secret_value_collection_allowed_count ??
0;
const locatorStatus =
summary?.windows99_vmx_source_locator_status ??
evidence?.windows99_vmx_source_locator_status ??
"waiting_readback";
const locatorCandidates =
summary?.windows99_vmx_source_locator_candidate_source_count ??
evidence?.windows99_vmx_source_locator_candidate_source_count ??
0;
const locatorIdentityCandidates =
summary?.windows99_vmx_source_locator_identity_unassigned_ubuntu_candidate_count ??
evidence?.windows99_vmx_source_locator_identity_unassigned_ubuntu_candidate_count ??
0;
const locatorConfirmationRequired =
summary?.windows99_vmx_source_locator_candidate_confirmation_required ??
evidence?.windows99_vmx_source_locator_candidate_confirmation_required ??
false;
const locatorRawPathOutput =
summary?.windows99_vmx_source_locator_raw_path_output ??
evidence?.windows99_vmx_source_locator_raw_path_output ??
false;
const locatorRemoteWrite =
summary?.windows99_vmx_source_locator_remote_write_performed ??
evidence?.windows99_vmx_source_locator_remote_write_performed ??
false;
const locatorVmPower =
summary?.windows99_vmx_source_locator_vm_power_change_performed ??
evidence?.windows99_vmx_source_locator_vm_power_change_performed ??
false;
const nextAction =
evidence?.windows99_vmx_source_locator_candidate_confirmation_safe_next_step ??
evidence?.windows99_vmx_source_locator_next_executable_step ??
summary?.ai_loop_current_blocker_safe_next_action ??
activeItem?.next_action ??
summary?.commander_inserted_requirement_next_action ??
"--";
const guardClear =
runtimeGateCount === 0 &&
hostWriteCount === 0 &&
activeResponseCount === 0 &&
secretValueAllowedCount === 0 &&
!locatorRawPathOutput &&
!locatorRemoteWrite &&
!locatorVmPower;
const mainSha =
priority?.current_head?.latest_successful_deployed_source_sha ??
priority?.current_head?.gitea_main_sha ??
null;
const shortSha = mainSha ? mainSha.slice(0, 10) : "--";
const cards = [
{
key: "p0",
label: copy.p0,
value: summary?.active_p0_workplan_id ?? activeItem?.id ?? "P0",
detail: `${copy.readiness} ${readiness}% · ${activeBlockers.length} ${copy.blockers}`,
icon: Radar,
tone: activeBlockers.length > 0 ? "blocked" : "live",
},
{
key: "registry",
label: copy.registry,
value: `${registryAccepted}/${registryExpected || "?"}`,
detail: `${copy.owner} ${ownerAccepted} · ${copy.reviewer} ${reviewerPassed}`,
icon: Network,
tone: registryExpected > 0 && registryAccepted >= registryExpected ? "live" : "in_progress",
},
{
key: "locator",
label: copy.locator,
value: `${locatorCandidates}`,
detail: `${copy.identity} ${locatorIdentityCandidates} · ${copy.confirmation} ${locatorConfirmationRequired ? "yes" : "no"}`,
icon: SearchCheck,
tone: locatorCandidates > 0 && locatorConfirmationRequired ? "in_progress" : locatorCandidates > 0 ? "live" : "blocked",
},
{
key: "guard",
label: copy.guard,
value: guardClear ? "0" : "!",
detail: `${copy.noRaw} · ${copy.noWrite} · ${copy.noPower}`,
icon: Lock,
tone: guardClear ? "live" : "blocked",
},
] as const;
return (
<section
data-testid="awooop-security-mainline-cockpit"
className="overflow-hidden border border-[#d7ddd8] bg-white"
>
<div className="grid gap-px bg-[#d7ddd8] lg:grid-cols-[1.15fr_2fr]">
<div className="grid gap-4 bg-[#111514] p-4 text-white">
<div className="flex flex-wrap items-center gap-2 text-xs font-semibold text-[#b8d8c5]">
<ShieldCheck className="h-4 w-4" aria-hidden="true" />
<span>{copy.eyebrow}</span>
<span className="ml-auto rounded-full border border-white/20 px-2 py-1 font-mono text-[10px] text-[#dfe7df]">
{liveLoading || loading ? copy.loading : copy.live}
</span>
</div>
<div className="min-w-0">
<h3 className="text-xl font-semibold leading-tight text-white">
{copy.title}
</h3>
<p className="mt-2 text-xs leading-5 text-[#dfe7df]">
{copy.subtitle}
</p>
</div>
<div className="grid grid-cols-2 gap-2">
<div className="rounded border border-white/15 bg-white/5 px-3 py-2">
<p className="text-[10px] font-semibold text-[#aeb7ad]">{copy.deployLabel}</p>
<p className="mt-1 truncate font-mono text-sm font-semibold text-[#b8d8c5]">
{shortSha}
</p>
</div>
<div className="rounded border border-white/15 bg-white/5 px-3 py-2">
<p className="text-[10px] font-semibold text-[#aeb7ad]">{copy.locatorLabel}</p>
<p className="mt-1 truncate text-sm font-semibold text-[#d7c6a9]">
{locatorStatus}
</p>
</div>
</div>
</div>
<div className="grid gap-3 bg-white p-3">
<div className="grid gap-2 sm:grid-cols-2 xl:grid-cols-4">
{cards.map((card) => {
const Icon = card.icon;
return (
<article
key={card.key}
className={cn(
"grid min-h-[118px] content-between gap-3 rounded border p-3",
card.tone === "live" && "border-[#bddfc9] bg-[#f4fbf6]",
card.tone === "in_progress" && "border-[#e2c08f] bg-[#fff8f1]",
card.tone === "blocked" && "border-[#e2a29b] bg-[#fff0ef]"
)}
>
<div className="flex items-center justify-between gap-2">
<p className="min-w-0 truncate text-[11px] font-semibold text-[#5f5b52]">
{card.label}
</p>
<Icon
className={cn(
"h-4 w-4",
card.tone === "live" && "text-[#17602a]",
card.tone === "in_progress" && "text-[#8a5a08]",
card.tone === "blocked" && "text-[#9f2f25]"
)}
aria-hidden="true"
/>
</div>
<p
className={cn(
"break-words font-mono text-2xl font-semibold leading-none",
card.tone === "live" && "text-[#17602a]",
card.tone === "in_progress" && "text-[#8a5a08]",
card.tone === "blocked" && "text-[#9f2f25]"
)}
>
{card.value}
</p>
<p className="text-[11px] leading-4 text-[#5f5b52]">
{card.detail}
</p>
</article>
);
})}
</div>
<div className="grid gap-2 rounded border border-[#d8d3c7] bg-[#faf9f3] p-3 md:grid-cols-[1fr_auto] md:items-center">
<div className="min-w-0">
<p className="text-[11px] font-semibold text-[#77736a]">
{copy.next}
</p>
<p className="mt-1 break-words text-sm font-semibold leading-5 text-[#141413]">
{nextAction}
</p>
</div>
<div className="flex flex-wrap gap-2 md:justify-end">
{[
[copy.noRaw, !locatorRawPathOutput],
[copy.noWrite, hostWriteCount === 0 && !locatorRemoteWrite],
[copy.noPower, !locatorVmPower],
[copy.locked, runtimeGateCount === 0 && activeResponseCount === 0],
].map(([label, ok]) => (
<span
key={String(label)}
className={cn(
"rounded-full border px-2 py-1 text-[10px] font-semibold",
ok
? "border-[#bddfc9] bg-white text-[#17602a]"
: "border-[#e2a29b] bg-[#fff0ef] text-[#9f2f25]"
)}
>
{String(label)}
</span>
))}
</div>
</div>
</div>
</div>
</section>
);
}
function ManagerSituationBoard({
priority,
loading,
@@ -11226,6 +11566,12 @@ export default function AwoooPWorkItemsPage() {
active={workspaceView === "overview"}
view="overview"
>
<SecurityMainlineCockpit
priority={commanderInsertedRequirementWorkOrder}
loading={loading || priorityWorkOrderLoading}
locale={locale}
/>
<ManagerSituationBoard
priority={commanderInsertedRequirementWorkOrder}
loading={false}