docs(security): expose missing owner response lanes

This commit is contained in:
Your Name
2026-05-18 09:22:11 +08:00
parent f3b6972b29
commit db6c9195de
9 changed files with 146 additions and 4 deletions

View File

@@ -1,3 +1,19 @@
## 2026-05-18 | 資安供應鏈 S4.13Owner Response Missing Lanes
**背景**Owner response guard 已能確認四包 response 仍未收到;本輪補上 AwoooP 可直接顯示的 `missing_response_lanes`,讓 Operator Console 能把下一步缺口講清楚,而不是只顯示 guard pass。
**完成**
- `source_control_owner_response_validation_rollup_v1` schema 新增 optional `missing_response_lanes`
- `source-control-owner-response-validation-rollup.snapshot.json` 新增 4 條 missing lanes對應 S4.9 / S4.10 / S4.11 / S4.12,合計 22 個 response templates、received / accepted 皆為 0。
- `source-control-owner-response-guard.py` 反查 `missing_response_lanes` 與 source packets / rollup lanes 的 counts 必須一致。
- 更新 S4.13 人讀文件、AwoooP checklist、status rollup、progress 與 handoff。
**仍禁止**
- 不把 missing lane 當成 owner response 已收到。
- 不建立 GitHub repo、不修改 visibility、不寫 Gitea、不 sync/delete refs、不 force push、不切 GitHub primary。
- 不修改 workflow / webhook / runner / deploy key / branch protection / CODEOWNERS / repository secret。
- 不收 token value、secret value、private key、cookie、session 或未脫敏 payload。
## 2026-05-18 | 資安供應鏈 S2.6Dry-run 納入 Owner Response Guard
**背景**S4.13 已新增 owner response guard本輪把它接進 AwoooP mirror dry-run避免 AwoooP dry-run 只檢查 58% 進度估算,卻漏掉真正會推動 GitHub primary / refs / workflow-secret readiness 的 owner response 缺口。

View File

