diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 2b9fd3cf5..8d40a6c45 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -1672,6 +1672,49 @@ "decision": "display gate candidate only; action buttons=false" } } + }, + "hostOwnerDecisionReviewChecklist": { + "title": "Host Owner Decision Review Checklist", + "subtitle": "After owner decision candidate packets, every item still requires human review. This only displays review checks and does not create decision records, mark approval, or open runtime gates.", + "checkLabel": "Owner review", + "guardLabel": "Safety boundary", + "items": { + "scopeBoundaryReadable": { + "title": "Scope boundary readable", + "body": "Confirm the owner can read hosts, networks, services, exclusions, and observation purpose without exceeding the original scope.", + "guard": "scope review only; owner decision received=0" + }, + "scanModeNotAuthorization": { + "title": "Scan mode not authorization", + "body": "Confirm observe-only, future active scan, and credentialed scan are mode descriptions only, not scan authorization.", + "guard": "scan authorized=false" + }, + "credentialBoundaryMetadataOnly": { + "title": "Credential boundary metadata only", + "body": "Confirm credential handling keeps only metadata, owner, and retention boundary without requesting sensitive material.", + "guard": "secret collection=false" + }, + "maintenanceWindowNotChange": { + "title": "Maintenance window not change", + "body": "Confirm the maintenance window is only a future candidate condition and does not allow Kali updates or host tuning.", + "guard": "host update=false" + }, + "rollbackOwnerReadable": { + "title": "Rollback owner readable", + "body": "Confirm rollback owner, recovery route, and human contact point are readable, but no change is approved.", + "guard": "approval record=false" + }, + "validationMetricsPredefined": { + "title": "Validation metrics predefined", + "body": "Confirm post-check metrics, baseline, and evidence pointers are defined first for later gate review.", + "guard": "runtime gate opened=false" + }, + "runtimeGateStillSeparate": { + "title": "Runtime gate still separate", + "body": "Confirm owner decision checklist cannot execute any later host action and still needs a separate runtime gate.", + "guard": "action buttons=false" + } + } } }, "tickets": { diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index 4e1f8daf8..9cfa62ae8 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -1673,6 +1673,49 @@ "decision": "只顯示 gate 候選;action buttons=false" } } + }, + "hostOwnerDecisionReviewChecklist": { + "title": "主機 Owner Decision Review Checklist", + "subtitle": "Owner decision candidate packets 之後仍需人工逐項核對。這裡只顯示核對項,不建立決策紀錄、不標示 approved、不開 runtime gate。", + "checkLabel": "Owner 核對", + "guardLabel": "安全邊界", + "items": { + "scopeBoundaryReadable": { + "title": "Scope boundary readable", + "body": "確認 owner 能讀懂主機、網段、服務、排除範圍與觀察目的,且沒有超出原始 scope。", + "guard": "只核對 scope;owner decision received=0" + }, + "scanModeNotAuthorization": { + "title": "Scan mode not authorization", + "body": "確認 observe-only、future active scan、credentialed scan 都只是選項說明,不是掃描授權。", + "guard": "scan authorized=false" + }, + "credentialBoundaryMetadataOnly": { + "title": "Credential boundary metadata only", + "body": "確認 credential handling 只保留 metadata、owner 與保存邊界,不要求敏感素材。", + "guard": "secret collection=false" + }, + "maintenanceWindowNotChange": { + "title": "Maintenance window not change", + "body": "確認維護窗口只是未來候選條件,不代表可以更新 Kali 或調校主機。", + "guard": "host update=false" + }, + "rollbackOwnerReadable": { + "title": "Rollback owner readable", + "body": "確認 rollback owner、復原路徑與人工聯絡點可讀,但尚未批准任何 change。", + "guard": "approval record=false" + }, + "validationMetricsPredefined": { + "title": "Validation metrics predefined", + "body": "確認 post-check metrics、baseline 與 evidence pointer 已先定義,供未來 gate 判讀。", + "guard": "runtime gate opened=false" + }, + "runtimeGateStillSeparate": { + "title": "Runtime gate still separate", + "body": "確認 owner decision checklist 不能直接執行任何後續主機動作,仍需獨立 runtime gate。", + "guard": "action buttons=false" + } + } } }, "tickets": { diff --git a/apps/web/src/app/[locale]/iwooos/page.tsx b/apps/web/src/app/[locale]/iwooos/page.tsx index 63fd3ab48..ce31726d2 100644 --- a/apps/web/src/app/[locale]/iwooos/page.tsx +++ b/apps/web/src/app/[locale]/iwooos/page.tsx @@ -144,6 +144,13 @@ type HostOwnerDecisionCandidatePacket = { tone: 'steady' | 'warn' | 'locked' } +type HostOwnerDecisionReviewChecklistItem = { + key: string + check: string + icon: typeof ShieldCheck + tone: 'steady' | 'warn' | 'locked' +} + const postureMetrics: PostureMetric[] = [ { key: 'overall', value: '58%', tone: 'warn' }, { key: 'framework', value: '80-85%', tone: 'steady' }, @@ -335,6 +342,16 @@ const hostOwnerDecisionCandidatePackets: HostOwnerDecisionCandidatePacket[] = [ { key: 'runtimeGateCandidate', packet: 'D7', icon: ShieldCheck, tone: 'locked' }, ] +const hostOwnerDecisionReviewChecklistItems: HostOwnerDecisionReviewChecklistItem[] = [ + { key: 'scopeBoundaryReadable', check: 'A1', icon: Radar, tone: 'warn' }, + { key: 'scanModeNotAuthorization', check: 'A2', icon: Activity, tone: 'locked' }, + { key: 'credentialBoundaryMetadataOnly', check: 'A3', icon: Lock, tone: 'locked' }, + { key: 'maintenanceWindowNotChange', check: 'A4', icon: Clock3, tone: 'warn' }, + { key: 'rollbackOwnerReadable', check: 'A5', icon: FileWarning, tone: 'warn' }, + { key: 'validationMetricsPredefined', check: 'A6', icon: CheckCircle2, tone: 'warn' }, + { key: 'runtimeGateStillSeparate', check: 'A7', icon: ShieldCheck, tone: 'locked' }, +] + const evidenceItems = [ 'iwooos-posture-projection.snapshot.json', 'security-rollout-policy.snapshot.json', @@ -861,6 +878,34 @@ function HostOwnerDecisionCandidateCard({ item }: { item: HostOwnerDecisionCandi ) } +function HostOwnerDecisionReviewChecklistCard({ item }: { item: HostOwnerDecisionReviewChecklistItem }) { + const t = useTranslations('iwooos.hostOwnerDecisionReviewChecklist') + const Icon = item.icon + return ( +
+ {t(`items.${item.key}.body` as never)} +
++ {t('hostOwnerDecisionReviewChecklist.subtitle')} +
+