feat(web): add IwoooS security mesh matrix
All checks were successful
CD Pipeline / tests (push) Successful in 1m31s
Code Review / ai-code-review (push) Successful in 14s
CD Pipeline / build-and-deploy (push) Successful in 5m1s
CD Pipeline / post-deploy-checks (push) Successful in 2m2s

This commit is contained in:
Your Name
2026-05-31 21:27:59 +08:00
parent 537faf6427
commit 70dfb2eec3
6 changed files with 549 additions and 0 deletions

View File

@@ -5477,6 +5477,101 @@
}
}
},
"globalSecurityMeshMatrix": {
"eyebrow": "全域資安納管矩陣",
"title": "所有產品、主機、工具放在同一張表",
"subtitle": "把 AwoooI、AwoooP、IwoooS、公開網站群、VibeWork、Kali 112、開發主機與 GitHub / Gitea 版本來源放到同一個只讀矩陣,讓使用者先看清楚納管範圍,再決定哪一段要收證或開人工閘門。",
"coverageLabel": "覆蓋",
"evidenceLabel": "證據",
"runtimeLabel": "執行",
"nextLabel": "下一步",
"boundaryTitle": "全域納管邊界",
"boundaryIntro": "以下鍵值固定:這張矩陣只呈現可視化、證據狀態與人工閘門,不提供掃描、修復、主機變更、部署或版本來源變更。",
"summary": {
"assets": {
"label": "資產列",
"detail": "八類產品、主機與工具同表。"
},
"readOnly": {
"label": "只讀納管",
"detail": "八類都只先納入觀測與證據欄位。"
},
"runtime": {
"label": "執行期",
"detail": "目前仍是 0不開主動動作。"
},
"nextGate": {
"label": "下一閘門",
"detail": "先等 S4.9 負責人證據。"
}
},
"items": {
"awoooi": {
"title": "AwoooI 核心產品",
"layer": "前台、API、工單、告警與授權頁面。",
"coverage": "已可視化",
"evidence": "真相鏈已接上",
"runtime": "仍鎖住",
"next": "延續 Incident 真相鏈,不新增執行按鈕。"
},
"awooop": {
"title": "AwoooP 工作流",
"layer": "Runs、Work Items、Approvals 與跨 Session 交接。",
"coverage": "已可視化",
"evidence": "正式頁已落地",
"runtime": "仍鎖住",
"next": "只同步狀態與證據,避免和另一個 Session 互踩。"
},
"iwooos": {
"title": "IwoooS 資安入口",
"layer": "資訊安全總覽、矩陣、雷達、攻擊路徑與收件卡。",
"coverage": "主入口",
"evidence": "guard 已保護",
"runtime": "仍鎖住",
"next": "把抽象進度轉成可見工作項與證據欄位。"
},
"publicSites": {
"title": "公開網站群",
"layer": "前台網站、品牌頁、服務頁與既有安全合規入口。",
"coverage": "已納入",
"evidence": "待補來源",
"runtime": "仍鎖住",
"next": "只收公開頁面與合規文案 evidence不做阻擋控制。"
},
"vibeWork": {
"title": "VibeWork 新專案",
"layer": "新專案收件、責任邊界、資料分級與部署邊界。",
"coverage": "已納入",
"evidence": "待補 6 項",
"runtime": "仍鎖住",
"next": "先完成 VibeWork 六項只讀收件。"
},
"kali112": {
"title": "Kali 192.168.0.112",
"layer": "安全主機、掃描能力、維護窗口與主機狀態。",
"coverage": "只讀快照",
"evidence": "待維護窗口",
"runtime": "仍鎖住",
"next": "維持觀測,不執行更新、掃描或 /execute。"
},
"devHosts": {
"title": "開發主機 111 / 168",
"layer": "兩台開發主機的資安範圍、證據收件與人工判定。",
"coverage": "已納入",
"evidence": "待補主機證據",
"runtime": "仍鎖住",
"next": "只收主機中繼資料與 owner decision。"
},
"sourceControl": {
"title": "GitHub / Gitea 版本來源",
"layer": "主倉判定、refs 真相、workflow 名稱與 secret 名稱。",
"coverage": "待負責人回覆",
"evidence": "待 S4.9",
"runtime": "仍鎖住",
"next": "不建立 repo、不同步 refs、不改 workflow 或 secret。"
}
}
},
"vibeWorkSecurityOnboarding": {
"eyebrow": "VibeWork 新專案收件卡",
"title": "先把缺口收齊,不急著加管制",

View File

@@ -5477,6 +5477,101 @@
}
}
},
"globalSecurityMeshMatrix": {
"eyebrow": "全域資安納管矩陣",
"title": "所有產品、主機、工具放在同一張表",
"subtitle": "把 AwoooI、AwoooP、IwoooS、公開網站群、VibeWork、Kali 112、開發主機與 GitHub / Gitea 版本來源放到同一個只讀矩陣,讓使用者先看清楚納管範圍,再決定哪一段要收證或開人工閘門。",
"coverageLabel": "覆蓋",
"evidenceLabel": "證據",
"runtimeLabel": "執行",
"nextLabel": "下一步",
"boundaryTitle": "全域納管邊界",
"boundaryIntro": "以下鍵值固定:這張矩陣只呈現可視化、證據狀態與人工閘門,不提供掃描、修復、主機變更、部署或版本來源變更。",
"summary": {
"assets": {
"label": "資產列",
"detail": "八類產品、主機與工具同表。"
},
"readOnly": {
"label": "只讀納管",
"detail": "八類都只先納入觀測與證據欄位。"
},
"runtime": {
"label": "執行期",
"detail": "目前仍是 0不開主動動作。"
},
"nextGate": {
"label": "下一閘門",
"detail": "先等 S4.9 負責人證據。"
}
},
"items": {
"awoooi": {
"title": "AwoooI 核心產品",
"layer": "前台、API、工單、告警與授權頁面。",
"coverage": "已可視化",
"evidence": "真相鏈已接上",
"runtime": "仍鎖住",
"next": "延續 Incident 真相鏈,不新增執行按鈕。"
},
"awooop": {
"title": "AwoooP 工作流",
"layer": "Runs、Work Items、Approvals 與跨 Session 交接。",
"coverage": "已可視化",
"evidence": "正式頁已落地",
"runtime": "仍鎖住",
"next": "只同步狀態與證據,避免和另一個 Session 互踩。"
},
"iwooos": {
"title": "IwoooS 資安入口",
"layer": "資訊安全總覽、矩陣、雷達、攻擊路徑與收件卡。",
"coverage": "主入口",
"evidence": "guard 已保護",
"runtime": "仍鎖住",
"next": "把抽象進度轉成可見工作項與證據欄位。"
},
"publicSites": {
"title": "公開網站群",
"layer": "前台網站、品牌頁、服務頁與既有安全合規入口。",
"coverage": "已納入",
"evidence": "待補來源",
"runtime": "仍鎖住",
"next": "只收公開頁面與合規文案 evidence不做阻擋控制。"
},
"vibeWork": {
"title": "VibeWork 新專案",
"layer": "新專案收件、責任邊界、資料分級與部署邊界。",
"coverage": "已納入",
"evidence": "待補 6 項",
"runtime": "仍鎖住",
"next": "先完成 VibeWork 六項只讀收件。"
},
"kali112": {
"title": "Kali 192.168.0.112",
"layer": "安全主機、掃描能力、維護窗口與主機狀態。",
"coverage": "只讀快照",
"evidence": "待維護窗口",
"runtime": "仍鎖住",
"next": "維持觀測,不執行更新、掃描或 /execute。"
},
"devHosts": {
"title": "開發主機 111 / 168",
"layer": "兩台開發主機的資安範圍、證據收件與人工判定。",
"coverage": "已納入",
"evidence": "待補主機證據",
"runtime": "仍鎖住",
"next": "只收主機中繼資料與 owner decision。"
},
"sourceControl": {
"title": "GitHub / Gitea 版本來源",
"layer": "主倉判定、refs 真相、workflow 名稱與 secret 名稱。",
"coverage": "待負責人回覆",
"evidence": "待 S4.9",
"runtime": "仍鎖住",
"next": "不建立 repo、不同步 refs、不改 workflow 或 secret。"
}
}
},
"vibeWorkSecurityOnboarding": {
"eyebrow": "VibeWork 新專案收件卡",
"title": "先把缺口收齊,不急著加管制",

View File

@@ -134,6 +134,15 @@ type AllProductCoverageSnapshotItem = {
tone: 'steady' | 'warn' | 'locked'
}
type GlobalSecurityMeshMatrixItem = {
key: string
code: string
icon: typeof ShieldCheck
coverageTone: 'steady' | 'warn' | 'locked'
evidenceTone: 'steady' | 'warn' | 'locked'
runtimeTone: 'steady' | 'warn' | 'locked'
}
type VibeWorkSecurityOnboardingItem = {
key: string
check: string
@@ -1356,6 +1365,40 @@ const iwooosConcreteSecurityBlockerResolutionBoundaries = [
'gitea_disablement_authorized=false',
] as const
const globalSecurityMeshMatrixSummary = [
{ key: 'assets', value: '8', icon: Radar, tone: 'steady' },
{ key: 'readOnly', value: '8', icon: ShieldCheck, tone: 'steady' },
{ key: 'runtime', value: '0', icon: Lock, tone: 'locked' },
{ key: 'nextGate', value: 'S4.9', icon: ClipboardCheck, tone: 'warn' },
] as const
const globalSecurityMeshMatrixItems: GlobalSecurityMeshMatrixItem[] = [
{ key: 'awoooi', code: 'G1', icon: ShieldCheck, coverageTone: 'steady', evidenceTone: 'steady', runtimeTone: 'locked' },
{ key: 'awooop', code: 'G2', icon: Radar, coverageTone: 'steady', evidenceTone: 'steady', runtimeTone: 'locked' },
{ key: 'iwooos', code: 'G3', icon: Activity, coverageTone: 'steady', evidenceTone: 'steady', runtimeTone: 'locked' },
{ key: 'publicSites', code: 'G4', icon: FileText, coverageTone: 'steady', evidenceTone: 'warn', runtimeTone: 'locked' },
{ key: 'vibeWork', code: 'G5', icon: ListChecks, coverageTone: 'steady', evidenceTone: 'warn', runtimeTone: 'locked' },
{ key: 'kali112', code: 'G6', icon: SearchCheck, coverageTone: 'steady', evidenceTone: 'warn', runtimeTone: 'locked' },
{ key: 'devHosts', code: 'G7', icon: Activity, coverageTone: 'steady', evidenceTone: 'warn', runtimeTone: 'locked' },
{ key: 'sourceControl', code: 'G8', icon: GitBranch, coverageTone: 'warn', evidenceTone: 'warn', runtimeTone: 'locked' },
]
const globalSecurityMeshMatrixBoundaries = [
'iwooos_global_security_mesh_first_layer=true',
'iwooos_global_security_mesh_asset_count=8',
'iwooos_global_security_mesh_read_only_count=8',
'iwooos_global_security_mesh_runtime_gate_count=0',
'iwooos_global_security_mesh_source_control_mutation_authorized=false',
'iwooos_global_security_mesh_kali_execution_authorized=false',
'iwooos_global_security_mesh_host_change_authorized=false',
'iwooos_global_security_mesh_scan_authorized=false',
'iwooos_global_security_mesh_production_deploy_authorized=false',
'runtime_execution_authorized=false',
'active_runtime_gate_count=0',
'action_buttons_allowed=false',
'not_authorization=true',
] as const
const vibeWorkSecurityOnboardingSummary = [
{ key: 'readOnly', value: '已納管', icon: ShieldCheck, tone: 'steady' },
{ key: 'missingEvidence', value: '6', icon: ListChecks, tone: 'warn' },
@@ -4567,6 +4610,178 @@ function IwoooSAllProductCoverageSnapshotBoard() {
)
}
function IwoooSGlobalSecurityMeshMatrixBoard() {
const t = useTranslations('iwooos.globalSecurityMeshMatrix')
const textWrap = { overflowWrap: 'anywhere' as const, wordBreak: 'break-word' as const }
return (
<section
style={{ marginBottom: 14, maxWidth: '100%', overflow: 'hidden' }}
data-testid="iwooos-global-security-mesh-matrix-board"
>
<div style={{ ...band, padding: 16, background: '#f7fbfa', borderColor: '#cfe2d8' }}>
<div
style={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 300px), 1fr))',
gap: 14,
alignItems: 'start',
}}
>
<div style={{ minWidth: 0 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 8, color: '#405f4f', fontSize: 12, fontWeight: 700 }}>
<Radar size={17} color="#1f7a4d" />
{t('eyebrow')}
</div>
<h2 style={{ fontSize: 17, margin: '8px 0 0', color: '#141413' }}>{t('title')}</h2>
<p style={{ fontSize: 12, color: '#405f4f', margin: '6px 0 0', lineHeight: 1.55, ...textWrap }}>
{t('subtitle')}
</p>
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(118px, 1fr))', gap: 8 }}>
{globalSecurityMeshMatrixSummary.map(item => {
const Icon = item.icon
return (
<div key={item.key} style={{ border: '0.5px solid #cfe2d8', borderRadius: 8, padding: 11, background: '#fff' }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>
<span style={{ fontSize: 11, color: '#607466' }}>{t(`summary.${item.key}.label` as never)}</span>
<Icon size={15} color={toneColors[item.tone]} />
</div>
<div style={{ fontSize: 19, fontWeight: 700, color: toneColors[item.tone], marginTop: 8, lineHeight: 1.1 }}>
{item.value}
</div>
<p style={{ fontSize: 11, color: '#405f4f', margin: '7px 0 0', lineHeight: 1.45, ...textWrap }}>
{t(`summary.${item.key}.detail` as never)}
</p>
</div>
)
})}
</div>
</div>
<div
style={{
marginTop: 14,
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 250px), 1fr))',
gap: 10,
}}
>
{globalSecurityMeshMatrixItems.map(item => {
const Icon = item.icon
return (
<div
key={item.key}
style={{
border: '0.5px solid #cfe2d8',
borderRadius: 8,
background: '#fff',
padding: 12,
minHeight: 184,
display: 'grid',
alignContent: 'space-between',
gap: 9,
minWidth: 0,
...textWrap,
}}
>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 10 }}>
<div style={{ minWidth: 0 }}>
<div style={{ fontSize: 11, color: '#607466', fontWeight: 700 }}>{item.code}</div>
<h3 style={{ fontSize: 14, margin: '5px 0 0', color: '#141413', lineHeight: 1.3 }}>
{t(`items.${item.key}.title` as never)}
</h3>
<p style={{ fontSize: 11, color: '#607466', margin: '5px 0 0', lineHeight: 1.4, ...textWrap }}>
{t(`items.${item.key}.layer` as never)}
</p>
</div>
<Icon size={18} color={toneColors[item.coverageTone]} />
</div>
<div style={{ display: 'grid', gap: 6 }}>
{[
{ label: t('coverageLabel'), value: t(`items.${item.key}.coverage` as never), tone: item.coverageTone },
{ label: t('evidenceLabel'), value: t(`items.${item.key}.evidence` as never), tone: item.evidenceTone },
{ label: t('runtimeLabel'), value: t(`items.${item.key}.runtime` as never), tone: item.runtimeTone },
].map(row => (
<div
key={row.label}
style={{
display: 'grid',
gridTemplateColumns: '66px minmax(0, 1fr)',
gap: 8,
alignItems: 'center',
}}
>
<span style={{ fontSize: 10, color: '#7c847c' }}>{row.label}</span>
<span
style={{
border: `0.5px solid ${row.tone === 'steady' ? '#cfe2d8' : row.tone === 'warn' ? '#e6c8b8' : '#dad7ce'}`,
borderRadius: 999,
padding: '4px 8px',
color: toneColors[row.tone],
background: row.tone === 'steady' ? '#f7fbfa' : row.tone === 'warn' ? '#fffaf7' : '#f8f7f3',
fontSize: 11,
lineHeight: 1.2,
...textWrap,
}}
>
{row.value}
</span>
</div>
))}
</div>
<p style={{ fontSize: 11, color: '#405f4f', margin: 0, lineHeight: 1.45, ...textWrap }}>
<strong>{t('nextLabel')}</strong>{t(`items.${item.key}.next` as never)}
</p>
</div>
)
})}
</div>
<details
data-testid="iwooos-global-security-mesh-matrix-boundaries"
style={{
marginTop: 12,
border: '0.5px solid #cfe2d8',
borderRadius: 8,
background: '#fff',
padding: '8px 10px',
}}
>
<summary style={{ cursor: 'pointer', fontSize: 12, fontWeight: 700, color: '#405f4f' }}>
{t('boundaryTitle')}
</summary>
<p style={{ fontSize: 11, color: '#405f4f', lineHeight: 1.5, margin: '8px 0', ...textWrap }}>
{t('boundaryIntro')}
</p>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(230px, 1fr))', gap: 6 }}>
{globalSecurityMeshMatrixBoundaries.map(item => (
<code
key={item}
style={{
border: '0.5px solid #d9eadf',
borderRadius: 8,
padding: '6px 8px',
color: '#405f4f',
fontSize: 11,
lineHeight: 1.4,
background: '#f7fbfa',
overflowWrap: 'anywhere',
}}
>
{item}
</code>
))}
</div>
</details>
</div>
</section>
)
}
function IwoooSVibeWorkSecurityOnboardingBoard() {
const t = useTranslations('iwooos.vibeWorkSecurityOnboarding')
const textWrap = { overflowWrap: 'anywhere' as const, wordBreak: 'break-word' as const }
@@ -13219,6 +13434,7 @@ export default function IwoooSPage({ params }: { params: { locale: string } }) {
<IwoooSVisualCommandDashboard />
<IwoooSProfessionalSecurityExperience />
<IwoooSConcreteWorkSnapshot />
<IwoooSGlobalSecurityMeshMatrixBoard />
<IwoooSVibeWorkSecurityOnboardingBoard />
<IwoooSSectionGroup