feat(web): add IwoooS candidate review checklist

This commit is contained in:
Your Name
2026-05-20 11:37:03 +08:00
parent 1fab4f7bd9
commit 3461d4eaff
11 changed files with 774 additions and 8 deletions

View File

@@ -2496,6 +2496,59 @@
"guard": "not_authorization=true; approval record=false"
}
}
},
"hostOwnerDecisionRecordHumanRecordOwnerReviewCandidateChecklist": {
"title": "Host Owner Decision Record Human Record Owner Review Candidate Checklist",
"subtitle": "Human record owner review candidate checklist only checks whether candidate packets are readable. It does not mark checklist passed, start review, mark review ready, collect owner decisions, create decision records, create approval records, or open runtime gates.",
"checkLabel": "Review candidate check",
"guardLabel": "Guardrail",
"items": {
"candidateIdentityTraceable": {
"title": "Candidate identity traceable",
"body": "Checks that candidate id, source outcome, version, trace pointer, and queue review link are traceable.",
"guard": "check passed=0; review started=0"
},
"candidateOwnerBoundaryReadable": {
"title": "Candidate owner boundary readable",
"body": "Checks that human record owner, backup owner, contact channel, and responsibility boundary are readable without treating the owner as engaged.",
"guard": "owner decision received=0; review ready=0"
},
"candidateDecisionSummaryReadable": {
"title": "Candidate decision summary readable",
"body": "Checks that candidate decision summary, risk acceptance boundary, and no-execution statement are readable while remaining outside a formal decision record.",
"guard": "decision record created=false; accepted=0"
},
"candidateScopeExpiryCurrent": {
"title": "Candidate scope and expiry current",
"body": "Checks that host, network, service, exclusion, observation intent, and expiry remain within the candidate scope.",
"guard": "scope check only; runtime gate opened=false"
},
"candidateScanLimitsNotAuthorization": {
"title": "Candidate scan limits not authorization",
"body": "Checks that observe-only, future active scan, and credentialed scan limits are not written as scan authorization.",
"guard": "scan authorized=false; action buttons=false"
},
"candidateCredentialBoundaryMetadataOnly": {
"title": "Candidate credential boundary metadata-only",
"body": "Checks that credential owner, retention, masking, and forbidden collection remain metadata-only.",
"guard": "secret collection=false; raw payload=false"
},
"candidateMaintenanceRollbackTraceable": {
"title": "Candidate maintenance and rollback traceable",
"body": "Checks that maintenance window, constraints, rollback owner, recovery path, and human contact are traceable.",
"guard": "host change=false; Kali update=false"
},
"candidateValidationRuntimeGateSeparate": {
"title": "Candidate validation and runtime gate separate",
"body": "Checks that validation evidence pointer, post-check metrics, and runtime gate requirement remain separate.",
"guard": "runtime gate opened=false; runtime execution=false"
},
"candidateNoExecutionAttestationPresent": {
"title": "Candidate no-execution attestation present",
"body": "Checks that not authorization, no execution, no approval, and no runtime gate statements are visible.",
"guard": "not_authorization=true; approval record=false"
}
}
}
},
"tickets": {

View File

@@ -2497,6 +2497,59 @@
"guard": "not_authorization=trueapproval record=false"
}
}
},
"hostOwnerDecisionRecordHumanRecordOwnerReviewCandidateChecklist": {
"title": "主機 Owner Decision Record Human Record Owner Review Candidate Checklist",
"subtitle": "Human record owner review candidate checklist 只核對 candidate packets 是否可讀。不代表 checklist passed、不開始 review、不標記 review ready、不收 owner decision、不建立 decision record、不建立 approval record、不開 runtime gate。",
"checkLabel": "Review candidate check",
"guardLabel": "保護邊界",
"items": {
"candidateIdentityTraceable": {
"title": "Candidate identity traceable",
"body": "確認 candidate id、來源 outcome、版本、trace pointer 與 queue review link 可追溯。",
"guard": "check passed=0review started=0"
},
"candidateOwnerBoundaryReadable": {
"title": "Candidate owner boundary readable",
"body": "確認 human record owner、backup owner、聯絡窗口與責任邊界可讀但不代表 owner 已接案。",
"guard": "owner decision received=0review ready=0"
},
"candidateDecisionSummaryReadable": {
"title": "Candidate decision summary readable",
"body": "確認候選決策摘要、風險接受邊界與 no-execution statement 可讀,仍不是正式 decision record。",
"guard": "decision record created=falseaccepted=0"
},
"candidateScopeExpiryCurrent": {
"title": "Candidate scope and expiry current",
"body": "確認 host、network、service、exclusion、observation intent 與 expiry 仍在候選範圍內。",
"guard": "scope check onlyruntime gate opened=false"
},
"candidateScanLimitsNotAuthorization": {
"title": "Candidate scan limits not authorization",
"body": "確認 observe-only、future active scan 與 credentialed scan limits 沒有被寫成掃描授權。",
"guard": "scan authorized=falseaction buttons=false"
},
"candidateCredentialBoundaryMetadataOnly": {
"title": "Candidate credential boundary metadata-only",
"body": "確認 credential owner、retention、masking 與 forbidden collection 仍是 metadata-only。",
"guard": "secret collection=falseraw payload=false"
},
"candidateMaintenanceRollbackTraceable": {
"title": "Candidate maintenance and rollback traceable",
"body": "確認 maintenance window、constraints、rollback owner、recovery path 與人工聯絡點可追溯。",
"guard": "host change=falseKali update=false"
},
"candidateValidationRuntimeGateSeparate": {
"title": "Candidate validation and runtime gate separate",
"body": "確認 validation evidence pointer、post-check metrics 與 runtime gate requirement 仍維持獨立。",
"guard": "runtime gate opened=falseruntime execution=false"
},
"candidateNoExecutionAttestationPresent": {
"title": "Candidate no-execution attestation present",
"body": "確認 not authorization、no execution、no approval、no runtime gate statement 都可見。",
"guard": "not_authorization=trueapproval record=false"
}
}
}
},
"tickets": {

View File

@@ -271,6 +271,13 @@ type HostOwnerDecisionRecordHumanRecordOwnerReviewCandidatePacket = {
tone: 'steady' | 'warn' | 'locked'
}
type HostOwnerDecisionRecordHumanRecordOwnerReviewCandidateChecklistItem = {
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' },
@@ -652,6 +659,18 @@ const hostOwnerDecisionRecordHumanRecordOwnerReviewCandidatePackets: HostOwnerDe
{ key: 'reviewNoExecutionAttestation', packet: 'FHR9', icon: ListChecks, tone: 'locked' },
]
const hostOwnerDecisionRecordHumanRecordOwnerReviewCandidateChecklistItems: HostOwnerDecisionRecordHumanRecordOwnerReviewCandidateChecklistItem[] = [
{ key: 'candidateIdentityTraceable', check: 'FRC1', icon: FileText, tone: 'warn' },
{ key: 'candidateOwnerBoundaryReadable', check: 'FRC2', icon: Bell, tone: 'warn' },
{ key: 'candidateDecisionSummaryReadable', check: 'FRC3', icon: ClipboardCheck, tone: 'warn' },
{ key: 'candidateScopeExpiryCurrent', check: 'FRC4', icon: Radar, tone: 'warn' },
{ key: 'candidateScanLimitsNotAuthorization', check: 'FRC5', icon: Activity, tone: 'locked' },
{ key: 'candidateCredentialBoundaryMetadataOnly', check: 'FRC6', icon: Lock, tone: 'locked' },
{ key: 'candidateMaintenanceRollbackTraceable', check: 'FRC7', icon: Clock3, tone: 'warn' },
{ key: 'candidateValidationRuntimeGateSeparate', check: 'FRC8', icon: ShieldCheck, tone: 'locked' },
{ key: 'candidateNoExecutionAttestationPresent', check: 'FRC9', icon: ListChecks, tone: 'locked' },
]
const evidenceItems = [
'iwooos-posture-projection.snapshot.json',
'security-rollout-policy.snapshot.json',
@@ -1730,6 +1749,38 @@ function HostOwnerDecisionRecordHumanRecordOwnerReviewCandidatePacketCard({
)
}
function HostOwnerDecisionRecordHumanRecordOwnerReviewCandidateChecklistCard({
item,
}: {
item: HostOwnerDecisionRecordHumanRecordOwnerReviewCandidateChecklistItem
}) {
const t = useTranslations('iwooos.hostOwnerDecisionRecordHumanRecordOwnerReviewCandidateChecklist')
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('guardLabel')}</div>
<div style={{ fontSize: 11, color: toneColors[item.tone], lineHeight: 1.45 }}>
{t(`items.${item.key}.guard` as never)}
</div>
</div>
</div>
)
}
export default function IwoooSPage({ params }: { params: { locale: string } }) {
const t = useTranslations('iwooos')
@@ -2366,6 +2417,28 @@ 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('hostOwnerDecisionRecordHumanRecordOwnerReviewCandidateChecklist.title')}
</h2>
<p style={{ fontSize: 12, color: '#6f6d66', margin: '6px 0 0', lineHeight: 1.55 }}>
{t('hostOwnerDecisionRecordHumanRecordOwnerReviewCandidateChecklist.subtitle')}
</p>
</div>
<div
style={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(210px, 1fr))',
gap: 12,
}}
>
{hostOwnerDecisionRecordHumanRecordOwnerReviewCandidateChecklistItems.map(item => (
<HostOwnerDecisionRecordHumanRecordOwnerReviewCandidateChecklistCard key={item.key} item={item} />
))}
</div>
</section>
<section
style={{
display: 'grid',