feat(web): add IwoooS operator journey
This commit is contained in:
@@ -1181,6 +1181,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"journey": {
|
||||
"title": "Security Handling Journey",
|
||||
"subtitle": "Pins the visible security mesh flow into a read-only status map: read posture, inspect existing surfaces, then move through owner evidence, human decisions, and follow-up gates.",
|
||||
"outputLabel": "Output",
|
||||
"steps": {
|
||||
"readPosture": {
|
||||
"title": "Read Current Posture",
|
||||
"body": "Start from the 58% headline, framework / runtime landing, active gates, and next high-level gate.",
|
||||
"output": "read-only posture, not authorization"
|
||||
},
|
||||
"openSurface": {
|
||||
"title": "Open Existing Surfaces",
|
||||
"body": "Enter the original page by security, alert, authorization, governance, audit, or code review responsibility.",
|
||||
"output": "preserve original owner and data boundary"
|
||||
},
|
||||
"triageLane": {
|
||||
"title": "Triage Non-blocking Lanes",
|
||||
"body": "LOW / MEDIUM, missing owner response, partial mirror, and Kali observe findings stay observe / warn first.",
|
||||
"output": "follow-up, not blocking"
|
||||
},
|
||||
"collectEvidence": {
|
||||
"title": "Collect Owner Evidence",
|
||||
"body": "The next recommended collection item remains S4.9 Gitea owner attestation response, accepting redacted evidence only.",
|
||||
"output": "update received / accepted state, no execution"
|
||||
},
|
||||
"humanDecision": {
|
||||
"title": "Wait for Human Decision",
|
||||
"body": "Security gates need decision records; AwoooP approval, Code Review, or progress numbers cannot replace that.",
|
||||
"output": "human decision, not runtime"
|
||||
},
|
||||
"runtimeGate": {
|
||||
"title": "Follow-up Runtime Gate",
|
||||
"body": "Only after human approval can work move into follow-up runtime gate templates; active runtime gates remain 0.",
|
||||
"output": "separate gate after approval"
|
||||
}
|
||||
}
|
||||
},
|
||||
"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."
|
||||
|
||||
@@ -1182,6 +1182,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"journey": {
|
||||
"title": "資安處理旅程",
|
||||
"subtitle": "把目前資安網的可見流程固定成只讀狀態圖:先看態勢,再查既有頁面,最後才進入 owner evidence、人工決策與後續 gate。",
|
||||
"outputLabel": "輸出",
|
||||
"steps": {
|
||||
"readPosture": {
|
||||
"title": "讀取目前態勢",
|
||||
"body": "先看 58% headline、framework / runtime landing、active gates 與下一個高層 gate。",
|
||||
"output": "只讀 posture,不代表授權"
|
||||
},
|
||||
"openSurface": {
|
||||
"title": "開啟既有頁面",
|
||||
"body": "依照 security、alert、authorization、governance、audit、code review 的責任面進入原頁。",
|
||||
"output": "保留原頁 owner 與資料邊界"
|
||||
},
|
||||
"triageLane": {
|
||||
"title": "判讀非阻擋分流",
|
||||
"body": "LOW / MEDIUM、缺 owner response、partial mirror 與 Kali observe finding 先維持 observe / warn。",
|
||||
"output": "follow-up,不升 blocking"
|
||||
},
|
||||
"collectEvidence": {
|
||||
"title": "收 owner evidence",
|
||||
"body": "下一個建議收件仍是 S4.9 Gitea owner attestation response,且只接受脫敏 evidence。",
|
||||
"output": "更新 received / accepted 狀態,不執行"
|
||||
},
|
||||
"humanDecision": {
|
||||
"title": "等待人工決策",
|
||||
"body": "資安 gate 需要 decision record;AwoooP approval、Code Review 或進度數字都不能自動替代。",
|
||||
"output": "人控決策,不是 runtime"
|
||||
},
|
||||
"runtimeGate": {
|
||||
"title": "後續 runtime gate",
|
||||
"body": "只有人工批准後,才進入 follow-up runtime gate template;目前 active runtime gates 仍為 0。",
|
||||
"output": "待批准後另開 gate"
|
||||
}
|
||||
}
|
||||
},
|
||||
"nextGate": {
|
||||
"title": "下一個高層 Gate",
|
||||
"body": "S4.9 Gitea owner attestation response 是目前建議先收的 owner evidence。任何 headline 提升都要等 owner response、redacted payload ingestion、active runtime gate 或 GitHub primary readiness 有真實變化。"
|
||||
|
||||
@@ -61,6 +61,12 @@ type ConflictControl = {
|
||||
tone: 'steady' | 'warn' | 'locked'
|
||||
}
|
||||
|
||||
type JourneyStep = {
|
||||
key: string
|
||||
icon: typeof ShieldCheck
|
||||
tone: 'steady' | 'warn' | 'locked'
|
||||
}
|
||||
|
||||
const postureMetrics: PostureMetric[] = [
|
||||
{ key: 'overall', value: '58%', tone: 'warn' },
|
||||
{ key: 'framework', value: '80-85%', tone: 'steady' },
|
||||
@@ -138,6 +144,15 @@ const conflictControls: ConflictControl[] = [
|
||||
{ key: 'kaliNotCalled', tone: 'locked' },
|
||||
]
|
||||
|
||||
const journeySteps: JourneyStep[] = [
|
||||
{ key: 'readPosture', icon: Radar, tone: 'warn' },
|
||||
{ key: 'openSurface', icon: ListChecks, tone: 'steady' },
|
||||
{ key: 'triageLane', icon: Activity, tone: 'warn' },
|
||||
{ key: 'collectEvidence', icon: ClipboardCheck, tone: 'warn' },
|
||||
{ key: 'humanDecision', icon: Lock, tone: 'locked' },
|
||||
{ key: 'runtimeGate', icon: ShieldCheck, tone: 'locked' },
|
||||
]
|
||||
|
||||
const evidenceItems = [
|
||||
'iwooos-posture-projection.snapshot.json',
|
||||
'security-rollout-policy.snapshot.json',
|
||||
@@ -333,6 +348,29 @@ function ConflictRow({ item, index }: { item: ConflictControl; index: number })
|
||||
)
|
||||
}
|
||||
|
||||
function JourneyStepCard({ item, index }: { item: JourneyStep; index: number }) {
|
||||
const t = useTranslations('iwooos.journey')
|
||||
const Icon = item.icon
|
||||
return (
|
||||
<div style={{ ...band, minHeight: 168, padding: 16 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 }}>
|
||||
<Icon size={18} color={toneColors[item.tone]} />
|
||||
<span style={{ fontSize: 11, color: '#9b978b' }}>{String(index + 1).padStart(2, '0')}</span>
|
||||
</div>
|
||||
<h2 style={{ fontSize: 14, margin: '12px 0 6px', color: '#141413' }}>{t(`steps.${item.key}.title` as never)}</h2>
|
||||
<p style={{ fontSize: 12, lineHeight: 1.55, color: '#6f6d66', margin: 0 }}>
|
||||
{t(`steps.${item.key}.body` as never)}
|
||||
</p>
|
||||
<div style={{ marginTop: 10, display: 'grid', gap: 5 }}>
|
||||
<div style={{ fontSize: 11, color: '#87867f' }}>{t('outputLabel')}</div>
|
||||
<div style={{ fontSize: 11, color: toneColors[item.tone], lineHeight: 1.45 }}>
|
||||
{t(`steps.${item.key}.output` as never)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default function IwoooSPage({ params }: { params: { locale: string } }) {
|
||||
const t = useTranslations('iwooos')
|
||||
|
||||
@@ -367,6 +405,24 @@ 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('journey.title')}</h2>
|
||||
<p style={{ fontSize: 12, color: '#6f6d66', margin: '6px 0 0', lineHeight: 1.55 }}>
|
||||
{t('journey.subtitle')}
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(auto-fit, minmax(190px, 1fr))',
|
||||
gap: 12,
|
||||
}}
|
||||
>
|
||||
{journeySteps.map((item, index) => <JourneyStepCard key={item.key} item={item} index={index} />)}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section
|
||||
style={{
|
||||
display: 'grid',
|
||||
|
||||
Reference in New Issue
Block a user