From 68e0cd7b2e51c04ed5fa2e8250e4c871f4216739 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 18 May 2026 09:42:54 +0800 Subject: [PATCH] docs(security): mark next owner response candidate --- docs/LOGBOOK.md | 15 ++++++ ..._response_validation_rollup_v1.schema.json | 47 +++++++++++++++++++ ...WOOOP-MIRROR-ONLY-CONSUMPTION-CHECKLIST.md | 2 +- ...ECURITY-SUPPLYCHAIN-INTEGRATION-HANDOFF.md | 2 + .../security/SECURITY-MIRROR-STATUS-ROLLUP.md | 2 +- ...SECURITY-SUPPLY-CHAIN-CONTRACT-MANIFEST.md | 2 +- .../SECURITY-SUPPLY-CHAIN-PROGRESS.md | 2 +- ...ONTROL-OWNER-RESPONSE-VALIDATION-ROLLUP.md | 12 +++++ .../security-mirror-readiness.snapshot.json | 2 +- ...ecurity-mirror-status-rollup.snapshot.json | 6 +-- ...pply-chain-contract-manifest.snapshot.json | 2 +- ...r-response-validation-rollup.snapshot.json | 29 ++++++++++++ .../security-mirror-progress-guard.py | 28 +++++++++++ .../source-control-owner-response-guard.py | 47 +++++++++++++++++++ 14 files changed, 189 insertions(+), 9 deletions(-) diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index 32996975..4b973245 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,18 @@ +## 2026-05-18 | 資安供應鏈 S4.13:Next Collection Candidate + +**背景**:S4.13 已有 4 條 missing response lanes 與 4 步 collection order;本輪補上單一 `next_collection_candidate`,讓 AwoooP 只顯示下一包建議收件,而不是把整串順序誤讀成 approval queue 或 execution queue。 + +**完成**: +- `source_control_owner_response_validation_rollup_v1` schema 新增 optional `next_collection_candidate`。 +- `source-control-owner-response-validation-rollup.snapshot.json` 標示目前下一個建議收件為 S4.9 Gitea owner attestation response,需要 5 個 Gitea coverage attestation items,received / accepted 仍為 0。 +- `source-control-owner-response-guard.py` 反查 `next_collection_candidate` 必須等於 collection order 第 1 步,且 `execution_authorized=false`、`not_approval=true`。 +- 更新 S4.13 人讀文件、AwoooP checklist、status rollup、readiness、manifest、progress 與 handoff。 + +**仍禁止**: +- 不把 next collection candidate 當成 approval、runtime gate、repo / refs / workflow / secret / runner 執行授權或 GitHub primary approval。 +- 不提前接受 S4.10 / S4.11 / S4.12 response。 +- 不收 token value、secret value、private key、cookie、session 或未脫敏 payload。 + ## 2026-05-18 | 資安供應鏈 S4.13:Owner Response Collection Order **背景**:S4.13 已能顯示 4 條 missing response lanes;本輪補上建議收件順序,讓 AwoooP 可以把下一個 owner response 工作排清楚,但仍不把收件順序變成 approval queue 或 execution queue。 diff --git a/docs/schemas/source_control_owner_response_validation_rollup_v1.schema.json b/docs/schemas/source_control_owner_response_validation_rollup_v1.schema.json index 6c8025e5..a3559086 100644 --- a/docs/schemas/source_control_owner_response_validation_rollup_v1.schema.json +++ b/docs/schemas/source_control_owner_response_validation_rollup_v1.schema.json @@ -286,6 +286,53 @@ }, "minItems": 1 }, + "next_collection_candidate": { + "type": "object", + "description": "AwoooP 可顯示的單一下一步 owner response 收件項目;此欄位只提示 reviewer 下一包 response,不是 approval queue 或 execution queue。", + "required": [ + "order", + "lane_id", + "display_status", + "source_contract", + "required_packet", + "required_response_template_count", + "received_response_count", + "accepted_response_count", + "minimum_response", + "awooop_display_mode", + "why_next", + "blocked_until_received", + "execution_authorized", + "not_approval", + "still_forbidden" + ], + "properties": { + "order": {"type": "integer", "minimum": 1}, + "lane_id": {"type": "string"}, + "display_status": {"type": "string", "enum": ["next_owner_response_required"]}, + "source_contract": {"type": "string"}, + "required_packet": {"type": "string"}, + "required_response_template_count": {"type": "integer", "minimum": 0}, + "received_response_count": {"type": "integer", "minimum": 0}, + "accepted_response_count": {"type": "integer", "minimum": 0}, + "minimum_response": { + "type": "array", + "items": {"type": "string"}, + "minItems": 1 + }, + "awooop_display_mode": {"type": "string", "enum": ["display_next_collection_item_only"]}, + "why_next": {"type": "string"}, + "blocked_until_received": {"type": "boolean", "const": true}, + "execution_authorized": {"type": "boolean", "const": false}, + "not_approval": {"type": "boolean", "const": true}, + "still_forbidden": { + "type": "array", + "items": {"type": "string"}, + "minItems": 1 + } + }, + "additionalProperties": false + }, "allowed_outputs": { "type": "array", "items": {"type": "string"}, diff --git a/docs/security/AWOOOP-MIRROR-ONLY-CONSUMPTION-CHECKLIST.md b/docs/security/AWOOOP-MIRROR-ONLY-CONSUMPTION-CHECKLIST.md index a7e6870b..a9b75e6d 100644 --- a/docs/security/AWOOOP-MIRROR-ONLY-CONSUMPTION-CHECKLIST.md +++ b/docs/security/AWOOOP-MIRROR-ONLY-CONSUMPTION-CHECKLIST.md @@ -42,7 +42,7 @@ AwoooP 初期不得直接啟動掃描、不得呼叫 Codex patch runner、不得 | `security_mirror_quarantine_v1` | AwoooP 鏡像隔離契約 | Operator Console、Audit | mirror-only | 只隔離驗收失敗 payload、顯示 recovery request 與 retry gate;不作 runtime blocker | | `security_mirror_dry_run_v1` | AwoooP 鏡像 dry-run 報告契約 | Operator Console、Audit | mirror-only | 只回報接入演練結果,且必須包含 progress guard、owner response guard 與 latest local validation;不得轉成 production ingestion | | `security_mirror_status_rollup_v1` | AwoooP 鏡像狀態彙整契約 | Operator Console、Runtime State、Audit | mirror-only | 只顯示階段狀態、58% 進度估算、下一個 gate 與禁止事項;不得視為 runtime authorization | -| `source_control_owner_response_validation_rollup_v1` | S4.9 / S4.10 / S4.11 / S4.12 owner response validation rollup | Operator Console、Source-control review、Audit | mirror-only | 只顯示四包 response packets、22 個 templates、missing response lanes、owner response collection order、10 個 cross-packet checks、quarantine rules 與 latest local validation;不得視為 approval 或 runtime gate | +| `source_control_owner_response_validation_rollup_v1` | S4.9 / S4.10 / S4.11 / S4.12 owner response validation rollup | Operator Console、Source-control review、Audit | mirror-only | 只顯示四包 response packets、22 個 templates、missing response lanes、owner response collection order、next collection candidate、10 個 cross-packet checks、quarantine rules 與 latest local validation;不得視為 approval 或 runtime gate | | `coding_task_v1` | Code Review / Codex Security / manual review | Approval candidate、Channel Event、Audit | suggest-only | 不自動開 patch runner、不自動 merge | | `source_control_migration_event_v1` | Gitea/GitHub branch/tag/SHA diff | Supply-chain evidence、Approval candidate | mirror-only | 不觸發 deploy、不切換 primary | | `gitea_repo_inventory_v1` | Gitea org/user repo list 或管理匯出 | Supply-chain evidence、migration matrix | mirror-only | 顯示 public-only evidence、S4.5 authenticated/admin export request、S4.6 redacted import acceptance、S4.7 owner coverage attestation 與 S4.9 owner response 收件包;不保存 token value、不刪除或停用 Gitea repo | diff --git a/docs/security/AWOOOP-SECURITY-SUPPLYCHAIN-INTEGRATION-HANDOFF.md b/docs/security/AWOOOP-SECURITY-SUPPLYCHAIN-INTEGRATION-HANDOFF.md index bf1385de..fabd36a3 100644 --- a/docs/security/AWOOOP-SECURITY-SUPPLYCHAIN-INTEGRATION-HANDOFF.md +++ b/docs/security/AWOOOP-SECURITY-SUPPLYCHAIN-INTEGRATION-HANDOFF.md @@ -56,6 +56,8 @@ AwoooP 顯示 S4.13 時,應把 `missing_response_lanes` 當成 Operator Consol 建議顯示 `owner_response_collection_order` 作為下一步收件順序:先 S4.9 Gitea scope / canonical owner,再 S4.10 GitHub target owner / visibility / canonical,再 S4.11 refs truth,最後 S4.12 workflow / secret name parity。這只是 review 順序,不是 approval queue 或 execution queue。 +可同步顯示 `next_collection_candidate`,目前只指向 S4.9 Gitea owner attestation response:需要 5 個 Gitea coverage attestation items、received / accepted 皆為 0、顯示模式為 `display_next_collection_item_only`。這個欄位只提示下一包 response,不是 approval,也不代表 S4.10 / S4.11 / S4.12 可被提前接受。 + ## 1. Session 分工 ### AwoooP 主線 Session diff --git a/docs/security/SECURITY-MIRROR-STATUS-ROLLUP.md b/docs/security/SECURITY-MIRROR-STATUS-ROLLUP.md index fd895b59..3f75c39f 100644 --- a/docs/security/SECURITY-MIRROR-STATUS-ROLLUP.md +++ b/docs/security/SECURITY-MIRROR-STATUS-ROLLUP.md @@ -32,7 +32,7 @@ | GitHub primary rollback ADR | S4.4 已建立;7 個 in-scope rollback drafts、0 個 owner approved、0 個 dry-run completed、0 個 active cutover | | Gitea inventory | S4.5 已補認證清冊匯出請求;S4.6 已補匯入驗收契約;S4.7 已補 owner coverage attestation;S4.8 已把既有 Gitea queue/gate/review packet/follow-up gate 對齊 attestation 先行;S4.9 已補 owner response 收件包;目前 status=`partial_waiting_authenticated_inventory`、未認證公開範圍 repos 2 個、本機可見 Gitea unique repos 4 個、匯出來源選項 2 類、匯入驗收 payload 0 筆、owner attestation items 5 個、收到 attestation 0 筆、owner response 0 筆、敏感 payload 必須隔離、允許收集 token value=false | | Workflow / secret name inventory | S4.1 已建立;S4.2 補 4 個 repos、31 個 workflow files、43 個 referenced secret names 的 local evidence;S4.3 補 7 個 repos、5 類 lanes 的 redacted export request;S4.12 補 5 個 owner response templates;0 個 inventory complete、禁止收集 secret value、禁止 write token | -| Owner response validation | S4.13 已建立;四包 owner response 目前 received/accepted 皆為 0;4 條 missing response lanes 與 4 步 collection order 可供 AwoooP 直接顯示;latest local validation 為 `SOURCE_CONTROL_OWNER_RESPONSE_GUARD_OK`,不代表 owner response 已收到或任何執行授權 | +| Owner response validation | S4.13 已建立;四包 owner response 目前 received/accepted 皆為 0;4 條 missing response lanes、4 步 collection order 與 next collection candidate 可供 AwoooP 直接顯示;下一個建議收件為 S4.9 Gitea owner attestation;latest local validation 為 `SOURCE_CONTROL_OWNER_RESPONSE_GUARD_OK`,不代表 owner response 已收到或任何執行授權 | | Dry-run | `contract_defined_not_executed`;已納入 `CHECK_PROGRESS_GUARD` 與 `CHECK_OWNER_RESPONSE_GUARD`,latest local validation 為 `repo_snapshot_guard_pass`,仍不代表 production ingestion | | Runtime actions | `false` | | Payload ingestion | `false` | diff --git a/docs/security/SECURITY-SUPPLY-CHAIN-CONTRACT-MANIFEST.md b/docs/security/SECURITY-SUPPLY-CHAIN-CONTRACT-MANIFEST.md index 474f4b9d..d17cc6ab 100644 --- a/docs/security/SECURITY-SUPPLY-CHAIN-CONTRACT-MANIFEST.md +++ b/docs/security/SECURITY-SUPPLY-CHAIN-CONTRACT-MANIFEST.md @@ -36,7 +36,7 @@ | `security_mirror_acceptance_v1` | mirror-only | AwoooP 只讀鏡像接入驗收 checks | `security-mirror-acceptance.snapshot.json` | | `security_mirror_quarantine_v1` | mirror-only | AwoooP 鏡像驗收失敗隔離與 retry gate | `security-mirror-quarantine.snapshot.json` | | `security_mirror_dry_run_v1` | mirror-only | AwoooP 鏡像接入演練回報格式 | `security-mirror-dry-run.snapshot.json` | -| `security_mirror_status_rollup_v1` | mirror-only | AwoooP / Security Supply Chain 跨 Session 狀態總覽;S4.13 owner response validation rollup | `security-mirror-status-rollup.snapshot.json` / `source-control-owner-response-validation-rollup.snapshot.json` | +| `security_mirror_status_rollup_v1` | mirror-only | AwoooP / Security Supply Chain 跨 Session 狀態總覽;S4.13 owner response validation rollup 與 next collection candidate | `security-mirror-status-rollup.snapshot.json` / `source-control-owner-response-validation-rollup.snapshot.json` | | `coding_task_v1` | suggest-only | Code Review 接 Codex patch-only | 無正式 snapshot | | `source_control_migration_event_v1` | mirror-only | Gitea/GitHub refs 差異 | `gitea-github-awoooi`、`clawbot-v5`、`wooo-aiops` | | `gitea_repo_inventory_v1` | mirror-only | Gitea repo inventory;S4.5 已補認證清冊匯出請求,S4.6 已補匯入驗收契約,S4.7 已補 owner coverage attestation,S4.9 已補 owner response 收件包 | public-only / blocked endpoint / S4.5 export request / S4.6 import acceptance / S4.7 coverage attestation / S4.9 response snapshots | diff --git a/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md b/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md index ea8694f9..7bfe74c0 100644 --- a/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md +++ b/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md @@ -59,7 +59,7 @@ python3 scripts/security/security-mirror-progress-guard.py | S4.2 Workflow / Secret 名稱 local evidence | 完成草案 | 已建立 local read-only collector 與 snapshot;7 個 local repos visible、4 個 local evidence repos、31 個 workflow files、43 個 referenced secret names、secret value detected=false | 補 webhook / deploy key / branch protection / repository secret parity 的 redacted evidence;仍不可切 primary | | S4.3 Workflow / Secret 名稱 redacted export request | 完成草案 | 已建立 export request schema / snapshot / 人讀版;7 個 in-scope repos、5 類 export lanes:webhook、runner、deploy key、branch protection / CODEOWNERS、repository secret name parity;write token allowed=false | repo owner 或未來只讀 API 依 request 補 redacted export;仍不可收 secret value、不可修改 GitHub/Gitea | | S4.12 Workflow / Secret Name Owner Response 收件包 | 完成草案 | 已建立 owner response schema / snapshot / 人讀版;5 個 response templates、8 個 acceptance checks、10 個 rejection rules、candidate repos 8、in-scope repos 7、received response 0、accepted 0、execution authorized=false | owner 依模板回覆 webhook、runner、deploy key、branch protection / CODEOWNERS、repository secret name parity;response 通過只更新 read-only inventory / export request / readiness wording,不代表收 secret value、改 workflow、啟用 runner 或 primary approval | -| S4.13 Source Control Owner Response Validation Rollup | 完成草案 | 已建立 validation rollup schema / snapshot / 人讀版;彙整 S4.9 / S4.10 / S4.11 / S4.12 四包 response packets、4 條 missing response lanes、4 步 owner response collection order、22 個 response templates、10 個 cross-packet checks、40 個 rejection rules、received / accepted / rejected response 皆為 0、execution authorized=false;latest local validation 為 `SOURCE_CONTROL_OWNER_RESPONSE_GUARD_OK` | AwoooP 可顯示四包 owner response 驗收總覽、缺口摘要、建議收件順序與 quarantine rules;rollup 不代表 approval、runtime gate、repo / refs / workflow / secret / runner 執行授權或 primary approval | +| S4.13 Source Control Owner Response Validation Rollup | 完成草案 | 已建立 validation rollup schema / snapshot / 人讀版;彙整 S4.9 / S4.10 / S4.11 / S4.12 四包 response packets、4 條 missing response lanes、4 步 owner response collection order、next collection candidate、22 個 response templates、10 個 cross-packet checks、40 個 rejection rules、received / accepted / rejected response 皆為 0、execution authorized=false;latest local validation 為 `SOURCE_CONTROL_OWNER_RESPONSE_GUARD_OK` | AwoooP 可顯示四包 owner response 驗收總覽、缺口摘要、建議收件順序、下一個建議收件項目與 quarantine rules;rollup 不代表 approval、runtime gate、repo / refs / workflow / secret / runner 執行授權或 primary approval | | S4.4 GitHub Primary rollback ADR | 完成草案 | 已建立 rollback ADR schema / snapshot / 人讀版;7 個 in-scope rollback drafts、0 owner approved、0 dry-run completed、0 active cutover | repo owner 審查 rollback owner、validation window 與 triggers;仍不可切 primary 或執行 rollback | | S4.5 Gitea 認證清冊匯出請求 | 完成草案 | 已建立匯出請求 schema / snapshot / 人讀版;目前未認證公開範圍 repo 2 個、本機可見 Gitea unique repo 4 個、覆蓋缺口 2 個、匯出來源選項 2 類;允許收集 token value=false | repo owner 依只讀 token API 或已脫敏管理匯出補私有 / 內部全量 repo list;仍不可保存 token、不可 write Gitea、不可 refs sync | | S4.6 Gitea 認證清冊匯入驗收契約 | 完成草案 | 已建立匯入驗收 schema / snapshot / 人讀版;目前 received payload 0、accepted 0、rejected 0;定義 10 個驗收檢查、10 個拒收規則與 4 個 quarantine lanes | owner 提供脫敏 payload 後先驗收 / 拒收 / 隔離;仍不可把驗收當 primary approval | diff --git a/docs/security/SOURCE-CONTROL-OWNER-RESPONSE-VALIDATION-ROLLUP.md b/docs/security/SOURCE-CONTROL-OWNER-RESPONSE-VALIDATION-ROLLUP.md index 148fbcb4..5da21e59 100644 --- a/docs/security/SOURCE-CONTROL-OWNER-RESPONSE-VALIDATION-ROLLUP.md +++ b/docs/security/SOURCE-CONTROL-OWNER-RESPONSE-VALIDATION-ROLLUP.md @@ -80,6 +80,18 @@ S4.13 不新增第 36 個主 contract,不新增 approval item,不啟用 runt 這個順序只讓 AwoooP 顯示下一個建議收件項目,不是 approval queue、不是 execution queue,也不授權任何 repo、refs、workflow、secret、runner 或 primary 動作。 +## 2.3 下一個建議收件項目 + +| 欄位 | 內容 | +|------|------| +| 下一步 | S4.9 Gitea owner attestation response | +| 需要回覆 | 5 個 Gitea coverage attestation items | +| 顯示模式 | `display_next_collection_item_only` | +| 目前 received / accepted | `0 / 0` | +| 仍禁止 | 不收 token value、不寫 Gitea、不 sync refs、不切 GitHub primary | + +`next_collection_candidate` 只讓 AwoooP Operator Console 顯示「現在先收 S4.9」。它不是批准、不是執行排程,也不是後續 S4.10 / S4.11 / S4.12 已可接受的訊號。 + ## 3. Cross-Packet 驗收規則 1. 四個 source response packets 都必須可解析,且 summary 欄位存在。 diff --git a/docs/security/security-mirror-readiness.snapshot.json b/docs/security/security-mirror-readiness.snapshot.json index c74f7f38..346706fd 100644 --- a/docs/security/security-mirror-readiness.snapshot.json +++ b/docs/security/security-mirror-readiness.snapshot.json @@ -203,7 +203,7 @@ "docs/security/SECURITY-MIRROR-STATUS-ROLLUP.md", "docs/security/SOURCE-CONTROL-OWNER-RESPONSE-VALIDATION-ROLLUP.md" ], - "notes": "提供 AwoooP / Security Supply Chain 跨 Session 狀態總覽、下一個 gate 與禁止事項;S4.13 owner response validation rollup 可 mirror 四個 response packets、22 個 templates、received=0、accepted=0;不授權執行。" + "notes": "提供 AwoooP / Security Supply Chain 跨 Session 狀態總覽、下一個 gate 與禁止事項;S4.13 owner response validation rollup 可 mirror 四個 response packets、22 個 templates、received=0、accepted=0、next_collection_candidate=S4.9;不授權執行。" }, { "contract": "coding_task_v1", diff --git a/docs/security/security-mirror-status-rollup.snapshot.json b/docs/security/security-mirror-status-rollup.snapshot.json index d7a8fc6b..1685702f 100644 --- a/docs/security/security-mirror-status-rollup.snapshot.json +++ b/docs/security/security-mirror-status-rollup.snapshot.json @@ -143,8 +143,8 @@ { "phase_id": "S4_migration_execution", "state": "not_started", - "current_result": "GitHub primary 是長期方向;source_control_primary_readiness_gate_v1 已定義 8 個 candidate repos、7 個 in-scope blocked repos、0 個 primary ready;S4.1 已定義 workflow / secret 名稱 inventory 契約;S4.2 已補 local evidence;S4.3 已補 redacted export request;S4.4 已補 rollback ADR 草案;S4.5 已補 Gitea authenticated inventory export request;S4.6 已補 redacted import acceptance;S4.7 已補 owner coverage attestation request;S4.9 已補 Gitea owner response intake packet;S4.10 已補 GitHub target owner decision response intake packet;S4.11 已補 refs truth owner response intake packet;S4.12 已補 workflow / secret 名稱 owner response intake packet;S4.13 已補四包 owner response validation rollup,彙整 22 個 templates、received=0、accepted=0,但 inventory status 仍 partial,GitHub target / refs truth / workflow-secret response 仍 0 筆。", - "next_gate": "依 S4.13 先集中檢查四包 owner response validation 狀態,再依 S4.9 收到並驗收 S4.7 Gitea owner response、依 S4.10 收到並驗收 7 個 GitHub target owner / visibility / canonical response、依 S4.11 收到並驗收 5 個 refs truth owner response templates、依 S4.12 收到並驗收 5 個 workflow / secret 名稱 owner response templates、authenticated inventory payload 通過 S4.6 驗收、rollback ADR owner approval 與逐 repo 人工批准。" + "current_result": "GitHub primary 是長期方向;source_control_primary_readiness_gate_v1 已定義 8 個 candidate repos、7 個 in-scope blocked repos、0 個 primary ready;S4.1 已定義 workflow / secret 名稱 inventory 契約;S4.2 已補 local evidence;S4.3 已補 redacted export request;S4.4 已補 rollback ADR 草案;S4.5 已補 Gitea authenticated inventory export request;S4.6 已補 redacted import acceptance;S4.7 已補 owner coverage attestation request;S4.9 已補 Gitea owner response intake packet;S4.10 已補 GitHub target owner decision response intake packet;S4.11 已補 refs truth owner response intake packet;S4.12 已補 workflow / secret 名稱 owner response intake packet;S4.13 已補四包 owner response validation rollup,彙整 22 個 templates、received=0、accepted=0,並標示 next_collection_candidate=S4.9,但 inventory status 仍 partial,GitHub target / refs truth / workflow-secret response 仍 0 筆。", + "next_gate": "依 S4.13 先集中檢查四包 owner response validation 狀態,AwoooP 只顯示 next_collection_candidate=S4.9 Gitea owner attestation;再依 S4.9 收到並驗收 S4.7 Gitea owner response、依 S4.10 收到並驗收 7 個 GitHub target owner / visibility / canonical response、依 S4.11 收到並驗收 5 個 refs truth owner response templates、依 S4.12 收到並驗收 5 個 workflow / secret 名稱 owner response templates、authenticated inventory payload 通過 S4.6 驗收、rollback ADR owner approval 與逐 repo 人工批准。" } ], "next_safe_actions": [ @@ -401,7 +401,7 @@ "S4.10 只新增 GitHub target owner decision response 收件包;response_template_count=7、received_response_count=0、accepted_response_count=0,不把 response packet 當 repo creation、visibility change、refs sync 或 GitHub primary approval。", "S4.11 只新增 refs truth owner response 收件包;response_template_count=5、received_response_count=0、accepted_response_count=0,不把 response packet 當 refs sync、delete、force push 或 GitHub primary approval。", "S4.12 只新增 workflow / secret 名稱 owner response 收件包;response_template_count=5、received_response_count=0、accepted_response_count=0,不把 response packet 當 secret value collection、workflow modification、GitHub hosted runner enablement 或 GitHub primary approval。", - "S4.13 只新增 owner response validation rollup;response_packet_count=4、template_count=22、received_response_count=0、accepted_response_count=0、cross_packet_check_count=10,不把 rollup 當 approval、runtime gate 或 execution authorization。" + "S4.13 只新增 owner response validation rollup;response_packet_count=4、template_count=22、received_response_count=0、accepted_response_count=0、cross_packet_check_count=10、next_collection_candidate=S4.9,不把 rollup 當 approval、runtime gate 或 execution authorization。" ], "forbidden_actions": [ "start_kali_scan", diff --git a/docs/security/security-supply-chain-contract-manifest.snapshot.json b/docs/security/security-supply-chain-contract-manifest.snapshot.json index 64db32c4..bf5f0af8 100644 --- a/docs/security/security-supply-chain-contract-manifest.snapshot.json +++ b/docs/security/security-supply-chain-contract-manifest.snapshot.json @@ -346,7 +346,7 @@ "sync_refs", "store_secret_value" ], - "notes": "定義 AwoooP 與 Security Supply Chain Session 的共同狀態摘要;S4.13 已補 owner response validation rollup,彙整 S4.9/S4.10/S4.11/S4.12 共 22 個 response templates、received=0、accepted=0;只顯示階段、下一個 gate 與禁止事項,不授權執行。" + "notes": "定義 AwoooP 與 Security Supply Chain Session 的共同狀態摘要;S4.13 已補 owner response validation rollup,彙整 S4.9/S4.10/S4.11/S4.12 共 22 個 response templates、received=0、accepted=0、next_collection_candidate=S4.9;只顯示階段、下一個 gate 與禁止事項,不授權執行。" }, { "contract": "coding_task_v1", diff --git a/docs/security/source-control-owner-response-validation-rollup.snapshot.json b/docs/security/source-control-owner-response-validation-rollup.snapshot.json index fafceb88..294c93ff 100644 --- a/docs/security/source-control-owner-response-validation-rollup.snapshot.json +++ b/docs/security/source-control-owner-response-validation-rollup.snapshot.json @@ -305,6 +305,7 @@ "mirror_owner_response_validation_rollup", "display_cross_packet_counts", "display_missing_owner_response_lanes", + "display_next_collection_candidate", "route_invalid_response_to_quarantine", "update_read_only_readiness_wording_after_accepted_response" ], @@ -466,6 +467,34 @@ ] } ], + "next_collection_candidate": { + "order": 1, + "lane_id": "s4_9_gitea_inventory_owner_attestation_response", + "display_status": "next_owner_response_required", + "source_contract": "gitea_inventory_owner_attestation_response_v1", + "required_packet": "docs/security/GITEA-INVENTORY-OWNER-ATTESTATION-RESPONSE.md", + "required_response_template_count": 5, + "received_response_count": 0, + "accepted_response_count": 0, + "minimum_response": [ + "public-only/local gap disposition", + "org/user endpoint disposition", + "110 adjacent source scope", + "canonical owner", + "legacy/inaccessible disposition" + ], + "awooop_display_mode": "display_next_collection_item_only", + "why_next": "S4.9 是後續 GitHub target、refs truth 與 workflow / secret parity 判定的前置 scope / canonical owner 來源;未收到前不得推進後續 source-control owner response 接受狀態。", + "blocked_until_received": true, + "execution_authorized": false, + "not_approval": true, + "still_forbidden": [ + "store_token_value", + "write_gitea_repo", + "sync_refs", + "switch_github_primary" + ] + }, "latest_local_validation": { "status": "repo_snapshot_guard_pass", "date": "2026-05-18", diff --git a/scripts/security/security-mirror-progress-guard.py b/scripts/security/security-mirror-progress-guard.py index 6d4c7866..0f99eaa0 100755 --- a/scripts/security/security-mirror-progress-guard.py +++ b/scripts/security/security-mirror-progress-guard.py @@ -87,6 +87,34 @@ def validate(root: Path) -> None: assert_false("owner_rollup.github_primary_switch_authorized", owner_summary["github_primary_switch_authorized"]) assert_false("owner_rollup.action_buttons_allowed", owner_summary["action_buttons_allowed"]) + next_candidate = owner_rollup["next_collection_candidate"] + assert_equal("owner_rollup.next_collection_candidate.order", next_candidate["order"], 1) + assert_equal( + "owner_rollup.next_collection_candidate.lane_id", + next_candidate["lane_id"], + "s4_9_gitea_inventory_owner_attestation_response", + ) + assert_equal( + "owner_rollup.next_collection_candidate.display_status", + next_candidate["display_status"], + "next_owner_response_required", + ) + assert_equal( + "owner_rollup.next_collection_candidate.required_response_template_count", + next_candidate["required_response_template_count"], + 5, + ) + assert_equal("owner_rollup.next_collection_candidate.received_response_count", next_candidate["received_response_count"], 0) + assert_equal("owner_rollup.next_collection_candidate.accepted_response_count", next_candidate["accepted_response_count"], 0) + assert_equal( + "owner_rollup.next_collection_candidate.awooop_display_mode", + next_candidate["awooop_display_mode"], + "display_next_collection_item_only", + ) + assert_true("owner_rollup.next_collection_candidate.blocked_until_received", next_candidate["blocked_until_received"]) + assert_false("owner_rollup.next_collection_candidate.execution_authorized", next_candidate["execution_authorized"]) + assert_true("owner_rollup.next_collection_candidate.not_approval", next_candidate["not_approval"]) + owner_local_validation = owner_rollup["latest_local_validation"] assert_equal("owner_rollup.latest_local_validation.status", owner_local_validation["status"], "repo_snapshot_guard_pass") assert_equal("owner_rollup.latest_local_validation.scope", owner_local_validation["scope"], "repo_snapshot_only") diff --git a/scripts/security/source-control-owner-response-guard.py b/scripts/security/source-control-owner-response-guard.py index bce015c6..4919585d 100755 --- a/scripts/security/source-control-owner-response-guard.py +++ b/scripts/security/source-control-owner-response-guard.py @@ -136,6 +136,7 @@ def validate(root: Path) -> None: lane_by_id = {lane["lane_id"]: lane for lane in rollup["validation_lanes"]} missing_lane_by_id = {lane["lane_id"]: lane for lane in rollup["missing_response_lanes"]} collection_order_by_id = {item["lane_id"]: item for item in rollup["owner_response_collection_order"]} + next_collection_candidate = rollup["next_collection_candidate"] total_templates = 0 total_acceptance_checks = 0 total_rejection_rules = 0 @@ -195,6 +196,52 @@ def validate(root: Path) -> None: assert_equal("missing_response_lanes.count", len(missing_lane_by_id), len(LANES)) assert_equal("owner_response_collection_order.count", len(collection_order_by_id), len(LANES)) + first_lane = LANES[0] + first_collection_item = collection_order_by_id[first_lane["lane_id"]] + first_missing_lane = missing_lane_by_id[first_lane["lane_id"]] + assert_equal("next_collection_candidate.order", next_collection_candidate["order"], 1) + assert_equal("next_collection_candidate.lane_id", next_collection_candidate["lane_id"], first_lane["lane_id"]) + assert_equal( + "next_collection_candidate.display_status", + next_collection_candidate["display_status"], + "next_owner_response_required", + ) + assert_equal( + "next_collection_candidate.source_contract", + next_collection_candidate["source_contract"], + first_missing_lane["source_contract"], + ) + assert_equal( + "next_collection_candidate.required_packet", + next_collection_candidate["required_packet"], + first_collection_item["required_packet"], + ) + assert_equal( + "next_collection_candidate.required_response_template_count", + next_collection_candidate["required_response_template_count"], + first_lane["expected_templates"], + ) + assert_equal("next_collection_candidate.received_response_count", next_collection_candidate["received_response_count"], 0) + assert_equal("next_collection_candidate.accepted_response_count", next_collection_candidate["accepted_response_count"], 0) + assert_equal( + "next_collection_candidate.minimum_response", + next_collection_candidate["minimum_response"], + first_collection_item["minimum_response"], + ) + assert_equal( + "next_collection_candidate.awooop_display_mode", + next_collection_candidate["awooop_display_mode"], + "display_next_collection_item_only", + ) + assert_true("next_collection_candidate.blocked_until_received", next_collection_candidate["blocked_until_received"]) + assert_false("next_collection_candidate.execution_authorized", next_collection_candidate["execution_authorized"]) + assert_true("next_collection_candidate.not_approval", next_collection_candidate["not_approval"]) + assert_equal( + "next_collection_candidate.still_forbidden", + next_collection_candidate["still_forbidden"], + first_collection_item["still_forbidden"], + ) + local_validation = rollup["latest_local_validation"] assert_equal("rollup.latest_local_validation.status", local_validation["status"], "repo_snapshot_guard_pass") assert_equal("rollup.latest_local_validation.scope", local_validation["scope"], "repo_snapshot_only")