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
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:
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user