diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 8745ad48d..ee60245c9 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -18347,6 +18347,67 @@ } } }, + "securityAssetControlLedger": { + "eyebrow": "P0-A 資安資產控制總帳", + "title": "把主機、入口、版本來源、監控、Wazuh、Kali 與供應鏈收成一張總帳", + "subtitle": "這張卡把 16 個資安資產群組、64 個 evidence refs 與 24 個 owner 必填欄位收成 P0-A 只讀總帳;目前只顯示脫敏群組、缺口與 0/false 邊界,不讀 live 主機、不呼叫 Wazuh / Kali、不執行掃描、封鎖、reload 或部署。", + "checkLabel": "檢核", + "stateLabel": "狀態", + "boundaryTitle": "資安資產總帳邊界", + "boundaryIntro": "以下鍵值固定:資安資產總帳完成只代表 repo-side 控制面已收斂;owner response、live evidence、runtime gate、host write、Kali active scan、Wazuh active response、SOAR、auto block 與 production write 仍全部維持 0 / false。", + "summary": { + "assetGroups": { + "label": "資產群組", + "detail": "16 個群組涵蓋主機、入口、版本來源、監控、備份、AI 與產品 runtime。" + }, + "p0Groups": { + "label": "P0 群組", + "detail": "14 個 P0 群組需要 owner packet 與 reviewer check。" + }, + "evidenceRefs": { + "label": "證據參照", + "detail": "64 個 committed evidence refs 全部存在,缺失為 0。" + }, + "runtimeGate": { + "label": "執行期", + "detail": "runtime gate、action button、host write、active scan 全部為 0。" + } + }, + "items": { + "gatewayTls": { + "title": "公開入口與憑證進總帳", + "body": "Nginx、route、WebSocket、ACME、DNS、TLS 與 certbot 都已列入 P0-A,仍待 live conf 與 owner evidence。" + }, + "hostNetwork": { + "title": "主機與網路待 owner", + "body": "Docker、systemd、SSH、firewall、WireGuard、NodePort 與 NetworkPolicy 只收脫敏狀態,不做 host write。" + }, + "k8sWorkflow": { + "title": "GitOps 與 workflow 待回讀", + "body": "K8s、ArgoCD、workflow、runner、deploy key 與 secret metadata 需補 revision、diff 與 redaction readback。" + }, + "wazuhKali": { + "title": "Wazuh / Kali 維持證據收件", + "body": "Wazuh event refs、Kali scope、health 與 finding envelope 仍待補;active response、active scan 與 /execute 仍未授權。" + }, + "alertBackup": { + "title": "告警與復原避免假綠燈", + "body": "Prometheus、Alertmanager、Telegram route、SigNoz、Sentry、backup、restore、offsite 與 escrow 都需要 receipt 與 drill evidence。" + }, + "supplyChain": { + "title": "供應鏈與 SBOM 待收斂", + "body": "Harbor、registry、image、SBOM、Cosign、SLSA、KEV、EPSS 與 dependency drift 先進 inventory。" + }, + "aiProduct": { + "title": "AI 與產品 runtime 待 owner", + "body": "OpenClaw、Ollama、NemoTron、Hermes、MCP / A2A、VibeWork 與 agent-bounty-protocol 都先停在 owner gate。" + }, + "runtimeBoundary": { + "title": "執行邊界固定 0 / false", + "body": "不掃描、不封鎖、不 reload、不 restart、不讀 secret、不送 Telegram、不建立 SOAR case、不新增操作按鈕。" + } + } + }, "externalHostIntrusionPreventionControl": { "eyebrow": "外部入侵主機防堵控制", "title": "把主機、入口、網路與供應鏈先收成 P0 防堵矩陣", diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index 8745ad48d..ee60245c9 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -18347,6 +18347,67 @@ } } }, + "securityAssetControlLedger": { + "eyebrow": "P0-A 資安資產控制總帳", + "title": "把主機、入口、版本來源、監控、Wazuh、Kali 與供應鏈收成一張總帳", + "subtitle": "這張卡把 16 個資安資產群組、64 個 evidence refs 與 24 個 owner 必填欄位收成 P0-A 只讀總帳;目前只顯示脫敏群組、缺口與 0/false 邊界,不讀 live 主機、不呼叫 Wazuh / Kali、不執行掃描、封鎖、reload 或部署。", + "checkLabel": "檢核", + "stateLabel": "狀態", + "boundaryTitle": "資安資產總帳邊界", + "boundaryIntro": "以下鍵值固定:資安資產總帳完成只代表 repo-side 控制面已收斂;owner response、live evidence、runtime gate、host write、Kali active scan、Wazuh active response、SOAR、auto block 與 production write 仍全部維持 0 / false。", + "summary": { + "assetGroups": { + "label": "資產群組", + "detail": "16 個群組涵蓋主機、入口、版本來源、監控、備份、AI 與產品 runtime。" + }, + "p0Groups": { + "label": "P0 群組", + "detail": "14 個 P0 群組需要 owner packet 與 reviewer check。" + }, + "evidenceRefs": { + "label": "證據參照", + "detail": "64 個 committed evidence refs 全部存在,缺失為 0。" + }, + "runtimeGate": { + "label": "執行期", + "detail": "runtime gate、action button、host write、active scan 全部為 0。" + } + }, + "items": { + "gatewayTls": { + "title": "公開入口與憑證進總帳", + "body": "Nginx、route、WebSocket、ACME、DNS、TLS 與 certbot 都已列入 P0-A,仍待 live conf 與 owner evidence。" + }, + "hostNetwork": { + "title": "主機與網路待 owner", + "body": "Docker、systemd、SSH、firewall、WireGuard、NodePort 與 NetworkPolicy 只收脫敏狀態,不做 host write。" + }, + "k8sWorkflow": { + "title": "GitOps 與 workflow 待回讀", + "body": "K8s、ArgoCD、workflow、runner、deploy key 與 secret metadata 需補 revision、diff 與 redaction readback。" + }, + "wazuhKali": { + "title": "Wazuh / Kali 維持證據收件", + "body": "Wazuh event refs、Kali scope、health 與 finding envelope 仍待補;active response、active scan 與 /execute 仍未授權。" + }, + "alertBackup": { + "title": "告警與復原避免假綠燈", + "body": "Prometheus、Alertmanager、Telegram route、SigNoz、Sentry、backup、restore、offsite 與 escrow 都需要 receipt 與 drill evidence。" + }, + "supplyChain": { + "title": "供應鏈與 SBOM 待收斂", + "body": "Harbor、registry、image、SBOM、Cosign、SLSA、KEV、EPSS 與 dependency drift 先進 inventory。" + }, + "aiProduct": { + "title": "AI 與產品 runtime 待 owner", + "body": "OpenClaw、Ollama、NemoTron、Hermes、MCP / A2A、VibeWork 與 agent-bounty-protocol 都先停在 owner gate。" + }, + "runtimeBoundary": { + "title": "執行邊界固定 0 / false", + "body": "不掃描、不封鎖、不 reload、不 restart、不讀 secret、不送 Telegram、不建立 SOAR case、不新增操作按鈕。" + } + } + }, "externalHostIntrusionPreventionControl": { "eyebrow": "外部入侵主機防堵控制", "title": "把主機、入口、網路與供應鏈先收成 P0 防堵矩陣", diff --git a/apps/web/src/app/[locale]/iwooos/page.tsx b/apps/web/src/app/[locale]/iwooos/page.tsx index 45d5be80e..006dadaea 100644 --- a/apps/web/src/app/[locale]/iwooos/page.tsx +++ b/apps/web/src/app/[locale]/iwooos/page.tsx @@ -279,6 +279,14 @@ type SocSiemKaliWazuhIntegrationItem = { tone: 'steady' | 'warn' | 'locked' } +type SecurityAssetControlLedgerItem = { + key: string + check: string + state: string + icon: typeof ShieldCheck + tone: 'steady' | 'warn' | 'locked' +} + type ExternalHostIntrusionPreventionControlItem = { key: string check: string @@ -2247,6 +2255,74 @@ const socSiemKaliWazuhIntegrationBoundaries = [ 'not_authorization=true', ] as const +const securityAssetControlLedgerSummary = [ + { key: 'assetGroups', value: '16', icon: ShieldCheck, tone: 'steady' }, + { key: 'p0Groups', value: '14', icon: AlertTriangle, tone: 'warn' }, + { key: 'evidenceRefs', value: '64 / 64', icon: FileText, tone: 'steady' }, + { key: 'runtimeGate', value: '0', icon: Lock, tone: 'locked' }, +] as const + +const securityAssetControlLedgerItems: SecurityAssetControlLedgerItem[] = [ + { key: 'gatewayTls', check: 'P0-A1', state: '已入總帳', icon: Route, tone: 'steady' }, + { key: 'hostNetwork', check: 'P0-A2', state: '待 owner', icon: Server, tone: 'warn' }, + { key: 'k8sWorkflow', check: 'P0-A3', state: '待 readback', icon: Workflow, tone: 'warn' }, + { key: 'wazuhKali', check: 'P0-A4', state: '待 evidence', icon: Radar, tone: 'warn' }, + { key: 'alertBackup', check: 'P0-A5', state: '待 no-false-green', icon: Bell, tone: 'warn' }, + { key: 'supplyChain', check: 'P0-A6', state: '待 SBOM', icon: Boxes, tone: 'warn' }, + { key: 'aiProduct', check: 'P0-A7', state: '待 owner', icon: Network, tone: 'warn' }, + { key: 'runtimeBoundary', check: 'P0-A8', state: '0 / false', icon: Lock, tone: 'locked' }, +] as const + +const securityAssetControlLedgerBoundaries = [ + 'security_asset_control_ledger_visible=true', + 'security_asset_control_ledger_asset_group_count=16', + 'security_asset_control_ledger_p0_asset_group_count=14', + 'security_asset_control_ledger_p1_asset_group_count=2', + 'security_asset_control_ledger_c0_asset_group_count=14', + 'security_asset_control_ledger_c1_asset_group_count=2', + 'security_asset_control_ledger_evidence_ref_count=64', + 'security_asset_control_ledger_existing_evidence_ref_count=64', + 'security_asset_control_ledger_missing_evidence_ref_count=0', + 'security_asset_control_ledger_required_owner_field_count=24', + 'security_asset_control_ledger_reviewer_check_count=24', + 'security_asset_control_ledger_outcome_lane_count=10', + 'security_asset_control_ledger_blocked_action_count=44', + 'security_asset_control_ledger_owner_packet_required_count=16', + 'security_asset_control_ledger_owner_response_received_count=0', + 'security_asset_control_ledger_owner_response_accepted_count=0', + 'security_asset_control_ledger_live_evidence_accepted_count=0', + 'security_asset_control_ledger_runtime_gate_count=0', + 'security_asset_control_ledger_action_button_count=0', + 'security_asset_control_ledger_host_write_authorized_count=0', + 'security_asset_control_ledger_active_scan_authorized_count=0', + 'security_asset_control_ledger_wazuh_active_response_authorized_count=0', + 'security_asset_control_ledger_kali_execute_authorized_count=0', + 'security_asset_control_ledger_soar_action_authorized_count=0', + 'security_asset_control_ledger_auto_block_authorized_count=0', + 'security_asset_control_ledger_secret_value_collected_count=0', + 'security_asset_control_ledger_raw_payload_stored_count=0', + 'security_asset_control_ledger_completion_percent=100', + 'iwooos_headline_progress_percent=64', + 'runtime_execution_authorized=false', + 'host_write_authorized=false', + 'ssh_read_authorized=false', + 'nginx_reload_authorized=false', + 'firewall_change_authorized=false', + 'argocd_sync_authorized=false', + 'workflow_modification_authorized=false', + 'secret_value_collection_allowed=false', + 'wazuh_active_response_authorized=false', + 'kali_active_scan_authorized=false', + 'kali_execute_authorized=false', + 'telegram_send_authorized=false', + 'soar_action_authorized=false', + 'auto_block_authorized=false', + 'production_write_authorized=false', + 'active_runtime_gate_count=0', + 'action_buttons_allowed=false', + 'not_authorization=true', +] as const + const externalHostIntrusionPreventionControlSummary = [ { key: 'domains', value: '12', icon: Network, tone: 'steady' }, { key: 'candidates', value: '14', icon: ListChecks, tone: 'warn' }, @@ -7724,6 +7800,137 @@ function IwoooSSocSiemKaliWazuhIntegrationBoard() { ) } +function IwoooSSecurityAssetControlLedgerBoard() { + const t = useTranslations('iwooos.securityAssetControlLedger') + const textWrap = { overflowWrap: 'anywhere' as const, wordBreak: 'break-word' as const } + + return ( +
+
+
+
+
+ + {t('eyebrow')} +
+

{t('title')}

+

+ {t('subtitle')} +

+
+ +
+ {securityAssetControlLedgerSummary.map(item => { + const Icon = item.icon + return ( +
+
+ {t(`summary.${item.key}.label` as never)} + +
+
+ {item.value} +
+

+ {t(`summary.${item.key}.detail` as never)} +

+
+ ) + })} +
+
+ +
+ {securityAssetControlLedgerItems.map(item => { + const Icon = item.icon + return ( +
+
+ + {t('checkLabel')} {item.check} + + +
+
+
+ {t(`items.${item.key}.title` as never)} +
+
+ {t('stateLabel')}:{item.state} +
+
+

+ {t(`items.${item.key}.body` as never)} +

+
+ ) + })} +
+ +
+ + {t('boundaryTitle')} + +

+ {t('boundaryIntro')} +

+
+ {securityAssetControlLedgerBoundaries.map(item => ( + + {item} + + ))} +
+
+
+
+ ) +} + function IwoooSExternalHostIntrusionPreventionControlBoard() { const t = useTranslations('iwooos.externalHostIntrusionPreventionControl') const textWrap = { overflowWrap: 'anywhere' as const, wordBreak: 'break-word' as const } @@ -20386,6 +20593,7 @@ export default function IwoooSPage({ params }: { params: { locale: string } }) { + diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index 0516c42d3..687bb4cf6 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,40 @@ +## 2026-06-18|P0-A 資安資產控制總帳本地收斂 + +**背景**:使用者要求 IwoooS 必須完整盤點所有主機、服務、套件、工具、網站前後台、Nginx、網路、Wazuh、Kali、告警監控、備份復原、供應鏈、AI provider 與跨專案 runtime,並優先處理會造成即時資安危害的配置控管。此段先把範圍收成 repo-side 只讀總帳與前台可視卡,避免再用零散長文或單一事故卡追蹤。 + +**完成內容**: +- 新增 `scripts/security/security-asset-control-ledger.py`,輸出 `security_asset_control_ledger_v1` snapshot。 +- 新增 `docs/security/SECURITY-ASSET-CONTROL-LEDGER.md` 與 `docs/security/security-asset-control-ledger.snapshot.json`,固定 16 個資安資產群組、14 個 P0 群組、2 個 P1 群組、64 個 committed evidence refs、24 個 owner 必填欄位、24 個 reviewer checks、10 條 outcome lanes、44 個 blocked actions。 +- `/zh-TW/iwooos` 新增「P0-A 資安資產控制總帳」卡片,放在 SOC / SIEM / Kali / Wazuh 整合卡之後、外部入侵防堵矩陣之前。 +- `apps/web/messages/zh-TW.json` 與 `apps/web/messages/en.json` 都補上繁體中文文案;前台只顯示脫敏群組、缺口與 0 / false 邊界,不放工作視窗內容、個人 namespace、內部對話或內網拓樸。 +- `iwooos-config-control-guard.py` 與 `security-mirror-progress-guard.py` 已鎖住新文件、snapshot、前端 testid、卡片順序、i18n key 與所有 0 / false marker。 + +**完成度同步**: +- P0-A repo-side 資安資產控制總帳:`100%`。 +- P0-A 前端本地可視化:`100%`。 +- owner packet 回覆:`0%`,`owner_response_received_count=0`、`owner_response_accepted_count=0`。 +- live evidence 驗收:`0%`,`live_evidence_accepted_count=0`。 +- runtime / response / containment:`0%`,`runtime_gate_count=0`、`action_button_count=0`、host write / active scan / Wazuh active response / Kali execute / SOAR / auto block / production write 全部維持 false。 +- IwoooS headline progress 仍維持 `64%`,不可因 repo-side 總帳完成而假性拉高。 + +**本地驗證**: +- `python3 scripts/security/security-asset-control-ledger.py --root . --generated-at 2026-06-18T13:44:00+08:00 --output docs/security/security-asset-control-ledger.snapshot.json`:`SECURITY_ASSET_CONTROL_LEDGER_OK groups=16 p0=14 evidence_refs=64 runtime_gate=0`。 +- `python3 -m json.tool docs/security/security-asset-control-ledger.snapshot.json`、`apps/web/messages/zh-TW.json`、`apps/web/messages/en.json`:通過。 +- `python3 -m py_compile scripts/security/security-asset-control-ledger.py scripts/security/iwooos-config-control-guard.py scripts/security/security-mirror-progress-guard.py`:通過。 +- `python3 scripts/security/iwooos-config-control-guard.py --root .`:通過。 +- `python3 scripts/security/security-mirror-progress-guard.py --root .`:通過。 +- `python3 scripts/ops/doc-secrets-sanity-check.py docs .gitea apps/web/messages/zh-TW.json apps/web/messages/en.json 'apps/web/src/app/[locale]/iwooos/page.tsx'`:通過,`scanned_files=907`。 +- `python3 scripts/security/public-frontend-env-guard.py --root .`:通過,`violations=0 runtime_gate=0`。 +- 針對本段前端與總帳文件掃描工作視窗、外部對話標記、個人 namespace、內網片語:命中 `0`。 +- `pnpm --filter @awoooi/web typecheck`:通過。 +- `git diff --check`:通過。 + +**尚未完成**: +- 本段尚未 push、尚未取得 Gitea run、尚未部署、尚未做正式站 desktop / mobile smoke。 +- 磁碟剩餘空間低於 1GiB,因此本地未執行 Next production build;正式部署後必須以 production route 補做 desktop / mobile、水平溢出、必要文字可見與外洩字串檢查。 + +**邊界**:本段沒有 SSH、沒有主機寫入、沒有 Nginx reload、沒有 firewall / K8s / workflow 變更、沒有 Wazuh active response、沒有 Kali active scan 或 `/execute`、沒有 Telegram 實發、沒有 SOAR case、沒有收 secret 明文、沒有新增任何正式操作按鈕。 + ## 2026-06-18|全 0 週報改為資料鏈異常而非正常報表 **背景**:使用者提供 AWOOOI 週報截圖,指出告警、AI 效能、開發活動、成本全部為 0,這種報表沒有用途,應該診斷資料鏈與 AI Agent 自動化,而不是只發出空報表。盤點後確認舊 `WeeklyReportService` 會在 Stats / K3s / Git 等資料來源失敗時 fallback 成 0,且 Git 統計依賴容器內 `/app`,成本 / token 也仍是缺資料路徑,導致「查不到資料」被偽裝成「沒有事件」。 diff --git a/docs/security/SECURITY-ASSET-CONTROL-LEDGER.md b/docs/security/SECURITY-ASSET-CONTROL-LEDGER.md new file mode 100644 index 000000000..1a9269b74 --- /dev/null +++ b/docs/security/SECURITY-ASSET-CONTROL-LEDGER.md @@ -0,0 +1,101 @@ +# IwoooS 資安資產控制總帳 + +| 項目 | 內容 | +|------|------| +| 日期 | 2026-06-18 | +| 狀態 | `security_asset_control_ledger_ready_no_runtime_action` | +| 工具 | `scripts/security/security-asset-control-ledger.py` | +| Snapshot | `docs/security/security-asset-control-ledger.snapshot.json` | +| 對應優先序 | P0-A 資產 / 配置總清冊 | +| runtime gate | `0` | + +## 1. 目的 + +此總帳把 IwoooS 既有的資安清冊、snapshot、owner gate、事故後回讀計畫與前台防洩漏 guard,彙整成一份可重跑的「資安資產控制總帳」。它回答的是: + +1. 哪些主機、公開入口、版本來源、workflow、監控、Wazuh、Kali、備份、供應鏈、AI agent 與產品 runtime 已進入資安控管視野。 +2. 每一類資產目前缺哪一種 owner packet 與脫敏 evidence refs。 +3. 哪些動作仍必須維持 `0 / false`,不能因 UI 可見、snapshot 存在或 CD 成功而自動升級。 + +本文件不是 live host truth,也不是主機修復、掃描、封鎖、reload、restart、secret rotation、workflow dispatch、SOAR action 或 production write 授權。 + +## 2. 固定摘要 + +| 指標 | 值 | +|------|----| +| 資安資產群組 | `16` | +| P0 資產群組 | `14` | +| P1 資產群組 | `2` | +| C0 群組 | `14` | +| C1 群組 | `2` | +| evidence refs | `64` | +| 已存在 evidence refs | `64` | +| 缺失 evidence refs | `0` | +| owner 必填欄位 | `24` | +| reviewer checks | `24` | +| outcome lanes | `10` | +| blocked actions | `44` | +| owner packet required | `16` | +| owner response received / accepted | `0 / 0` | +| live evidence accepted | `0` | +| runtime gate / action button | `0 / 0` | +| P0-A repo 總帳完成度 | `100%` | +| IwoooS headline | 仍維持 `64%` | + +## 3. 資產群組與優先序 + +| 優先 | 群組 | 控制範圍 | 下一步 | +|------|------|----------|--------| +| P0 | Nginx / Public Gateway / Route | 公開入口、API、WebSocket、ACME、admin route、Ollama proxy | 補 live conf、rendered diff、`nginx -t`、route smoke、rollback owner | +| P0 | DNS / TLS / Certbot | domain、certificate path、ACME、renewal owner、TLS route | 補憑證覆蓋依據、到期 metadata、renewal owner、ACME route owner | +| P0 | Docker / systemd / Host Service | compose、systemd、repair-bot、port binding、process / persistence baseline | 補 live hash、incident readback、restart window、rollback owner、post-check | +| P0 | SSH / Firewall / WireGuard / NodePort | SSH、known_hosts、sudoers、firewall、WireGuard、NetworkPolicy、NodePort | 補 actor、before / after、impact、operator notification、restoration evidence | +| P0 | K8s / ArgoCD / GitOps | manifests、ArgoCD、RBAC、NetworkPolicy、CronJob、Velero | 補 ArgoCD revision、health / sync、rendered diff、rollback revision、postcheck owner | +| P0 | Gitea Workflow / Runner / Secret Metadata | workflow、runner、deploy key、webhook、secret name parity、redaction guard | 補 runner attestation、secret injection route、log redaction、Gitea run readback | +| P0 | Gitea / GitHub / Source Control | repo visibility、canonical refs、GitHub primary readiness、branch / tag / workflow boundary | 補 owner response;不得自動建 repo、改 visibility、sync refs 或切 primary | +| P0 | Wazuh / Endpoint / SIEM | Wazuh manager、agent、FIM、rule / decoder、event ref、active response dry-run 邊界 | 補 Wazuh health refs、agent refs、event refs 與 no-raw-payload attestation | +| P0 | Kali 112 / Assessment Tooling | Kali health、tool version、scope、finding envelope、maintenance window | 補 scope ref、health ref、normalized finding envelope;active scan 與 `/execute` 另批 | +| P0 | Monitoring / Alerting / Observability | Prometheus、Alertmanager、Telegram route、SigNoz、Sentry、Langfuse、no-false-green | 補 route owner、receiver diff、receipt evidence、noise budget、reload owner | +| P0 | Backup / Restore / DR / Escrow | backup、restic、offsite、escrow、Velero、restore drill、retention | 補 restore drill、offsite ref、escrow non-secret proof、retention runway、DR scorecard | +| P0 | Harbor / Registry / SBOM / Supply Chain | Harbor、registry、image tag、SBOM、Cosign、SLSA、dependency drift、CVE / KEV | 補 SBOM / VEX / provenance intake、image signing、KEV / EPSS / exposure SLA | +| P0 | Public / Admin / API / Frontend Runtime | public URL、CORS、auth boundary、middleware、webhook、frontend env、i18n redaction | 補 route owner、API readback、CORS diff、desktop / mobile smoke、bundle scan | +| P0 | AI Provider / Model Router / Agent Runtime | OpenClaw、Ollama、NemoTron、Hermes、Gemini、MCP / A2A、tool allowlist、cost / privacy | 補 dry-run、benchmark、cost review、privacy review、fallback order、rollback owner | +| P1 | Product Surface / Runtime Route | AWOOOI、AwoooP、IwoooS、VibeWork、agent-bounty-protocol、StockPlatform、Tsenyang、Bitan | 補逐產品 owner、route、admin、API、backup、webhook、rollback 與 validation 指標 | +| P1 | KM / PlayBook / Script / Schedule / Verifier | incident、approval、repair candidate、manual handoff 的自動化資產沉澱 | 補 incident / approval / manual handoff writeback contract | + +## 4. Owner Packet 必填欄位 + +每個資產群組要從候選進到 reviewer review,至少必須具備: + +`asset_group_id`、`asset_alias`、`owner_role`、`owner_team`、`business_impact`、`technical_scope`、`affected_routes_or_services`、`data_classification`、`redacted_evidence_refs`、`source_of_truth_ref`、`live_state_ref`、`config_diff_ref`、`monitoring_signal_ref`、`wazuh_or_siem_ref`、`kali_scope_ref`、`backup_restore_ref`、`supply_chain_ref`、`secret_absence_attestation`、`raw_payload_absence_attestation`、`maintenance_window`、`rollback_owner`、`postcheck_owner`、`followup_owner`、`decision_reason`。 + +## 5. 固定停止線 + +以下項目仍維持 `0 / false`: + +- owner response received / accepted。 +- live evidence accepted。 +- runtime gate / action button。 +- host write、SSH read、Nginx reload、firewall change、ArgoCD sync、workflow modification。 +- secret value collection。 +- Wazuh active response。 +- Kali active scan / Kali `/execute`。 +- Telegram send、SOAR action、auto block、production write。 + +## 6. 驗證指令 + +```bash +python3 scripts/security/security-asset-control-ledger.py \ + --root . \ + --generated-at 2026-06-18T13:44:00+08:00 \ + --output docs/security/security-asset-control-ledger.snapshot.json +``` + +## 7. 完成度 + +| 工作 | 完成度 | 說明 | +|------|--------|------| +| P0-A repo-side 資安資產控制總帳 | `100%` | 16 個群組、64 個 evidence refs 全部對上 | +| owner packet 收件 | `0%` | 尚未收到或接受 owner response | +| live evidence 驗收 | `0%` | 未 SSH、未讀 live host、未呼叫 Wazuh / Kali | +| runtime / response / containment | `0%` | 未開掃描、封鎖、reload、restart、SOAR、auto block | diff --git a/docs/security/security-asset-control-ledger.snapshot.json b/docs/security/security-asset-control-ledger.snapshot.json new file mode 100644 index 000000000..e13bf93cf --- /dev/null +++ b/docs/security/security-asset-control-ledger.snapshot.json @@ -0,0 +1,823 @@ +{ + "asset_groups": [ + { + "action_button": 0, + "evidence_ref_states": [ + { + "exists": true, + "ref": "docs/security/PUBLIC-GATEWAY-PREFLIGHT-INVENTORY.md" + }, + { + "exists": true, + "ref": "docs/security/public-gateway-preflight-inventory.snapshot.json" + }, + { + "exists": true, + "ref": "docs/security/PUBLIC-GATEWAY-POST-INCIDENT-READBACK-PLAN.md" + }, + { + "exists": true, + "ref": "docs/security/public-gateway-post-incident-readback-plan.snapshot.json" + } + ], + "evidence_refs": [ + "docs/security/PUBLIC-GATEWAY-PREFLIGHT-INVENTORY.md", + "docs/security/public-gateway-preflight-inventory.snapshot.json", + "docs/security/PUBLIC-GATEWAY-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/public-gateway-post-incident-readback-plan.snapshot.json" + ], + "group_id": "public_gateway_nginx", + "label": "Nginx / Public Gateway / Route", + "live_evidence_accepted": 0, + "next_owner_action": "補 owner-provided live conf、rendered diff、nginx -t、route smoke、rollback owner。", + "owner_packet_status": "waiting_asset_owner_packet", + "owner_response_accepted": 0, + "owner_response_received": 0, + "priority": "P0", + "raw_payload_allowed": false, + "redacted_evidence_refs_required": true, + "runtime_gate": 0, + "scope": "公開入口、API、WebSocket、ACME、admin route、Ollama proxy", + "secret_value_collection_allowed": false, + "tier": "C0" + }, + { + "action_button": 0, + "evidence_ref_states": [ + { + "exists": true, + "ref": "docs/security/DOMAIN-TLS-CERTBOT-INVENTORY.md" + }, + { + "exists": true, + "ref": "docs/security/domain-tls-certbot-inventory.snapshot.json" + }, + { + "exists": true, + "ref": "docs/security/DOMAIN-TLS-CERTBOT-OWNER-RESPONSE-ACCEPTANCE.md" + }, + { + "exists": true, + "ref": "docs/security/domain-tls-certbot-owner-response-acceptance.snapshot.json" + } + ], + "evidence_refs": [ + "docs/security/DOMAIN-TLS-CERTBOT-INVENTORY.md", + "docs/security/domain-tls-certbot-inventory.snapshot.json", + "docs/security/DOMAIN-TLS-CERTBOT-OWNER-RESPONSE-ACCEPTANCE.md", + "docs/security/domain-tls-certbot-owner-response-acceptance.snapshot.json" + ], + "group_id": "dns_tls_certbot", + "label": "DNS / TLS / Certbot", + "live_evidence_accepted": 0, + "next_owner_action": "補 SAN / wildcard 覆蓋依據、expiry metadata、renewal owner、ACME route owner。", + "owner_packet_status": "waiting_asset_owner_packet", + "owner_response_accepted": 0, + "owner_response_received": 0, + "priority": "P0", + "raw_payload_allowed": false, + "redacted_evidence_refs_required": true, + "runtime_gate": 0, + "scope": "domain、certificate path、ACME、renewal owner、TLS route", + "secret_value_collection_allowed": false, + "tier": "C0" + }, + { + "action_button": 0, + "evidence_ref_states": [ + { + "exists": true, + "ref": "docs/security/HOST-SERVICE-CONFIG-INVENTORY.md" + }, + { + "exists": true, + "ref": "docs/security/host-service-config-inventory.snapshot.json" + }, + { + "exists": true, + "ref": "docs/security/HOST-SERVICE-POST-INCIDENT-READBACK-PLAN.md" + }, + { + "exists": true, + "ref": "docs/security/host-service-post-incident-readback-plan.snapshot.json" + } + ], + "evidence_refs": [ + "docs/security/HOST-SERVICE-CONFIG-INVENTORY.md", + "docs/security/host-service-config-inventory.snapshot.json", + "docs/security/HOST-SERVICE-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/host-service-post-incident-readback-plan.snapshot.json" + ], + "group_id": "host_service_runtime", + "label": "Docker / systemd / Host Service", + "live_evidence_accepted": 0, + "next_owner_action": "補 live hash metadata、incident readback、restart window、rollback owner、post-check。", + "owner_packet_status": "waiting_asset_owner_packet", + "owner_response_accepted": 0, + "owner_response_received": 0, + "priority": "P0", + "raw_payload_allowed": false, + "redacted_evidence_refs_required": true, + "runtime_gate": 0, + "scope": "Docker Compose、systemd、repair-bot、port binding、process / persistence baseline", + "secret_value_collection_allowed": false, + "tier": "C0" + }, + { + "action_button": 0, + "evidence_ref_states": [ + { + "exists": true, + "ref": "docs/security/SSH-NETWORK-ACCESS-INVENTORY.md" + }, + { + "exists": true, + "ref": "docs/security/ssh-network-access-inventory.snapshot.json" + }, + { + "exists": true, + "ref": "docs/security/SSH-NETWORK-POST-INCIDENT-READBACK-PLAN.md" + }, + { + "exists": true, + "ref": "docs/security/ssh-network-post-incident-readback-plan.snapshot.json" + } + ], + "evidence_refs": [ + "docs/security/SSH-NETWORK-ACCESS-INVENTORY.md", + "docs/security/ssh-network-access-inventory.snapshot.json", + "docs/security/SSH-NETWORK-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/ssh-network-post-incident-readback-plan.snapshot.json" + ], + "group_id": "ssh_firewall_network", + "label": "SSH / Firewall / WireGuard / NodePort", + "live_evidence_accepted": 0, + "next_owner_action": "補 actor、before / after state、impact、operator notification、restoration evidence。", + "owner_packet_status": "waiting_asset_owner_packet", + "owner_response_accepted": 0, + "owner_response_received": 0, + "priority": "P0", + "raw_payload_allowed": false, + "redacted_evidence_refs_required": true, + "runtime_gate": 0, + "scope": "SSH target、known_hosts、sudoers、firewall、WireGuard、NetworkPolicy、NodePort", + "secret_value_collection_allowed": false, + "tier": "C0" + }, + { + "action_button": 0, + "evidence_ref_states": [ + { + "exists": true, + "ref": "docs/security/K8S-ARGOCD-MANIFEST-INVENTORY.md" + }, + { + "exists": true, + "ref": "docs/security/k8s-argocd-manifest-inventory.snapshot.json" + }, + { + "exists": true, + "ref": "docs/security/K8S-ARGOCD-POST-INCIDENT-READBACK-PLAN.md" + }, + { + "exists": true, + "ref": "docs/security/k8s-argocd-post-incident-readback-plan.snapshot.json" + } + ], + "evidence_refs": [ + "docs/security/K8S-ARGOCD-MANIFEST-INVENTORY.md", + "docs/security/k8s-argocd-manifest-inventory.snapshot.json", + "docs/security/K8S-ARGOCD-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/k8s-argocd-post-incident-readback-plan.snapshot.json" + ], + "group_id": "k8s_argocd_gitops", + "label": "K8s / ArgoCD / GitOps", + "live_evidence_accepted": 0, + "next_owner_action": "補 ArgoCD revision、health / sync、rendered manifest diff、rollback revision、postcheck owner。", + "owner_packet_status": "waiting_asset_owner_packet", + "owner_response_accepted": 0, + "owner_response_received": 0, + "priority": "P0", + "raw_payload_allowed": false, + "redacted_evidence_refs_required": true, + "runtime_gate": 0, + "scope": "K8s manifests、ArgoCD app、RBAC、NetworkPolicy、CronJob、Velero", + "secret_value_collection_allowed": false, + "tier": "C0" + }, + { + "action_button": 0, + "evidence_ref_states": [ + { + "exists": true, + "ref": "docs/security/SOURCE-CONTROL-WORKFLOW-SECRET-NAME-INVENTORY.md" + }, + { + "exists": true, + "ref": "docs/security/source-control-workflow-secret-name-inventory.snapshot.json" + }, + { + "exists": true, + "ref": "docs/security/CD-RUNNER-SECRET-INJECTION-POST-INCIDENT-READBACK-PLAN.md" + }, + { + "exists": true, + "ref": "docs/security/cd-runner-secret-injection-post-incident-readback-plan.snapshot.json" + } + ], + "evidence_refs": [ + "docs/security/SOURCE-CONTROL-WORKFLOW-SECRET-NAME-INVENTORY.md", + "docs/security/source-control-workflow-secret-name-inventory.snapshot.json", + "docs/security/CD-RUNNER-SECRET-INJECTION-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/cd-runner-secret-injection-post-incident-readback-plan.snapshot.json" + ], + "group_id": "workflow_runner_secret", + "label": "Gitea Workflow / Runner / Secret Metadata", + "live_evidence_accepted": 0, + "next_owner_action": "補 runner attestation、workspace cleanup、secret injection route、log redaction、Gitea run readback。", + "owner_packet_status": "waiting_asset_owner_packet", + "owner_response_accepted": 0, + "owner_response_received": 0, + "priority": "P0", + "raw_payload_allowed": false, + "redacted_evidence_refs_required": true, + "runtime_gate": 0, + "scope": "workflow、runner label、deploy key、webhook、secret name parity、redaction guard", + "secret_value_collection_allowed": false, + "tier": "C0" + }, + { + "action_button": 0, + "evidence_ref_states": [ + { + "exists": true, + "ref": "docs/security/GITEA-GITHUB-MIGRATION-INVENTORY.md" + }, + { + "exists": true, + "ref": "docs/security/SOURCE-CONTROL-PRIMARY-READINESS-GATE.md" + }, + { + "exists": true, + "ref": "docs/security/GITHUB-TARGET-OWNER-DECISION-RESPONSE.md" + }, + { + "exists": true, + "ref": "docs/security/source-control-primary-readiness-gate.snapshot.json" + } + ], + "evidence_refs": [ + "docs/security/GITEA-GITHUB-MIGRATION-INVENTORY.md", + "docs/security/SOURCE-CONTROL-PRIMARY-READINESS-GATE.md", + "docs/security/GITHUB-TARGET-OWNER-DECISION-RESPONSE.md", + "docs/security/source-control-primary-readiness-gate.snapshot.json" + ], + "group_id": "source_control_repo_visibility", + "label": "Gitea / GitHub / Source Control", + "live_evidence_accepted": 0, + "next_owner_action": "補 owner response;不得建立 repo、改 visibility、sync refs 或切 primary。", + "owner_packet_status": "waiting_asset_owner_packet", + "owner_response_accepted": 0, + "owner_response_received": 0, + "priority": "P0", + "raw_payload_allowed": false, + "redacted_evidence_refs_required": true, + "runtime_gate": 0, + "scope": "repo visibility、canonical refs、GitHub primary readiness、branch / tag / workflow boundary", + "secret_value_collection_allowed": false, + "tier": "C0" + }, + { + "action_button": 0, + "evidence_ref_states": [ + { + "exists": true, + "ref": "docs/security/WAZUH-IWOOOS-INTRUSION-READBACK-PLAN.md" + }, + { + "exists": true, + "ref": "docs/security/wazuh-iwooos-intrusion-readback-plan.snapshot.json" + }, + { + "exists": true, + "ref": "docs/security/SOC-SIEM-KALI-WAZUH-INTEGRATION-CONTROL.md" + }, + { + "exists": true, + "ref": "docs/security/soc-siem-kali-wazuh-integration-control.snapshot.json" + } + ], + "evidence_refs": [ + "docs/security/WAZUH-IWOOOS-INTRUSION-READBACK-PLAN.md", + "docs/security/wazuh-iwooos-intrusion-readback-plan.snapshot.json", + "docs/security/SOC-SIEM-KALI-WAZUH-INTEGRATION-CONTROL.md", + "docs/security/soc-siem-kali-wazuh-integration-control.snapshot.json" + ], + "group_id": "wazuh_endpoint_siem", + "label": "Wazuh / Endpoint / SIEM", + "live_evidence_accepted": 0, + "next_owner_action": "補 Wazuh health refs、agent refs、event refs、rule / decoder readback 與 no-raw-payload attestation。", + "owner_packet_status": "waiting_asset_owner_packet", + "owner_response_accepted": 0, + "owner_response_received": 0, + "priority": "P0", + "raw_payload_allowed": false, + "redacted_evidence_refs_required": true, + "runtime_gate": 0, + "scope": "Wazuh manager、agent、FIM、rule / decoder、event ref、active response dry-run boundary", + "secret_value_collection_allowed": false, + "tier": "C0" + }, + { + "action_button": 0, + "evidence_ref_states": [ + { + "exists": true, + "ref": "docs/security/KALI-INTEGRATION-STATUS.md" + }, + { + "exists": true, + "ref": "docs/security/kali-integration-status.snapshot.json" + }, + { + "exists": true, + "ref": "docs/security/KALI-112-MAINTENANCE-WINDOW-DRAFT.md" + }, + { + "exists": true, + "ref": "docs/security/kali-112-maintenance-window-draft.snapshot.json" + } + ], + "evidence_refs": [ + "docs/security/KALI-INTEGRATION-STATUS.md", + "docs/security/kali-integration-status.snapshot.json", + "docs/security/KALI-112-MAINTENANCE-WINDOW-DRAFT.md", + "docs/security/kali-112-maintenance-window-draft.snapshot.json" + ], + "group_id": "kali_112_assessment", + "label": "Kali 112 / Assessment Tooling", + "live_evidence_accepted": 0, + "next_owner_action": "補 scope ref、health ref、normalized finding envelope;active scan 與 /execute 仍獨立批准。", + "owner_packet_status": "waiting_asset_owner_packet", + "owner_response_accepted": 0, + "owner_response_received": 0, + "priority": "P0", + "raw_payload_allowed": false, + "redacted_evidence_refs_required": true, + "runtime_gate": 0, + "scope": "Kali health、tool version、scope、finding envelope、maintenance window", + "secret_value_collection_allowed": false, + "tier": "C0" + }, + { + "action_button": 0, + "evidence_ref_states": [ + { + "exists": true, + "ref": "docs/security/MONITORING-ALERTING-OBSERVABILITY-INVENTORY.md" + }, + { + "exists": true, + "ref": "docs/security/monitoring-alerting-observability-inventory.snapshot.json" + }, + { + "exists": true, + "ref": "docs/security/MONITORING-POST-INCIDENT-READBACK-PLAN.md" + }, + { + "exists": true, + "ref": "docs/security/monitoring-post-incident-readback-plan.snapshot.json" + } + ], + "evidence_refs": [ + "docs/security/MONITORING-ALERTING-OBSERVABILITY-INVENTORY.md", + "docs/security/monitoring-alerting-observability-inventory.snapshot.json", + "docs/security/MONITORING-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/monitoring-post-incident-readback-plan.snapshot.json" + ], + "group_id": "monitoring_alerting_observability", + "label": "Monitoring / Alerting / Observability", + "live_evidence_accepted": 0, + "next_owner_action": "補 route owner、receiver diff、receipt evidence、noise budget、reload owner 與 no-false-green。", + "owner_packet_status": "waiting_asset_owner_packet", + "owner_response_accepted": 0, + "owner_response_received": 0, + "priority": "P0", + "raw_payload_allowed": false, + "redacted_evidence_refs_required": true, + "runtime_gate": 0, + "scope": "Prometheus、Alertmanager、Telegram route、SigNoz、Sentry、Langfuse、no-false-green", + "secret_value_collection_allowed": false, + "tier": "C0" + }, + { + "action_button": 0, + "evidence_ref_states": [ + { + "exists": true, + "ref": "docs/security/BACKUP-RESTORE-ESCROW-INVENTORY.md" + }, + { + "exists": true, + "ref": "docs/security/backup-restore-escrow-inventory.snapshot.json" + }, + { + "exists": true, + "ref": "docs/security/BACKUP-RESTORE-POST-INCIDENT-READBACK-PLAN.md" + }, + { + "exists": true, + "ref": "docs/security/backup-restore-post-incident-readback-plan.snapshot.json" + } + ], + "evidence_refs": [ + "docs/security/BACKUP-RESTORE-ESCROW-INVENTORY.md", + "docs/security/backup-restore-escrow-inventory.snapshot.json", + "docs/security/BACKUP-RESTORE-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/backup-restore-post-incident-readback-plan.snapshot.json" + ], + "group_id": "backup_restore_dr", + "label": "Backup / Restore / DR / Escrow", + "live_evidence_accepted": 0, + "next_owner_action": "補 restore drill、offsite sync ref、escrow non-secret proof、retention runway、DR scorecard。", + "owner_packet_status": "waiting_asset_owner_packet", + "owner_response_accepted": 0, + "owner_response_received": 0, + "priority": "P0", + "raw_payload_allowed": false, + "redacted_evidence_refs_required": true, + "runtime_gate": 0, + "scope": "backup scripts、restic、offsite、credential escrow、Velero、restore drill、retention", + "secret_value_collection_allowed": false, + "tier": "C0" + }, + { + "action_button": 0, + "evidence_ref_states": [ + { + "exists": true, + "ref": "docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md" + }, + { + "exists": true, + "ref": "docs/security/SECURITY-SUPPLY-CHAIN-CONTRACT-MANIFEST.md" + }, + { + "exists": true, + "ref": "docs/security/security-supply-chain-contract-manifest.snapshot.json" + }, + { + "exists": true, + "ref": "docs/evaluations/dependency_supply_chain_drift_monitor_2026-06-18.json" + } + ], + "evidence_refs": [ + "docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md", + "docs/security/SECURITY-SUPPLY-CHAIN-CONTRACT-MANIFEST.md", + "docs/security/security-supply-chain-contract-manifest.snapshot.json", + "docs/evaluations/dependency_supply_chain_drift_monitor_2026-06-18.json" + ], + "group_id": "container_registry_supply_chain", + "label": "Harbor / Registry / SBOM / Supply Chain", + "live_evidence_accepted": 0, + "next_owner_action": "補 SBOM / VEX / provenance intake、image signing、KEV / EPSS / exposure SLA。", + "owner_packet_status": "waiting_asset_owner_packet", + "owner_response_accepted": 0, + "owner_response_received": 0, + "priority": "P0", + "raw_payload_allowed": false, + "redacted_evidence_refs_required": true, + "runtime_gate": 0, + "scope": "Harbor、registry、image tag、SBOM、Cosign、SLSA、dependency drift、CVE / KEV", + "secret_value_collection_allowed": false, + "tier": "C0" + }, + { + "action_button": 0, + "evidence_ref_states": [ + { + "exists": true, + "ref": "docs/security/PUBLIC-RUNTIME-CONFIG-CHANGE-EVIDENCE-ACCEPTANCE.md" + }, + { + "exists": true, + "ref": "docs/security/public-runtime-config-change-evidence-acceptance.snapshot.json" + }, + { + "exists": true, + "ref": "docs/security/public-frontend-sensitive-surface-guard.snapshot.json" + }, + { + "exists": true, + "ref": "docs/HARD_RULES.md" + } + ], + "evidence_refs": [ + "docs/security/PUBLIC-RUNTIME-CONFIG-CHANGE-EVIDENCE-ACCEPTANCE.md", + "docs/security/public-runtime-config-change-evidence-acceptance.snapshot.json", + "docs/security/public-frontend-sensitive-surface-guard.snapshot.json", + "docs/HARD_RULES.md" + ], + "group_id": "public_admin_api_runtime", + "label": "Public / Admin / API / Frontend Runtime", + "live_evidence_accepted": 0, + "next_owner_action": "補 route owner、API contract readback、CORS diff、desktop / mobile smoke、bundle sensitive scan。", + "owner_packet_status": "waiting_asset_owner_packet", + "owner_response_accepted": 0, + "owner_response_received": 0, + "priority": "P0", + "raw_payload_allowed": false, + "redacted_evidence_refs_required": true, + "runtime_gate": 0, + "scope": "public URL、CORS、auth boundary、middleware、webhook、frontend env、i18n redaction", + "secret_value_collection_allowed": false, + "tier": "C0" + }, + { + "action_button": 0, + "evidence_ref_states": [ + { + "exists": true, + "ref": "docs/security/AI-PROVIDER-OWNER-RESPONSE-ACCEPTANCE.md" + }, + { + "exists": true, + "ref": "docs/security/ai-provider-owner-response-acceptance.snapshot.json" + }, + { + "exists": true, + "ref": "docs/ai" + }, + { + "exists": true, + "ref": "docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md" + } + ], + "evidence_refs": [ + "docs/security/AI-PROVIDER-OWNER-RESPONSE-ACCEPTANCE.md", + "docs/security/ai-provider-owner-response-acceptance.snapshot.json", + "docs/ai", + "docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md" + ], + "group_id": "ai_provider_agent_runtime", + "label": "AI Provider / Model Router / Agent Runtime", + "live_evidence_accepted": 0, + "next_owner_action": "補 dry-run、benchmark、cost review、privacy review、fallback order 與 rollback owner。", + "owner_packet_status": "waiting_asset_owner_packet", + "owner_response_accepted": 0, + "owner_response_received": 0, + "priority": "P0", + "raw_payload_allowed": false, + "redacted_evidence_refs_required": true, + "runtime_gate": 0, + "scope": "OpenClaw、Ollama、NemoTron、Hermes、Gemini、MCP / A2A、tool allowlist、cost / privacy", + "secret_value_collection_allowed": false, + "tier": "C0" + }, + { + "action_button": 0, + "evidence_ref_states": [ + { + "exists": true, + "ref": "docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md" + }, + { + "exists": true, + "ref": "docs/security/VIBEWORK-IWOOOS-ONBOARDING-HANDOFF.md" + }, + { + "exists": true, + "ref": "docs/security/AGENT-BOUNTY-IWOOOS-ONBOARDING-HANDOFF.md" + }, + { + "exists": true, + "ref": "docs/security/agent-bounty-iwooos-onboarding-handoff.snapshot.json" + } + ], + "evidence_refs": [ + "docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md", + "docs/security/VIBEWORK-IWOOOS-ONBOARDING-HANDOFF.md", + "docs/security/AGENT-BOUNTY-IWOOOS-ONBOARDING-HANDOFF.md", + "docs/security/agent-bounty-iwooos-onboarding-handoff.snapshot.json" + ], + "group_id": "product_surface_runtime_routes", + "label": "Product Surface / Runtime Route", + "live_evidence_accepted": 0, + "next_owner_action": "補逐產品 owner、route、admin、API、backup、webhook、rollback 與 validation 指標。", + "owner_packet_status": "waiting_asset_owner_packet", + "owner_response_accepted": 0, + "owner_response_received": 0, + "priority": "P1", + "raw_payload_allowed": false, + "redacted_evidence_refs_required": true, + "runtime_gate": 0, + "scope": "AWOOOI、AwoooP、IwoooS、VibeWork、agent-bounty-protocol、StockPlatform、Tsenyang、Bitan", + "secret_value_collection_allowed": false, + "tier": "C1" + }, + { + "action_button": 0, + "evidence_ref_states": [ + { + "exists": true, + "ref": "docs/LOGBOOK.md" + }, + { + "exists": true, + "ref": "apps/api/src/services/repair_candidate_service.py" + }, + { + "exists": true, + "ref": "apps/api/src/services/telegram_gateway.py" + }, + { + "exists": true, + "ref": "apps/web/src/app/[locale]/awooop/work-items/page.tsx" + } + ], + "evidence_refs": [ + "docs/LOGBOOK.md", + "apps/api/src/services/repair_candidate_service.py", + "apps/api/src/services/telegram_gateway.py", + "apps/web/src/app/[locale]/awooop/work-items/page.tsx" + ], + "group_id": "automation_asset_sedimentation", + "label": "KM / PlayBook / Script / Schedule / Verifier", + "live_evidence_accepted": 0, + "next_owner_action": "補 incident / approval / manual handoff writeback contract,讓資產總帳從可視化進入可追蹤閉環。", + "owner_packet_status": "waiting_asset_owner_packet", + "owner_response_accepted": 0, + "owner_response_received": 0, + "priority": "P1", + "raw_payload_allowed": false, + "redacted_evidence_refs_required": true, + "runtime_gate": 0, + "scope": "incident、approval、repair candidate、manual handoff 的自動化資產沉澱", + "secret_value_collection_allowed": false, + "tier": "C1" + } + ], + "blocked_actions": [ + "ssh_to_host", + "read_live_host_log", + "write_host_file", + "nginx_reload", + "certbot_renew", + "dns_change", + "firewall_change", + "wireguard_change", + "nodeport_change", + "networkpolicy_apply", + "kubectl_action", + "argocd_sync", + "helm_upgrade", + "docker_restart", + "docker_compose_up", + "systemctl_restart", + "repair_bot_execute", + "ansible_apply", + "wazuh_active_response", + "wazuh_rule_change", + "kali_active_scan", + "kali_execute", + "nmap_scan", + "nuclei_scan", + "trivy_live_scan", + "package_upgrade", + "workflow_modify", + "workflow_dispatch", + "runner_restart", + "secret_read", + "secret_rotate", + "webhook_modify", + "deploy_key_modify", + "refs_sync", + "force_push", + "github_primary_switch", + "backup_run", + "restore_run", + "offsite_sync", + "remote_delete", + "telegram_send", + "soar_case_create", + "auto_block", + "production_write" + ], + "execution_boundaries": { + "action_buttons_allowed": false, + "argocd_sync_authorized": false, + "auto_block_authorized": false, + "firewall_change_authorized": false, + "host_write_authorized": false, + "kali_active_scan_authorized": false, + "kali_execute_authorized": false, + "nginx_reload_authorized": false, + "not_authorization": true, + "production_write_authorized": false, + "runtime_execution_authorized": false, + "secret_value_collection_allowed": false, + "soar_action_authorized": false, + "ssh_read_authorized": false, + "telegram_send_authorized": false, + "wazuh_active_response_authorized": false, + "workflow_modification_authorized": false + }, + "generated_at": "2026-06-18T13:44:00+08:00", + "git_commit": "c7597df2", + "outcome_lanes": [ + "waiting_asset_owner_packet", + "request_gateway_supplement", + "request_host_service_supplement", + "request_network_supplement", + "request_wazuh_kali_supplement", + "request_backup_restore_supplement", + "request_supply_chain_supplement", + "request_product_surface_supplement", + "quarantine_secret_or_raw_payload", + "ready_for_security_reviewer_review" + ], + "required_owner_fields": [ + "asset_group_id", + "asset_alias", + "owner_role", + "owner_team", + "business_impact", + "technical_scope", + "affected_routes_or_services", + "data_classification", + "redacted_evidence_refs", + "source_of_truth_ref", + "live_state_ref", + "config_diff_ref", + "monitoring_signal_ref", + "wazuh_or_siem_ref", + "kali_scope_ref", + "backup_restore_ref", + "supply_chain_ref", + "secret_absence_attestation", + "raw_payload_absence_attestation", + "maintenance_window", + "rollback_owner", + "postcheck_owner", + "followup_owner", + "decision_reason" + ], + "reviewer_checks": [ + "asset alias 不得暴露個人 namespace", + "owner role / team 必填", + "source-of-truth 必須可追溯", + "live evidence 只能收脫敏 ref", + "secret value / hash / partial token 一律拒收", + "raw Wazuh / raw Kali output 一律拒收", + "Nginx / firewall / K8s / workflow 變更需獨立 runtime approval", + "route 200 不得當資安完成", + "dashboard 可見不得當 remediation 完成", + "backup 存在不得當 restore drill 完成", + "Kali 納入範圍不得當 active scan 授權", + "Wazuh event 可見不得當 active response 授權", + "repo snapshot 不得當 live host truth", + "事故後回讀需含 actor、before / after、impact、postcheck", + "no-false-green 必須明確標示", + "owner response received / accepted 必須維持 0,除非有實際收件", + "runtime gate 必須維持 0", + "action button 必須維持 0", + "Gitea / GitHub refs 不得自動同步", + "GitHub primary 不得自動切換", + "Telegram 不得實發", + "SOAR 不得 auto block", + "AI agent 不得讀 secret 或 host write", + "LOGBOOK 不得包含內部對話逐字稿" + ], + "schema_version": "security_asset_control_ledger_v1", + "status": "security_asset_control_ledger_ready_no_runtime_action", + "summary": { + "action_button_count": 0, + "active_scan_authorized_count": 0, + "asset_group_count": 16, + "auto_block_authorized_count": 0, + "blocked_action_count": 44, + "c0_asset_group_count": 14, + "c1_asset_group_count": 2, + "evidence_ref_count": 64, + "existing_evidence_ref_count": 64, + "host_write_authorized_count": 0, + "iwooos_headline_progress_percent": 64, + "kali_execute_authorized_count": 0, + "live_evidence_accepted_count": 0, + "missing_evidence_ref_count": 0, + "outcome_lane_count": 10, + "owner_packet_required_count": 16, + "owner_response_accepted_count": 0, + "owner_response_received_count": 0, + "p0_asset_group_count": 14, + "p1_asset_group_count": 2, + "raw_payload_stored_count": 0, + "required_owner_field_count": 24, + "reviewer_check_count": 24, + "runtime_gate_count": 0, + "secret_value_collected_count": 0, + "security_asset_control_ledger_completion_percent": 100, + "soar_action_authorized_count": 0, + "wazuh_active_response_authorized_count": 0 + } +} diff --git a/scripts/security/iwooos-config-control-guard.py b/scripts/security/iwooos-config-control-guard.py index bb85797f2..6e599abb7 100644 --- a/scripts/security/iwooos-config-control-guard.py +++ b/scripts/security/iwooos-config-control-guard.py @@ -71,6 +71,7 @@ REQUIRED_CONTROL_DOCS = [ "docs/security/WAZUH-IWOOOS-INTRUSION-READBACK-PLAN.md", "docs/security/EXTERNAL-HOST-INTRUSION-PREVENTION-CONTROL.md", "docs/security/SOC-SIEM-KALI-WAZUH-INTEGRATION-CONTROL.md", + "docs/security/SECURITY-ASSET-CONTROL-LEDGER.md", "docs/security/AI-PROVIDER-OWNER-RESPONSE-ACCEPTANCE.md", "docs/security/AGENT-BOUNTY-OWNER-REQUEST-DRAFT.md", "docs/security/SECURITY-SUPPLY-CHAIN-CONTRACT-MANIFEST.md", @@ -983,6 +984,49 @@ ARTIFACT_SPECS = [ "action_button_count": 0, }, }, + { + "label": "security asset control ledger", + "path": "docs/security/security-asset-control-ledger.snapshot.json", + "schema": "security_asset_control_ledger_v1", + "status": "security_asset_control_ledger_ready_no_runtime_action", + "list_counts": { + "asset_groups": 16, + "required_owner_fields": 24, + "reviewer_checks": 24, + "outcome_lanes": 10, + "blocked_actions": 44, + }, + "summary_counts": { + "asset_group_count": 16, + "p0_asset_group_count": 14, + "p1_asset_group_count": 2, + "c0_asset_group_count": 14, + "c1_asset_group_count": 2, + "evidence_ref_count": 64, + "existing_evidence_ref_count": 64, + "missing_evidence_ref_count": 0, + "required_owner_field_count": 24, + "reviewer_check_count": 24, + "outcome_lane_count": 10, + "blocked_action_count": 44, + "owner_packet_required_count": 16, + "owner_response_received_count": 0, + "owner_response_accepted_count": 0, + "live_evidence_accepted_count": 0, + "runtime_gate_count": 0, + "action_button_count": 0, + "host_write_authorized_count": 0, + "active_scan_authorized_count": 0, + "wazuh_active_response_authorized_count": 0, + "kali_execute_authorized_count": 0, + "soar_action_authorized_count": 0, + "auto_block_authorized_count": 0, + "secret_value_collected_count": 0, + "raw_payload_stored_count": 0, + "security_asset_control_ledger_completion_percent": 100, + "iwooos_headline_progress_percent": 64, + }, + }, { "label": "ai provider owner response acceptance", "path": "docs/security/ai-provider-owner-response-acceptance.snapshot.json", diff --git a/scripts/security/security-asset-control-ledger.py b/scripts/security/security-asset-control-ledger.py new file mode 100644 index 000000000..e59617c43 --- /dev/null +++ b/scripts/security/security-asset-control-ledger.py @@ -0,0 +1,503 @@ +#!/usr/bin/env python3 +"""IwoooS 資安資產控制總帳產生器。 + +本工具只彙整 repo 內已提交的資安清冊、snapshot 與規範,將主機、 +公開入口、版本來源、workflow、Wazuh、Kali、備份、監控、AI provider、 +產品 runtime 與自動化資產沉澱狀態收斂成 P0-A 可驗證總帳。 + +它不連線主機、不讀 live log、不呼叫 Wazuh / Kali / Gitea / GitHub、 +不做 active scan、不讀 secret、不修改 Nginx / firewall / K8s / workflow。 +""" + +from __future__ import annotations + +import argparse +import json +import subprocess +import sys +from datetime import datetime, timedelta, timezone +from pathlib import Path +from typing import Any + + +TAIPEI = timezone(timedelta(hours=8)) + +ASSET_GROUPS = [ + { + "group_id": "public_gateway_nginx", + "label": "Nginx / Public Gateway / Route", + "priority": "P0", + "tier": "C0", + "scope": "公開入口、API、WebSocket、ACME、admin route、Ollama proxy", + "evidence_refs": [ + "docs/security/PUBLIC-GATEWAY-PREFLIGHT-INVENTORY.md", + "docs/security/public-gateway-preflight-inventory.snapshot.json", + "docs/security/PUBLIC-GATEWAY-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/public-gateway-post-incident-readback-plan.snapshot.json", + ], + "next_owner_action": "補 owner-provided live conf、rendered diff、nginx -t、route smoke、rollback owner。", + }, + { + "group_id": "dns_tls_certbot", + "label": "DNS / TLS / Certbot", + "priority": "P0", + "tier": "C0", + "scope": "domain、certificate path、ACME、renewal owner、TLS route", + "evidence_refs": [ + "docs/security/DOMAIN-TLS-CERTBOT-INVENTORY.md", + "docs/security/domain-tls-certbot-inventory.snapshot.json", + "docs/security/DOMAIN-TLS-CERTBOT-OWNER-RESPONSE-ACCEPTANCE.md", + "docs/security/domain-tls-certbot-owner-response-acceptance.snapshot.json", + ], + "next_owner_action": "補 SAN / wildcard 覆蓋依據、expiry metadata、renewal owner、ACME route owner。", + }, + { + "group_id": "host_service_runtime", + "label": "Docker / systemd / Host Service", + "priority": "P0", + "tier": "C0", + "scope": "Docker Compose、systemd、repair-bot、port binding、process / persistence baseline", + "evidence_refs": [ + "docs/security/HOST-SERVICE-CONFIG-INVENTORY.md", + "docs/security/host-service-config-inventory.snapshot.json", + "docs/security/HOST-SERVICE-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/host-service-post-incident-readback-plan.snapshot.json", + ], + "next_owner_action": "補 live hash metadata、incident readback、restart window、rollback owner、post-check。", + }, + { + "group_id": "ssh_firewall_network", + "label": "SSH / Firewall / WireGuard / NodePort", + "priority": "P0", + "tier": "C0", + "scope": "SSH target、known_hosts、sudoers、firewall、WireGuard、NetworkPolicy、NodePort", + "evidence_refs": [ + "docs/security/SSH-NETWORK-ACCESS-INVENTORY.md", + "docs/security/ssh-network-access-inventory.snapshot.json", + "docs/security/SSH-NETWORK-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/ssh-network-post-incident-readback-plan.snapshot.json", + ], + "next_owner_action": "補 actor、before / after state、impact、operator notification、restoration evidence。", + }, + { + "group_id": "k8s_argocd_gitops", + "label": "K8s / ArgoCD / GitOps", + "priority": "P0", + "tier": "C0", + "scope": "K8s manifests、ArgoCD app、RBAC、NetworkPolicy、CronJob、Velero", + "evidence_refs": [ + "docs/security/K8S-ARGOCD-MANIFEST-INVENTORY.md", + "docs/security/k8s-argocd-manifest-inventory.snapshot.json", + "docs/security/K8S-ARGOCD-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/k8s-argocd-post-incident-readback-plan.snapshot.json", + ], + "next_owner_action": "補 ArgoCD revision、health / sync、rendered manifest diff、rollback revision、postcheck owner。", + }, + { + "group_id": "workflow_runner_secret", + "label": "Gitea Workflow / Runner / Secret Metadata", + "priority": "P0", + "tier": "C0", + "scope": "workflow、runner label、deploy key、webhook、secret name parity、redaction guard", + "evidence_refs": [ + "docs/security/SOURCE-CONTROL-WORKFLOW-SECRET-NAME-INVENTORY.md", + "docs/security/source-control-workflow-secret-name-inventory.snapshot.json", + "docs/security/CD-RUNNER-SECRET-INJECTION-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/cd-runner-secret-injection-post-incident-readback-plan.snapshot.json", + ], + "next_owner_action": "補 runner attestation、workspace cleanup、secret injection route、log redaction、Gitea run readback。", + }, + { + "group_id": "source_control_repo_visibility", + "label": "Gitea / GitHub / Source Control", + "priority": "P0", + "tier": "C0", + "scope": "repo visibility、canonical refs、GitHub primary readiness、branch / tag / workflow boundary", + "evidence_refs": [ + "docs/security/GITEA-GITHUB-MIGRATION-INVENTORY.md", + "docs/security/SOURCE-CONTROL-PRIMARY-READINESS-GATE.md", + "docs/security/GITHUB-TARGET-OWNER-DECISION-RESPONSE.md", + "docs/security/source-control-primary-readiness-gate.snapshot.json", + ], + "next_owner_action": "補 owner response;不得建立 repo、改 visibility、sync refs 或切 primary。", + }, + { + "group_id": "wazuh_endpoint_siem", + "label": "Wazuh / Endpoint / SIEM", + "priority": "P0", + "tier": "C0", + "scope": "Wazuh manager、agent、FIM、rule / decoder、event ref、active response dry-run boundary", + "evidence_refs": [ + "docs/security/WAZUH-IWOOOS-INTRUSION-READBACK-PLAN.md", + "docs/security/wazuh-iwooos-intrusion-readback-plan.snapshot.json", + "docs/security/SOC-SIEM-KALI-WAZUH-INTEGRATION-CONTROL.md", + "docs/security/soc-siem-kali-wazuh-integration-control.snapshot.json", + ], + "next_owner_action": "補 Wazuh health refs、agent refs、event refs、rule / decoder readback 與 no-raw-payload attestation。", + }, + { + "group_id": "kali_112_assessment", + "label": "Kali 112 / Assessment Tooling", + "priority": "P0", + "tier": "C0", + "scope": "Kali health、tool version、scope、finding envelope、maintenance window", + "evidence_refs": [ + "docs/security/KALI-INTEGRATION-STATUS.md", + "docs/security/kali-integration-status.snapshot.json", + "docs/security/KALI-112-MAINTENANCE-WINDOW-DRAFT.md", + "docs/security/kali-112-maintenance-window-draft.snapshot.json", + ], + "next_owner_action": "補 scope ref、health ref、normalized finding envelope;active scan 與 /execute 仍獨立批准。", + }, + { + "group_id": "monitoring_alerting_observability", + "label": "Monitoring / Alerting / Observability", + "priority": "P0", + "tier": "C0", + "scope": "Prometheus、Alertmanager、Telegram route、SigNoz、Sentry、Langfuse、no-false-green", + "evidence_refs": [ + "docs/security/MONITORING-ALERTING-OBSERVABILITY-INVENTORY.md", + "docs/security/monitoring-alerting-observability-inventory.snapshot.json", + "docs/security/MONITORING-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/monitoring-post-incident-readback-plan.snapshot.json", + ], + "next_owner_action": "補 route owner、receiver diff、receipt evidence、noise budget、reload owner 與 no-false-green。", + }, + { + "group_id": "backup_restore_dr", + "label": "Backup / Restore / DR / Escrow", + "priority": "P0", + "tier": "C0", + "scope": "backup scripts、restic、offsite、credential escrow、Velero、restore drill、retention", + "evidence_refs": [ + "docs/security/BACKUP-RESTORE-ESCROW-INVENTORY.md", + "docs/security/backup-restore-escrow-inventory.snapshot.json", + "docs/security/BACKUP-RESTORE-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/backup-restore-post-incident-readback-plan.snapshot.json", + ], + "next_owner_action": "補 restore drill、offsite sync ref、escrow non-secret proof、retention runway、DR scorecard。", + }, + { + "group_id": "container_registry_supply_chain", + "label": "Harbor / Registry / SBOM / Supply Chain", + "priority": "P0", + "tier": "C0", + "scope": "Harbor、registry、image tag、SBOM、Cosign、SLSA、dependency drift、CVE / KEV", + "evidence_refs": [ + "docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md", + "docs/security/SECURITY-SUPPLY-CHAIN-CONTRACT-MANIFEST.md", + "docs/security/security-supply-chain-contract-manifest.snapshot.json", + "docs/evaluations/dependency_supply_chain_drift_monitor_2026-06-18.json", + ], + "next_owner_action": "補 SBOM / VEX / provenance intake、image signing、KEV / EPSS / exposure SLA。", + }, + { + "group_id": "public_admin_api_runtime", + "label": "Public / Admin / API / Frontend Runtime", + "priority": "P0", + "tier": "C0", + "scope": "public URL、CORS、auth boundary、middleware、webhook、frontend env、i18n redaction", + "evidence_refs": [ + "docs/security/PUBLIC-RUNTIME-CONFIG-CHANGE-EVIDENCE-ACCEPTANCE.md", + "docs/security/public-runtime-config-change-evidence-acceptance.snapshot.json", + "docs/security/public-frontend-sensitive-surface-guard.snapshot.json", + "docs/HARD_RULES.md", + ], + "next_owner_action": "補 route owner、API contract readback、CORS diff、desktop / mobile smoke、bundle sensitive scan。", + }, + { + "group_id": "ai_provider_agent_runtime", + "label": "AI Provider / Model Router / Agent Runtime", + "priority": "P0", + "tier": "C0", + "scope": "OpenClaw、Ollama、NemoTron、Hermes、Gemini、MCP / A2A、tool allowlist、cost / privacy", + "evidence_refs": [ + "docs/security/AI-PROVIDER-OWNER-RESPONSE-ACCEPTANCE.md", + "docs/security/ai-provider-owner-response-acceptance.snapshot.json", + "docs/ai", + "docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md", + ], + "next_owner_action": "補 dry-run、benchmark、cost review、privacy review、fallback order 與 rollback owner。", + }, + { + "group_id": "product_surface_runtime_routes", + "label": "Product Surface / Runtime Route", + "priority": "P1", + "tier": "C1", + "scope": "AWOOOI、AwoooP、IwoooS、VibeWork、agent-bounty-protocol、StockPlatform、Tsenyang、Bitan", + "evidence_refs": [ + "docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md", + "docs/security/VIBEWORK-IWOOOS-ONBOARDING-HANDOFF.md", + "docs/security/AGENT-BOUNTY-IWOOOS-ONBOARDING-HANDOFF.md", + "docs/security/agent-bounty-iwooos-onboarding-handoff.snapshot.json", + ], + "next_owner_action": "補逐產品 owner、route、admin、API、backup、webhook、rollback 與 validation 指標。", + }, + { + "group_id": "automation_asset_sedimentation", + "label": "KM / PlayBook / Script / Schedule / Verifier", + "priority": "P1", + "tier": "C1", + "scope": "incident、approval、repair candidate、manual handoff 的自動化資產沉澱", + "evidence_refs": [ + "docs/LOGBOOK.md", + "apps/api/src/services/repair_candidate_service.py", + "apps/api/src/services/telegram_gateway.py", + "apps/web/src/app/[locale]/awooop/work-items/page.tsx", + ], + "next_owner_action": "補 incident / approval / manual handoff writeback contract,讓資產總帳從可視化進入可追蹤閉環。", + }, +] + +REQUIRED_OWNER_FIELDS = [ + "asset_group_id", + "asset_alias", + "owner_role", + "owner_team", + "business_impact", + "technical_scope", + "affected_routes_or_services", + "data_classification", + "redacted_evidence_refs", + "source_of_truth_ref", + "live_state_ref", + "config_diff_ref", + "monitoring_signal_ref", + "wazuh_or_siem_ref", + "kali_scope_ref", + "backup_restore_ref", + "supply_chain_ref", + "secret_absence_attestation", + "raw_payload_absence_attestation", + "maintenance_window", + "rollback_owner", + "postcheck_owner", + "followup_owner", + "decision_reason", +] + +REVIEWER_CHECKS = [ + "asset alias 不得暴露個人 namespace", + "owner role / team 必填", + "source-of-truth 必須可追溯", + "live evidence 只能收脫敏 ref", + "secret value / hash / partial token 一律拒收", + "raw Wazuh / raw Kali output 一律拒收", + "Nginx / firewall / K8s / workflow 變更需獨立 runtime approval", + "route 200 不得當資安完成", + "dashboard 可見不得當 remediation 完成", + "backup 存在不得當 restore drill 完成", + "Kali 納入範圍不得當 active scan 授權", + "Wazuh event 可見不得當 active response 授權", + "repo snapshot 不得當 live host truth", + "事故後回讀需含 actor、before / after、impact、postcheck", + "no-false-green 必須明確標示", + "owner response received / accepted 必須維持 0,除非有實際收件", + "runtime gate 必須維持 0", + "action button 必須維持 0", + "Gitea / GitHub refs 不得自動同步", + "GitHub primary 不得自動切換", + "Telegram 不得實發", + "SOAR 不得 auto block", + "AI agent 不得讀 secret 或 host write", + "LOGBOOK 不得包含內部對話逐字稿", +] + +OUTCOME_LANES = [ + "waiting_asset_owner_packet", + "request_gateway_supplement", + "request_host_service_supplement", + "request_network_supplement", + "request_wazuh_kali_supplement", + "request_backup_restore_supplement", + "request_supply_chain_supplement", + "request_product_surface_supplement", + "quarantine_secret_or_raw_payload", + "ready_for_security_reviewer_review", +] + +BLOCKED_ACTIONS = [ + "ssh_to_host", + "read_live_host_log", + "write_host_file", + "nginx_reload", + "certbot_renew", + "dns_change", + "firewall_change", + "wireguard_change", + "nodeport_change", + "networkpolicy_apply", + "kubectl_action", + "argocd_sync", + "helm_upgrade", + "docker_restart", + "docker_compose_up", + "systemctl_restart", + "repair_bot_execute", + "ansible_apply", + "wazuh_active_response", + "wazuh_rule_change", + "kali_active_scan", + "kali_execute", + "nmap_scan", + "nuclei_scan", + "trivy_live_scan", + "package_upgrade", + "workflow_modify", + "workflow_dispatch", + "runner_restart", + "secret_read", + "secret_rotate", + "webhook_modify", + "deploy_key_modify", + "refs_sync", + "force_push", + "github_primary_switch", + "backup_run", + "restore_run", + "offsite_sync", + "remote_delete", + "telegram_send", + "soar_case_create", + "auto_block", + "production_write", +] + + +def get_git_commit(root: Path) -> str: + try: + return subprocess.check_output(["git", "rev-parse", "--short=8", "HEAD"], cwd=root, text=True).strip() + except Exception: + return "unknown" + + +def build_snapshot(root: Path, generated_at: str) -> dict[str, Any]: + enriched_groups = [] + evidence_refs: set[str] = set() + existing_refs: set[str] = set() + missing_refs: set[str] = set() + + for group in ASSET_GROUPS: + refs = group["evidence_refs"] + evidence_refs.update(refs) + ref_states = [] + for ref in refs: + exists = (root / ref).exists() + ref_states.append({"ref": ref, "exists": exists}) + if exists: + existing_refs.add(ref) + else: + missing_refs.add(ref) + enriched_groups.append( + { + **group, + "owner_packet_status": "waiting_asset_owner_packet", + "runtime_gate": 0, + "action_button": 0, + "owner_response_received": 0, + "owner_response_accepted": 0, + "live_evidence_accepted": 0, + "redacted_evidence_refs_required": True, + "secret_value_collection_allowed": False, + "raw_payload_allowed": False, + "evidence_ref_states": ref_states, + } + ) + + summary = { + "asset_group_count": len(enriched_groups), + "p0_asset_group_count": sum(1 for group in enriched_groups if group["priority"] == "P0"), + "p1_asset_group_count": sum(1 for group in enriched_groups if group["priority"] == "P1"), + "c0_asset_group_count": sum(1 for group in enriched_groups if group["tier"] == "C0"), + "c1_asset_group_count": sum(1 for group in enriched_groups if group["tier"] == "C1"), + "evidence_ref_count": len(evidence_refs), + "existing_evidence_ref_count": len(existing_refs), + "missing_evidence_ref_count": len(missing_refs), + "required_owner_field_count": len(REQUIRED_OWNER_FIELDS), + "reviewer_check_count": len(REVIEWER_CHECKS), + "outcome_lane_count": len(OUTCOME_LANES), + "blocked_action_count": len(BLOCKED_ACTIONS), + "owner_packet_required_count": len(enriched_groups), + "owner_response_received_count": 0, + "owner_response_accepted_count": 0, + "live_evidence_accepted_count": 0, + "runtime_gate_count": 0, + "action_button_count": 0, + "host_write_authorized_count": 0, + "active_scan_authorized_count": 0, + "wazuh_active_response_authorized_count": 0, + "kali_execute_authorized_count": 0, + "soar_action_authorized_count": 0, + "auto_block_authorized_count": 0, + "secret_value_collected_count": 0, + "raw_payload_stored_count": 0, + "security_asset_control_ledger_completion_percent": 100, + "iwooos_headline_progress_percent": 64, + } + + return { + "schema_version": "security_asset_control_ledger_v1", + "status": "security_asset_control_ledger_ready_no_runtime_action", + "generated_at": generated_at, + "git_commit": get_git_commit(root), + "summary": summary, + "asset_groups": enriched_groups, + "required_owner_fields": REQUIRED_OWNER_FIELDS, + "reviewer_checks": REVIEWER_CHECKS, + "outcome_lanes": OUTCOME_LANES, + "blocked_actions": BLOCKED_ACTIONS, + "execution_boundaries": { + "not_authorization": True, + "runtime_execution_authorized": False, + "host_write_authorized": False, + "ssh_read_authorized": False, + "nginx_reload_authorized": False, + "firewall_change_authorized": False, + "argocd_sync_authorized": False, + "workflow_modification_authorized": False, + "secret_value_collection_allowed": False, + "wazuh_active_response_authorized": False, + "kali_active_scan_authorized": False, + "kali_execute_authorized": False, + "telegram_send_authorized": False, + "soar_action_authorized": False, + "auto_block_authorized": False, + "production_write_authorized": False, + "action_buttons_allowed": False, + }, + } + + +def main(argv: list[str]) -> int: + parser = argparse.ArgumentParser() + parser.add_argument("--root", default=".") + parser.add_argument("--output") + parser.add_argument("--generated-at") + args = parser.parse_args(argv) + + root = Path(args.root).resolve() + generated_at = args.generated_at or datetime.now(TAIPEI).replace(microsecond=0).isoformat() + snapshot = build_snapshot(root, generated_at) + + if args.output: + output = Path(args.output) + if not output.is_absolute(): + output = root / output + output.parent.mkdir(parents=True, exist_ok=True) + output.write_text(json.dumps(snapshot, ensure_ascii=False, indent=2, sort_keys=True) + "\n", encoding="utf-8") + else: + print(json.dumps(snapshot, ensure_ascii=False, indent=2, sort_keys=True)) + + summary = snapshot["summary"] + print( + "SECURITY_ASSET_CONTROL_LEDGER_OK " + f"groups={summary['asset_group_count']} " + f"p0={summary['p0_asset_group_count']} " + f"evidence_refs={summary['evidence_ref_count']} " + f"runtime_gate={summary['runtime_gate_count']}" + ) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main(sys.argv[1:])) diff --git a/scripts/security/security-mirror-progress-guard.py b/scripts/security/security-mirror-progress-guard.py index e24176d27..4f9384350 100755 --- a/scripts/security/security-mirror-progress-guard.py +++ b/scripts/security/security-mirror-progress-guard.py @@ -18637,6 +18637,124 @@ def validate(root: Path) -> None: iwooos_projection_page, text, ) + for key in ["eyebrow", "title", "subtitle", "boundaryTitle", "boundaryIntro"]: + assert_contains( + "web_messages.zh-TW.iwooos.securityAssetControlLedger.keys", + list(web_messages_zh["iwooos"]["securityAssetControlLedger"].keys()), + key, + ) + assert_contains( + "web_messages.en.iwooos.securityAssetControlLedger.keys", + list(web_messages_en["iwooos"]["securityAssetControlLedger"].keys()), + key, + ) + for key in ["assetGroups", "p0Groups", "evidenceRefs", "runtimeGate"]: + assert_contains( + "web_messages.zh-TW.iwooos.securityAssetControlLedger.summary", + list(web_messages_zh["iwooos"]["securityAssetControlLedger"]["summary"].keys()), + key, + ) + assert_contains( + "web_messages.en.iwooos.securityAssetControlLedger.summary", + list(web_messages_en["iwooos"]["securityAssetControlLedger"]["summary"].keys()), + key, + ) + for key in [ + "gatewayTls", + "hostNetwork", + "k8sWorkflow", + "wazuhKali", + "alertBackup", + "supplyChain", + "aiProduct", + "runtimeBoundary", + ]: + assert_contains( + "web_messages.zh-TW.iwooos.securityAssetControlLedger.items", + list(web_messages_zh["iwooos"]["securityAssetControlLedger"]["items"].keys()), + key, + ) + assert_contains( + "web_messages.en.iwooos.securityAssetControlLedger.items", + list(web_messages_en["iwooos"]["securityAssetControlLedger"]["items"].keys()), + key, + ) + assert_text_contains( + "iwooos_page.security_asset_control_ledger_testid", + iwooos_projection_page, + 'data-testid="iwooos-security-asset-control-ledger-board"', + ) + assert_text_contains( + "iwooos_page.security_asset_control_ledger_boundary_testid", + iwooos_projection_page, + 'data-testid="iwooos-security-asset-control-ledger-boundaries"', + ) + assert_text_before( + "iwooos_page.security_asset_control_after_soc", + iwooos_projection_page, + "", + "", + ) + assert_text_before( + "iwooos_page.security_asset_control_before_external_host", + iwooos_projection_page, + "", + "", + ) + for text in [ + "security_asset_control_ledger_visible=true", + "security_asset_control_ledger_asset_group_count=16", + "security_asset_control_ledger_p0_asset_group_count=14", + "security_asset_control_ledger_p1_asset_group_count=2", + "security_asset_control_ledger_c0_asset_group_count=14", + "security_asset_control_ledger_c1_asset_group_count=2", + "security_asset_control_ledger_evidence_ref_count=64", + "security_asset_control_ledger_existing_evidence_ref_count=64", + "security_asset_control_ledger_missing_evidence_ref_count=0", + "security_asset_control_ledger_required_owner_field_count=24", + "security_asset_control_ledger_reviewer_check_count=24", + "security_asset_control_ledger_outcome_lane_count=10", + "security_asset_control_ledger_blocked_action_count=44", + "security_asset_control_ledger_owner_packet_required_count=16", + "security_asset_control_ledger_owner_response_received_count=0", + "security_asset_control_ledger_owner_response_accepted_count=0", + "security_asset_control_ledger_live_evidence_accepted_count=0", + "security_asset_control_ledger_runtime_gate_count=0", + "security_asset_control_ledger_action_button_count=0", + "security_asset_control_ledger_host_write_authorized_count=0", + "security_asset_control_ledger_active_scan_authorized_count=0", + "security_asset_control_ledger_wazuh_active_response_authorized_count=0", + "security_asset_control_ledger_kali_execute_authorized_count=0", + "security_asset_control_ledger_soar_action_authorized_count=0", + "security_asset_control_ledger_auto_block_authorized_count=0", + "security_asset_control_ledger_secret_value_collected_count=0", + "security_asset_control_ledger_raw_payload_stored_count=0", + "security_asset_control_ledger_completion_percent=100", + "iwooos_headline_progress_percent=64", + "runtime_execution_authorized=false", + "host_write_authorized=false", + "ssh_read_authorized=false", + "nginx_reload_authorized=false", + "firewall_change_authorized=false", + "argocd_sync_authorized=false", + "workflow_modification_authorized=false", + "secret_value_collection_allowed=false", + "wazuh_active_response_authorized=false", + "kali_active_scan_authorized=false", + "kali_execute_authorized=false", + "telegram_send_authorized=false", + "soar_action_authorized=false", + "auto_block_authorized=false", + "production_write_authorized=false", + "active_runtime_gate_count=0", + "action_buttons_allowed=false", + "not_authorization=true", + ]: + assert_text_contains( + "iwooos_page.security_asset_control_ledger_boundary", + iwooos_projection_page, + text, + ) for key in ["eyebrow", "title", "subtitle", "boundaryTitle", "boundaryIntro"]: assert_contains( "web_messages.zh-TW.iwooos.externalHostIntrusionPreventionControl.keys",