diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 5a29ab182..447d98ab9 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -4965,16 +4965,88 @@ "iwooos": { "eyebrow": "資訊安全網", "title": "IwoooS", - "subtitle": "資安網的態勢入口。把 Kali、原始碼管控、負責人回覆、審批閘門、AwoooP 只讀鏡像證據收成一個可讀的資安態勢,不啟動掃描、不修復、不阻擋產品流程。", + "subtitle": "Kali、原始碼、主機、Gate 與 AwoooP evidence 的可視化資安態勢。", "boundary": { "label": "目前邊界", "state": "只讀鏡像 / 先觀測", - "detail": "所有數字來自已驗證 snapshot 與 guard。此頁只顯示態勢、缺口、下一個 閘門 與非阻擋分流。" + "detail": "只顯示態勢與缺口;掃描、修復、更新、阻擋仍未開閘。" + }, + "visualCommandDashboard": { + "eyebrow": "視覺化資安指揮板", + "title": "先看圖,再展開證據", + "subtitle": "第一層只呈現風險、覆蓋、Gate 與主機缺口。詳細文件、長說明與 contract 轉到下方可展開區。", + "metrics": { + "overall": { + "label": "整體態勢", + "detail": "目前重點進度 61%" + }, + "framework": { + "label": "框架完成", + "detail": "文件 / schema / evidence" + }, + "runtime": { + "label": "落地執行", + "detail": "仍在 Gate 0" + } + }, + "nodes": { + "awoooiCore": { + "title": "核心產品", + "caption": "IwoooS / AwoooP 已連動" + }, + "websites": { + "title": "網站入口", + "caption": "六類產品先只讀套用" + }, + "kali112": { + "title": "Kali 112", + "caption": "只讀快照已接入" + }, + "devHosts": { + "title": "開發主機", + "caption": "168 / 111 納入視野" + }, + "githubPrimary": { + "title": "GitHub Primary", + "caption": "等待負責人證據" + }, + "runtimeGate": { + "title": "Runtime Gate", + "caption": "主動執行為 0" + } + }, + "gateMatrix": { + "title": "Gate 矩陣" + }, + "gates": { + "kaliMaintenance": { + "title": "Kali 維護", + "caption": "1994 套件待維護窗口" + }, + "ownerResponse": { + "title": "負責人回覆", + "caption": "S4.9 仍未收到可驗收回覆" + }, + "githubPrimary": { + "title": "版本主來源", + "caption": "尚未批准切 GitHub primary" + }, + "runtimeExecution": { + "title": "執行期", + "caption": "掃描、修復、更新都未開閘" + } + }, + "drilldown": { + "title": "展開 evidence / host / action drill-down", + "evidence": "Evidence:快照、guard、LOGBOOK、approval queue 保留在下方可展開區。", + "hosts": "Hosts:Kali 112、開發主機 168 / 111 都以只讀納管,不直接 SSH 或掃描。", + "actions": "Actions:所有高風險動作仍需人工決策,頁面不提供執行按鈕。" + } }, "informationArchitecture": { "overview": { "title": "一眼看懂", - "summary": "預設只展開 重點、下一個 閘門、進度移動條件與目前仍鎖住的邊界。" + "summary": "詳細重點、下一個 閘門、進度移動條件與目前仍鎖住的邊界;預設收合,避免首頁文字過重。" }, "frontStage": { "title": "前台入口與既有資安頁", @@ -5449,6 +5521,35 @@ } } }, + "kaliMaintenanceReadiness": { + "eyebrow": "Kali 112 維護就緒度", + "title": "Kali 112 已納管,但更新與重啟仍在維護 閘門", + "subtitle": "這個看板把 2026-05-31 17:22 的只讀快照轉成操作可讀狀態:目前能確認主機存在、健康資訊可見、風險缺口明確;但 full-upgrade、autoremove、reboot、掃描與 /execute 都還沒有批准。", + "maintenanceGateLabel": "維護 閘門", + "maintenanceGate": "Kali rolling full-upgrade / autoremove / reboot 仍是 security approval queue 的 pending approval。必須先有維護窗口、snapshot、rollback、post-health 複驗與人工批准,才能往主機更新前進。", + "nextEvidenceLabel": "下一份要補的 evidence", + "nextEvidence": "把 `kali-full-upgrade-reboot-approval-20260513` 的窗口、回復 owner、服務驗證清單與失敗處理 lane 補齊。補齊前 IwoooS 只顯示就緒度,不提供任何更新或重啟入口。", + "boundaryTitle": "只讀邊界", + "boundaryIntro": "以下邊界由 `kali-integration-status.snapshot.json` 與 approval queue 投影而來,用來避免把可見狀態誤讀成執行授權。", + "items": { + "readOnlySnapshot": { + "label": "最新只讀快照", + "detail": "既有 SSH key 只讀收集,沒有改主機。" + }, + "upgradablePackages": { + "label": "待更新套件", + "detail": "代表需要排維護窗口,不代表現在可直接更新。" + }, + "failedSystemdUnits": { + "label": "failed systemd unit", + "detail": "需要維護前檢查與事後健康複驗。" + }, + "runtimeGate": { + "label": "執行期閘門", + "detail": "active runtime gate 仍為 0。" + } + } + }, "hostActionGates": { "title": "主機動作 閘門 矩陣", "subtitle": "把主機相關高風險動作拆成只讀 閘門。這裡只說明哪些動作仍被鎖住,以及需要哪一類人工決策;不提供任何執行入口。", diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index 5a29ab182..447d98ab9 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -4965,16 +4965,88 @@ "iwooos": { "eyebrow": "資訊安全網", "title": "IwoooS", - "subtitle": "資安網的態勢入口。把 Kali、原始碼管控、負責人回覆、審批閘門、AwoooP 只讀鏡像證據收成一個可讀的資安態勢,不啟動掃描、不修復、不阻擋產品流程。", + "subtitle": "Kali、原始碼、主機、Gate 與 AwoooP evidence 的可視化資安態勢。", "boundary": { "label": "目前邊界", "state": "只讀鏡像 / 先觀測", - "detail": "所有數字來自已驗證 snapshot 與 guard。此頁只顯示態勢、缺口、下一個 閘門 與非阻擋分流。" + "detail": "只顯示態勢與缺口;掃描、修復、更新、阻擋仍未開閘。" + }, + "visualCommandDashboard": { + "eyebrow": "視覺化資安指揮板", + "title": "先看圖,再展開證據", + "subtitle": "第一層只呈現風險、覆蓋、Gate 與主機缺口。詳細文件、長說明與 contract 轉到下方可展開區。", + "metrics": { + "overall": { + "label": "整體態勢", + "detail": "目前重點進度 61%" + }, + "framework": { + "label": "框架完成", + "detail": "文件 / schema / evidence" + }, + "runtime": { + "label": "落地執行", + "detail": "仍在 Gate 0" + } + }, + "nodes": { + "awoooiCore": { + "title": "核心產品", + "caption": "IwoooS / AwoooP 已連動" + }, + "websites": { + "title": "網站入口", + "caption": "六類產品先只讀套用" + }, + "kali112": { + "title": "Kali 112", + "caption": "只讀快照已接入" + }, + "devHosts": { + "title": "開發主機", + "caption": "168 / 111 納入視野" + }, + "githubPrimary": { + "title": "GitHub Primary", + "caption": "等待負責人證據" + }, + "runtimeGate": { + "title": "Runtime Gate", + "caption": "主動執行為 0" + } + }, + "gateMatrix": { + "title": "Gate 矩陣" + }, + "gates": { + "kaliMaintenance": { + "title": "Kali 維護", + "caption": "1994 套件待維護窗口" + }, + "ownerResponse": { + "title": "負責人回覆", + "caption": "S4.9 仍未收到可驗收回覆" + }, + "githubPrimary": { + "title": "版本主來源", + "caption": "尚未批准切 GitHub primary" + }, + "runtimeExecution": { + "title": "執行期", + "caption": "掃描、修復、更新都未開閘" + } + }, + "drilldown": { + "title": "展開 evidence / host / action drill-down", + "evidence": "Evidence:快照、guard、LOGBOOK、approval queue 保留在下方可展開區。", + "hosts": "Hosts:Kali 112、開發主機 168 / 111 都以只讀納管,不直接 SSH 或掃描。", + "actions": "Actions:所有高風險動作仍需人工決策,頁面不提供執行按鈕。" + } }, "informationArchitecture": { "overview": { "title": "一眼看懂", - "summary": "預設只展開 重點、下一個 閘門、進度移動條件與目前仍鎖住的邊界。" + "summary": "詳細重點、下一個 閘門、進度移動條件與目前仍鎖住的邊界;預設收合,避免首頁文字過重。" }, "frontStage": { "title": "前台入口與既有資安頁", @@ -5449,6 +5521,35 @@ } } }, + "kaliMaintenanceReadiness": { + "eyebrow": "Kali 112 維護就緒度", + "title": "Kali 112 已納管,但更新與重啟仍在維護 閘門", + "subtitle": "這個看板把 2026-05-31 17:22 的只讀快照轉成操作可讀狀態:目前能確認主機存在、健康資訊可見、風險缺口明確;但 full-upgrade、autoremove、reboot、掃描與 /execute 都還沒有批准。", + "maintenanceGateLabel": "維護 閘門", + "maintenanceGate": "Kali rolling full-upgrade / autoremove / reboot 仍是 security approval queue 的 pending approval。必須先有維護窗口、snapshot、rollback、post-health 複驗與人工批准,才能往主機更新前進。", + "nextEvidenceLabel": "下一份要補的 evidence", + "nextEvidence": "把 `kali-full-upgrade-reboot-approval-20260513` 的窗口、回復 owner、服務驗證清單與失敗處理 lane 補齊。補齊前 IwoooS 只顯示就緒度,不提供任何更新或重啟入口。", + "boundaryTitle": "只讀邊界", + "boundaryIntro": "以下邊界由 `kali-integration-status.snapshot.json` 與 approval queue 投影而來,用來避免把可見狀態誤讀成執行授權。", + "items": { + "readOnlySnapshot": { + "label": "最新只讀快照", + "detail": "既有 SSH key 只讀收集,沒有改主機。" + }, + "upgradablePackages": { + "label": "待更新套件", + "detail": "代表需要排維護窗口,不代表現在可直接更新。" + }, + "failedSystemdUnits": { + "label": "failed systemd unit", + "detail": "需要維護前檢查與事後健康複驗。" + }, + "runtimeGate": { + "label": "執行期閘門", + "detail": "active runtime gate 仍為 0。" + } + } + }, "hostActionGates": { "title": "主機動作 閘門 矩陣", "subtitle": "把主機相關高風險動作拆成只讀 閘門。這裡只說明哪些動作仍被鎖住,以及需要哪一類人工決策;不提供任何執行入口。", diff --git a/apps/web/src/app/[locale]/iwooos/page.tsx b/apps/web/src/app/[locale]/iwooos/page.tsx index 81b95112d..a5a50ace4 100644 --- a/apps/web/src/app/[locale]/iwooos/page.tsx +++ b/apps/web/src/app/[locale]/iwooos/page.tsx @@ -39,6 +39,29 @@ type FastProgressItem = { tone: 'steady' | 'warn' | 'locked' } +type VisualDashboardMetric = { + key: string + value: string + arc: number + icon: typeof ShieldCheck + tone: 'steady' | 'warn' | 'locked' +} + +type VisualDashboardNode = { + key: string + state: string + icon: typeof ShieldCheck + tone: 'steady' | 'warn' | 'locked' +} + +type VisualDashboardGate = { + key: string + gate: string + value: string + icon: typeof ShieldCheck + tone: 'steady' | 'warn' | 'locked' +} + type ProgressAccelerationLane = { key: string lane: string @@ -409,6 +432,13 @@ type HostCoverageItem = { tone: 'steady' | 'warn' | 'locked' } +type KaliMaintenanceReadinessItem = { + key: string + value: string + icon: typeof ShieldCheck + tone: 'steady' | 'warn' | 'locked' +} + type HostActionGateItem = { key: string gate: string @@ -641,6 +671,28 @@ const fastProgressItems: FastProgressItem[] = [ { key: 'runtime', value: 'Gate 0', icon: Lock, tone: 'locked' }, ] +const visualDashboardMetrics: VisualDashboardMetric[] = [ + { key: 'overall', value: '61%', arc: 220, icon: Activity, tone: 'warn' }, + { key: 'framework', value: '88%', arc: 317, icon: ShieldCheck, tone: 'steady' }, + { key: 'runtime', value: '45%', arc: 162, icon: Lock, tone: 'locked' }, +] + +const visualDashboardNodes: VisualDashboardNode[] = [ + { key: 'awoooiCore', state: 'OK', icon: ShieldCheck, tone: 'steady' }, + { key: 'websites', state: '6/6', icon: Radar, tone: 'steady' }, + { key: 'kali112', state: '112', icon: Activity, tone: 'warn' }, + { key: 'devHosts', state: '2', icon: ListChecks, tone: 'warn' }, + { key: 'githubPrimary', state: '0', icon: GitBranch, tone: 'locked' }, + { key: 'runtimeGate', state: '0', icon: Lock, tone: 'locked' }, +] + +const visualDashboardGates: VisualDashboardGate[] = [ + { key: 'kaliMaintenance', gate: 'S3.4', value: '1994', icon: FileWarning, tone: 'warn' }, + { key: 'ownerResponse', gate: 'S4.9', value: '0/5', icon: ClipboardCheck, tone: 'warn' }, + { key: 'githubPrimary', gate: 'S4.10', value: '0', icon: GitBranch, tone: 'locked' }, + { key: 'runtimeExecution', gate: 'Gate 0', value: '0', icon: Lock, tone: 'locked' }, +] + const allProductCoverageSnapshotSummary = [ { key: 'scopeCount', value: '6', icon: ListChecks, tone: 'steady' }, { key: 'readOnlyScopes', value: '6', icon: ShieldCheck, tone: 'steady' }, @@ -3018,6 +3070,27 @@ const hostCoverageItems: HostCoverageItem[] = [ { key: 'dev111', address: '192.168.0.111', icon: Radar, tone: 'warn' }, ] +const kaliMaintenanceReadinessItems: KaliMaintenanceReadinessItem[] = [ + { key: 'readOnlySnapshot', value: '2026-05-31 17:22', icon: ShieldCheck, tone: 'steady' }, + { key: 'upgradablePackages', value: '1994', icon: FileWarning, tone: 'warn' }, + { key: 'failedSystemdUnits', value: '1', icon: AlertTriangle, tone: 'warn' }, + { key: 'runtimeGate', value: 'Gate 0', icon: Lock, tone: 'locked' }, +] + +const kaliMaintenanceReadinessBoundaries = [ + 'kali_112_read_only_snapshot_collected=true', + 'kali_112_upgradable_package_count=1994', + 'kali_112_failed_systemd_unit_count=1', + 'kali_112_full_upgrade_authorized=false', + 'kali_112_reboot_authorized=false', + 'kali_112_package_update_executed=false', + 'kali_112_host_reboot_executed=false', + 'kali_112_active_scan_executed=false', + 'kali_112_runtime_execution_authorized=false', + 'active_runtime_gate_count=0', + 'not_authorization=true', +] as const + const hostActionGateItems: HostActionGateItem[] = [ { key: 'activeScan', gate: 'S1.6', icon: Radar, tone: 'locked' }, { key: 'credentialedScan', gate: 'S1.6', icon: Lock, tone: 'locked' }, @@ -3454,6 +3527,199 @@ function MetricCard({ item }: { item: PostureMetric }) { ) } +function IwoooSVisualCommandDashboard() { + const t = useTranslations('iwooos.visualCommandDashboard') + const textWrap = { overflowWrap: 'anywhere' as const, wordBreak: 'break-word' as const } + + return ( +
+
+
+
+
+ + {t('eyebrow')} +
+

{t('title')}

+
+
+ {t('subtitle')} +
+
+ +
+ {visualDashboardMetrics.map(item => { + const Icon = item.icon + return ( +
+
+ {t(`metrics.${item.key}.label` as never)} + +
+
+
+
+
+
+
+ {item.value} +
+
+ {t(`metrics.${item.key}.detail` as never)} +
+
+
+
+ ) + })} +
+ +
+ {visualDashboardNodes.map(item => { + const Icon = item.icon + return ( +
+
+ + {item.state} +
+
+
+ {t(`nodes.${item.key}.title` as never)} +
+
+ {t(`nodes.${item.key}.caption` as never)} +
+
+
+ ) + })} +
+
+ +
+
+ +

{t('gateMatrix.title')}

+
+
+ {visualDashboardGates.map(item => { + const Icon = item.icon + return ( +
+ +
+
+ {t(`gates.${item.key}.title` as never)} +
+
+ {t(`gates.${item.key}.caption` as never)} +
+
+
+ {item.gate} + {item.value} +
+
+ ) + })} +
+ +
+ + {t('drilldown.title')} + +
+ {['evidence', 'hosts', 'actions'].map(key => ( +
+ {t(`drilldown.${key}` as never)} +
+ ))} +
+
+
+
+ ) +} + function IwoooSFastProgressSummary() { const t = useTranslations('iwooos.fastProgress') return ( @@ -11187,6 +11453,136 @@ function HostCoverageCard({ item, index }: { item: HostCoverageItem; index: numb ) } +function KaliMaintenanceReadinessBoard() { + const t = useTranslations('iwooos.kaliMaintenanceReadiness') + const textWrap = { overflowWrap: 'anywhere' as const, wordBreak: 'break-word' as const } + + return ( +
+
+
+
+
+ + {t('eyebrow')} +
+

{t('title')}

+

+ {t('subtitle')} +

+
+ +
+ {kaliMaintenanceReadinessItems.map(item => { + const Icon = item.icon + return ( +
+
+ {t(`items.${item.key}.label` as never)} + +
+
+ {item.value} +
+

+ {t(`items.${item.key}.detail` as never)} +

+
+ ) + })} +
+
+ +
+
+
{t('maintenanceGateLabel')}
+
+ {t('maintenanceGate')} +
+
+
+
{t('nextEvidenceLabel')}
+
+ {t('nextEvidence')} +
+
+
+ +
+ + {t('boundaryTitle')} + +

+ {t('boundaryIntro')} +

+
+ {kaliMaintenanceReadinessBoundaries.map(boundary => ( + + {boundary} + + ))} +
+
+
+
+ ) +} + function HostActionGateCard({ item, index }: { item: HostActionGateItem; index: number }) { const t = useTranslations('iwooos.hostActionGates') const Icon = item.icon @@ -12154,13 +12550,14 @@ export default function IwoooSPage({ params }: { params: { locale: string } }) { - + + +
+ +

{t('hostActionGates.title')}

diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index 0270fdbdd..486b806ed 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,58 @@ +## 2026-05-31|IwoooS 視覺化資安指揮板與 Kali 維護就緒度 + +**背景**: + +- 使用者指出 `/zh-TW/iwooos` 文字量過高,不符合專業資安市場主流的視覺化、圖表化、互動式資安體驗。 +- 本輪保持 Gate 0 與低摩擦原則:只改善前台 UX、只讀 evidence 與 guard,不啟動掃描、`/execute`、Kali 更新、重啟或 GitHub primary 切換。 + +**本次調整**: + +- `apps/web/src/app/[locale]/iwooos/page.tsx`: + - 新增 `IwoooSVisualCommandDashboard`,第一層改成風險環、產品 / 主機覆蓋節點、Gate 矩陣與 drill-down details。 + - overview 長內容改為預設收合,避免首頁一進來就被大量文字淹沒。 + - 新增 `KaliMaintenanceReadinessBoard`,把 Kali `192.168.0.112` 的只讀快照、待更新套件 `1994`、failed systemd unit `1`、full-upgrade / reboot Gate 0 邊界視覺化。 +- `apps/web/messages/zh-TW.json` / `apps/web/messages/en.json`: + - 補齊視覺化資安指揮板與 Kali 維護就緒度文案;兩個語系維持繁體中文鏡像。 +- `docs/security/iwooos-posture-projection.snapshot.json`: + - 新增 `display_visual_command_dashboard`、`visual_command_dashboard_widget_count=13`、`long_form_sections_default_collapsed=true`。 + - 新增 Kali 維護就緒度四個只讀 projection item。 +- `scripts/security/security-mirror-progress-guard.py`: + - 新增視覺化指揮板、Kali 維護就緒度、繁中鏡像與禁止升級成執行授權的 guard。 + +**驗證**: + +```text +python3 scripts/security/security-mirror-progress-guard.py -> SECURITY_MIRROR_PROGRESS_GUARD_OK +python3 scripts/security/source-control-owner-response-guard.py -> SOURCE_CONTROL_OWNER_RESPONSE_GUARD_OK +python3 -m json.tool apps/web/messages/zh-TW.json / en.json / docs/security/iwooos-posture-projection.snapshot.json -> pass +cmp -s apps/web/messages/zh-TW.json apps/web/messages/en.json -> pass +pnpm --dir apps/web run typecheck -> pass +NEXT_PUBLIC_API_URL=https://awoooi.wooo.work pnpm --dir apps/web run build -> pass + +local browser smoke: + /zh-TW/iwooos desktop 1440: + visualDashboardVisible=true + overviewOpen=false + horizontalOverflow=false + hasChartRing=true + hasKaliGate=true + /zh-TW/iwooos mobile 390: + visualDashboardVisible=true + overviewOpen=false + horizontalOverflow=false + hasChartRing=true + hasKaliGate=true + screenshots: + /tmp/iwooos-visual-dashboard-desktop-20260531.png + /tmp/iwooos-visual-dashboard-mobile-20260531.png +``` + +**進度邊界**: + +- 整體資安進度仍維持 `61%`;這是 UX / 可理解性 / read-only projection 進步,不是 runtime 開閘。 +- Kali `192.168.0.112` 仍沒有執行 full-upgrade、autoremove、reboot、active scan 或 `/execute`。 +- 下一個真正推動 headline progress 的 Gate 仍是負責人回覆被驗收、redacted finding ingestion、GitHub primary evidence 或 active runtime gate 其中之一。 + ## 2026-05-31|Work Items 焦點 Incident 稽核鏈 local 收斂 **背景**: diff --git a/docs/security/iwooos-posture-projection.snapshot.json b/docs/security/iwooos-posture-projection.snapshot.json index 078f9ba7a..39bc0012d 100644 --- a/docs/security/iwooos-posture-projection.snapshot.json +++ b/docs/security/iwooos-posture-projection.snapshot.json @@ -32,6 +32,9 @@ "approval_queue_total": 8, "pending_approval_count": 7, "block_candidate_count": 1, + "visual_command_dashboard_widget_count": 13, + "visual_command_dashboard_first_layer": true, + "long_form_sections_default_collapsed": true, "owner_response_validation_received_count": 0, "owner_response_validation_accepted_count": 0, "github_primary_ready_count": 0, @@ -49,6 +52,7 @@ "operator_journey_step_count": 6, "owner_evidence_readiness_item_count": 7, "host_coverage_item_count": 3, + "kali_maintenance_readiness_item_count": 4, "host_action_gate_item_count": 6, "host_evidence_readiness_item_count": 7, "host_evidence_collection_step_count": 7, @@ -242,6 +246,7 @@ "allowed_frontend_outputs": [ "display_security_posture", "display_progress_estimate", + "display_visual_command_dashboard", "display_awooop_read_only_landing_readiness", "display_awooop_cross_session_handoff_packets", "display_progress_hold_movement_gates", @@ -254,6 +259,7 @@ "display_operator_journey_steps", "display_owner_evidence_readiness_board", "display_host_coverage_view", + "display_kali_maintenance_readiness_board", "display_host_action_gate_matrix", "display_host_evidence_readiness_board", "display_evidence_refs", @@ -1139,6 +1145,57 @@ "not_authorization": true } ], + "kali_maintenance_readiness_items": [ + { + "item_id": "kali_112_read_only_snapshot", + "display_order": 1, + "source_contract": "kali_integration_status_v1", + "source_observed_at_taipei": "2026-05-31T17:22:20+08:00", + "readiness_state": "snapshot_collected_read_only", + "display_mode": "maintenance_readiness_only", + "runtime_execution_authorized": false, + "package_update_executed": false, + "host_reboot_executed": false, + "active_scan_executed": false, + "not_authorization": true + }, + { + "item_id": "kali_112_upgradable_package_count", + "display_order": 2, + "source_contract": "kali_integration_status_v1", + "metric_value": 1994, + "readiness_state": "maintenance_window_required", + "display_mode": "maintenance_readiness_only", + "full_upgrade_authorized": false, + "runtime_execution_authorized": false, + "package_update_executed": false, + "not_authorization": true + }, + { + "item_id": "kali_112_failed_systemd_unit_count", + "display_order": 3, + "source_contract": "kali_integration_status_v1", + "metric_value": 1, + "readiness_state": "pre_maintenance_health_check_required", + "display_mode": "maintenance_readiness_only", + "runtime_execution_authorized": false, + "host_reboot_executed": false, + "not_authorization": true + }, + { + "item_id": "kali_112_full_upgrade_reboot_gate", + "display_order": 4, + "source_contract": "security_approval_queue_v1", + "source_queue_item_id": "kali-full-upgrade-reboot-approval-20260513", + "readiness_state": "pending_approval_requires_window_snapshot_rollback_post_health", + "display_mode": "maintenance_readiness_only", + "full_upgrade_authorized": false, + "reboot_authorized": false, + "runtime_execution_authorized": false, + "action_buttons_allowed": false, + "not_authorization": true + } + ], "host_action_gate_items": [ { "action_id": "host_active_scan_gate", diff --git a/scripts/security/security-mirror-progress-guard.py b/scripts/security/security-mirror-progress-guard.py index f5c6789ed..90ca4967f 100755 --- a/scripts/security/security-mirror-progress-guard.py +++ b/scripts/security/security-mirror-progress-guard.py @@ -225,6 +225,90 @@ def validate(root: Path) -> None: web_messages_en, web_messages_zh, ) + for text in [ + "IwoooSVisualCommandDashboard", + 'data-testid="iwooos-visual-command-dashboard"', + "visualDashboardMetrics", + "visualDashboardNodes", + "visualDashboardGates", + "conic-gradient", + "visualCommandDashboard", + ]: + assert_text_contains("iwooos_projection_page.visual_command_dashboard", iwooos_projection_page, text) + for key in [ + "eyebrow", + "title", + "subtitle", + "metrics", + "nodes", + "gateMatrix", + "gates", + "drilldown", + ]: + assert_contains( + "web_messages.zh-TW.iwooos.visualCommandDashboard", + list(web_messages_zh["iwooos"]["visualCommandDashboard"].keys()), + key, + ) + for key in ["overall", "framework", "runtime"]: + assert_contains( + "web_messages.zh-TW.iwooos.visualCommandDashboard.metrics", + list(web_messages_zh["iwooos"]["visualCommandDashboard"]["metrics"].keys()), + key, + ) + for key in ["awoooiCore", "websites", "kali112", "devHosts", "githubPrimary", "runtimeGate"]: + assert_contains( + "web_messages.zh-TW.iwooos.visualCommandDashboard.nodes", + list(web_messages_zh["iwooos"]["visualCommandDashboard"]["nodes"].keys()), + key, + ) + for key in ["kaliMaintenance", "ownerResponse", "githubPrimary", "runtimeExecution"]: + assert_contains( + "web_messages.zh-TW.iwooos.visualCommandDashboard.gates", + list(web_messages_zh["iwooos"]["visualCommandDashboard"]["gates"].keys()), + key, + ) + for key in [ + "eyebrow", + "title", + "subtitle", + "maintenanceGateLabel", + "maintenanceGate", + "nextEvidenceLabel", + "nextEvidence", + "boundaryTitle", + "boundaryIntro", + "items", + ]: + assert_contains( + "web_messages.zh-TW.iwooos.kaliMaintenanceReadiness", + list(web_messages_zh["iwooos"]["kaliMaintenanceReadiness"].keys()), + key, + ) + for key in [ + "readOnlySnapshot", + "upgradablePackages", + "failedSystemdUnits", + "runtimeGate", + ]: + assert_contains( + "web_messages.zh-TW.iwooos.kaliMaintenanceReadiness.items", + list(web_messages_zh["iwooos"]["kaliMaintenanceReadiness"]["items"].keys()), + key, + ) + for text in [ + "KaliMaintenanceReadinessBoard", + 'data-testid="iwooos-kali-maintenance-readiness-board"', + "kali_112_upgradable_package_count=1994", + "kali_112_failed_systemd_unit_count=1", + "kali_112_full_upgrade_authorized=false", + "kali_112_reboot_authorized=false", + "kali_112_package_update_executed=false", + "kali_112_host_reboot_executed=false", + "kali_112_active_scan_executed=false", + "kali_112_runtime_execution_authorized=false", + ]: + assert_text_contains("iwooos_projection_page.kali_maintenance_readiness", iwooos_projection_page, text) progress = rollup["progress_estimate"] assert_equal("progress.overall_percent", progress["overall_percent"], 61) @@ -1305,6 +1389,12 @@ def validate(root: Path) -> None: "dev_168_development_host", "dev_111_development_host", ] + expected_iwooos_kali_maintenance_readiness_item_ids = [ + "kali_112_read_only_snapshot", + "kali_112_upgradable_package_count", + "kali_112_failed_systemd_unit_count", + "kali_112_full_upgrade_reboot_gate", + ] expected_iwooos_host_action_gate_item_ids = [ "host_active_scan_gate", "host_credentialed_scan_gate", @@ -1601,6 +1691,19 @@ def validate(root: Path) -> None: "host_decision_record_human_record_owner_review_preparation_validation_runtime_gate_separate_check", "host_decision_record_human_record_owner_review_preparation_no_execution_attestation_present_check", ] + assert_equal( + "iwooos_projection.summary.visual_command_dashboard_widget_count", + iwooos_projection["summary"]["visual_command_dashboard_widget_count"], + 13, + ) + assert_true( + "iwooos_projection.summary.visual_command_dashboard_first_layer", + iwooos_projection["summary"]["visual_command_dashboard_first_layer"], + ) + assert_true( + "iwooos_projection.summary.long_form_sections_default_collapsed", + iwooos_projection["summary"]["long_form_sections_default_collapsed"], + ) assert_equal( "iwooos_projection.summary.frontend_surface_coverage_group_count", iwooos_projection["summary"]["frontend_surface_coverage_group_count"], @@ -1626,6 +1729,11 @@ def validate(root: Path) -> None: iwooos_projection["summary"]["host_coverage_item_count"], len(expected_iwooos_host_coverage_item_ids), ) + assert_equal( + "iwooos_projection.summary.kali_maintenance_readiness_item_count", + iwooos_projection["summary"]["kali_maintenance_readiness_item_count"], + len(expected_iwooos_kali_maintenance_readiness_item_ids), + ) assert_equal( "iwooos_projection.summary.host_action_gate_item_count", iwooos_projection["summary"]["host_action_gate_item_count"], @@ -2819,6 +2927,76 @@ def validate(root: Path) -> None: f"iwooos_projection.host_coverage_items.{item['host_id']}.not_authorization", item["not_authorization"], ) + iwooos_kali_maintenance_readiness = iwooos_projection["kali_maintenance_readiness_items"] + assert_equal( + "iwooos_projection.kali_maintenance_readiness_items.ids", + [item["item_id"] for item in iwooos_kali_maintenance_readiness], + expected_iwooos_kali_maintenance_readiness_item_ids, + ) + assert_equal( + "iwooos_projection.kali_maintenance_readiness_items.display_order", + [item["display_order"] for item in iwooos_kali_maintenance_readiness], + list(range(1, len(expected_iwooos_kali_maintenance_readiness_item_ids) + 1)), + ) + assert_equal( + "iwooos_projection.kali_maintenance_readiness_items.upgradable_package_count", + iwooos_kali_maintenance_readiness[1]["metric_value"], + 1994, + ) + assert_equal( + "iwooos_projection.kali_maintenance_readiness_items.failed_systemd_unit_count", + iwooos_kali_maintenance_readiness[2]["metric_value"], + 1, + ) + assert_equal( + "iwooos_projection.kali_maintenance_readiness_items.reboot_gate_queue_item", + iwooos_kali_maintenance_readiness[3]["source_queue_item_id"], + "kali-full-upgrade-reboot-approval-20260513", + ) + for item in iwooos_kali_maintenance_readiness: + assert_equal( + f"iwooos_projection.kali_maintenance_readiness_items.{item['item_id']}.display_mode", + item["display_mode"], + "maintenance_readiness_only", + ) + assert_false( + f"iwooos_projection.kali_maintenance_readiness_items.{item['item_id']}.runtime_execution_authorized", + item["runtime_execution_authorized"], + ) + if "full_upgrade_authorized" in item: + assert_false( + f"iwooos_projection.kali_maintenance_readiness_items.{item['item_id']}.full_upgrade_authorized", + item["full_upgrade_authorized"], + ) + if "reboot_authorized" in item: + assert_false( + f"iwooos_projection.kali_maintenance_readiness_items.{item['item_id']}.reboot_authorized", + item["reboot_authorized"], + ) + if "package_update_executed" in item: + assert_false( + f"iwooos_projection.kali_maintenance_readiness_items.{item['item_id']}.package_update_executed", + item["package_update_executed"], + ) + if "host_reboot_executed" in item: + assert_false( + f"iwooos_projection.kali_maintenance_readiness_items.{item['item_id']}.host_reboot_executed", + item["host_reboot_executed"], + ) + if "active_scan_executed" in item: + assert_false( + f"iwooos_projection.kali_maintenance_readiness_items.{item['item_id']}.active_scan_executed", + item["active_scan_executed"], + ) + if "action_buttons_allowed" in item: + assert_false( + f"iwooos_projection.kali_maintenance_readiness_items.{item['item_id']}.action_buttons_allowed", + item["action_buttons_allowed"], + ) + assert_true( + f"iwooos_projection.kali_maintenance_readiness_items.{item['item_id']}.not_authorization", + item["not_authorization"], + ) iwooos_host_action_gates = iwooos_projection["host_action_gate_items"] assert_equal( "iwooos_projection.host_action_gate_items.ids", @@ -5588,6 +5766,7 @@ def validate(root: Path) -> None: for output in [ "display_security_posture", "display_progress_estimate", + "display_visual_command_dashboard", "display_awooop_read_only_landing_readiness", "display_awooop_cross_session_handoff_packets", "display_progress_hold_movement_gates", @@ -5603,6 +5782,7 @@ def validate(root: Path) -> None: "display_operator_journey_steps", "display_owner_evidence_readiness_board", "display_host_coverage_view", + "display_kali_maintenance_readiness_board", "display_host_action_gate_matrix", "display_host_evidence_readiness_board", "display_host_evidence_collection_order",