diff --git a/docs/security/DOMAIN-TLS-CERTBOT-OWNER-RESPONSE-ACCEPTANCE.md b/docs/security/DOMAIN-TLS-CERTBOT-OWNER-RESPONSE-ACCEPTANCE.md new file mode 100644 index 00000000..6541f463 --- /dev/null +++ b/docs/security/DOMAIN-TLS-CERTBOT-OWNER-RESPONSE-ACCEPTANCE.md @@ -0,0 +1,130 @@ +# IwoooS DNS / TLS / certbot Owner Response Acceptance + +| 項目 | 內容 | +|------|------| +| 日期 | 2026-06-14 | +| 狀態 | `owner_response_acceptance_ledger_ready_no_runtime_action` | +| 工具 | `scripts/security/domain-tls-certbot-owner-response-acceptance.py` | +| 輸入 | `docs/security/domain-tls-certbot-owner-confirmation-request.snapshot.json` | +| Snapshot | `docs/security/domain-tls-certbot-owner-response-acceptance.snapshot.json` | +| runtime gate | `0` | + +## 1. 目的 + +DNS / TLS / certbot 屬於 C0 公開入口配置。既有 owner confirmation request 已把 4 個 certificate path 需確認關係列出,但若缺少 owner response acceptance 帳本,後續容易把 SAN / wildcard / 共用憑證覆蓋確認、renewal owner 或 ACME route owner 誤判成 DNS query、TLS probe、certbot renew、Nginx reload 或 route smoke 授權。 + +本文件只定義 owner response 如何收件、補證、隔離、拒收與進 reviewer review。它不是 request sent、不是 owner response received、不是 accepted response、不是 DNS query、不是 live TLS probe、不是 certbot renew、不是 Nginx reload、不是 route smoke,也不是 host write、production write 或 runtime gate 授權。 + +## 2. 摘要 + +| 指標 | 值 | 說明 | +|------|----|------| +| acceptance candidate count | `4` | 4 個 domain / certificate path relation candidate | +| C0 acceptance candidate count | `4` | 全部位於 188 public gateway / internal tools HTTPS 範圍 | +| acceptance field count | `23` | 每份 candidate 的 metadata-only 欄位 | +| required owner response field count | `13` | owner / decision / scope / redacted refs / coverage / expiry / renewal / ACME / window / rollback / validation | +| reviewer check count | `13` | raw cert、private key、credential、execution request、coverage ref 與 runtime gate 檢查 | +| outcome lane count | `7` | waiting、quarantine、reject、supplement、coverage review、read-only update、waiting runtime gate | +| blocked action count | `20` | DNS query、TLS probe、certbot renew、Nginx reload、route smoke、secret collection 等 | +| owner response received / accepted | `0 / 0` | 尚未收到,尚未驗收 | +| DNS query / TLS probe / certbot renew / Nginx reload / route smoke | `0 / 0 / 0 / 0 / 0` | 尚未批准且未執行 | +| runtime gate / action button | `0 / 0` | 未開啟 | + +## 3. 四份驗收候選 + +| Acceptance candidate | Control tier | 來源 request | 驗收焦點 | +|----------------------|--------------|--------------|----------| +| `domain_tls_certbot_owner_response_acceptance:gitea.wooo.work` | `C0` | `domain_tls_certbot_owner_confirmation:gitea.wooo.work` | 憑證覆蓋依據 ref、到期 metadata ref、renewal owner、ACME route owner、維護窗口與 rollback owner | +| `domain_tls_certbot_owner_response_acceptance:langfuse.wooo.work` | `C0` | `domain_tls_certbot_owner_confirmation:langfuse.wooo.work` | 憑證覆蓋依據 ref、到期 metadata ref、renewal owner、ACME route owner、維護窗口與 rollback owner | +| `domain_tls_certbot_owner_response_acceptance:signoz.wooo.work` | `C0` | `domain_tls_certbot_owner_confirmation:signoz.wooo.work` | 憑證覆蓋依據 ref、到期 metadata ref、renewal owner、ACME route owner、維護窗口與 rollback owner | +| `domain_tls_certbot_owner_response_acceptance:tsenyang.com` | `C0` | `domain_tls_certbot_owner_confirmation:tsenyang.com` | 憑證覆蓋依據 ref、到期 metadata ref、renewal owner、ACME route owner、維護窗口與 rollback owner | + +## 4. Owner response 必填欄位 + +| 欄位 | 規則 | +|------|------| +| `owner_role_or_team` | 只填角色或團隊,不填私人聯絡資料或 credential | +| `decision` | 允許 `confirm`、`defer`、`reject`、`request_more_evidence` | +| `decision_reason` | 摘要說明,不貼 raw cert、private key、certbot log 或 DNS credential | +| `affected_scope` | 明確列出 domain、certificate path metadata、ACME / route 影響範圍 | +| `redacted_evidence_refs` | 只接受脫敏 ref、ticket id、文件路徑、hash 或摘要 | +| `certificate_coverage_basis_ref` | SAN / wildcard / 共用憑證覆蓋依據的脫敏 ref | +| `certificate_expiry_metadata_ref` | 憑證到期資訊只能是 owner-provided metadata ref,不得貼 raw cert | +| `renewal_owner` | 未來 renewal 負責角色;不代表可執行 certbot renew | +| `acme_challenge_route_owner` | HTTP-01 ACME path 與 route smoke owner | +| `maintenance_window` | 未來 probe / renew / reload 的維護窗口;本 response 不開執行權 | +| `rollback_owner` | 未來若進變更的 rollback owner | +| `validation_plan` | DNS / TLS / ACME / route post-check 指標,不授權執行 | +| `followup_owner` | 後續補證、reviewer 或 runtime gate 負責角色 | + +## 5. Reviewer checks + +| Check | 說明 | +|-------|------| +| `owner_identity_present` | owner role / team 必須可追溯 | +| `decision_and_reason_present` | decision 與 reason 必須同時存在 | +| `redacted_refs_only` | evidence 只能是脫敏 ref、ticket、hash、文件路徑或摘要 | +| `raw_certificate_absent` | 不得出現 raw certificate payload、完整 SAN dump、private key 或 ACME account key | +| `secret_value_absent` | 不得出現 DNS credential、registrar credential、token、cookie、authorization header 或 Basic Auth | +| `coverage_basis_ref_present` | 覆蓋依據必須是 metadata ref | +| `expiry_metadata_ref_not_probe` | 到期資訊不得由本帳本觸發 live probe | +| `renewal_owner_separate_from_action` | renewal owner 與 certbot renew action 必須分離 | +| `acme_route_owner_present` | ACME path 與 route smoke owner 必須清楚 | +| `maintenance_window_present` | 未來執行期操作需維護窗口或明確禁止窗口 | +| `rollback_owner_present` | rollback owner 與 rollback ref 必須存在 | +| `validation_plan_present` | validation plan 只列 post-check,不授權執行 | +| `counts_transition_safe` | 只有 reviewer record 可更新 received / accepted / rejected,且不得開 runtime gate | + +## 6. Outcome lanes + +| Lane | 意義 | +|------|------| +| `waiting_owner_response` | 尚未收到 owner response | +| `quarantine_raw_certificate_or_secret` | 收到 raw cert、private key、DNS credential 或 certbot account 內容時隔離 | +| `reject_execution_request` | 夾帶 DNS query、TLS probe、certbot renew、Nginx reload 或 host write 要求時拒收 | +| `request_supplement` | 欄位不足、scope 不清或 evidence ref 不可追溯時要求補件 | +| `ready_for_certificate_coverage_review` | metadata 合格後,只能進憑證覆蓋關係 reviewer review | +| `owner_review_only_update` | 只允許更新只讀 owner review ledger | +| `waiting_runtime_gate` | 即使 owner response accepted,runtime gate 仍等待獨立人工批准 | + +## 7. 禁止事項 + +1. 不做 DNS query。 +2. 不做 live TLS probe。 +3. 不執行 certbot renew。 +4. 不 reload Nginx。 +5. 不執行 route smoke。 +6. 不讀 TLS private key。 +7. 不保存 raw certificate payload、DNS credential、certbot account key、secret value、未脫敏 certbot log、shell history 或 env dump。 +8. 不修改 DNS record、TLS certificate path、ACME challenge route 或 production host。 +9. 不開 runtime gate,不建立 action button。 + +## 8. 指令 + +產生 committed snapshot: + +```bash +python3 scripts/security/domain-tls-certbot-owner-response-acceptance.py \ + --root . \ + --owner-confirmation-request-report docs/security/domain-tls-certbot-owner-confirmation-request.snapshot.json \ + --output docs/security/domain-tls-certbot-owner-response-acceptance.snapshot.json \ + --generated-at 2026-06-14T23:05:00+08:00 +``` + +驗證 guard: + +```bash +python3 scripts/security/security-mirror-progress-guard.py --root . +``` + +## 9. 完成度 + +| 工作 | 完成度 | 說明 | +|------|--------|------| +| owner response acceptance ledger artifact | `100%` | 產生器、snapshot 與文件已固定 | +| DNS / TLS / certbot 只讀治理成熟度 | `74% -> 78%` | 收件驗收帳本更完整;不代表 live evidence 或 runtime action | +| owner response received / accepted | `0%` | 尚未收到,尚未驗收 | +| certificate coverage confirmed | `0%` | 尚未收到 owner-provided metadata ref | +| DNS query / TLS probe | `0%` | 尚未批准且未執行 | +| certbot renew / Nginx reload / route smoke | `0%` | 尚未批准且未執行 | +| runtime gate / host write | `0%` | 未授權且未執行 | diff --git a/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md b/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md index f7d4ee7b..90ae32d3 100644 --- a/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md +++ b/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md @@ -48,6 +48,12 @@ 固定數字為 `acceptance_candidate_count=3`、`c0_acceptance_candidate_count=2`、`c1_acceptance_candidate_count=1`、`acceptance_field_count=23`、`required_owner_response_field_count=12`、`reviewer_check_count=12`、`outcome_lane_count=7`、`blocked_action_count=18`、`owner_response_received_count=0`、`owner_response_accepted_count=0`、`runtime_gate_count=0`。此更新只讓 `nginx_public_gateway` 從 `84%` 推進到 `86%`,代表收件驗收帳本更完整;live conf、rendered diff、`nginx -t`、reload、route smoke、DNS / TLS probe、certbot renew、maintenance window、rollback owner、runtime gate 與 action button 仍全部為 `0 / false`。 +## 1.5 2026-06-14 DNS / TLS / certbot owner response acceptance 只讀帳本 + +已新增 `docs/security/DOMAIN-TLS-CERTBOT-OWNER-RESPONSE-ACCEPTANCE.md` 與 `docs/security/domain-tls-certbot-owner-response-acceptance.snapshot.json`,將 4 份 DNS / TLS / certbot owner confirmation request 轉成 metadata-only owner response acceptance 只讀帳本。 + +固定數字為 `acceptance_candidate_count=4`、`c0_acceptance_candidate_count=4`、`acceptance_field_count=23`、`required_owner_response_field_count=13`、`reviewer_check_count=13`、`outcome_lane_count=7`、`blocked_action_count=20`、`owner_response_received_count=0`、`owner_response_accepted_count=0`、`certificate_coverage_confirmed_count=0`、`dns_query_authorized_count=0`、`live_tls_probe_authorized_count=0`、`certbot_renew_authorized_count=0`、`nginx_reload_authorized_count=0`、`route_smoke_authorized_count=0`、`runtime_gate_count=0`。此更新讓 `dns_tls_certbot` 從 `74%` 推進到 `78%`,代表未來 owner 回覆可被補件、隔離、拒收或送 reviewer review;它不代表 DNS query、TLS probe、certbot renew、Nginx reload、route smoke、host write 或 runtime gate 已授權。 + ## 2. 覆蓋摘要 | 指標 | 目前值 | 說明 | @@ -161,6 +167,7 @@ python3 scripts/security/high-value-config-control-coverage.py \ |------|--------|------| | 全高價值配置類別註冊 | `100%` | 14 類全部來自既有 Gate 定義 | | 覆蓋 snapshot / schema | `100%` | 已新增可重跑 snapshot 與 JSON schema | +| DNS / TLS / certbot owner response acceptance | `100%` | 已新增 `domain_tls_certbot_owner_response_acceptance_v1`,4 個 C0 candidate、13 個 owner 必填欄位、13 個 reviewer checks、7 條 outcome lanes、20 類 blocked action;成熟度 `74% -> 78%` | | owner response 收件 | `0%` | 尚未收到或接受任何 owner response | | live evidence collection | `0%` | 未 SSH、未 live probe、未 active scan | | runtime gate | `0%` | 未開啟任何執行期閘門 | @@ -198,3 +205,9 @@ python3 scripts/security/high-value-config-control-coverage.py \ `public_gateway_preflight_inventory_v1` 已把 Nginx public gateway reload / route change 前置 Gate 固定成只讀清冊,共 `3` 份 source config、`14` 個 route impact、`14` 個 unique upstream、`12` 個 preflight gate,其中 `2` 個 gate 只代表 repo-only ready,`10` 個 gate 仍需 owner acceptance。此更新讓 `nginx_public_gateway` 從 `78%` 推進到 `84%`;owner response、owner-provided live conf、rendered diff、`nginx -t` evidence、route smoke、maintenance window、rollback owner、runtime gate 與 action button 仍全部為 `0`。 2026-06-14 再新增 `public_gateway_owner_response_acceptance_v1`,把 3 份 public gateway config 轉成 `acceptance_candidate_count=3`、`c0_acceptance_candidate_count=2`、`required_owner_response_field_count=12`、`reviewer_check_count=12`、`outcome_lane_count=7`、`blocked_action_count=18` 的 owner response acceptance 只讀帳本。此更新只讓 `nginx_public_gateway` 從 `84%` 推進到 `86%`;owner response received / accepted、redacted export received / accepted、rendered diff ready、`nginx -t`、reload、route smoke、DNS / TLS probe、certbot renew、runtime gate 與 action button 仍全部為 `0`。 + +## 13. P0 DNS / TLS / certbot owner response acceptance 更新 + +`domain_tls_certbot_owner_response_acceptance_v1` 已把 4 份 DNS / TLS / certbot owner confirmation request 轉成 owner response acceptance 只讀帳本。四份候選全部為 `C0`,固定 `acceptance_candidate_count=4`、`required_owner_response_field_count=13`、`reviewer_check_count=13`、`outcome_lane_count=7`、`blocked_action_count=20`,讓 `dns_tls_certbot` 從 `74%` 推進到 `78%`。 + +此更新只補齊 SAN / wildcard / 共用憑證覆蓋關係、certificate expiry metadata ref、renewal owner、ACME route owner、maintenance window、rollback owner 與 validation plan 的收件驗收規則;owner response received / accepted、certificate coverage confirmed、DNS query、live TLS probe、certbot renew、Nginx reload、route smoke、DNS record 修改、certificate path 修改、ACME challenge route 修改、host write、runtime gate 與 action button 仍全部為 `0 / false`。 diff --git a/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md b/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md index c368aa92..7a8eb268 100644 --- a/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md +++ b/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md @@ -83,6 +83,12 @@ 2026-06-14 已新增 `public_gateway_owner_response_acceptance_v1`,把 3 份 Public Gateway config 轉成 owner response acceptance 只讀帳本。固定 `candidates=3`、`c0=2`、`owner_fields=12`、`reviewer_checks=12`、`outcome_lanes=7`、`blocked_actions=18`,讓 Nginx public gateway 類別成熟度從 `84%` 推進到 `86%`。此更新只表示未來 owner 回覆可安全收件、補件、隔離或拒收;owner response received / accepted、redacted export、rendered diff、`nginx -t`、reload、route smoke、DNS / TLS probe、certbot renew、host write、runtime gate 仍全部為 `0 / false`。 +### 0.7 2026-06-14 DNS / TLS / certbot owner response acceptance 只讀帳本 + +`domain_tls_certbot_owner_response_acceptance_v1` 已把 4 份 DNS / TLS / certbot owner confirmation request 轉成 owner response acceptance 只讀帳本。固定 `candidates=4`、`c0=4`、`owner_fields=13`、`reviewer_checks=13`、`outcome_lanes=7`、`blocked_actions=20`,讓 DNS / TLS / certbot 類別成熟度從 `74%` 推進到 `78%`。 + +此更新只表示 SAN / wildcard / 共用憑證覆蓋關係、certificate expiry metadata、renewal owner、ACME route owner、maintenance window、rollback owner 與 validation plan 已有收件驗收規則;owner response received / accepted、certificate coverage confirmed、DNS query、TLS probe、certbot renew、Nginx reload、route smoke、DNS record / certificate path / ACME route 變更、host write、runtime gate 仍全部為 `0 / false`。 + ## 1. 目前已不符合新要求的項目 | 優先 | 項目 | 現況 | 風險 | 本階段處置 | @@ -94,7 +100,7 @@ | P0 | `apps/api/src/api/v1/monitoring.py` Grafana 探測認證 | 程式碼內有 Grafana Basic Auth 常值 | API 程式碼保存 credential,且會被複製到後續部署 | 已改為 `settings.GRAFANA_API_KEY` Bearer token;未設定時不送 Authorization header | | P1 | Nginx 188 / 110 live conf drift | repo 有 templates 與 drift detector,比對模式需 owner 提供脫敏 live conf;目前 live evidence 仍為 `0` | 手改後 repo 不知道,下一次 Ansible 可能覆蓋或保留錯誤路由 | 下一步收 owner-provided live conf 與 rendered diff,不主動 SSH | | P1 | 高價值配置變更 Gate | 已有 C0-C3 清冊與 Hard Rule,但原本缺少可重跑 path 分類 | reviewer 只能靠人工記憶判斷 Nginx、workflow、secret、K8s、DNS、AI provider 是否需 owner gate | 已新增 `scripts/security/high-value-config-change-gate.py`;本階段只分類,不接 CI blocking | -| P1 | DNS / TLS / certbot | 多產品共用 188 / 110 public gateway,憑證路徑與 renewal 仍分散在 runbook / template | 憑證過期、錯誤 cert path、ACME challenge 被覆蓋會造成公開服務中斷 | 納入 C0,需建立 domain / cert / renewal 清冊 | +| P0 | DNS / TLS / certbot | 已有 domain / certificate path 清冊、owner confirmation request 與 owner response acceptance 只讀帳本,但仍缺 owner-provided coverage metadata、expiry metadata、renewal owner、ACME route owner、maintenance window 與 rollback owner | 憑證過期、錯誤 cert path、ACME challenge 被覆蓋會造成公開服務中斷 | 維持 C0;下一步只收脫敏 metadata ref,不做 DNS query、TLS probe、certbot renew 或 reload | | P1 | workflow / runner / deploy key / secret name | 已有 Gitea / GitHub readiness 盤點,但尚未把配置變更和 IwoooS 高價值配置共用 gate 合併 | workflow 或 runner 改錯會直接影響部署與 secret 注入 | 納入 C0,維持只讀 owner response,不收 secret value | | P1 | Docker Compose / systemd live config | 110 / 188 多服務由 compose、systemd 與 recovery scripts 管理 | restart policy、port、volume、env 改動會影響 Harbor、Sentry、Langfuse、Gitea、agent-bounty-protocol | 已有 repo-only inventory 與 owner request draft;下一步只收脫敏 owner response / live hash,不主動 SSH | | P1 | AI provider / Ollama proxy | 110 Nginx proxy、GCP-A/B、111 fallback、API provider route 多處配置 | provider route drift 會造成成本、可用性、資料外送與模型品質風險 | 納入 C1,任何切換仍需 dry-run / benchmark / owner gate | @@ -137,7 +143,7 @@ Nginx 是目前必須最先資安控管的配置,原因是它同時控制公 | 優先 | 配置 | 代表 repo 路徑 | live / owner 來源 | 必要控管 | |------|------|----------------|-------------------|----------| | P0 | Nginx public gateway | `infra/ansible/roles/nginx/templates/*.j2`、`infra/ansible/playbooks/nginx-sync.yml`、`ops/nginx/*` | 188 / 110 live Nginx | source-of-truth、drift detector、owner gate、`nginx -t`、route smoke、rollback | -| P0 | DNS / TLS / certbot | Nginx templates、`docs/runbooks/REGISTRY-CERTBOT-188.md`、TLS alert rules | DNS provider、Let's Encrypt、188 / 110 | domain inventory、cert path、renewal check、ACME path smoke | +| P0 | DNS / TLS / certbot | Nginx templates、`docs/runbooks/REGISTRY-CERTBOT-188.md`、TLS alert rules、`docs/security/DOMAIN-TLS-CERTBOT-OWNER-CONFIRMATION-REQUEST.md`、`docs/security/DOMAIN-TLS-CERTBOT-OWNER-RESPONSE-ACCEPTANCE.md` | DNS provider、Let's Encrypt、188 / 110 | domain inventory、cert path、owner coverage metadata、renewal owner、ACME path owner、rollback、validation plan;不得 live probe 或 renew | | P0 | K8s production manifests | `k8s/awoooi-prod/*`、`k8s/argocd/awoooi-prod-app.yaml` | ArgoCD / K3s | GitOps diff、ArgoCD health / sync readback、rollback revision、no manual kubectl unless approved | | P0 | K8s Secret metadata | `k8s/awoooi-prod/03-secrets.example.yaml`、secret templates、workflow injection | Gitea Secrets / K8s Secret names | secret name parity only、no value collection、rotation owner | | P0 | Gitea workflows | `.gitea/workflows/*.yaml` | Gitea Actions | self-hosted runner, secret reference guard, deployment verification, no write action without owner | @@ -172,6 +178,7 @@ Nginx 是目前必須最先資安控管的配置,原因是它同時控制公 6. Grafana / Harbor / MinIO / ArgoCD / Gitea / Telegram / AI provider 等管理面密碼只能由 owner secret store 注入。 7. agent-bounty-protocol、VibeWork 與其他產品的 route / admin / webhook / payout / deploy config 必須放入 IwoooS 控管,但不能混用 AWOOOI runtime approval。 8. Backup / restore / offsite / escrow / retention 清冊可見只代表需被控管;不得把 runbook 命令、snapshot、AwoooP approval 或 IwoooS UI 當作 backup run、restore drill、rclone sync、remote delete、restic prune、escrow marker write 或 Velero restore 授權。 +9. DNS / TLS / certbot owner response 只能收脫敏 metadata ref、coverage basis、expiry metadata、renewal owner、ACME route owner、maintenance window、rollback owner 與 validation plan;不得因 owner 回覆而自動做 DNS query、live TLS probe、certbot renew、Nginx reload、route smoke、DNS record 變更、certificate path 變更或 ACME route 變更。 ## 5. 需要調整的既有規範 @@ -195,6 +202,7 @@ Nginx 是目前必須最先資安控管的配置,原因是它同時控制公 | repo-only Nginx drift detector | `100%` | 已新增 `scripts/security/nginx-config-drift-detector.py` 與 repo source-of-truth snapshot | | public gateway preflight 清冊 | `100%` | 已新增 `public_gateway_preflight_inventory_v1`,固定 12 個 reload / route change 前置 Gate;成熟度 `78% -> 84%` | | 高價值配置變更分類 Gate | `100%` | 已新增 `scripts/security/high-value-config-change-gate.py`,可用 git diff 或手動檔案分類 C0/C1/C2/C3 並列出 owner / rollback / evidence / 驗證欄位 | +| DNS / TLS / certbot owner response acceptance | `100%` | 已新增 `domain_tls_certbot_owner_response_acceptance_v1`,4 個 C0 candidate、13 個 owner 必填欄位、13 個 reviewer checks、7 條 outcome lanes、20 類 blocked action;成熟度 `74% -> 78%` | | owner response evidence JSON 欄位檢查 | `70%` | Gate 可檢查必要欄位與 false flags;尚未接正式收件 API 或 AwoooP queue | | Gate → owner response packet 草案 | `100%` | 已新增 `scripts/security/high-value-config-owner-packet.py`,可將 impacted category 轉成 canonical owner response packet 草案 | | canonical owner 欄位對齊 | `100%` | 高價值配置 Gate 已對齊 S4.9 `owner_role_or_team`,並保留 `owner_role_team` 等 alias 支援 | @@ -221,7 +229,7 @@ Nginx 是目前必須最先資安控管的配置,原因是它同時控制公 1. P0:將 owner response packet 草案接入 AwoooP 只讀狀態,顯示 request / received / accepted 仍為 0。 2. P0:由 owner 提供脫敏 live Nginx conf 匯出檔,重跑 compare mode;不自動覆寫、不 reload。 -3. P0:補 DNS / TLS / certbot domain inventory,先只讀,不 renew、不 reload。 +3. P0:向 owner 收 DNS / TLS / certbot 脫敏 coverage metadata ref、expiry metadata ref、renewal owner、ACME route owner、maintenance window、rollback owner 與 validation plan;不做 DNS query、TLS probe、certbot renew 或 reload。 4. P0:把 workflow / runner / secret name owner response 與高價值配置 C0 gate 串成同一個 IwoooS 狀態。 5. P0:把 agent-bounty-protocol compose / MCP / A2A / treasury 高價值配置欄位接入同一個 owner packet queue;不啟用 runtime。 6. P1:向 owner 收 110 / 188 Docker Compose 與 systemd 脫敏 live hash、restart window、rollback owner 與 post-check 指標;不主動 SSH、不重啟、不跑 repair-bot。 diff --git a/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md b/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md index 1c232fc3..2787b841 100644 --- a/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md +++ b/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md @@ -3,7 +3,7 @@ | 項目 | 內容 | |------|------| | 日期 | 2026-06-15 | -| 狀態 | IwoooS 64% 只讀治理推進中;P2-145 owner response acceptance gate 已完成正式驗證;P0 配置控管優先序已完成正式驗證;S4.9 owner response gate 仍是第一優先 | +| 狀態 | IwoooS 64% 只讀治理推進中;P2-145 owner response acceptance gate 已完成正式驗證;P0 DNS / TLS / certbot owner response acceptance 只讀帳本已本地完成;S4.9 owner response gate 仍是第一優先 | | 本階段完成 | 資安供應鏈 contract manifest + Source Control Approval Board + Draft Reconcile Plan + Ref Detail Diff + Ref Truth Classification + Source Control Ref Truth Owner Response 收件包 + GitHub Primary Readiness Gate + GitHub Primary Rollback ADR + GitHub Target Owner Decision Response 收件包 + Gitea 認證清冊匯出請求 + Gitea 認證清冊匯入驗收契約 + Gitea 清冊覆蓋 Owner Attestation + Gitea Owner Attestation Approval Lane 對齊 + Gitea Owner Attestation Response 收件包 + Workflow / Secret Name Inventory + Workflow / Secret Name Local Evidence + Workflow / Secret Name Redacted Export Request + Workflow / Secret Name Owner Response 收件包 + Source Control Owner Response Validation Rollup + Kali 112 live integration status + Security Finding contract + Kali scan scope approval package + Security Approval Queue + S3 人工批准 Gate + S3 人工決策紀錄 + S3 人工審查封包 + S3 人工決策狀態轉移 + S3 後續 runtime gate 準備契約 + 鏡像 readiness index + 鏡像接收計畫 + 鏡像事件信封 + 鏡像路由矩陣 + 鏡像驗收契約 + 鏡像隔離契約 + 鏡像 dry-run 報告契約 + 鏡像狀態彙整契約 + IwoooS 前端態勢入口 + IwoooS posture projection contract + IwoooS 既有前端資安頁面整合 + IwoooS 覆蓋與邊界矩陣 + IwoooS 只讀資安處理旅程 + IwoooS owner evidence readiness board + IwoooS host coverage view + IwoooS host action gate matrix + IwoooS host evidence readiness board + IwoooS host evidence collection order + IwoooS host evidence intake preflight + IwoooS host evidence review outcome lanes + IwoooS host evidence review handoff packets + IwoooS host evidence reviewer checklist + IwoooS host evidence reviewer outcome lanes + IwoooS host owner decision candidate packets + IwoooS host owner decision review checklist + IwoooS host owner decision review outcome lanes + IwoooS host owner decision record draft packets + IwoooS host owner decision record draft review checklist + IwoooS host owner decision record draft review outcome lanes + IwoooS host owner decision record write-up packets + IwoooS host owner decision record write-up review checklist + IwoooS host owner decision record write-up review outcome lanes + IwoooS host owner decision record formal candidate packets + IwoooS host owner decision record formal candidate review checklist + IwoooS host owner decision record formal candidate review outcome lanes + IwoooS host owner decision record formal record queue packets + IwoooS host owner decision record formal record queue review checklist + IwoooS host owner decision record formal record queue review outcome lanes + IwoooS host owner decision record human handoff readiness packets + IwoooS host owner decision record human handoff readiness review checklist + IwoooS host owner decision record human handoff readiness review outcome lanes + IwoooS host owner decision record human record owner review candidate packets + IwoooS host owner decision record human record owner review candidate checklist + IwoooS host owner decision record human record owner review candidate outcome lanes + IwoooS host owner decision record human record owner review preparation packets + IwoooS host owner decision record human record owner review preparation checklist + IwoooS progress acceleration lanes + IwoooS owner response next-action focus + IwoooS S4.9 owner response preflight + IwoooS S4.9 owner response request templates + IwoooS progress hold movement gates + IwoooS AwoooP read-only landing readiness + IwoooS AwoooP cross-session handoff packets + AwoooP 首頁 IwoooS 資安鏡像候選 + AwoooP 工作鏈路 IwoooS 資安鏡像候選 + AwoooP 審批佇列 IwoooS owner response 只讀焦點 | | 本階段追加 | AwoooP 合約儀表板 IwoooS 資安契約只讀候選 + AwoooP 租戶管理 IwoooS 資安租戶範圍只讀候選 + AwoooP 執行監控 IwoooS 執行狀態只讀候選 + 既有安全 / 合規頁面 IwoooS 只讀反向橋接 + 告警 / 錯誤 / 授權 / 治理頁面 IwoooS 只讀反向橋接 + 稽核 / 工程審查頁面 IwoooS 深色只讀反向橋接 + IwoooS 前端資安頁面連接狀態板 + IwoooS GitHub 主要來源就緒度只讀狀態板 + AwoooP 工作鏈路 GitHub 主要來源就緒度只讀工作項 + AwoooP 合約儀表板 GitHub 主要來源就緒度合約只讀候選 + AwoooP 審批佇列 GitHub 主要來源就緒度審批邊界 + AwoooP 首頁 GitHub 主要來源就緒度只讀摘要 + AwoooP 租戶管理 GitHub 主要來源就緒度租戶範圍 + AwoooP 執行監控 GitHub 主要來源就緒度執行邊界 + IwoooS / AwoooP 資安可視區塊繁體中文呈現防護檢查 + AwoooP 執行詳情 / 審批詳情繁體中文呈現防護檢查 + AwoooP 首頁負責人回覆驗收總覽 + AwoooP 工作鏈路負責人回覆驗收只讀工作項 + AwoooP 合約儀表板負責人回覆驗收契約只讀候選 + AwoooP 審批佇列負責人回覆驗收只讀審查邊界 + AwoooP 租戶管理負責人回覆驗收租戶範圍 + AwoooP 執行監控負責人回覆驗收執行邊界 + AwoooP 執行詳情負責人回覆驗收詳情邊界 + AwoooP 審批決策負責人回覆驗收審批邊界 + IwoooS AwoooP 資安入口覆蓋狀態板 + IwoooS 階段式資安收斂節奏圖 + IwoooS 下一步人工收件作戰板 + IwoooS 人工回覆安全驗收閘道 + IwoooS 人工回覆審查結果分流 + IwoooS 人工決策準備佇列 + IwoooS 人工決策紀錄草稿防誤用 + IwoooS 人工決策正式紀錄負責人指派確認準備包 + IwoooS 人工決策正式紀錄負責人指派確認清單 + IwoooS 人工決策正式紀錄負責人指派確認結果分流 + IwoooS 人工決策正式紀錄負責人指派決策準備包 + IwoooS 人工決策正式紀錄負責人指派決策檢查清單 + IwoooS S4.9 負責人回覆封套欄位 + IwoooS S4.9 負責人回覆封套送件前檢查 + IwoooS S4.9 負責人回覆封套送件前結果分流 + IwoooS S4.9 負責人回覆送件請求草稿 + IwoooS S4.9 負責人回覆送件鏈路摘要 + IwoooS 低摩擦分階段收斂主控 + IwoooS 低摩擦下一步行動邊界 + IwoooS 64% 進度移動訊號驗收條 + IwoooS 第一個進度解鎖路徑 + IwoooS 第一解鎖證據包 + IwoooS 第一解鎖證據包預檢分流 + IwoooS 第一解鎖證據包補件路徑 + IwoooS 第一解鎖證據包補件送審前檢查 + IwoooS 第一解鎖證據包補件送審結果分流 + IwoooS 第一解鎖證據包 reviewer 指派準備包 + IwoooS 第一解鎖證據包 reviewer 指派前檢查 + IwoooS 第一解鎖證據包 reviewer 指派前檢查結果分流 + IwoooS 正式只讀 landing 與 Kali 112 只讀證據進度重估 | | 本階段追加補充 | IwoooS 目前具體工作地圖 + IwoooS 目前具體交付清單 + IwoooS 目前阻塞與解除條件 + IwoooS 三軸進度與全產品套用範圍 + IwoooS 全產品分階段套用台帳 + IwoooS 全產品 rollout 波次驗收門檻 + IwoooS 全產品 rollout 驗收結果分流 + IwoooS 全產品證據接線地圖 + IwoooS 全產品證據接線預檢 + IwoooS 全產品證據接線預檢結果分流 + IwoooS 全產品預檢補件回收台帳 + IwoooS 全產品補件重試門檻 + IwoooS 全產品重試結果分流 + IwoooS 全產品人工審查候選準備 + IwoooS 全產品人工審查候選預檢 + IwoooS 全產品人工審查候選預檢結果分流 + IwoooS 全產品人工審查候選預檢補件回收台帳 + IwoooS 全產品人工審查候選預檢補件重試門檻 + IwoooS 全產品只讀套用快照 + P2-145 owner response acceptance gate 正式驗證完成 | @@ -13,6 +13,12 @@ | 原則 | 低摩擦分階段;文件、schema、read-only evidence 優先;不做 runtime enforcement、不切 primary | | P0 主控板 | `docs/workplans/2026-06-04-iwooos-security-governance-p0.md` | +## 0.00 2026-06-14 DNS / TLS / certbot owner response acceptance + +本輪把 DNS / TLS / certbot 從 owner confirmation request 草稿推進到 owner response acceptance 只讀帳本:`domain_tls_certbot_owner_response_acceptance_v1` 固定 `candidates=4`、`c0=4`、`owner_fields=13`、`reviewer_checks=13`、`outcome_lanes=7`、`blocked_actions=20`,並讓 `dns_tls_certbot` 只讀治理成熟度 `74% -> 78%`。這是 metadata-only 收件驗收,不是 request sent、owner response received / accepted、certificate coverage confirmed、DNS query、live TLS probe、certbot renew、Nginx reload、route smoke、host write、production write 或 runtime gate。 + +同步邊界:IwoooS headline 維持 `64%`,active runtime gate 維持 `0`;owner response / live evidence / runtime gate / action buttons 全部仍為 `0 / false`。本段只更新文件、snapshot、guard 與覆蓋矩陣,不改前端 bundle、不部署、不碰 DNS provider、TLS private key、certbot account、Nginx 或主機。 + ## 0.0 2026-06-04 IwoooS P0 狀態邊界 本輪工作只推進 IwoooS 規範、總帳、owner response gate 與跨 Session 同步邊界,不代表 runtime、Kali、GitHub primary 或 AwoooP execution 已授權。 diff --git a/docs/security/domain-tls-certbot-owner-response-acceptance.snapshot.json b/docs/security/domain-tls-certbot-owner-response-acceptance.snapshot.json new file mode 100644 index 00000000..c2be2db5 --- /dev/null +++ b/docs/security/domain-tls-certbot-owner-response-acceptance.snapshot.json @@ -0,0 +1,803 @@ +{ + "acceptance_candidates": [ + { + "acceptance_candidate_id": "domain_tls_certbot_owner_response_acceptance:gitea.wooo.work", + "acceptance_fields": [ + "acceptance_candidate_id", + "request_id", + "domain", + "control_tier", + "hosts", + "certificate_path_domains", + "certificate_paths", + "owner_response_ref", + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "certificate_coverage_basis_ref", + "certificate_expiry_metadata_ref", + "renewal_owner", + "acme_challenge_route_owner", + "maintenance_window", + "rollback_owner", + "validation_plan", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "acme_challenge_route_owner": "pending_owner_response", + "acme_route_owner_accepted": false, + "action_buttons_allowed": false, + "affected_scope": "pending_owner_response", + "blocked_actions": [ + "perform_dns_query", + "perform_live_tls_probe", + "run_certbot_renew", + "run_nginx_reload", + "run_route_smoke", + "read_tls_private_key", + "store_raw_certificate_payload", + "store_dns_provider_credential", + "store_certbot_account_key", + "collect_secret_value", + "accept_unredacted_certbot_log", + "accept_shell_history_or_env_dump", + "mark_owner_response_accepted_without_reviewer_record", + "mark_certificate_coverage_confirmed_without_ref", + "modify_dns_record", + "modify_tls_certificate_path", + "modify_acme_challenge_route", + "write_production_host", + "open_runtime_gate", + "add_action_button" + ], + "certbot_renew_authorized": false, + "certbot_renew_executed": false, + "certificate_coverage_basis_ref": null, + "certificate_coverage_confirmed": false, + "certificate_expiry_metadata_accepted": false, + "certificate_expiry_metadata_ref": null, + "certificate_path_domains": [ + "sentry.wooo.work" + ], + "certificate_paths": [ + "/etc/letsencrypt/live/sentry.wooo.work/fullchain.pem" + ], + "control_tier": "C0", + "decision": "pending_owner_response", + "decision_reason": "pending_owner_response", + "dns_query_authorized": false, + "dns_query_executed": false, + "domain": "gitea.wooo.work", + "followup_owner": "pending_owner_response", + "host_write_authorized": false, + "hosts": [ + "192.168.0.188" + ], + "live_tls_probe_authorized": false, + "live_tls_probe_executed": false, + "maintenance_window": "pending_owner_response", + "maintenance_window_accepted": false, + "nginx_reload_authorized": false, + "nginx_reload_executed": false, + "not_approval": true, + "outcome_lanes": [ + "waiting_owner_response", + "quarantine_raw_certificate_or_secret", + "reject_execution_request", + "request_supplement", + "ready_for_certificate_coverage_review", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "owner_response_accepted": false, + "owner_response_quarantined": false, + "owner_response_received": false, + "owner_response_ref": null, + "owner_response_rejected": false, + "owner_role_or_team": "pending_owner_response", + "production_write_authorized": false, + "recipient_confirmed": false, + "redacted_evidence_refs": [], + "renewal_owner": "pending_owner_response", + "renewal_owner_accepted": false, + "request_id": "domain_tls_certbot_owner_confirmation:gitea.wooo.work", + "request_sent": false, + "required_owner_response_fields": [ + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "certificate_coverage_basis_ref", + "certificate_expiry_metadata_ref", + "renewal_owner", + "acme_challenge_route_owner", + "maintenance_window", + "rollback_owner", + "validation_plan", + "followup_owner" + ], + "reviewer_checks": [ + "owner_identity_present", + "decision_and_reason_present", + "redacted_refs_only", + "raw_certificate_absent", + "secret_value_absent", + "coverage_basis_ref_present", + "expiry_metadata_ref_not_probe", + "renewal_owner_separate_from_action", + "acme_route_owner_present", + "maintenance_window_present", + "rollback_owner_present", + "validation_plan_present", + "counts_transition_safe" + ], + "reviewer_outcome": "waiting_owner_response", + "rollback_owner": "pending_owner_response", + "rollback_owner_accepted": false, + "route_smoke_authorized": false, + "route_smoke_executed": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "status": "waiting_owner_response", + "supplement_requested": false, + "validation_plan": "pending_owner_response" + }, + { + "acceptance_candidate_id": "domain_tls_certbot_owner_response_acceptance:langfuse.wooo.work", + "acceptance_fields": [ + "acceptance_candidate_id", + "request_id", + "domain", + "control_tier", + "hosts", + "certificate_path_domains", + "certificate_paths", + "owner_response_ref", + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "certificate_coverage_basis_ref", + "certificate_expiry_metadata_ref", + "renewal_owner", + "acme_challenge_route_owner", + "maintenance_window", + "rollback_owner", + "validation_plan", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "acme_challenge_route_owner": "pending_owner_response", + "acme_route_owner_accepted": false, + "action_buttons_allowed": false, + "affected_scope": "pending_owner_response", + "blocked_actions": [ + "perform_dns_query", + "perform_live_tls_probe", + "run_certbot_renew", + "run_nginx_reload", + "run_route_smoke", + "read_tls_private_key", + "store_raw_certificate_payload", + "store_dns_provider_credential", + "store_certbot_account_key", + "collect_secret_value", + "accept_unredacted_certbot_log", + "accept_shell_history_or_env_dump", + "mark_owner_response_accepted_without_reviewer_record", + "mark_certificate_coverage_confirmed_without_ref", + "modify_dns_record", + "modify_tls_certificate_path", + "modify_acme_challenge_route", + "write_production_host", + "open_runtime_gate", + "add_action_button" + ], + "certbot_renew_authorized": false, + "certbot_renew_executed": false, + "certificate_coverage_basis_ref": null, + "certificate_coverage_confirmed": false, + "certificate_expiry_metadata_accepted": false, + "certificate_expiry_metadata_ref": null, + "certificate_path_domains": [ + "sentry.wooo.work" + ], + "certificate_paths": [ + "/etc/letsencrypt/live/sentry.wooo.work/fullchain.pem" + ], + "control_tier": "C0", + "decision": "pending_owner_response", + "decision_reason": "pending_owner_response", + "dns_query_authorized": false, + "dns_query_executed": false, + "domain": "langfuse.wooo.work", + "followup_owner": "pending_owner_response", + "host_write_authorized": false, + "hosts": [ + "192.168.0.188" + ], + "live_tls_probe_authorized": false, + "live_tls_probe_executed": false, + "maintenance_window": "pending_owner_response", + "maintenance_window_accepted": false, + "nginx_reload_authorized": false, + "nginx_reload_executed": false, + "not_approval": true, + "outcome_lanes": [ + "waiting_owner_response", + "quarantine_raw_certificate_or_secret", + "reject_execution_request", + "request_supplement", + "ready_for_certificate_coverage_review", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "owner_response_accepted": false, + "owner_response_quarantined": false, + "owner_response_received": false, + "owner_response_ref": null, + "owner_response_rejected": false, + "owner_role_or_team": "pending_owner_response", + "production_write_authorized": false, + "recipient_confirmed": false, + "redacted_evidence_refs": [], + "renewal_owner": "pending_owner_response", + "renewal_owner_accepted": false, + "request_id": "domain_tls_certbot_owner_confirmation:langfuse.wooo.work", + "request_sent": false, + "required_owner_response_fields": [ + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "certificate_coverage_basis_ref", + "certificate_expiry_metadata_ref", + "renewal_owner", + "acme_challenge_route_owner", + "maintenance_window", + "rollback_owner", + "validation_plan", + "followup_owner" + ], + "reviewer_checks": [ + "owner_identity_present", + "decision_and_reason_present", + "redacted_refs_only", + "raw_certificate_absent", + "secret_value_absent", + "coverage_basis_ref_present", + "expiry_metadata_ref_not_probe", + "renewal_owner_separate_from_action", + "acme_route_owner_present", + "maintenance_window_present", + "rollback_owner_present", + "validation_plan_present", + "counts_transition_safe" + ], + "reviewer_outcome": "waiting_owner_response", + "rollback_owner": "pending_owner_response", + "rollback_owner_accepted": false, + "route_smoke_authorized": false, + "route_smoke_executed": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "status": "waiting_owner_response", + "supplement_requested": false, + "validation_plan": "pending_owner_response" + }, + { + "acceptance_candidate_id": "domain_tls_certbot_owner_response_acceptance:signoz.wooo.work", + "acceptance_fields": [ + "acceptance_candidate_id", + "request_id", + "domain", + "control_tier", + "hosts", + "certificate_path_domains", + "certificate_paths", + "owner_response_ref", + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "certificate_coverage_basis_ref", + "certificate_expiry_metadata_ref", + "renewal_owner", + "acme_challenge_route_owner", + "maintenance_window", + "rollback_owner", + "validation_plan", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "acme_challenge_route_owner": "pending_owner_response", + "acme_route_owner_accepted": false, + "action_buttons_allowed": false, + "affected_scope": "pending_owner_response", + "blocked_actions": [ + "perform_dns_query", + "perform_live_tls_probe", + "run_certbot_renew", + "run_nginx_reload", + "run_route_smoke", + "read_tls_private_key", + "store_raw_certificate_payload", + "store_dns_provider_credential", + "store_certbot_account_key", + "collect_secret_value", + "accept_unredacted_certbot_log", + "accept_shell_history_or_env_dump", + "mark_owner_response_accepted_without_reviewer_record", + "mark_certificate_coverage_confirmed_without_ref", + "modify_dns_record", + "modify_tls_certificate_path", + "modify_acme_challenge_route", + "write_production_host", + "open_runtime_gate", + "add_action_button" + ], + "certbot_renew_authorized": false, + "certbot_renew_executed": false, + "certificate_coverage_basis_ref": null, + "certificate_coverage_confirmed": false, + "certificate_expiry_metadata_accepted": false, + "certificate_expiry_metadata_ref": null, + "certificate_path_domains": [ + "sentry.wooo.work" + ], + "certificate_paths": [ + "/etc/letsencrypt/live/sentry.wooo.work/fullchain.pem" + ], + "control_tier": "C0", + "decision": "pending_owner_response", + "decision_reason": "pending_owner_response", + "dns_query_authorized": false, + "dns_query_executed": false, + "domain": "signoz.wooo.work", + "followup_owner": "pending_owner_response", + "host_write_authorized": false, + "hosts": [ + "192.168.0.188" + ], + "live_tls_probe_authorized": false, + "live_tls_probe_executed": false, + "maintenance_window": "pending_owner_response", + "maintenance_window_accepted": false, + "nginx_reload_authorized": false, + "nginx_reload_executed": false, + "not_approval": true, + "outcome_lanes": [ + "waiting_owner_response", + "quarantine_raw_certificate_or_secret", + "reject_execution_request", + "request_supplement", + "ready_for_certificate_coverage_review", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "owner_response_accepted": false, + "owner_response_quarantined": false, + "owner_response_received": false, + "owner_response_ref": null, + "owner_response_rejected": false, + "owner_role_or_team": "pending_owner_response", + "production_write_authorized": false, + "recipient_confirmed": false, + "redacted_evidence_refs": [], + "renewal_owner": "pending_owner_response", + "renewal_owner_accepted": false, + "request_id": "domain_tls_certbot_owner_confirmation:signoz.wooo.work", + "request_sent": false, + "required_owner_response_fields": [ + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "certificate_coverage_basis_ref", + "certificate_expiry_metadata_ref", + "renewal_owner", + "acme_challenge_route_owner", + "maintenance_window", + "rollback_owner", + "validation_plan", + "followup_owner" + ], + "reviewer_checks": [ + "owner_identity_present", + "decision_and_reason_present", + "redacted_refs_only", + "raw_certificate_absent", + "secret_value_absent", + "coverage_basis_ref_present", + "expiry_metadata_ref_not_probe", + "renewal_owner_separate_from_action", + "acme_route_owner_present", + "maintenance_window_present", + "rollback_owner_present", + "validation_plan_present", + "counts_transition_safe" + ], + "reviewer_outcome": "waiting_owner_response", + "rollback_owner": "pending_owner_response", + "rollback_owner_accepted": false, + "route_smoke_authorized": false, + "route_smoke_executed": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "status": "waiting_owner_response", + "supplement_requested": false, + "validation_plan": "pending_owner_response" + }, + { + "acceptance_candidate_id": "domain_tls_certbot_owner_response_acceptance:tsenyang.com", + "acceptance_fields": [ + "acceptance_candidate_id", + "request_id", + "domain", + "control_tier", + "hosts", + "certificate_path_domains", + "certificate_paths", + "owner_response_ref", + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "certificate_coverage_basis_ref", + "certificate_expiry_metadata_ref", + "renewal_owner", + "acme_challenge_route_owner", + "maintenance_window", + "rollback_owner", + "validation_plan", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "acme_challenge_route_owner": "pending_owner_response", + "acme_route_owner_accepted": false, + "action_buttons_allowed": false, + "affected_scope": "pending_owner_response", + "blocked_actions": [ + "perform_dns_query", + "perform_live_tls_probe", + "run_certbot_renew", + "run_nginx_reload", + "run_route_smoke", + "read_tls_private_key", + "store_raw_certificate_payload", + "store_dns_provider_credential", + "store_certbot_account_key", + "collect_secret_value", + "accept_unredacted_certbot_log", + "accept_shell_history_or_env_dump", + "mark_owner_response_accepted_without_reviewer_record", + "mark_certificate_coverage_confirmed_without_ref", + "modify_dns_record", + "modify_tls_certificate_path", + "modify_acme_challenge_route", + "write_production_host", + "open_runtime_gate", + "add_action_button" + ], + "certbot_renew_authorized": false, + "certbot_renew_executed": false, + "certificate_coverage_basis_ref": null, + "certificate_coverage_confirmed": false, + "certificate_expiry_metadata_accepted": false, + "certificate_expiry_metadata_ref": null, + "certificate_path_domains": [ + "www.tsenyang.com" + ], + "certificate_paths": [ + "/etc/letsencrypt/live/www.tsenyang.com/fullchain.pem" + ], + "control_tier": "C0", + "decision": "pending_owner_response", + "decision_reason": "pending_owner_response", + "dns_query_authorized": false, + "dns_query_executed": false, + "domain": "tsenyang.com", + "followup_owner": "pending_owner_response", + "host_write_authorized": false, + "hosts": [ + "192.168.0.188" + ], + "live_tls_probe_authorized": false, + "live_tls_probe_executed": false, + "maintenance_window": "pending_owner_response", + "maintenance_window_accepted": false, + "nginx_reload_authorized": false, + "nginx_reload_executed": false, + "not_approval": true, + "outcome_lanes": [ + "waiting_owner_response", + "quarantine_raw_certificate_or_secret", + "reject_execution_request", + "request_supplement", + "ready_for_certificate_coverage_review", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "owner_response_accepted": false, + "owner_response_quarantined": false, + "owner_response_received": false, + "owner_response_ref": null, + "owner_response_rejected": false, + "owner_role_or_team": "pending_owner_response", + "production_write_authorized": false, + "recipient_confirmed": false, + "redacted_evidence_refs": [], + "renewal_owner": "pending_owner_response", + "renewal_owner_accepted": false, + "request_id": "domain_tls_certbot_owner_confirmation:tsenyang.com", + "request_sent": false, + "required_owner_response_fields": [ + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "certificate_coverage_basis_ref", + "certificate_expiry_metadata_ref", + "renewal_owner", + "acme_challenge_route_owner", + "maintenance_window", + "rollback_owner", + "validation_plan", + "followup_owner" + ], + "reviewer_checks": [ + "owner_identity_present", + "decision_and_reason_present", + "redacted_refs_only", + "raw_certificate_absent", + "secret_value_absent", + "coverage_basis_ref_present", + "expiry_metadata_ref_not_probe", + "renewal_owner_separate_from_action", + "acme_route_owner_present", + "maintenance_window_present", + "rollback_owner_present", + "validation_plan_present", + "counts_transition_safe" + ], + "reviewer_outcome": "waiting_owner_response", + "rollback_owner": "pending_owner_response", + "rollback_owner_accepted": false, + "route_smoke_authorized": false, + "route_smoke_executed": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "status": "waiting_owner_response", + "supplement_requested": false, + "validation_plan": "pending_owner_response" + } + ], + "acceptance_fields": [ + "acceptance_candidate_id", + "request_id", + "domain", + "control_tier", + "hosts", + "certificate_path_domains", + "certificate_paths", + "owner_response_ref", + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "certificate_coverage_basis_ref", + "certificate_expiry_metadata_ref", + "renewal_owner", + "acme_challenge_route_owner", + "maintenance_window", + "rollback_owner", + "validation_plan", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "blocked_actions": [ + "perform_dns_query", + "perform_live_tls_probe", + "run_certbot_renew", + "run_nginx_reload", + "run_route_smoke", + "read_tls_private_key", + "store_raw_certificate_payload", + "store_dns_provider_credential", + "store_certbot_account_key", + "collect_secret_value", + "accept_unredacted_certbot_log", + "accept_shell_history_or_env_dump", + "mark_owner_response_accepted_without_reviewer_record", + "mark_certificate_coverage_confirmed_without_ref", + "modify_dns_record", + "modify_tls_certificate_path", + "modify_acme_challenge_route", + "write_production_host", + "open_runtime_gate", + "add_action_button" + ], + "execution_boundaries": { + "action_buttons_allowed": false, + "certbot_renew_authorized": false, + "certbot_renew_executed": false, + "dns_query_authorized": false, + "dns_query_executed": false, + "host_write_authorized": false, + "live_tls_probe_authorized": false, + "live_tls_probe_executed": false, + "nginx_reload_authorized": false, + "nginx_reload_executed": false, + "not_authorization": true, + "owner_response_accepted": false, + "production_write_authorized": false, + "raw_certificate_storage_allowed": false, + "request_dispatch_authorized": false, + "route_smoke_authorized": false, + "route_smoke_executed": false, + "runtime_execution_authorized": false, + "secret_value_collection_allowed": false, + "tls_private_key_read_authorized": false + }, + "generated_at": "2026-06-14T23:05:00+08:00", + "git_commit": "d26f3bef", + "next_steps": [ + "等待 owner response;未收到前不得更新 accepted count。", + "收到回覆後先走 raw cert / private key / credential / execution request 檢查,不合格即隔離、拒收或補件。", + "metadata 合格也只能進 certificate coverage reviewer review;DNS query、TLS probe、certbot renew、Nginx reload 與 route smoke 仍需獨立人工批准。" + ], + "outcome_lanes": [ + { + "lane_id": "waiting_owner_response", + "meaning": "尚未收到 owner response;所有 accepted / runtime count 維持 0。" + }, + { + "lane_id": "quarantine_raw_certificate_or_secret", + "meaning": "收到 raw cert、private key、DNS credential 或 certbot account 內容時,只能隔離。" + }, + { + "lane_id": "reject_execution_request", + "meaning": "夾帶 DNS query、TLS probe、certbot renew、Nginx reload 或 host write 要求時拒收。" + }, + { + "lane_id": "request_supplement", + "meaning": "欄位不足、scope 不清或 evidence ref 不可追溯時要求補件。" + }, + { + "lane_id": "ready_for_certificate_coverage_review", + "meaning": "metadata 合格後,只能進憑證覆蓋關係 reviewer review,不自動 probe。" + }, + { + "lane_id": "owner_review_only_update", + "meaning": "只允許更新只讀 owner review ledger,不得修改 DNS、TLS、certbot 或 Nginx。" + }, + { + "lane_id": "waiting_runtime_gate", + "meaning": "即使 owner response accepted,DNS / TLS / certbot runtime gate 仍等待獨立人工批准。" + } + ], + "required_owner_response_fields": [ + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "certificate_coverage_basis_ref", + "certificate_expiry_metadata_ref", + "renewal_owner", + "acme_challenge_route_owner", + "maintenance_window", + "rollback_owner", + "validation_plan", + "followup_owner" + ], + "reviewer_checks": [ + { + "check_id": "owner_identity_present", + "instruction": "owner role / team 必須可追溯,不能只寫個人暱稱或聊天同意。" + }, + { + "check_id": "decision_and_reason_present", + "instruction": "decision 與 decision reason 必須同時存在,且不得包含機敏值。" + }, + { + "check_id": "redacted_refs_only", + "instruction": "evidence 只能是脫敏 ref、ticket、hash、文件路徑或摘要。" + }, + { + "check_id": "raw_certificate_absent", + "instruction": "不得出現 raw certificate payload、完整 SAN dump、private key 或 ACME account key。" + }, + { + "check_id": "secret_value_absent", + "instruction": "不得出現 DNS credential、registrar credential、token、cookie、authorization header 或 Basic Auth。" + }, + { + "check_id": "coverage_basis_ref_present", + "instruction": "SAN、wildcard 或共用憑證覆蓋依據必須是 metadata ref,不得貼 raw cert。" + }, + { + "check_id": "expiry_metadata_ref_not_probe", + "instruction": "憑證到期資訊只能是 owner-provided metadata ref;不得由本帳本觸發 live probe。" + }, + { + "check_id": "renewal_owner_separate_from_action", + "instruction": "renewal owner 可以被記錄,但 certbot renew 需另開人工批准包。" + }, + { + "check_id": "acme_route_owner_present", + "instruction": "HTTP-01 ACME path 與 route smoke owner 必須清楚,且不得自動 route smoke。" + }, + { + "check_id": "maintenance_window_present", + "instruction": "任何未來 probe、renew、reload 都必須有維護窗口或明確禁止窗口。" + }, + { + "check_id": "rollback_owner_present", + "instruction": "rollback owner 與 rollback ref 必須存在,且不可指向 raw secret。" + }, + { + "check_id": "validation_plan_present", + "instruction": "validation plan 必須列 DNS / TLS / ACME / route post-check 指標,但不授權執行。" + }, + { + "check_id": "counts_transition_safe", + "instruction": "只有 reviewer record 可更新 received / accepted / rejected;不得同時開 runtime gate。" + } + ], + "schema_version": "domain_tls_certbot_owner_response_acceptance_v1", + "source_owner_confirmation_request_schema_version": "domain_tls_certbot_owner_confirmation_request_v1", + "source_owner_confirmation_request_status": "owner_confirmation_request_ready_not_dispatched", + "status": "owner_response_acceptance_ledger_ready_no_runtime_action", + "summary": { + "acceptance_candidate_count": 4, + "acceptance_field_count": 23, + "acme_route_owner_accepted_count": 0, + "action_button_count": 0, + "blocked_action_count": 20, + "c0_acceptance_candidate_count": 4, + "certbot_renew_authorized_count": 0, + "certbot_renew_executed_count": 0, + "certificate_coverage_confirmed_count": 0, + "certificate_expiry_metadata_accepted_count": 0, + "dns_query_authorized_count": 0, + "dns_query_executed_count": 0, + "host_write_authorized_count": 0, + "live_tls_probe_authorized_count": 0, + "live_tls_probe_executed_count": 0, + "maintenance_window_accepted_count": 0, + "nginx_reload_authorized_count": 0, + "nginx_reload_executed_count": 0, + "outcome_lane_count": 7, + "owner_response_accepted_count": 0, + "owner_response_quarantined_count": 0, + "owner_response_received_count": 0, + "owner_response_rejected_count": 0, + "recipient_confirmed_count": 0, + "renewal_owner_accepted_count": 0, + "request_sent_count": 0, + "required_owner_response_field_count": 13, + "reviewer_check_count": 13, + "rollback_owner_accepted_count": 0, + "route_smoke_authorized_count": 0, + "route_smoke_executed_count": 0, + "runtime_gate_count": 0, + "source_owner_confirmation_request_count": 4, + "supplement_requested_count": 0 + } +} diff --git a/docs/security/high-value-config-control-coverage.snapshot.json b/docs/security/high-value-config-control-coverage.snapshot.json index 1f50e3fa..3d6ca170 100644 --- a/docs/security/high-value-config-control-coverage.snapshot.json +++ b/docs/security/high-value-config-control-coverage.snapshot.json @@ -45,15 +45,19 @@ "action_buttons_allowed": false, "category_id": "dns_tls_certbot", "control_tier": "C0", - "coverage_percent": 74, - "coverage_status": "repo_only_inventory_ready", - "current_gap": "4 個 certificate path 關係需 owner 確認;live DNS / TLS probe 未執行。", + "coverage_percent": 78, + "coverage_status": "owner_response_acceptance_ledger_ready_needs_certificate_owner_evidence", + "current_gap": "已固定 4 份 DNS / TLS / certbot owner response acceptance candidate;仍缺 owner response、certificate coverage metadata ref、expiry metadata ref、renewal owner、ACME route owner、maintenance window、rollback owner 與 validation plan。", "evidence_refs": [ "docs/security/DOMAIN-TLS-CERTBOT-INVENTORY.md", - "docs/security/domain-tls-certbot-inventory.snapshot.json" + "docs/security/domain-tls-certbot-inventory.snapshot.json", + "docs/security/DOMAIN-TLS-CERTBOT-OWNER-CONFIRMATION-REQUEST.md", + "docs/security/domain-tls-certbot-owner-confirmation-request.snapshot.json", + "docs/security/DOMAIN-TLS-CERTBOT-OWNER-RESPONSE-ACCEPTANCE.md", + "docs/security/domain-tls-certbot-owner-response-acceptance.snapshot.json" ], "label": "DNS / TLS / certbot / certificate path", - "next_owner_action": "確認 SAN / 共用憑證關係、renewal owner、ACME smoke 與 rollback owner。", + "next_owner_action": "補 SAN / wildcard / 共用憑證覆蓋依據 ref、到期 metadata ref、renewal owner、ACME route owner、維護窗口、rollback owner 與 validation plan。", "owner_response_accepted": false, "owner_response_received": false, "owner_response_required": true, @@ -580,8 +584,8 @@ "websocket_route_change_authorized": false, "workflow_modification_authorized": false }, - "generated_at": "2026-06-15T01:18:00+08:00", - "git_commit": "1d0de1d4", + "generated_at": "2026-06-14T23:05:00+08:00", + "git_commit": "d26f3bef", "lowest_coverage_categories": [ { "category_id": "docker_compose_systemd_host_config", diff --git a/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md b/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md index 6f41ef59..4c5d255d 100644 --- a/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md +++ b/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md @@ -4797,6 +4797,19 @@ Trigger commit `f5cd37b7` 與 deploy marker `0ba92357` 已把 governance UI 的 **裁決:** 這是 SAN / wildcard / 共用憑證覆蓋關係的 owner confirmation request 草稿,不是 request sent、recipient confirmed、owner response received / accepted、DNS query、live TLS probe、certbot renew、Nginx reload、route smoke、host write、active scan、production write 或 runtime gate;IwoooS headline 仍維持 `64%`,active runtime gate 仍 `0`。 +### 2026-06-14 23:05 (台北) — §3.2 / §5 — 新增 DNS / TLS / certbot Owner Response Acceptance 只讀帳本 — 把憑證 owner 回覆驗收固定成可 guard artifact + +**觸發**:P0-19 已把 4 個 certificate path 需確認 domain 轉成 owner confirmation request,但 DNS / TLS / certbot 屬於 C0 公開入口風險,若沒有 acceptance ledger,未來容易把 SAN / wildcard / 共用憑證覆蓋確認、expiry metadata、renewal owner 或 ACME route owner 誤判成 DNS query、live TLS probe、certbot renew、Nginx reload 或 route smoke 授權。 + +**已推進:** +- 新增 `scripts/security/domain-tls-certbot-owner-response-acceptance.py`,讀取 `docs/security/domain-tls-certbot-owner-confirmation-request.snapshot.json`,產生 4 份 owner response acceptance candidate。 +- 新增 `docs/security/domain-tls-certbot-owner-response-acceptance.snapshot.json`,固定 `acceptance_candidate_count=4`、`c0_acceptance_candidate_count=4`、`required_owner_response_field_count=13`、`reviewer_check_count=13`、`outcome_lane_count=7`、`blocked_action_count=20`。 +- 新增 `docs/security/DOMAIN-TLS-CERTBOT-OWNER-RESPONSE-ACCEPTANCE.md`,說明 owner 必填欄位、reviewer checks、outcome lanes、blocked actions、完成度與 0 / false 邊界。 +- `security-mirror-progress-guard.py` 已鎖住新 snapshot 的 schema、summary、execution false flags、candidate ids、reviewer checks、outcome lanes、blocked actions 與每份候選 false flags。 +- 高價值配置 coverage、IwoooS 配置控管總清單、P0 主控板、供應鏈進度與 MASTER artifact 表已同步 P0-27;`dns_tls_certbot` 只讀治理成熟度從 `74%` 推進到 `78%`,但 runtime gate 仍為 `0`。 + +**裁決:** 這是 owner response acceptance 只讀帳本,不是 request sent、owner response received / accepted、certificate coverage confirmed、DNS query、live TLS probe、certbot renew、Nginx reload、route smoke、DNS record 變更、certificate path 變更、ACME challenge route 變更、host write、active scan、production write 或 runtime gate;IwoooS headline 仍維持 `64%`,active runtime gate 仍 `0`。 + ### 2026-06-14 21:05 (台北) — §3.2 / §5 — 新增 K8s / ArgoCD manifest repo-only 清冊 — 把 production manifests 轉成 owner gate 基線 **觸發**:K8s / ArgoCD / production manifests 會直接影響 deployment、cronjob、RBAC、NetworkPolicy、Secret metadata、Velero restore 與 monitoring rule;高價值配置 coverage 已指出尚未把 ArgoCD health / sync readback 與 rollback revision 收成 owner packet。此階段仍不得 live cluster read、ArgoCD API read、ArgoCD sync、kubectl action、Helm upgrade、secret collection、manual pod restart、scale workload、restore backup 或 production write。 diff --git a/docs/workplans/2026-06-04-iwooos-security-governance-p0.md b/docs/workplans/2026-06-04-iwooos-security-governance-p0.md index 25a0652c..f28cebbf 100644 --- a/docs/workplans/2026-06-04-iwooos-security-governance-p0.md +++ b/docs/workplans/2026-06-04-iwooos-security-governance-p0.md @@ -21,7 +21,7 @@ | 最新 P2-D2 Code Review 候選分類基準 | code `292cfec9`、deploy marker `4cfe5ff7`、CD `2586`、code-review `2587`;Code Review route 可見文案已搬到 `codeReview` i18n namespace,四類候選分類與人工批准流程已正式驗證 | | 最新 P2-D2 AwoooP Runs fallback 文案基準 | code `7f6028c3`、deploy marker `bf016e91`、CD `2590`、code-review `2591`;Runs / Callback / Source Flow fallback 文案已正式驗證 | | 最新 AwoooP Tenants 全域產品資產台帳 D1 基準 | code `fef94df8`、deploy marker `180a6543`、code-review `2967`、CD `2966`;正式 API 顯示產品 / 專案 `16`、網站 / 服務入口 `31`、source-control candidate repo `10`,已納入 `2026fifa.wooo.work`、WOOO Open Design、n8n、Grist、Vault、Ollama、Monitor 與 AWOOOI API / AIOps 服務入口;owner response / runtime gate / action button 仍 `0` | -| 最新 P0 Public Gateway / DNS TLS / K8s 配置控管基準 | P0-15 `5068654d` live conf 匯出請求包、P0-16 `f856df1c` redacted export 收件預檢、P0-17 `762f73a6` rendered diff / nginx gate 草稿、P0-19 `551d8144` DNS / TLS / certbot owner confirmation request 草稿、P0-20 `e8876c45` K8s / ArgoCD manifest repo-only 清冊、P0-21 `e8de19d7` K8s / ArgoCD owner request draft;本輪新增 P0-24 Public Gateway owner response acceptance 只讀帳本與 P0-25 K8s / ArgoCD owner response acceptance 只讀帳本;Public Gateway 四段固定 requests / candidates `3`、C0 `2`、owner response acceptance fields `12`、reviewer checks `12`、outcome lanes `7`,DNS / TLS 固定 owner confirmation requests `4`、C0 `4`,K8s manifest 固定 files `49`、C0 `36`、YAML `45`、kinds `20`,K8s owner request 固定 drafts `4`、C0 `3`,K8s owner response acceptance 固定 candidates `4`、C0 `3`、reviewer checks `12`、outcome lanes `7`;request sent、owner response received / accepted、redacted export received / accepted、raw conf stored、rendered diff ready、`nginx -t`、reload、DNS query、TLS probe、certbot renew、ArgoCD API read、ArgoCD sync、kubectl action、route smoke、runtime gate、action button 全部 `0` | +| 最新 P0 Public Gateway / DNS TLS / K8s 配置控管基準 | P0-15 `5068654d` live conf 匯出請求包、P0-16 `f856df1c` redacted export 收件預檢、P0-17 `762f73a6` rendered diff / nginx gate 草稿、P0-19 `551d8144` DNS / TLS / certbot owner confirmation request 草稿、P0-20 `e8876c45` K8s / ArgoCD manifest repo-only 清冊、P0-21 `e8de19d7` K8s / ArgoCD owner request draft;本輪新增 P0-24 Public Gateway owner response acceptance 只讀帳本、P0-25 K8s / ArgoCD owner response acceptance 只讀帳本與 P0-27 DNS / TLS / certbot owner response acceptance 只讀帳本;Public Gateway 四段固定 requests / candidates `3`、C0 `2`、owner response acceptance fields `12`、reviewer checks `12`、outcome lanes `7`,DNS / TLS 固定 owner confirmation requests `4`、C0 `4`,DNS / TLS owner response acceptance 固定 candidates `4`、C0 `4`、owner fields `13`、reviewer checks `13`、outcome lanes `7`、blocked actions `20`,K8s manifest 固定 files `49`、C0 `36`、YAML `45`、kinds `20`,K8s owner request 固定 drafts `4`、C0 `3`,K8s owner response acceptance 固定 candidates `4`、C0 `3`、reviewer checks `12`、outcome lanes `7`;request sent、owner response received / accepted、redacted export received / accepted、raw conf stored、rendered diff ready、`nginx -t`、reload、DNS query、TLS probe、certbot renew、ArgoCD API read、ArgoCD sync、kubectl action、route smoke、runtime gate、action button 全部 `0` | | 最新 P0 agent-bounty-protocol 配置控管基準 | onboarding handoff 已固定 `product_scope_handoff_only`、owner response / runtime gate 全部 `false`;本輪新增 owner request draft,固定 `drafts=11`、`control=4`、`surface=7`、`write_capable=8`、`treasury=4`、`mcp_a2a=5`、`owner_fields=22`、`forbidden_inputs=25`、`blocked_actions=28`、request sent / received / accepted / repo push / refs sync / deploy / claim / submit / payout / daemon / cron / runtime gate 全部 `0` | | 最新 P1 Docker / systemd / Host Service 配置控管基準 | repo-only inventory 已固定 `surface=9`、`write_capable=3`、`live_evidence_required=8`、成熟度 `42% -> 50%`;本輪新增 owner request draft,固定 `drafts=9`、`owner_fields=12`、`blocked_actions=14`、request sent / received / accepted / live evidence / restart window / rollback owner / host write / runtime gate 全部 `0` | | 最新 P1 SSH / Firewall / Network Access 配置控管基準 | repo-only inventory 已固定 `surface=16`、`write_capable=6`、`live_evidence_required=16`、成熟度 `48% -> 54%`;本輪新增 owner request draft,固定 `drafts=16`、`owner_fields=13`、`blocked_actions=16`、request sent / received / accepted / live access state / firewall / port change / NetworkPolicy / NodePort / WireGuard / host write / runtime gate 全部 `0` | @@ -91,6 +91,7 @@ | P0-24 | Public Gateway owner response acceptance 只讀帳本 | 100% | 已新增 `public-gateway-owner-response-acceptance.py`、snapshot 與文件,把 Public Gateway live conf 匯出請求、redacted export 收件預檢與 rendered diff / `nginx -t` gate 草稿串成 3 份 owner response acceptance candidate;C0 `2`、required owner fields `12`、reviewer checks `12`、outcome lanes `7`、blocked actions `18`;owner response received / accepted、redacted export、rendered diff、`nginx -t`、reload、route smoke、DNS / TLS probe、certbot renew、runtime gate 仍全部為 `0` | `PUBLIC_GATEWAY_OWNER_RESPONSE_ACCEPTANCE_OK candidates=3 c0=2 checks=12 lanes=7 accepted=0 runtime_gate=0`;progress guard 固定 snapshot schema、summary、false flags、candidate ids、reviewer checks、outcome lanes、blocked actions 與每份候選 false flags;純 repo 內文件 / snapshot / guard,不需要 production browser smoke | | P0-18 | P0 主控板同步基線回填 | 100% | 已將本次 worktree、分支、最新 `gitea/main`、Public Gateway P0-15~P0-17 基準與平行 AwoooP Session 同步狀態回填,避免下一個 Session 用舊 2026-06-11 worktree / 舊 commit 判讀 | 只改 P0 總帳與 LOGBOOK;需跑 progress guard、owner response guard、doc secret sanity、diff check 與工作視窗片語掃描;不需要 production browser smoke | | P0-19 | DNS / TLS / certbot owner confirmation request | 100% | 已新增 `domain-tls-certbot-owner-confirmation-request.py`、snapshot 與文件,把 4 個 certificate path 需確認 domain 轉成 owner confirmation request 草稿;全部 `C0`,必填 owner 欄位 `9`,confirmation questions `5`,rejection guards `12`;request sent、recipient confirmed、owner response received / accepted、DNS query、TLS probe、certbot renew、Nginx reload、host write、runtime gate 仍全部為 `0` | `DOMAIN_TLS_CERTBOT_OWNER_CONFIRMATION_REQUEST_OK requests=4 c0=4 fields=9 received=0 runtime_gate=0`;progress guard 固定 snapshot schema、summary、false flags、request ids、confirmation questions、rejection guards 與每份草稿 false flags;純 repo 內文件 / snapshot / guard,不需要 production browser smoke | +| P0-27 | DNS / TLS / certbot owner response acceptance 只讀帳本 | 100% | 已新增 `domain-tls-certbot-owner-response-acceptance.py`、snapshot 與文件,把 4 份 owner confirmation request 轉成 owner response acceptance candidate;全部 `C0`,必填 owner 欄位 `13`,reviewer checks `13`,outcome lanes `7`,blocked actions `20`;owner response received / accepted、certificate coverage confirmed、DNS query、TLS probe、certbot renew、Nginx reload、route smoke、host write、runtime gate 仍全部為 `0` | `DOMAIN_TLS_CERTBOT_OWNER_RESPONSE_ACCEPTANCE_OK candidates=4 c0=4 checks=13 lanes=7 accepted=0 runtime_gate=0`;progress guard 固定 snapshot schema、summary、false flags、candidate ids、reviewer checks、outcome lanes、blocked actions 與每份候選 false flags;純 repo 內文件 / snapshot / guard,不需要 production browser smoke | | P0-20 | K8s / ArgoCD manifest repo-only 清冊 | 100% | 已新增 `k8s-argocd-manifest-inventory.py`、snapshot 與文件,把 `k8s/awoooi-prod`、`k8s/argocd`、`k8s/velero`、`k8s/monitoring` 轉成 repo-only manifest inventory;files `49`、C0 `36`、YAML `45`、unique kinds `20`、blocked actions `13`;owner response、rendered diff、ArgoCD health readback、ArgoCD sync、kubectl action、live cluster read、secret collection、runtime gate 仍全部為 `0` | `K8S_ARGOCD_MANIFEST_INVENTORY_OK files=49 c0=36 yaml=45 kinds=20 runtime_gate=0`;progress guard 固定 snapshot schema、summary、group ids、kind counts、blocked actions 與每列 false flags;純 repo 內文件 / snapshot / guard,不需要 production browser smoke | | P0-21 | K8s / ArgoCD owner request draft | 100% | 已新增 `k8s-argocd-owner-request-draft.py`、snapshot 與文件,把 P0-20 四個 scan group 轉成 4 份 request draft;C0 `3`、C1 `1`、request fields `20`、owner fields `11`、evidence gaps `8`、blocked actions `13`;request sent、recipient confirmed、owner response received / accepted、rendered manifest diff、ArgoCD health readback、ArgoCD sync、kubectl action、live cluster read、runtime gate 仍全部為 `0` | `K8S_ARGOCD_OWNER_REQUEST_DRAFT_OK drafts=4 c0=3 fields=11 sent=0 runtime_gate=0`;progress guard 固定 snapshot schema、summary、false flags、request ids、blocked actions 與每份草稿 false flags;純 repo 內文件 / snapshot / guard,不需要 production browser smoke | | P0-25 | K8s / ArgoCD owner response acceptance 只讀帳本 | 100% | 已新增 `k8s-argocd-owner-response-acceptance.py`、snapshot 與文件,把 K8s / ArgoCD manifest inventory 與 owner request draft 串成 4 份 owner response acceptance candidate;C0 `3`、required owner fields `11`、reviewer checks `12`、outcome lanes `7`、blocked actions `18`;owner response received / accepted、rendered manifest diff、ArgoCD API read、ArgoCD sync、kubectl action、live cluster read、secret collection、runtime gate 仍全部為 `0` | `K8S_ARGOCD_OWNER_RESPONSE_ACCEPTANCE_OK candidates=4 c0=3 checks=12 lanes=7 accepted=0 runtime_gate=0`;progress guard 固定 snapshot schema、summary、false flags、candidate ids、reviewer checks、outcome lanes、blocked actions 與每份候選 false flags;純 repo 內文件 / snapshot / guard,不需要 production browser smoke | @@ -314,6 +315,7 @@ P1 只讀重盤階段整體完成度:`70%`。它代表 freshness / inventory / | P0-24 | Public Gateway owner response acceptance 只讀帳本 | 已新增 `PUBLIC-GATEWAY-OWNER-RESPONSE-ACCEPTANCE.md`、`public-gateway-owner-response-acceptance.snapshot.json` 與產生器;3 份 acceptance candidate、2 份 C0、12 個 owner 必填欄位、12 個 reviewer checks、7 條 outcome lanes、18 類 blocked action | 帳本 artifact `100%`;owner response received / accepted、redacted export、rendered diff、`nginx -t`、reload、route smoke、DNS / TLS probe、certbot renew、host write、runtime gate 仍全部 `0 / false` | | P0-25 | K8s / ArgoCD owner response acceptance 只讀帳本 | 已新增 `K8S-ARGOCD-OWNER-RESPONSE-ACCEPTANCE.md`、`k8s-argocd-owner-response-acceptance.snapshot.json` 與產生器;4 份 acceptance candidate、3 份 C0、11 個 owner 必填欄位、12 個 reviewer checks、7 條 outcome lanes、18 類 blocked action | 帳本 artifact `100%`;owner response received / accepted、rendered manifest diff、ArgoCD API read、ArgoCD sync、kubectl action、live cluster read、secret collection、host write、runtime gate 仍全部 `0 / false` | | P0-26 | Backup / Restore / Escrow owner response acceptance 只讀帳本 | 已新增 `BACKUP-RESTORE-OWNER-RESPONSE-ACCEPTANCE.md`、`backup-restore-owner-response-acceptance.snapshot.json` 與產生器;38 份 acceptance candidate、27 份 write-capable、14 個 owner 必填欄位、13 個 reviewer checks、7 條 outcome lanes、22 類 blocked action | 帳本 artifact `100%`;owner response received / accepted、live backup evidence、backup run、restore run、offsite sync、remote delete、escrow marker write、retention change、secret collection、host write、runtime gate 仍全部 `0 / false`;backup / restore 類別成熟度 `58% -> 62%` | +| P0-27 | DNS / TLS / certbot owner response acceptance 只讀帳本 | 已新增 `DOMAIN-TLS-CERTBOT-OWNER-RESPONSE-ACCEPTANCE.md`、`domain-tls-certbot-owner-response-acceptance.snapshot.json` 與產生器;4 份 acceptance candidate、4 份 C0、13 個 owner 必填欄位、13 個 reviewer checks、7 條 outcome lanes、20 類 blocked action | 帳本 artifact `100%`;owner response received / accepted、certificate coverage confirmed、DNS query、live TLS probe、certbot renew、Nginx reload、route smoke、DNS record / certificate path / ACME route 變更、host write、runtime gate 仍全部 `0 / false`;DNS / TLS 類別成熟度 `74% -> 78%` | ## 7. 2026-06-04 本輪驗證紀錄 diff --git a/scripts/security/domain-tls-certbot-owner-response-acceptance.py b/scripts/security/domain-tls-certbot-owner-response-acceptance.py new file mode 100644 index 00000000..e71adfb3 --- /dev/null +++ b/scripts/security/domain-tls-certbot-owner-response-acceptance.py @@ -0,0 +1,390 @@ +#!/usr/bin/env python3 +""" +IwoooS DNS / TLS / certbot owner response acceptance 只讀帳本產生器。 + +本工具讀取 Domain / TLS / certbot owner confirmation request 草稿,建立未來 +owner response 如何收件、補證、隔離、拒收或進 reviewer review 的 +metadata-only acceptance ledger。它不做 DNS query、不做 live TLS probe、 +不執行 certbot renew、不 reload Nginx、不 SSH、不讀 private key。 +""" + +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)) + +ACCEPTANCE_FIELDS = [ + "acceptance_candidate_id", + "request_id", + "domain", + "control_tier", + "hosts", + "certificate_path_domains", + "certificate_paths", + "owner_response_ref", + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "certificate_coverage_basis_ref", + "certificate_expiry_metadata_ref", + "renewal_owner", + "acme_challenge_route_owner", + "maintenance_window", + "rollback_owner", + "validation_plan", + "reviewer_outcome", + "followup_owner", + "not_approval", +] + +REQUIRED_OWNER_RESPONSE_FIELDS = [ + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "certificate_coverage_basis_ref", + "certificate_expiry_metadata_ref", + "renewal_owner", + "acme_challenge_route_owner", + "maintenance_window", + "rollback_owner", + "validation_plan", + "followup_owner", +] + +REVIEWER_CHECKS = [ + { + "check_id": "owner_identity_present", + "instruction": "owner role / team 必須可追溯,不能只寫個人暱稱或聊天同意。", + }, + { + "check_id": "decision_and_reason_present", + "instruction": "decision 與 decision reason 必須同時存在,且不得包含機敏值。", + }, + { + "check_id": "redacted_refs_only", + "instruction": "evidence 只能是脫敏 ref、ticket、hash、文件路徑或摘要。", + }, + { + "check_id": "raw_certificate_absent", + "instruction": "不得出現 raw certificate payload、完整 SAN dump、private key 或 ACME account key。", + }, + { + "check_id": "secret_value_absent", + "instruction": "不得出現 DNS credential、registrar credential、token、cookie、authorization header 或 Basic Auth。", + }, + { + "check_id": "coverage_basis_ref_present", + "instruction": "SAN、wildcard 或共用憑證覆蓋依據必須是 metadata ref,不得貼 raw cert。", + }, + { + "check_id": "expiry_metadata_ref_not_probe", + "instruction": "憑證到期資訊只能是 owner-provided metadata ref;不得由本帳本觸發 live probe。", + }, + { + "check_id": "renewal_owner_separate_from_action", + "instruction": "renewal owner 可以被記錄,但 certbot renew 需另開人工批准包。", + }, + { + "check_id": "acme_route_owner_present", + "instruction": "HTTP-01 ACME path 與 route smoke owner 必須清楚,且不得自動 route smoke。", + }, + { + "check_id": "maintenance_window_present", + "instruction": "任何未來 probe、renew、reload 都必須有維護窗口或明確禁止窗口。", + }, + { + "check_id": "rollback_owner_present", + "instruction": "rollback owner 與 rollback ref 必須存在,且不可指向 raw secret。", + }, + { + "check_id": "validation_plan_present", + "instruction": "validation plan 必須列 DNS / TLS / ACME / route post-check 指標,但不授權執行。", + }, + { + "check_id": "counts_transition_safe", + "instruction": "只有 reviewer record 可更新 received / accepted / rejected;不得同時開 runtime gate。", + }, +] + +OUTCOME_LANES = [ + { + "lane_id": "waiting_owner_response", + "meaning": "尚未收到 owner response;所有 accepted / runtime count 維持 0。", + }, + { + "lane_id": "quarantine_raw_certificate_or_secret", + "meaning": "收到 raw cert、private key、DNS credential 或 certbot account 內容時,只能隔離。", + }, + { + "lane_id": "reject_execution_request", + "meaning": "夾帶 DNS query、TLS probe、certbot renew、Nginx reload 或 host write 要求時拒收。", + }, + { + "lane_id": "request_supplement", + "meaning": "欄位不足、scope 不清或 evidence ref 不可追溯時要求補件。", + }, + { + "lane_id": "ready_for_certificate_coverage_review", + "meaning": "metadata 合格後,只能進憑證覆蓋關係 reviewer review,不自動 probe。", + }, + { + "lane_id": "owner_review_only_update", + "meaning": "只允許更新只讀 owner review ledger,不得修改 DNS、TLS、certbot 或 Nginx。", + }, + { + "lane_id": "waiting_runtime_gate", + "meaning": "即使 owner response accepted,DNS / TLS / certbot runtime gate 仍等待獨立人工批准。", + }, +] + +BLOCKED_ACTIONS = [ + "perform_dns_query", + "perform_live_tls_probe", + "run_certbot_renew", + "run_nginx_reload", + "run_route_smoke", + "read_tls_private_key", + "store_raw_certificate_payload", + "store_dns_provider_credential", + "store_certbot_account_key", + "collect_secret_value", + "accept_unredacted_certbot_log", + "accept_shell_history_or_env_dump", + "mark_owner_response_accepted_without_reviewer_record", + "mark_certificate_coverage_confirmed_without_ref", + "modify_dns_record", + "modify_tls_certificate_path", + "modify_acme_challenge_route", + "write_production_host", + "open_runtime_gate", + "add_action_button", +] + + +def git_short_sha(root: Path) -> str: + try: + result = subprocess.run( + ["git", "rev-parse", "--short", "HEAD"], + cwd=root, + check=True, + capture_output=True, + text=True, + ) + return result.stdout.strip() + except Exception: + return "unknown" + + +def load_json(path: Path) -> dict[str, Any]: + return json.loads(path.read_text(encoding="utf-8")) + + +def acceptance_candidate(request: dict[str, Any]) -> dict[str, Any]: + request_id = request["request_id"] + return { + "acceptance_candidate_id": request_id.replace( + "domain_tls_certbot_owner_confirmation:", + "domain_tls_certbot_owner_response_acceptance:", + ), + "status": "waiting_owner_response", + "request_id": request_id, + "domain": request["domain"], + "control_tier": request["control_tier"], + "hosts": request["hosts"], + "certificate_path_domains": request["certificate_path_domains"], + "certificate_paths": request["certificate_paths"], + "owner_response_ref": None, + "owner_role_or_team": "pending_owner_response", + "decision": "pending_owner_response", + "decision_reason": "pending_owner_response", + "affected_scope": "pending_owner_response", + "redacted_evidence_refs": [], + "certificate_coverage_basis_ref": None, + "certificate_expiry_metadata_ref": None, + "renewal_owner": "pending_owner_response", + "acme_challenge_route_owner": "pending_owner_response", + "maintenance_window": "pending_owner_response", + "rollback_owner": "pending_owner_response", + "validation_plan": "pending_owner_response", + "reviewer_outcome": "waiting_owner_response", + "followup_owner": "pending_owner_response", + "acceptance_fields": ACCEPTANCE_FIELDS, + "required_owner_response_fields": REQUIRED_OWNER_RESPONSE_FIELDS, + "reviewer_checks": [item["check_id"] for item in REVIEWER_CHECKS], + "outcome_lanes": [item["lane_id"] for item in OUTCOME_LANES], + "blocked_actions": BLOCKED_ACTIONS, + "not_approval": True, + "request_sent": False, + "recipient_confirmed": False, + "owner_response_received": False, + "owner_response_accepted": False, + "owner_response_rejected": False, + "owner_response_quarantined": False, + "supplement_requested": False, + "certificate_coverage_confirmed": False, + "certificate_expiry_metadata_accepted": False, + "renewal_owner_accepted": False, + "acme_route_owner_accepted": False, + "maintenance_window_accepted": False, + "rollback_owner_accepted": False, + "dns_query_authorized": False, + "dns_query_executed": False, + "live_tls_probe_authorized": False, + "live_tls_probe_executed": False, + "certbot_renew_authorized": False, + "certbot_renew_executed": False, + "nginx_reload_authorized": False, + "nginx_reload_executed": False, + "route_smoke_authorized": False, + "route_smoke_executed": False, + "host_write_authorized": False, + "production_write_authorized": False, + "runtime_gate": False, + "action_buttons_allowed": False, + "secret_value_collection_allowed": False, + } + + +def build_report( + root: Path, + request_report: dict[str, Any], + generated_at: str | None, +) -> dict[str, Any]: + report_time = generated_at or datetime.now(TAIPEI).isoformat(timespec="seconds") + requests = request_report.get("owner_confirmation_requests", []) + acceptance_candidates = [acceptance_candidate(item) for item in requests] + c0_candidates = [item for item in acceptance_candidates if item["control_tier"] == "C0"] + + return { + "schema_version": "domain_tls_certbot_owner_response_acceptance_v1", + "generated_at": report_time, + "git_commit": git_short_sha(root), + "source_owner_confirmation_request_schema_version": request_report.get("schema_version"), + "source_owner_confirmation_request_status": request_report.get("status"), + "status": "owner_response_acceptance_ledger_ready_no_runtime_action", + "summary": { + "source_owner_confirmation_request_count": request_report.get("summary", {}).get( + "owner_confirmation_request_count", 0 + ), + "acceptance_candidate_count": len(acceptance_candidates), + "c0_acceptance_candidate_count": len(c0_candidates), + "acceptance_field_count": len(ACCEPTANCE_FIELDS), + "required_owner_response_field_count": len(REQUIRED_OWNER_RESPONSE_FIELDS), + "reviewer_check_count": len(REVIEWER_CHECKS), + "outcome_lane_count": len(OUTCOME_LANES), + "blocked_action_count": len(BLOCKED_ACTIONS), + "request_sent_count": 0, + "recipient_confirmed_count": 0, + "owner_response_received_count": 0, + "owner_response_accepted_count": 0, + "owner_response_rejected_count": 0, + "owner_response_quarantined_count": 0, + "supplement_requested_count": 0, + "certificate_coverage_confirmed_count": 0, + "certificate_expiry_metadata_accepted_count": 0, + "renewal_owner_accepted_count": 0, + "acme_route_owner_accepted_count": 0, + "maintenance_window_accepted_count": 0, + "rollback_owner_accepted_count": 0, + "dns_query_authorized_count": 0, + "dns_query_executed_count": 0, + "live_tls_probe_authorized_count": 0, + "live_tls_probe_executed_count": 0, + "certbot_renew_authorized_count": 0, + "certbot_renew_executed_count": 0, + "nginx_reload_authorized_count": 0, + "nginx_reload_executed_count": 0, + "route_smoke_authorized_count": 0, + "route_smoke_executed_count": 0, + "host_write_authorized_count": 0, + "runtime_gate_count": 0, + "action_button_count": 0, + }, + "execution_boundaries": { + "request_dispatch_authorized": False, + "owner_response_accepted": False, + "raw_certificate_storage_allowed": False, + "tls_private_key_read_authorized": False, + "secret_value_collection_allowed": False, + "dns_query_authorized": False, + "dns_query_executed": False, + "live_tls_probe_authorized": False, + "live_tls_probe_executed": False, + "certbot_renew_authorized": False, + "certbot_renew_executed": False, + "nginx_reload_authorized": False, + "nginx_reload_executed": False, + "route_smoke_authorized": False, + "route_smoke_executed": False, + "host_write_authorized": False, + "production_write_authorized": False, + "runtime_execution_authorized": False, + "action_buttons_allowed": False, + "not_authorization": True, + }, + "acceptance_fields": ACCEPTANCE_FIELDS, + "required_owner_response_fields": REQUIRED_OWNER_RESPONSE_FIELDS, + "reviewer_checks": REVIEWER_CHECKS, + "outcome_lanes": OUTCOME_LANES, + "blocked_actions": BLOCKED_ACTIONS, + "acceptance_candidates": acceptance_candidates, + "next_steps": [ + "等待 owner response;未收到前不得更新 accepted count。", + "收到回覆後先走 raw cert / private key / credential / execution request 檢查,不合格即隔離、拒收或補件。", + "metadata 合格也只能進 certificate coverage reviewer review;DNS query、TLS probe、certbot renew、Nginx reload 與 route smoke 仍需獨立人工批准。", + ], + } + + +def main() -> int: + parser = argparse.ArgumentParser(description="IwoooS DNS / TLS / certbot owner response acceptance 只讀帳本產生器") + parser.add_argument("--root", default=".", help="repo root") + parser.add_argument( + "--owner-confirmation-request-report", + default="docs/security/domain-tls-certbot-owner-confirmation-request.snapshot.json", + help="domain-tls-certbot-owner-confirmation-request.py 輸出的 JSON", + ) + parser.add_argument("--output", help="寫出 JSON 報告") + parser.add_argument("--generated-at", help="固定報告時間,供 committed snapshot 使用") + args = parser.parse_args() + + root = Path(args.root).resolve() + request_report = load_json(root / args.owner_confirmation_request_report) + report = build_report(root, request_report, args.generated_at) + payload = json.dumps(report, ensure_ascii=False, indent=2, sort_keys=True) + + if args.output: + output = root / args.output + output.parent.mkdir(parents=True, exist_ok=True) + output.write_text(payload + "\n", encoding="utf-8") + else: + print(payload) + + summary = report["summary"] + print( + "DOMAIN_TLS_CERTBOT_OWNER_RESPONSE_ACCEPTANCE_OK " + f"candidates={summary['acceptance_candidate_count']} " + f"c0={summary['c0_acceptance_candidate_count']} " + f"checks={summary['reviewer_check_count']} " + f"lanes={summary['outcome_lane_count']} " + f"accepted={summary['owner_response_accepted_count']} " + f"runtime_gate={summary['runtime_gate_count']}", + file=sys.stderr, + ) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/security/high-value-config-control-coverage.py b/scripts/security/high-value-config-control-coverage.py index baa954b8..07de04ff 100644 --- a/scripts/security/high-value-config-control-coverage.py +++ b/scripts/security/high-value-config-control-coverage.py @@ -40,14 +40,18 @@ CONTROL_STATUS_BY_CATEGORY = { "next_owner_action": "補 public gateway owner 回覆、owner-provided live conf、source-to-live rendered diff、nginx -t evidence、route smoke、maintenance window 與 rollback owner。", }, "dns_tls_certbot": { - "coverage_status": "repo_only_inventory_ready", - "coverage_percent": 74, + "coverage_status": "owner_response_acceptance_ledger_ready_needs_certificate_owner_evidence", + "coverage_percent": 78, "evidence_refs": [ "docs/security/DOMAIN-TLS-CERTBOT-INVENTORY.md", "docs/security/domain-tls-certbot-inventory.snapshot.json", + "docs/security/DOMAIN-TLS-CERTBOT-OWNER-CONFIRMATION-REQUEST.md", + "docs/security/domain-tls-certbot-owner-confirmation-request.snapshot.json", + "docs/security/DOMAIN-TLS-CERTBOT-OWNER-RESPONSE-ACCEPTANCE.md", + "docs/security/domain-tls-certbot-owner-response-acceptance.snapshot.json", ], - "current_gap": "4 個 certificate path 關係需 owner 確認;live DNS / TLS probe 未執行。", - "next_owner_action": "確認 SAN / 共用憑證關係、renewal owner、ACME smoke 與 rollback owner。", + "current_gap": "已固定 4 份 DNS / TLS / certbot owner response acceptance candidate;仍缺 owner response、certificate coverage metadata ref、expiry metadata ref、renewal owner、ACME route owner、maintenance window、rollback owner 與 validation plan。", + "next_owner_action": "補 SAN / wildcard / 共用憑證覆蓋依據 ref、到期 metadata ref、renewal owner、ACME route owner、維護窗口、rollback owner 與 validation plan。", }, "k8s_production_gitops": { "coverage_status": "owner_response_acceptance_ledger_ready_needs_runtime_evidence", diff --git a/scripts/security/security-mirror-progress-guard.py b/scripts/security/security-mirror-progress-guard.py index 0fd4c7c4..18548759 100755 --- a/scripts/security/security-mirror-progress-guard.py +++ b/scripts/security/security-mirror-progress-guard.py @@ -125,6 +125,9 @@ def validate(root: Path) -> None: domain_tls_owner_confirmation_request = load_json( security_dir / "domain-tls-certbot-owner-confirmation-request.snapshot.json" ) + domain_tls_owner_response_acceptance = load_json( + security_dir / "domain-tls-certbot-owner-response-acceptance.snapshot.json" + ) k8s_argocd_manifest_inventory = load_json( security_dir / "k8s-argocd-manifest-inventory.snapshot.json" ) @@ -2539,6 +2542,34 @@ def validate(root: Path) -> None: agent_bounty_category["evidence_refs"], evidence_ref, ) + dns_tls_category = next( + item + for item in high_value_config_coverage["coverage_categories"] + if item["category_id"] == "dns_tls_certbot" + ) + assert_equal( + "high_value_config_coverage.coverage_categories.dns_tls.coverage_percent", + dns_tls_category["coverage_percent"], + 78, + ) + assert_equal( + "high_value_config_coverage.coverage_categories.dns_tls.coverage_status", + dns_tls_category["coverage_status"], + "owner_response_acceptance_ledger_ready_needs_certificate_owner_evidence", + ) + for evidence_ref in [ + "docs/security/DOMAIN-TLS-CERTBOT-INVENTORY.md", + "docs/security/domain-tls-certbot-inventory.snapshot.json", + "docs/security/DOMAIN-TLS-CERTBOT-OWNER-CONFIRMATION-REQUEST.md", + "docs/security/domain-tls-certbot-owner-confirmation-request.snapshot.json", + "docs/security/DOMAIN-TLS-CERTBOT-OWNER-RESPONSE-ACCEPTANCE.md", + "docs/security/domain-tls-certbot-owner-response-acceptance.snapshot.json", + ]: + assert_contains( + "high_value_config_coverage.coverage_categories.dns_tls.evidence_refs", + dns_tls_category["evidence_refs"], + evidence_ref, + ) assert_equal( "agent_bounty_owner_request_draft.schema", agent_bounty_owner_request_draft["schema_version"], @@ -15243,6 +15274,224 @@ def validate(root: Path) -> None: f"domain_tls_owner_confirmation_request.{request['request_id']}.{false_key}", request[false_key], ) + domain_tls_owner_response_acceptance_summary = domain_tls_owner_response_acceptance["summary"] + assert_equal( + "domain_tls_owner_response_acceptance.schema", + domain_tls_owner_response_acceptance["schema_version"], + "domain_tls_certbot_owner_response_acceptance_v1", + ) + assert_equal( + "domain_tls_owner_response_acceptance.source_owner_confirmation_request_schema_version", + domain_tls_owner_response_acceptance["source_owner_confirmation_request_schema_version"], + "domain_tls_certbot_owner_confirmation_request_v1", + ) + assert_equal( + "domain_tls_owner_response_acceptance.status", + domain_tls_owner_response_acceptance["status"], + "owner_response_acceptance_ledger_ready_no_runtime_action", + ) + expected_domain_tls_owner_response_acceptance_summary = { + "source_owner_confirmation_request_count": 4, + "acceptance_candidate_count": 4, + "c0_acceptance_candidate_count": 4, + "acceptance_field_count": 23, + "required_owner_response_field_count": 13, + "reviewer_check_count": 13, + "outcome_lane_count": 7, + "blocked_action_count": 20, + "request_sent_count": 0, + "recipient_confirmed_count": 0, + "owner_response_received_count": 0, + "owner_response_accepted_count": 0, + "owner_response_rejected_count": 0, + "owner_response_quarantined_count": 0, + "supplement_requested_count": 0, + "certificate_coverage_confirmed_count": 0, + "certificate_expiry_metadata_accepted_count": 0, + "renewal_owner_accepted_count": 0, + "acme_route_owner_accepted_count": 0, + "maintenance_window_accepted_count": 0, + "rollback_owner_accepted_count": 0, + "dns_query_authorized_count": 0, + "dns_query_executed_count": 0, + "live_tls_probe_authorized_count": 0, + "live_tls_probe_executed_count": 0, + "certbot_renew_authorized_count": 0, + "certbot_renew_executed_count": 0, + "nginx_reload_authorized_count": 0, + "nginx_reload_executed_count": 0, + "route_smoke_authorized_count": 0, + "route_smoke_executed_count": 0, + "host_write_authorized_count": 0, + "runtime_gate_count": 0, + "action_button_count": 0, + } + for key, expected in expected_domain_tls_owner_response_acceptance_summary.items(): + assert_equal( + f"domain_tls_owner_response_acceptance.summary.{key}", + domain_tls_owner_response_acceptance_summary[key], + expected, + ) + for false_key in [ + "request_dispatch_authorized", + "owner_response_accepted", + "raw_certificate_storage_allowed", + "tls_private_key_read_authorized", + "secret_value_collection_allowed", + "dns_query_authorized", + "dns_query_executed", + "live_tls_probe_authorized", + "live_tls_probe_executed", + "certbot_renew_authorized", + "certbot_renew_executed", + "nginx_reload_authorized", + "nginx_reload_executed", + "route_smoke_authorized", + "route_smoke_executed", + "host_write_authorized", + "production_write_authorized", + "runtime_execution_authorized", + "action_buttons_allowed", + ]: + assert_false( + f"domain_tls_owner_response_acceptance.execution_boundaries.{false_key}", + domain_tls_owner_response_acceptance["execution_boundaries"][false_key], + ) + assert_true( + "domain_tls_owner_response_acceptance.execution_boundaries.not_authorization", + domain_tls_owner_response_acceptance["execution_boundaries"]["not_authorization"], + ) + expected_domain_tls_owner_response_acceptance_ids = [ + "domain_tls_certbot_owner_response_acceptance:gitea.wooo.work", + "domain_tls_certbot_owner_response_acceptance:langfuse.wooo.work", + "domain_tls_certbot_owner_response_acceptance:signoz.wooo.work", + "domain_tls_certbot_owner_response_acceptance:tsenyang.com", + ] + assert_equal( + "domain_tls_owner_response_acceptance.candidate_ids", + [item["acceptance_candidate_id"] for item in domain_tls_owner_response_acceptance["acceptance_candidates"]], + expected_domain_tls_owner_response_acceptance_ids, + ) + expected_domain_tls_owner_response_acceptance_checks = [ + "owner_identity_present", + "decision_and_reason_present", + "redacted_refs_only", + "raw_certificate_absent", + "secret_value_absent", + "coverage_basis_ref_present", + "expiry_metadata_ref_not_probe", + "renewal_owner_separate_from_action", + "acme_route_owner_present", + "maintenance_window_present", + "rollback_owner_present", + "validation_plan_present", + "counts_transition_safe", + ] + assert_equal( + "domain_tls_owner_response_acceptance.reviewer_checks", + [item["check_id"] for item in domain_tls_owner_response_acceptance["reviewer_checks"]], + expected_domain_tls_owner_response_acceptance_checks, + ) + expected_domain_tls_owner_response_acceptance_lanes = [ + "waiting_owner_response", + "quarantine_raw_certificate_or_secret", + "reject_execution_request", + "request_supplement", + "ready_for_certificate_coverage_review", + "owner_review_only_update", + "waiting_runtime_gate", + ] + assert_equal( + "domain_tls_owner_response_acceptance.outcome_lanes", + [item["lane_id"] for item in domain_tls_owner_response_acceptance["outcome_lanes"]], + expected_domain_tls_owner_response_acceptance_lanes, + ) + expected_domain_tls_owner_response_acceptance_blocked_actions = [ + "perform_dns_query", + "perform_live_tls_probe", + "run_certbot_renew", + "run_nginx_reload", + "run_route_smoke", + "read_tls_private_key", + "store_raw_certificate_payload", + "store_dns_provider_credential", + "store_certbot_account_key", + "collect_secret_value", + "accept_unredacted_certbot_log", + "accept_shell_history_or_env_dump", + "mark_owner_response_accepted_without_reviewer_record", + "mark_certificate_coverage_confirmed_without_ref", + "modify_dns_record", + "modify_tls_certificate_path", + "modify_acme_challenge_route", + "write_production_host", + "open_runtime_gate", + "add_action_button", + ] + assert_equal( + "domain_tls_owner_response_acceptance.blocked_actions", + domain_tls_owner_response_acceptance["blocked_actions"], + expected_domain_tls_owner_response_acceptance_blocked_actions, + ) + for candidate in domain_tls_owner_response_acceptance["acceptance_candidates"]: + assert_equal( + f"domain_tls_owner_response_acceptance.{candidate['acceptance_candidate_id']}.acceptance_field_count", + len(candidate["acceptance_fields"]), + 23, + ) + assert_equal( + f"domain_tls_owner_response_acceptance.{candidate['acceptance_candidate_id']}.required_owner_response_field_count", + len(candidate["required_owner_response_fields"]), + 13, + ) + assert_equal( + f"domain_tls_owner_response_acceptance.{candidate['acceptance_candidate_id']}.reviewer_check_count", + len(candidate["reviewer_checks"]), + 13, + ) + assert_equal( + f"domain_tls_owner_response_acceptance.{candidate['acceptance_candidate_id']}.outcome_lane_count", + len(candidate["outcome_lanes"]), + 7, + ) + assert_true( + f"domain_tls_owner_response_acceptance.{candidate['acceptance_candidate_id']}.not_approval", + candidate["not_approval"], + ) + for false_key in [ + "request_sent", + "recipient_confirmed", + "owner_response_received", + "owner_response_accepted", + "owner_response_rejected", + "owner_response_quarantined", + "supplement_requested", + "certificate_coverage_confirmed", + "certificate_expiry_metadata_accepted", + "renewal_owner_accepted", + "acme_route_owner_accepted", + "maintenance_window_accepted", + "rollback_owner_accepted", + "dns_query_authorized", + "dns_query_executed", + "live_tls_probe_authorized", + "live_tls_probe_executed", + "certbot_renew_authorized", + "certbot_renew_executed", + "nginx_reload_authorized", + "nginx_reload_executed", + "route_smoke_authorized", + "route_smoke_executed", + "host_write_authorized", + "production_write_authorized", + "runtime_gate", + "action_buttons_allowed", + "secret_value_collection_allowed", + ]: + assert_false( + f"domain_tls_owner_response_acceptance.{candidate['acceptance_candidate_id']}.{false_key}", + candidate[false_key], + ) k8s_argocd_summary = k8s_argocd_manifest_inventory["summary"] assert_equal( "k8s_argocd_manifest_inventory.schema",