@@ -212,6 +212,41 @@
},
"minItems": 1
},
"missing_response_lanes": {
"type": "array",
"description": "AwoooP 可直接顯示的 owner response 缺口摘要;此欄位只供 read-only review不代表 response 已收到。",
"items": {
"type": "object",
"required": [
"lane_id",
"source_contract",
"response_template_count",
"received_response_count",
"accepted_response_count",
"current_status",
"next_owner_action",
"awooop_display_mode",
"still_forbidden"
],
"properties": {
"lane_id": {"type": "string"},
"source_contract": {"type": "string"},
"response_template_count": {"type": "integer", "minimum": 0},
"received_response_count": {"type": "integer", "minimum": 0},
"accepted_response_count": {"type": "integer", "minimum": 0},
"current_status": {"type": "string", "enum": ["waiting_owner_response"]},
"next_owner_action": {"type": "string"},
"awooop_display_mode": {"type": "string", "enum": ["observe_missing_response"]},
"still_forbidden": {
"type": "array",
"items": {"type": "string"},
"minItems": 1
}
},
"additionalProperties": false
},
"minItems": 1
},
"allowed_outputs": {
"type": "array",
"items": {"type": "string"},

View File

@@ -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、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、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 |
@@ -112,7 +112,7 @@ AwoooP 初期不得直接啟動掃描、不得呼叫 Codex patch runner、不得
| `security_mirror_quarantine_v1.status=draft` | `observe` | 顯示 5 個 quarantine lanes、recovery request 與 retry gate不得自動重試失敗 payload |
| `security_mirror_dry_run_v1.dry_run_status=contract_defined_not_executed` | `observe` | 顯示 8 個 dry-run steps 與 `latest_local_validation.status=repo_snapshot_guard_pass``CHECK_PROGRESS_GUARD` 必須維持 58% 不是執行授權,`CHECK_OWNER_RESPONSE_GUARD` 必須維持 owner response received / accepted 皆為 0不得視為 production ingestion 已啟用 |
| `security_mirror_status_rollup_v1.rollup_status=framework_ready_waiting_approval` | `observe` | 顯示 S0-S4 階段、58% 進度估算、approval queue summary 與下一個 gate不得新增 execution action |
| `source_control_owner_response_validation_rollup_v1.status=draft_waiting_owner_responses` | `observe` | 顯示四包 owner response packets、22 個 templates、received / accepted / rejected 皆為 0`latest_local_validation.result=SOURCE_CONTROL_OWNER_RESPONSE_GUARD_OK`;不得當成 approval 或 execution authorization |
| `source_control_owner_response_validation_rollup_v1.status=draft_waiting_owner_responses` | `observe` | 顯示四包 owner response packets、4 條 missing response lanes、22 個 templates、received / accepted / rejected 皆為 0`latest_local_validation.result=SOURCE_CONTROL_OWNER_RESPONSE_GUARD_OK`;不得當成 approval 或 execution authorization |
| `coding_task_v1.risk=LOW|MEDIUM` | `warn` | 可排入 Codex patch-only backlog |
| `coding_task_v1.risk=HIGH|CRITICAL` | `approve_required` | 必須指定 `critic``vuln-verifier` |
| `source_control_migration_event_v1.status=blocked` | `observe` | 顯示 blocking reason不允許切 primary |

View File

@@ -52,6 +52,8 @@ python3 scripts/security/source-control-owner-response-guard.py
此腳本只讀 S4.9 / S4.10 / S4.11 / S4.12 四包 response snapshots 與 S4.13 validation rollup確認目前 response received / accepted 仍為 0且 repo、refs、workflow、secret、runner、GitHub primary 與 runtime action 皆未授權。
AwoooP 顯示 S4.13 時,應把 `missing_response_lanes` 當成 Operator Console 的主要缺口摘要4 條 lane、22 個 response templates、目前 received / accepted 皆為 0。這只是在告訴 reviewer 下一步要補哪些 owner response不代表可以建立 repo、sync refs、修改 workflow / secret、啟用 runner或切 GitHub primary。
## 1. Session 分工
### AwoooP 主線 Session

View File

@@ -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 attestationS4.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 evidenceS4.3 補 7 個 repos、5 類 lanes 的 redacted export requestS4.12 補 5 個 owner response templates0 個 inventory complete、禁止收集 secret value、禁止 write token |
| Owner response validation | S4.13 已建立;四包 owner response 目前 received/accepted 皆為 0latest local validation 為 `SOURCE_CONTROL_OWNER_RESPONSE_GUARD_OK`,不代表 owner response 已收到或任何執行授權 |
| Owner response validation | S4.13 已建立;四包 owner response 目前 received/accepted 皆為 04 條 missing response lanes 可供 AwoooP 直接顯示;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` |

View File

@@ -59,7 +59,7 @@ python3 scripts/security/security-mirror-progress-guard.py
| S4.2 Workflow / Secret 名稱 local evidence | 完成草案 | 已建立 local read-only collector 與 snapshot7 個 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 laneswebhook、runner、deploy key、branch protection / CODEOWNERS、repository secret name paritywrite 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 parityresponse 通過只更新 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、22 個 response templates、10 個 cross-packet checks、40 個 rejection rules、received / accepted / rejected response 皆為 0、execution authorized=falselatest local validation 為 `SOURCE_CONTROL_OWNER_RESPONSE_GUARD_OK` | AwoooP 可顯示四包 owner response 驗收總覽與 quarantine rulesrollup 不代表 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、22 個 response templates、10 個 cross-packet checks、40 個 rejection rules、received / accepted / rejected response 皆為 0、execution authorized=falselatest local validation 為 `SOURCE_CONTROL_OWNER_RESPONSE_GUARD_OK` | AwoooP 可顯示四包 owner response 驗收總覽、缺口摘要與 quarantine rulesrollup 不代表 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 |

View File

@@ -60,6 +60,15 @@ S4.13 不新增第 36 個主 contract不新增 approval item不啟用 runt
| S4.11 refs truth owner response | `SOURCE-CONTROL-REF-TRUTH-OWNER-RESPONSE.md` | 5 | 等待 response |
| S4.12 workflow / secret name owner response | `SOURCE-CONTROL-WORKFLOW-SECRET-NAME-OWNER-RESPONSE.md` | 5 | 等待 response |
## 2.1 AwoooP 可顯示的缺口摘要
| Lane | 缺口 | 下一步 | 仍禁止 |
|------|------|--------|--------|
| S4.9 Gitea owner attestation | 5 個 response templates 尚未收到 | Owner 回覆 5 個 Gitea coverage attestation items只引用脫敏 evidence refs | 不收 token value、不寫 Gitea、不 sync refs、不切 primary |
| S4.10 GitHub target decision | 7 個 response templates 尚未收到 | Owner 回覆 7 個 GitHub target 的 owner / visibility / canonical disposition | 不建 repo、不改 visibility、不 sync refs、不切 primary |
| S4.11 refs truth | 5 個 response templates 尚未收到 | Owner 回覆 refs truth、deprecated drift、release tags 與 GitHub-only refs disposition | 不 fetch / push / delete refs、不 force push、不切 primary |
| S4.12 workflow / secret name | 5 個 response templates 尚未收到 | Owner 回覆 webhook、runner、deploy key、branch protection / CODEOWNERS、secret name parity 的脫敏狀態 | 不收 secret value、不改 workflow、不啟用 runner、不切 primary |
## 3. Cross-Packet 驗收規則
1. 四個 source response packets 都必須可解析,且 summary 欄位存在。

View File

@@ -308,6 +308,74 @@
"route_invalid_response_to_quarantine",
"update_read_only_readiness_wording_after_accepted_response"
],
"missing_response_lanes": [
{
"lane_id": "s4_9_gitea_inventory_owner_attestation_response",
"source_contract": "gitea_inventory_owner_attestation_response_v1",
"response_template_count": 5,
"received_response_count": 0,
"accepted_response_count": 0,
"current_status": "waiting_owner_response",
"next_owner_action": "Owner 需依 S4.9 回覆 5 個 Gitea coverage attestation items且只能引用脫敏 evidence refs。",
"awooop_display_mode": "observe_missing_response",
"still_forbidden": [
"store_token_value",
"write_gitea_repo",
"sync_refs",
"switch_github_primary"
]
},
{
"lane_id": "s4_10_github_target_owner_decision_response",
"source_contract": "github_target_owner_decision_response_v1",
"response_template_count": 7,
"received_response_count": 0,
"accepted_response_count": 0,
"current_status": "waiting_owner_response",
"next_owner_action": "Owner 需依 S4.10 回覆 7 個 GitHub target 的 owner / visibility / canonical disposition。",
"awooop_display_mode": "observe_missing_response",
"still_forbidden": [
"create_github_repo",
"change_repo_visibility",
"sync_refs",
"switch_github_primary"
]
},
{
"lane_id": "s4_11_ref_truth_owner_response",
"source_contract": "source_control_ref_truth_owner_response_v1",
"response_template_count": 5,
"received_response_count": 0,
"accepted_response_count": 0,
"current_status": "waiting_owner_response",
"next_owner_action": "Owner 需依 S4.11 回覆 refs truth、deprecated drift、release tags 與 GitHub-only refs disposition。",
"awooop_display_mode": "observe_missing_response",
"still_forbidden": [
"fetch_refs",
"push_refs",
"delete_refs",
"force_push",
"switch_github_primary"
]
},
{
"lane_id": "s4_12_workflow_secret_name_owner_response",
"source_contract": "source_control_workflow_secret_name_owner_response_v1",
"response_template_count": 5,
"received_response_count": 0,
"accepted_response_count": 0,
"current_status": "waiting_owner_response",
"next_owner_action": "Owner 需依 S4.12 回覆 webhook、runner、deploy key、branch protection / CODEOWNERS、repository secret name parity 的脫敏狀態。",
"awooop_display_mode": "observe_missing_response",
"still_forbidden": [
"store_secret_value",
"modify_workflow",
"enable_runner",
"enable_github_hosted_runner",
"switch_github_primary"
]
}
],
"latest_local_validation": {
"status": "repo_snapshot_guard_pass",
"date": "2026-05-18",

View File

@@ -134,6 +134,7 @@ def validate(root: Path) -> None:
assert_false(f"rollup.{flag}", rollup_summary[flag])
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"]}
total_templates = 0
total_acceptance_checks = 0
total_rejection_rules = 0
@@ -142,6 +143,7 @@ def validate(root: Path) -> None:
snapshot = load_json(security_dir / lane["path"])
summary = snapshot["summary"]
rollup_lane = lane_by_id[lane["lane_id"]]
missing_lane = missing_lane_by_id[lane["lane_id"]]
assert_equal(f"{lane['lane_id']}.status", summary["owner_response_status"], "waiting_owner_response")
assert_equal(f"{lane['lane_id']}.response_template_count", summary["response_template_count"], lane["expected_templates"])
@@ -160,6 +162,15 @@ def validate(root: Path) -> None:
assert_equal(f"{lane['lane_id']}.rollup_received_response_count", rollup_lane["received_response_count"], 0)
assert_equal(f"{lane['lane_id']}.rollup_accepted_response_count", rollup_lane["accepted_response_count"], 0)
assert_equal(f"{lane['lane_id']}.rollup_rejected_response_count", rollup_lane["rejected_response_count"], 0)
assert_equal(f"{lane['lane_id']}.missing_current_status", missing_lane["current_status"], "waiting_owner_response")
assert_equal(
f"{lane['lane_id']}.missing_response_template_count",
missing_lane["response_template_count"],
lane["expected_templates"],
)
assert_equal(f"{lane['lane_id']}.missing_received_response_count", missing_lane["received_response_count"], 0)
assert_equal(f"{lane['lane_id']}.missing_accepted_response_count", missing_lane["accepted_response_count"], 0)
assert_equal(f"{lane['lane_id']}.missing_awooop_display_mode", missing_lane["awooop_display_mode"], "observe_missing_response")
for flag in lane["false_flags"]:
assert_false(f"{lane['lane_id']}.{flag}", summary[flag])
@@ -171,6 +182,7 @@ def validate(root: Path) -> None:
assert_equal("source_packets.total_templates", total_templates, rollup_summary["total_response_template_count"])
assert_equal("source_packets.total_acceptance_checks", total_acceptance_checks, rollup_summary["total_acceptance_check_count"])
assert_equal("source_packets.total_rejection_rules", total_rejection_rules, rollup_summary["total_rejection_rule_count"])
assert_equal("missing_response_lanes.count", len(missing_lane_by_id), len(LANES))
local_validation = rollup["latest_local_validation"]
assert_equal("rollup.latest_local_validation.status", local_validation["status"], "repo_snapshot_guard_pass")