feat(web): add IwoooS security mesh matrix
This commit is contained in:
@@ -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": "先把缺口收齊,不急著加管制",
|
||||
|
||||
@@ -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": "先把缺口收齊,不急著加管制",
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user