feat(web): add IwoooS host intake preflight
This commit is contained in:
@@ -1404,6 +1404,49 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"hostEvidenceIntake": {
|
||||
"title": "Host Evidence Intake Preflight",
|
||||
"subtitle": "Before future host evidence enters human review, this read-only preflight checks whether it is safe to review. It does not accept raw payloads, plaintext credentials, or change received / accepted.",
|
||||
"checkLabel": "Preflight",
|
||||
"rejectLabel": "Reject / quarantine condition",
|
||||
"items": {
|
||||
"metadataPointer": {
|
||||
"title": "Metadata pointer only",
|
||||
"body": "Host evidence only accepts redacted metadata pointers, source steps, and summaries, not full scan output.",
|
||||
"reject": "reject when redacted metadata pointer is missing"
|
||||
},
|
||||
"dependencyOrder": {
|
||||
"title": "Collection order match",
|
||||
"body": "Submitted evidence must follow the S2.17 collection order and cannot skip scope or owner decision.",
|
||||
"reject": "quarantine when prerequisite dependencies are skipped"
|
||||
},
|
||||
"scopeBeforeScan": {
|
||||
"title": "Scope before scan",
|
||||
"body": "Any scan-related evidence must map to scope boundary before it can enter human review.",
|
||||
"reject": "reject scan evidence without scope"
|
||||
},
|
||||
"ownerBeforeChange": {
|
||||
"title": "Owner before host change",
|
||||
"body": "SSH, updates, tuning, or blocking-control evidence requires an owner decision pointer.",
|
||||
"reject": "reject host-change evidence without decision record"
|
||||
},
|
||||
"credentialPlaintext": {
|
||||
"title": "Credential plaintext blocked",
|
||||
"body": "Passwords, tokens, private keys, sessions, or plaintext credentials cannot enter IwoooS mirror.",
|
||||
"reject": "reject and quarantine when plaintext credential material is detected"
|
||||
},
|
||||
"rawPayload": {
|
||||
"title": "Raw payload blocked",
|
||||
"body": "Full raw scan output, unredacted findings, host dumps, or log bundles do not enter projection.",
|
||||
"reject": "raw payload is always rejected"
|
||||
},
|
||||
"counterFreeze": {
|
||||
"title": "Frontend counters frozen",
|
||||
"body": "The frontend can display preflight state only and cannot move received / accepted away from 0.",
|
||||
"reject": "block frontend attempts to advance counters"
|
||||
}
|
||||
}
|
||||
},
|
||||
"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."
|
||||
|
||||
@@ -1405,6 +1405,49 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"hostEvidenceIntake": {
|
||||
"title": "主機 Evidence Intake Preflight",
|
||||
"subtitle": "未來收到主機 evidence 前,先用這組只讀預檢規則判斷能否進人工 review。預檢不會收 raw payload、憑證明文,也不會改 received / accepted。",
|
||||
"checkLabel": "預檢",
|
||||
"rejectLabel": "拒收 / 隔離條件",
|
||||
"items": {
|
||||
"metadataPointer": {
|
||||
"title": "Metadata pointer only",
|
||||
"body": "主機 evidence 只接受脫敏 metadata pointer、來源步驟與摘要,不直接吃完整掃描輸出。",
|
||||
"reject": "缺 redacted metadata pointer 就拒收"
|
||||
},
|
||||
"dependencyOrder": {
|
||||
"title": "Collection order match",
|
||||
"body": "提交的 evidence 必須符合 S2.17 收件順序,不能跳過 scope 或 owner decision。",
|
||||
"reject": "跳過前置依賴就隔離"
|
||||
},
|
||||
"scopeBeforeScan": {
|
||||
"title": "Scope before scan",
|
||||
"body": "任何 scan 相關 evidence 都要先能對到 scope boundary;沒有 scope 不進人工審。",
|
||||
"reject": "scan evidence 沒有 scope 就拒收"
|
||||
},
|
||||
"ownerBeforeChange": {
|
||||
"title": "Owner before host change",
|
||||
"body": "SSH、更新、調校或 blocking control 的 evidence 需要 owner decision pointer。",
|
||||
"reject": "主機變更缺 decision record 就拒收"
|
||||
},
|
||||
"credentialPlaintext": {
|
||||
"title": "Credential plaintext blocked",
|
||||
"body": "任何帳密、token、private key、session 或憑證明文都不能進 IwoooS mirror。",
|
||||
"reject": "偵測到憑證明文就拒收並隔離"
|
||||
},
|
||||
"rawPayload": {
|
||||
"title": "Raw payload blocked",
|
||||
"body": "完整掃描 raw output、未脫敏 finding、主機 dump 或 log bundle 不進 projection。",
|
||||
"reject": "raw payload 一律拒收"
|
||||
},
|
||||
"counterFreeze": {
|
||||
"title": "Frontend counters frozen",
|
||||
"body": "前端只能顯示預檢狀態,不能把 received / accepted 從 0 推進。",
|
||||
"reject": "前端嘗試推 counter 就阻擋"
|
||||
}
|
||||
}
|
||||
},
|
||||
"nextGate": {
|
||||
"title": "下一個高層 Gate",
|
||||
"body": "S4.9 Gitea owner attestation response 是目前建議先收的 owner evidence。任何 headline 提升都要等 owner response、redacted payload ingestion、active runtime gate 或 GitHub primary readiness 有真實變化。"
|
||||
|
||||
@@ -102,6 +102,13 @@ type HostEvidenceCollectionStep = {
|
||||
tone: 'steady' | 'warn' | 'locked'
|
||||
}
|
||||
|
||||
type HostEvidenceIntakeCheck = {
|
||||
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' },
|
||||
@@ -233,6 +240,16 @@ const hostEvidenceCollectionSteps: HostEvidenceCollectionStep[] = [
|
||||
{ key: 'redactedSeventh', step: '07', icon: ShieldCheck, tone: 'locked' },
|
||||
]
|
||||
|
||||
const hostEvidenceIntakeChecks: HostEvidenceIntakeCheck[] = [
|
||||
{ key: 'metadataPointer', check: 'P1', icon: ListChecks, tone: 'warn' },
|
||||
{ key: 'dependencyOrder', check: 'P2', icon: GitBranch, tone: 'warn' },
|
||||
{ key: 'scopeBeforeScan', check: 'P3', icon: Radar, tone: 'locked' },
|
||||
{ key: 'ownerBeforeChange', check: 'P4', icon: ClipboardCheck, tone: 'locked' },
|
||||
{ key: 'credentialPlaintext', check: 'P5', icon: Lock, tone: 'locked' },
|
||||
{ key: 'rawPayload', check: 'P6', icon: FileWarning, tone: 'locked' },
|
||||
{ key: 'counterFreeze', check: 'P7', icon: ShieldCheck, tone: 'locked' },
|
||||
]
|
||||
|
||||
const evidenceItems = [
|
||||
'iwooos-posture-projection.snapshot.json',
|
||||
'security-rollout-policy.snapshot.json',
|
||||
@@ -591,6 +608,34 @@ function HostEvidenceCollectionCard({ item }: { item: HostEvidenceCollectionStep
|
||||
)
|
||||
}
|
||||
|
||||
function HostEvidenceIntakeCard({ item }: { item: HostEvidenceIntakeCheck }) {
|
||||
const t = useTranslations('iwooos.hostEvidenceIntake')
|
||||
const Icon = item.icon
|
||||
return (
|
||||
<div style={{ ...band, minHeight: 190, padding: 16 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 9 }}>
|
||||
<Icon size={18} color={toneColors[item.tone]} />
|
||||
<span style={{ fontSize: 11, color: '#87867f' }}>{t('checkLabel')}</span>
|
||||
</div>
|
||||
<span style={{ fontSize: 11, color: '#9b978b' }}>{item.check}</span>
|
||||
</div>
|
||||
<h2 style={{ fontSize: 14, margin: '12px 0 6px', color: '#141413' }}>
|
||||
{t(`items.${item.key}.title` as never)}
|
||||
</h2>
|
||||
<p style={{ fontSize: 12, lineHeight: 1.55, color: '#6f6d66', margin: 0 }}>
|
||||
{t(`items.${item.key}.body` as never)}
|
||||
</p>
|
||||
<div style={{ marginTop: 10, display: 'grid', gap: 5 }}>
|
||||
<div style={{ fontSize: 11, color: '#87867f' }}>{t('rejectLabel')}</div>
|
||||
<div style={{ fontSize: 11, color: toneColors[item.tone], lineHeight: 1.45 }}>
|
||||
{t(`items.${item.key}.reject` as never)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default function IwoooSPage({ params }: { params: { locale: string } }) {
|
||||
const t = useTranslations('iwooos')
|
||||
|
||||
@@ -743,6 +788,26 @@ export default function IwoooSPage({ params }: { params: { locale: string } }) {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section style={{ marginBottom: 14 }}>
|
||||
<div style={{ marginBottom: 14 }}>
|
||||
<h2 style={{ fontSize: 16, margin: 0 }}>{t('hostEvidenceIntake.title')}</h2>
|
||||
<p style={{ fontSize: 12, color: '#6f6d66', margin: '6px 0 0', lineHeight: 1.55 }}>
|
||||
{t('hostEvidenceIntake.subtitle')}
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(auto-fit, minmax(210px, 1fr))',
|
||||
gap: 12,
|
||||
}}
|
||||
>
|
||||
{hostEvidenceIntakeChecks.map(item => (
|
||||
<HostEvidenceIntakeCard key={item.key} item={item} />
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section
|
||||
style={{
|
||||
display: 'grid',
|
||||
|
||||
Reference in New Issue
Block a user