diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 185a0a31b..237ba6c8c 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -1447,6 +1447,49 @@ } } }, + "hostEvidenceReviewOutcomes": { + "title": "Host Evidence Review Outcome Lanes", + "subtitle": "After preflight, evidence can only move into these read-only lanes. This shows possible human review outcomes and does not create approval records, runtime gates, or host actions.", + "laneLabel": "Outcome lane", + "nextLabel": "Next step", + "items": { + "readyForHumanReview": { + "title": "Ready for human review", + "body": "Evidence becomes a human review candidate only when metadata pointer, dependency order, scope, and owner pointer are readable.", + "next": "display candidate only; received=0, accepted=0" + }, + "needsScopeEvidence": { + "title": "Needs scope evidence", + "body": "Scan or finding evidence that cannot map to scope boundary returns to the scope lane.", + "next": "collect scope, no scan" + }, + "needsOwnerDecision": { + "title": "Needs owner decision", + "body": "Host change, update, SSH, or blocking evidence without decision pointer returns to owner decision lane.", + "next": "collect decision record, no host action" + }, + "quarantineDependencySkip": { + "title": "Quarantine dependency skip", + "body": "Evidence that skips the S2.17 order or has incomplete prerequisites is quarantined for human interpretation.", + "next": "show quarantine reason, do not advance counters" + }, + "rejectRawPayload": { + "title": "Reject raw payload", + "body": "Full scan output, unredacted findings, host dumps, or log bundles do not enter IwoooS.", + "next": "request redacted summary instead" + }, + "rejectCredentialPlaintext": { + "title": "Reject credential plaintext", + "body": "Passwords, tokens, private keys, sessions, or plaintext credentials are rejected and quarantined.", + "next": "do not store, forward, or display plaintext" + }, + "waitingRuntimeGate": { + "title": "Waiting runtime gate", + "body": "Even after human review allows action, the work waits for a later runtime gate and is not executed by this lane.", + "next": "active runtime gates remain 0" + } + } + }, "nextGate": { "title": "Next High-level Gate", "body": "S4.9 Gitea owner attestation response is the recommended next owner evidence. Headline progress should only increase after owner responses, redacted payload ingestion, active runtime gates, or GitHub primary readiness actually change." diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index 3f2b3d383..4acdcfe06 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -1448,6 +1448,49 @@ } } }, + "hostEvidenceReviewOutcomes": { + "title": "主機 Evidence Review Outcome Lanes", + "subtitle": "預檢後的 evidence 只能進這些只讀分流。這裡顯示人工審查可能結果,不會建立 approval record、runtime gate 或主機動作。", + "laneLabel": "結果分流", + "nextLabel": "下一步", + "items": { + "readyForHumanReview": { + "title": "Ready for human review", + "body": "metadata pointer、依賴順序、scope 與 owner pointer 都可讀時,才可標示為人工審查候選。", + "next": "只顯示候選;received=0、accepted=0" + }, + "needsScopeEvidence": { + "title": "Needs scope evidence", + "body": "scan 或 finding evidence 無法對到 scope boundary 時,回到補 scope lane。", + "next": "補 scope,不進 scan" + }, + "needsOwnerDecision": { + "title": "Needs owner decision", + "body": "主機變更、更新、SSH 或 blocking 類 evidence 缺 decision pointer 時,回到 owner decision lane。", + "next": "補 decision record,不啟動主機動作" + }, + "quarantineDependencySkip": { + "title": "Quarantine dependency skip", + "body": "跳過 S2.17 收件順序或前置依賴不完整時,先隔離再人工判讀。", + "next": "隔離原因可見,不推 counter" + }, + "rejectRawPayload": { + "title": "Reject raw payload", + "body": "完整掃描輸出、未脫敏 finding、host dump 或 log bundle 不進 IwoooS。", + "next": "要求改交脫敏摘要" + }, + "rejectCredentialPlaintext": { + "title": "Reject credential plaintext", + "body": "任何帳密、token、private key、session 或憑證明文都直接拒收並隔離。", + "next": "不保存、不轉送、不顯示明文" + }, + "waitingRuntimeGate": { + "title": "Waiting runtime gate", + "body": "即使人工審查後可採取行動,也只能等待後續 runtime gate,不由 outcome lane 執行。", + "next": "active runtime gates 仍為 0" + } + } + }, "nextGate": { "title": "下一個高層 Gate", "body": "S4.9 Gitea owner attestation response 是目前建議先收的 owner evidence。任何 headline 提升都要等 owner response、redacted payload ingestion、active runtime gate 或 GitHub primary readiness 有真實變化。" diff --git a/apps/web/src/app/[locale]/iwooos/page.tsx b/apps/web/src/app/[locale]/iwooos/page.tsx index 41f3f9841..bfafabd40 100644 --- a/apps/web/src/app/[locale]/iwooos/page.tsx +++ b/apps/web/src/app/[locale]/iwooos/page.tsx @@ -109,6 +109,13 @@ type HostEvidenceIntakeCheck = { tone: 'steady' | 'warn' | 'locked' } +type HostEvidenceReviewOutcomeLane = { + key: string + lane: string + icon: typeof ShieldCheck + tone: 'steady' | 'warn' | 'locked' +} + const postureMetrics: PostureMetric[] = [ { key: 'overall', value: '58%', tone: 'warn' }, { key: 'framework', value: '80-85%', tone: 'steady' }, @@ -250,6 +257,16 @@ const hostEvidenceIntakeChecks: HostEvidenceIntakeCheck[] = [ { key: 'counterFreeze', check: 'P7', icon: ShieldCheck, tone: 'locked' }, ] +const hostEvidenceReviewOutcomeLanes: HostEvidenceReviewOutcomeLane[] = [ + { key: 'readyForHumanReview', lane: 'R1', icon: CheckCircle2, tone: 'steady' }, + { key: 'needsScopeEvidence', lane: 'R2', icon: Radar, tone: 'warn' }, + { key: 'needsOwnerDecision', lane: 'R3', icon: ClipboardCheck, tone: 'warn' }, + { key: 'quarantineDependencySkip', lane: 'R4', icon: GitBranch, tone: 'warn' }, + { key: 'rejectRawPayload', lane: 'R5', icon: FileWarning, tone: 'locked' }, + { key: 'rejectCredentialPlaintext', lane: 'R6', icon: Lock, tone: 'locked' }, + { key: 'waitingRuntimeGate', lane: 'R7', icon: Clock3, tone: 'locked' }, +] + const evidenceItems = [ 'iwooos-posture-projection.snapshot.json', 'security-rollout-policy.snapshot.json', @@ -636,6 +653,34 @@ function HostEvidenceIntakeCard({ item }: { item: HostEvidenceIntakeCheck }) { ) } +function HostEvidenceReviewOutcomeCard({ item }: { item: HostEvidenceReviewOutcomeLane }) { + const t = useTranslations('iwooos.hostEvidenceReviewOutcomes') + const Icon = item.icon + return ( +
+ {t(`items.${item.key}.body` as never)} +
++ {t('hostEvidenceReviewOutcomes.subtitle')} +
+