fix(iwooos): 固定 s4.9 缺口稽核
All checks were successful
Code Review / ai-code-review (push) Successful in 15s

This commit is contained in:
Your Name
2026-06-14 22:31:27 +08:00
parent 8795c08d14
commit 4abc1fb893
6 changed files with 1082 additions and 5 deletions

View File

@@ -1,3 +1,38 @@
## 2026-06-14S4.9 owner response gap audit snapshot 與 public surface redaction guard 完成
**背景**:使用者指出 `/zh-TW/awooop/tenants` 曾把 raw repository owner / namespace 顯示在前台,且 IwoooS 風險卡容易讓人誤以為「看得到」就是「已處理」。本輪將這兩個問題納入 S4.9 owner response gate 的固定缺口稽核:前台 / public API / HTML / bundle / messages 不得顯示 raw namespace、個人識別、外部 raw namespace 或內部協作語句;風險卡必須標示仍卡在哪些 owner gate不得假性拉高進度。
**完成項目**
- 新增 `scripts/security/s4-9-owner-response-gap-audit.py`,產生 S4.9 owner response gap audit 的 machine-readable snapshot。
- 新增 `docs/security/s4-9-owner-response-gap-audit.snapshot.json`,固定 `current_requirement_gap_count=8``new_rule_count=7``rule_adjustment_count=7``priority_work_item_count=9`、S4.9 owner response gate `0%`、runtime gate `0`
- 新增 `docs/schemas/s4_9_owner_response_gap_audit_v1.schema.json`,明確禁止 request dispatch、owner response accepted、repo / refs / workflow / secret / runtime action。
- 更新 `docs/security/S4-9-OWNER-RESPONSE-GATE-CURRENT-GAP-AUDIT.md`,基準改為 `gitea/main=8795c08d`、runtime deploy marker `605fde43`、Tenants redaction code commit `4bbc5269`,並新增 public surface identity redaction、internal evidence private boundary 與 repo-local `MEMORY.md` 缺檔啟動例外。
- 更新 `scripts/security/source-control-owner-response-guard.py`,把 S4.9 gap audit snapshot 納入檢查8 個 gap id、7 條新增規範、7 條調整規範、9 個優先工作項、public surface forbidden display 與所有 false boundaries 都被鎖住。
**本地驗證**
- `python3 scripts/security/s4-9-owner-response-gap-audit.py --root . --generated-at 2026-06-14T22:35:00+08:00 --output docs/security/s4-9-owner-response-gap-audit.snapshot.json``S4_9_OWNER_RESPONSE_GAP_AUDIT_OK gaps=8 new_rules=7 adjustments=7 owner_gate=0 runtime_gate=0`
- `python3 scripts/security/source-control-owner-response-guard.py --root .``SOURCE_CONTROL_OWNER_RESPONSE_GUARD_OK`
- `python3 scripts/security/security-mirror-progress-guard.py --root .``SECURITY_MIRROR_PROGRESS_GUARD_OK`
- `python3 scripts/ops/doc-secrets-sanity-check.py docs .gitea``DOC_SECRET_SANITY_OK scanned_files=844`
- `python3 -m py_compile scripts/security/s4-9-owner-response-gap-audit.py scripts/security/source-control-owner-response-guard.py` 通過。
- `python3 -m json.tool docs/security/s4-9-owner-response-gap-audit.snapshot.json``docs/schemas/s4_9_owner_response_gap_audit_v1.schema.json` 通過。
- `git diff --check` 通過。
- 新增檔與 S4.9 gap audit 相關檔案 sensitive scanraw personal namespace、external raw namespace、in-app request phrase 與 approval-loop phrase 無命中。
**Production 驗證(沿用既有 deploy marker `605fde43`,本輪未變更前端 bundle**
- `/zh-TW/awooop/tenants?_v=8795c08d-s49-gap-prod-check` in-app browser current viewportraw personal namespace `false`、external raw namespace `false`、internal collaboration phrase `false``SRC-###` 可見、redaction boundary 可見;`innerWidth=1006``scrollWidth=1000``horizontalOverflow=false`
- `GET /api/v1/platform/tenants?_v=8795c08d-s49-gap-api-check`HTTP `200`raw personal namespace `false`、external raw namespace `false`、internal collaboration phrase `false`;第一筆 `github_repo=SRC-001``source_scope_id=SRC-001``source_namespace_redacted=true`boundaries 含 `repo_owner_namespace_redacted=true``raw_repository_namespace_visible=false``public_api_raw_repo_namespace_allowed=false`
- `/zh-TW/iwooos?_v=8795c08d-s49-gap-prod-check` in-app browser current viewportIwoooS、審查後修正候選、高價值配置矩陣與 runtime gate `0` 可見raw personal namespace `false`、external raw namespace `false`、internal collaboration phrase `false``innerWidth=1006``scrollWidth=1000``horizontalOverflow=false`
- Chrome mobile viewport `390x844``/zh-TW/awooop/tenants?_v=8795c08d-s49-gap-mobile``/zh-TW/iwooos?_v=8795c08d-s49-gap-mobile` 均 raw namespace `false`、internal collaboration phrase `false``scrollWidth=390``horizontalOverflow=false`IwoooS mobile 可見 runtime gate `0` 與審查後修正候選。
**完成度與邊界**
- S4.9 gap audit snapshot / schema / guard`100%`
- Public surface identity redaction guard`100%`
- Production readback / desktop / mobile sensitive scan`100%`
- S4.9 owner response gate`0%`request sent、owner response received / accepted / rejected 全部 `0`
- IwoooS headline維持 `64%`active runtime gate維持 `0`
- 這次沒有送 owner request、沒有收 owner response、沒有 repo creation、沒有 refs sync、沒有 workflow 修改、沒有 secret value collection、沒有 Nginx / Docker / host / firewall 寫操作、沒有 production deploy、沒有 runtime execution、沒有 action button。
## 2026-06-14AwoooP Tenants source namespace 脫敏正式驗證完成
**背景**`/zh-TW/awooop/tenants` 的「原始碼 / 專案庫範圍」曾直接顯示 raw repository owner / namespace屬於前台資訊揭露缺口。這次先做 P0 低摩擦修補:產品 API 與前台只顯示脫敏範圍代號raw owner / namespace 仍只允許留在內部只讀 evidence 文件,不出現在產品頁或瀏覽器 API payload。

View File

@@ -0,0 +1,198 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "urn:awoooi:s4-9-owner-response-gap-audit-v1",
"title": "S4.9 Owner Response Gap Audit v1",
"description": "S4.9 owner response gate 的只讀缺口稽核。此 schema 僅允許記錄不符合項、需新增規範、需調整規範與優先工作佇列,不授權 request dispatch、owner response accepted、repo / refs / workflow / secret / runtime action。",
"type": "object",
"required": [
"schema_version",
"generated_at",
"git_commit",
"status",
"mode",
"basis",
"summary",
"false_boundaries",
"public_surface_redaction_requirements",
"current_requirement_gaps",
"new_rules_required",
"rule_adjustments_required",
"priority_work_queue",
"next_safe_actions"
],
"properties": {
"schema_version": {
"const": "s4_9_owner_response_gap_audit_v1"
},
"generated_at": {
"type": "string"
},
"git_commit": {
"type": "string"
},
"status": {
"const": "gap_audit_ready_owner_gate_zero"
},
"mode": {
"const": "read_only_gap_audit_no_runtime_action"
},
"basis": {
"type": "object",
"required": [
"gitea_main_commit",
"latest_runtime_deploy_marker",
"latest_tenants_redaction_commit",
"latest_logbook_commit",
"source_control_rollup_date",
"source_control_rollup_templates",
"production_verification_required_for_frontend_changes"
],
"properties": {
"gitea_main_commit": {"type": "string"},
"latest_runtime_deploy_marker": {"type": "string"},
"latest_tenants_redaction_commit": {"type": "string"},
"latest_logbook_commit": {"type": "string"},
"source_control_rollup_date": {"type": "string"},
"source_control_rollup_templates": {"type": "integer"},
"production_verification_required_for_frontend_changes": {"type": "boolean", "const": true}
},
"additionalProperties": false
},
"summary": {
"type": "object",
"required": [
"current_requirement_gap_count",
"active_blocker_count",
"active_risk_or_process_gap_count",
"mitigated_needs_guard_count",
"new_rule_count",
"rule_adjustment_count",
"priority_work_item_count",
"s4_9_owner_response_gate_percent",
"request_sent_count",
"owner_response_received_count",
"owner_response_accepted_count",
"owner_response_rejected_count",
"runtime_gate_count",
"public_surface_redaction_guard_ready",
"public_surface_raw_namespace_allowed",
"work_session_transcript_public_allowed"
],
"properties": {
"current_requirement_gap_count": {"type": "integer", "minimum": 1},
"active_blocker_count": {"type": "integer", "minimum": 0},
"active_risk_or_process_gap_count": {"type": "integer", "minimum": 0},
"mitigated_needs_guard_count": {"type": "integer", "minimum": 0},
"new_rule_count": {"type": "integer", "minimum": 1},
"rule_adjustment_count": {"type": "integer", "minimum": 1},
"priority_work_item_count": {"type": "integer", "minimum": 1},
"s4_9_owner_response_gate_percent": {"type": "integer", "const": 0},
"request_sent_count": {"type": "integer", "const": 0},
"owner_response_received_count": {"type": "integer", "const": 0},
"owner_response_accepted_count": {"type": "integer", "const": 0},
"owner_response_rejected_count": {"type": "integer", "const": 0},
"runtime_gate_count": {"type": "integer", "const": 0},
"public_surface_redaction_guard_ready": {"type": "boolean", "const": true},
"public_surface_raw_namespace_allowed": {"type": "boolean", "const": false},
"work_session_transcript_public_allowed": {"type": "boolean", "const": false}
},
"additionalProperties": false
},
"false_boundaries": {
"type": "object",
"additionalProperties": {"type": "boolean", "const": false},
"minProperties": 1
},
"public_surface_redaction_requirements": {
"type": "object",
"required": [
"allowed_display",
"forbidden_display",
"required_fields_or_markers",
"verification"
],
"properties": {
"allowed_display": {"type": "array", "items": {"type": "string"}, "minItems": 1},
"forbidden_display": {"type": "array", "items": {"type": "string"}, "minItems": 1},
"required_fields_or_markers": {"type": "array", "items": {"type": "string"}, "minItems": 1},
"verification": {"type": "array", "items": {"type": "string"}, "minItems": 1}
},
"additionalProperties": false
},
"current_requirement_gaps": {
"type": "array",
"items": {"$ref": "#/$defs/gap_item"},
"minItems": 1
},
"new_rules_required": {
"type": "array",
"items": {"$ref": "#/$defs/rule_item"},
"minItems": 1
},
"rule_adjustments_required": {
"type": "array",
"items": {"$ref": "#/$defs/adjustment_item"},
"minItems": 1
},
"priority_work_queue": {
"type": "array",
"items": {"$ref": "#/$defs/work_item"},
"minItems": 1
},
"next_safe_actions": {
"type": "array",
"items": {"type": "string"},
"minItems": 1
}
},
"$defs": {
"gap_item": {
"type": "object",
"required": ["gap_id", "priority", "status", "requirement", "current_state", "required_next_step"],
"properties": {
"gap_id": {"type": "string"},
"priority": {"type": "string"},
"status": {"type": "string"},
"requirement": {"type": "string"},
"current_state": {"type": "string"},
"required_next_step": {"type": "string"}
},
"additionalProperties": false
},
"rule_item": {
"type": "object",
"required": ["rule_id", "priority", "rule", "verification"],
"properties": {
"rule_id": {"type": "string"},
"priority": {"type": "string"},
"rule": {"type": "string"},
"verification": {"type": "string"}
},
"additionalProperties": false
},
"adjustment_item": {
"type": "object",
"required": ["adjustment_id", "priority", "from_rule", "adjusted_rule"],
"properties": {
"adjustment_id": {"type": "string"},
"priority": {"type": "string"},
"from_rule": {"type": "string"},
"adjusted_rule": {"type": "string"}
},
"additionalProperties": false
},
"work_item": {
"type": "object",
"required": ["priority", "work_item", "completion_percent", "blocked_by", "next_validation"],
"properties": {
"priority": {"type": "string"},
"work_item": {"type": "string"},
"completion_percent": {"type": "integer", "minimum": 0, "maximum": 100},
"blocked_by": {"type": "string"},
"next_validation": {"type": "string"}
},
"additionalProperties": false
}
},
"additionalProperties": false
}

View File

@@ -2,11 +2,13 @@
| 項目 | 內容 |
|------|------|
| 日期 | 2026-06-13 |
| 基準 | `gitea/main=2afb7c0a fix(governance): harden agent evidence redaction` |
| 範圍 | S4.9 Gitea owner attestation response gateS4.13 owner response validation rollup |
| 日期 | 2026-06-14 |
| 基準 | `gitea/main=8795c08d docs(iwooos): 記錄 ssh network production 驗證 [skip ci]`runtime deploy marker `605fde43`Tenants redaction code commit `4bbc5269` |
| 範圍 | S4.9 Gitea owner attestation response gateS4.13 owner response validation rollup、public surface identity redaction boundary |
| 模式 | 只讀 committed snapshot / 文件稽核 |
| 不可誤讀 | 不是 request sent、不是 owner response received、不是 accepted、不是 repo / refs / workflow / secret / runtime 授權 |
| Machine-readable snapshot | `docs/security/s4-9-owner-response-gap-audit.snapshot.json` |
| Schema | `docs/schemas/s4_9_owner_response_gap_audit_v1.schema.json` |
## 1. 核心結論
@@ -14,6 +16,8 @@ S4.9 的基礎規範已存在,且已能被 `source-control-owner-response-guar
真正尚未完成的是「owner 回覆本身」。目前 `request_sent=false``received=0``accepted=0``rejected=0`,所以 S4.9 owner response gate 仍是 `0%`。任何 UI、request template、AwoooP 顯示、reviewer checklist 或 LOGBOOK 文字都不得把這個 gate 拉高。
本輪另外把使用者指出的前台資訊揭露問題納入 S4.9 缺口稽核前台、public API、HTML、bundle 與 messages 不得顯示個人 namespace、外部 raw namespace、工作視窗對話或內部 session 語句。AwoooP Tenants 已改成 `SRC-###` 脫敏範圍代號,但此規則必須持續由 guard 與 production desktop / mobile sensitive scan 保護。
## 2. 已符合目前要求
| 類別 | 現況 | 依據 |
@@ -25,12 +29,13 @@ S4.9 的基礎規範已存在,且已能被 `source-control-owner-response-guar
| 五題齊備才可 accepted | 已要求 5 個 response templates 都收到可驗收回覆,部分回覆只能 waiting 或 request_more_evidence | `preflight-all-five-items-before-accepted` |
| 四包收件順序 | S4.9 -> S4.10 -> S4.11 -> S4.12 已固定 | `source-control-owner-response-validation-rollup.snapshot.json` |
| 安全旗標 | token、secret、repo write、refs sync、GitHub primary、action button 全部 `false` | owner response guard |
| Public surface redaction | `/zh-TW/awooop/tenants``GET /api/v1/platform/tenants` 已改用 `SRC-###``source_scope_id``source_namespace_redacted=true` | `security-mirror-progress-guard.py`、production desktop / mobile verification |
## 3. 目前仍不符合最新推進要求
| 缺口 | 影響 | 下一步 |
|------|------|--------|
| P0 主控總帳與缺口稽核基準需跟上最新 `gitea/main` | 平行 Session 已推進 P0-PUBLICENV public host alias redaction、P2-105 critic / reviewer result capture、governance evidence redaction hardening 與多次正式 Browser smoke舊 commit 基準會讓新 Session 誤判下一步 | 本輪已更新到 `2afb7c0a`;最新 S4.9 仍是等待 owner response後續每次推送前仍需 fetch、讀 LOGBOOK 最新段落與同步 runs / deploy marker |
| P0 主控總帳與缺口稽核基準需跟上最新 `gitea/main` | 平行 Session 已推進 Tenants redaction、Backup / Restore、Public Gateway、K8s / ArgoCD、SSH / network acceptance ledger 與 production Browser smoke舊 commit 基準會讓新 Session 誤判下一步 | 本輪已更新到 `gitea/main=8795c08d` 與 deploy marker `605fde43`;最新 S4.9 仍是等待 owner response後續每次推送前仍需 fetch、讀 LOGBOOK 最新段落與同步 runs / deploy marker |
| S4.9 gate 仍只有 request-ready沒有 owner response | IwoooS 64% 不能因規範存在而往前解鎖 | 維持 `0%`,只準備收件缺口,不調高 progress |
| S4.13 rollup 文件曾殘留舊模板總數 | Snapshot 已是 `5 + 9 + 5 + 5 = 24`,但文件仍可能寫成 `22`,會造成 reviewer 誤判 S4.10 目標數 | 已同步文件並把 `source-control-owner-response-guard.py` 納入文件一致性檢查 |
| request packet 的欄位名稱存在同義詞 | `affected_repos``affected_sources``affected_repos_or_sources_or_namespace``evidence_refs` 與使用者要求的 `affected_scope``redacted_evidence_refs` 容易在 UI / handoff 中混用 | 已補 `S4-9-CANONICAL-OWNER-RESPONSE-ENVELOPE.md`,後續顯示層以六欄 canonical envelope 呈現source templates 可保留細分欄位 |
@@ -38,6 +43,9 @@ S4.9 的基礎規範已存在,且已能被 `source-control-owner-response-guar
| 尚未有 owner response reviewer outcome | reviewer checklist 存在,但沒有任何可分類 response | 等脫敏 metadata 進來後,才能進補件、隔離、拒收、只讀更新候選 |
| 部分文件仍可能把近期 P2-403I/J/K 或資安 P1 工作誤當 S4.9 已解鎖 | 平行 Session 已推進 AI Agent 報表 / 告警路由,但 S4.9 owner response 仍是獨立 P0 gate | 後續 LOGBOOK / workplan 每次都標註平行 Session、最新基線與 S4.9 received / accepted 仍為 `0 / 0` |
| P0-PUBLICENV 與 P2-105 容易被誤讀為 S4.9 owner response | 公開主機 alias redaction、bundle clean、production smoke、critic / reviewer scorecard 都不是 owner role / team、decision、reason、scope、redacted refs、followup owner 的實際回覆 | 在 rollup 與 LOGBOOK 明確標記:這些進展不增加 request_sent、received、accepted 或 runtime gate |
| 前台 raw namespace 或工作視窗內容外洩 | 產品頁若直接顯示 raw source-control evidence會暴露個人 namespace、外部 namespace 或內部協作脈絡 | 已補 Tenants 脫敏;後續新增頁面 / API 必須先走 public surface redaction gate 與 production sensitive scan |
| 內部 evidence 與產品文案邊界不清 | `docs/security` 可能保留必要技術識別供內部稽核,但不得被直接接到前台渲染 | 前台只能顯示 redacted scope id、aggregate count、risk tier、readiness state、redacted evidence ref |
| repo-local `MEMORY.md` 缺檔 | 啟動規範要求讀 `MEMORY.md`,但本 release worktree 沒有此檔 | 已改讀全域 memory 摘要與 LOGBOOK後續需把此視為啟動程序缺口不得假稱 repo-local MEMORY.md 已讀 |
## 4. 需要新增或強化的規範
@@ -48,6 +56,9 @@ S4.9 的基礎規範已存在,且已能被 `source-control-owner-response-guar
| Request sent 與 received 分離 | request packet 顯示、人工送件、owner response received、accepted 必須是四個獨立狀態 | 已有規範,需在後續 audit metadata 實作時保持 |
| Quarantine-first 收件 | 疑似 token、secret、private key、cookie、session、authorization header、private URL credential、未脫敏截圖先隔離不渲染 raw payload | 已有規範,需維持 |
| 平行 Session 衝突規則 | 任一 Session 推送前必須 fetch / fast-forward 到最新 `gitea/main`,並同步 commit / run / production evidence / gate 0 false | 已執行,需持續 |
| Public surface redaction gate | 前台、public API、HTML、bundle、messages 不得出現 raw owner namespace、個人識別、外部 raw namespace 或工作視窗對話 | 已補 snapshot 與 guard 接入;每次前端 / API 變更需 production sensitive scan |
| Internal evidence private boundary | 內部 source-control raw evidence 只能留在 private evidence / docs不得直接作為產品渲染來源 | 已納入 `s4-9-owner-response-gap-audit.snapshot.json` |
| Machine-readable S4.9 gap audit | S4.9 缺口稽核不得只停在 MD必須有 snapshot 與 guard | 已新增 `s4_9_owner_response_gap_audit_v1` |
## 5. 下一個 owner response 需要補的五題
@@ -87,9 +98,11 @@ S4.9 的基礎規範已存在,且已能被 `source-control-owner-response-guar
| 工作 | 完成度 | 說明 |
|------|--------|------|
| S4.9 現況缺口稽核 | 100% | 已列出已符合、仍不符合、需新增、需調整、五題回覆與 0 / false 邊界 |
| S4.9 machine-readable gap audit snapshot | 100% | 已新增 `s4-9-owner-response-gap-audit.snapshot.json` 與 schema固定 `gaps=8``new_rules=7``adjustments=7`、owner gate `0`、runtime gate `0` |
| Public surface identity redaction boundary | 100% | Tenants 前台 / public API 已用 `SRC-###`;後續由 guard 與 production sensitive scan 持續保護 |
| S4.9 canonical owner response envelope | 100% | 已補六欄信封、alias 映射、五題投影、quarantine-first 與 reviewer checklist |
| S4.9 owner response gate | 0% | 沒有收到 owner response不得調高 |
| S4.9 基準與日期一致性 | 100% | 已跟到 `gitea/main=2afb7c0a`,並要求 guard 擋下過期 rollup 日期與舊模板公式 |
| S4.9 基準與日期一致性 | 100% | 已跟到 `gitea/main=8795c08d`、deploy marker `605fde43`,並要求 guard 擋下過期 rollup 日期與舊模板公式 |
| S4.13 rollup 文件一致性 | 100% | 已把 `22` 舊口徑修正為 `24`,並由 guard 檢查 |
| IwoooS 整體 | 維持 64% | 只讀稽核不改 runtime readiness |
| active runtime gate | 0 | 不變 |

View File

@@ -0,0 +1,307 @@
{
"basis": {
"gitea_main_commit": "8795c08d",
"latest_logbook_commit": "8795c08d",
"latest_runtime_deploy_marker": "605fde43",
"latest_tenants_redaction_commit": "4bbc5269",
"production_verification_required_for_frontend_changes": true,
"source_control_rollup_date": "2026-06-13",
"source_control_rollup_templates": 24
},
"current_requirement_gaps": [
{
"current_state": "request_sent=false、received=0、accepted=0、rejected=0。",
"gap_id": "s49_owner_response_absent",
"priority": "P0",
"required_next_step": "只能等待人工送件與 owner 脫敏回覆;不得用 UI、LOGBOOK 或 AwoooP approval 補成 accepted。",
"requirement": "S4.9 必須收到完整 owner response metadata且五題都通過 reviewer checklist。",
"status": "active_blocker"
},
{
"current_state": "audit event templates 存在,但 emitted_event_count=0。",
"gap_id": "s49_dispatch_audit_event_absent",
"priority": "P0",
"required_next_step": "送件前維持 0送件後只保存 metadata不保存 raw response body。",
"requirement": "request shown、request sent、owner response received、reviewer outcome 必須是分離 audit metadata。",
"status": "active_blocker"
},
{
"current_state": "尚無 owner responsereviewer outcome 仍是 template-only。",
"gap_id": "s49_reviewer_outcome_absent",
"priority": "P0",
"required_next_step": "補 reviewer outcome ledger但不得因此開 runtime gate。",
"requirement": "任何 owner response 都要先分類為 waiting、supplement、quarantine、reject 或 read-only update candidate。",
"status": "active_blocker"
},
{
"current_state": "AwoooP Tenants 已改用 SRC-###;仍需由 guard 固定 public surface redaction 規則。",
"gap_id": "public_surface_identity_leak_risk",
"priority": "P0",
"required_next_step": "持續跑 security mirror guard新增頁面或 API payload 時一律先做 sensitive public-surface scan。",
"requirement": "前台與瀏覽器 API 不得顯示個人 namespace、外部 org namespace、工作視窗對話或內部 session 語句。",
"status": "mitigated_needs_guard"
},
{
"current_state": "部分 docs/security source-control evidence 仍有 raw repo identifiers屬內部 evidence需要明確 public/private boundary。",
"gap_id": "raw_namespace_internal_evidence_misroute_risk",
"priority": "P0",
"required_next_step": "所有前台資料源必須使用 redacted scope id 或 evidence ref不直接讀 raw source-control evidence。",
"requirement": "內部 source-control evidence 可保留必要技術識別但不得被路由到產品頁、public API、公開 bundle 或截圖文案。",
"status": "active_risk"
},
{
"current_state": "舊 MD 仍提到 2026-06-13 與舊基準;本 snapshot 將基準更新到目前 release worktree。",
"gap_id": "latest_basis_staleness_risk",
"priority": "P0",
"required_next_step": "每次推送前 fetch gitea 並更新 basis不得沿用舊 commit 宣稱最新。",
"requirement": "S4.9 缺口稽核基準需跟上最新 gitea/main、deploy marker、production verification 與 LOGBOOK。",
"status": "remediated_by_this_snapshot"
},
{
"current_state": "本輪已 fetch 且 worktree 與 gitea/main 一致;仍需每次推送前重查。",
"gap_id": "parallel_session_conflict_risk",
"priority": "P0",
"required_next_step": "禁止 force push若 gitea/main 前進,只能 fast-forward / rebase 正常收斂。",
"requirement": "另一個 AwoooP Session 與本 Session 的 commit、run、deploy marker、production evidence 必須同步。",
"status": "active_risk"
},
{
"current_state": "此 release worktree 未包含 repo-local MEMORY.md。",
"gap_id": "release_worktree_memory_index_absent",
"priority": "P1",
"required_next_step": "把缺檔視為啟動程序缺口,不阻擋只讀工作,但不得聲稱已讀 repo-local MEMORY.md。",
"requirement": "Session 啟動必讀 MEMORY.md若 release worktree 缺檔,必須改讀全域 memory 與 LOGBOOK並記錄例外。",
"status": "active_process_gap"
}
],
"false_boundaries": {
"action_buttons_allowed": false,
"force_push_authorized": false,
"owner_response_accepted": false,
"owner_response_received": false,
"raw_namespace_public_surface_allowed": false,
"redacted_payload_ingested": false,
"refs_sync_authorized": false,
"repo_creation_authorized": false,
"request_dispatch_authorized": false,
"request_sent": false,
"runner_enablement_authorized": false,
"runtime_execution_authorized": false,
"secret_value_collection_allowed": false,
"visibility_change_authorized": false,
"work_session_transcript_public_allowed": false,
"workflow_modification_authorized": false
},
"generated_at": "2026-06-14T22:35:00+08:00",
"git_commit": "8795c08d",
"mode": "read_only_gap_audit_no_runtime_action",
"new_rules_required": [
{
"priority": "P0",
"rule": "前台、public API、HTML、bundle、messages 不得出現 raw owner namespace、個人識別或工作視窗對話。",
"rule_id": "public_surface_redaction_gate",
"verification": "security-mirror-progress-guard + production desktop/mobile sensitive scan。"
},
{
"priority": "P0",
"rule": "S4.9 現況缺口稽核不得只停在 MD必須有 machine-readable snapshot 與 guard。",
"rule_id": "s49_gap_audit_snapshot_required",
"verification": "source-control-owner-response-guard 必須讀取本 snapshot。"
},
{
"priority": "P0",
"rule": "內部 source-control raw evidence 僅能留在 private docs / committed evidence不得直接成為產品渲染來源。",
"rule_id": "raw_evidence_private_boundary",
"verification": "前台只讀 redacted scope id、evidence ref 或 aggregate count。"
},
{
"priority": "P0",
"rule": "owner response received / accepted / rejected 只能由 reviewer record 更新,不得由 request draft、UI 或 LOGBOOK 文字更新。",
"rule_id": "owner_response_counts_are_runtime_locked",
"verification": "所有 snapshot false boundaries 維持 0 / false。"
},
{
"priority": "P0",
"rule": "request ready、request sent、response received、response accepted、runtime approval 必須是五個獨立狀態。",
"rule_id": "dispatch_received_accepted_separation",
"verification": "summary counters 必須分離,且 runtime gate 永遠等待獨立批准。"
},
{
"priority": "P0",
"rule": "每次 commit / push 前必須 fetch gitea並同步另一 Session 的 run / deploy / production evidence。",
"rule_id": "parallel_session_basis_refresh",
"verification": "LOGBOOK 必須記錄 basis、runs、deploy marker 與 gate 邊界。"
},
{
"priority": "P1",
"rule": "repo-local MEMORY.md 缺檔時,需記錄使用全域 memory 與 LOGBOOK 的替代讀取路徑。",
"rule_id": "memory_index_startup_exception",
"verification": "啟動記錄不得假稱 repo-local MEMORY.md 已讀。"
}
],
"next_safe_actions": [
"更新 S4.9 缺口稽核文件基準與 snapshot reference。",
"把本 snapshot 納入 source-control owner response guard。",
"繼續補 owner response acceptance ledger但所有 request / received / accepted / runtime gate 維持 0 / false。"
],
"priority_work_queue": [
{
"blocked_by": "尚未人工送件、尚未收到 owner response。",
"completion_percent": 70,
"next_validation": "source-control-owner-response-guard。",
"priority": "P0-1",
"work_item": "S4.9 owner response gate 收件前置"
},
{
"blocked_by": "後續新增頁面仍需 guard 持續保護。",
"completion_percent": 100,
"next_validation": "production desktop/mobile sensitive scan。",
"priority": "P0-2",
"work_item": "前台 / public API identity redaction"
},
{
"blocked_by": "尚缺 owner-provided live conf、rendered diff、nginx -t evidence、route smoke、maintenance window、rollback owner。",
"completion_percent": 86,
"next_validation": "public gateway acceptance snapshot + owner-provided evidence review。",
"priority": "P0-3",
"work_item": "Nginx public gateway owner response acceptance"
},
{
"blocked_by": "尚缺 ArgoCD health readback、rendered manifest diff、rollback revision、owner response。",
"completion_percent": 62,
"next_validation": "k8s-argocd owner response acceptance snapshot。",
"priority": "P0-4",
"work_item": "K8s / ArgoCD owner response acceptance"
},
{
"blocked_by": "尚缺 restore drill approval package、offsite owner、escrow owner、retention owner、validation plan。",
"completion_percent": 62,
"next_validation": "backup restore acceptance snapshot。",
"priority": "P0-5",
"work_item": "Backup / restore / escrow owner response acceptance"
},
{
"blocked_by": "尚缺 110 / 188 live hash、restart window、rollback owner、post-check 指標。",
"completion_percent": 50,
"next_validation": "host service owner request / future acceptance ledger。",
"priority": "P1-1",
"work_item": "Docker Compose / systemd / host service owner response"
},
{
"blocked_by": "尚缺 live access state、allowed source CIDR、host key pinning、firewall owner、NetworkPolicy / NodePort / WireGuard owner。",
"completion_percent": 58,
"next_validation": "ssh network acceptance snapshot。",
"priority": "P1-2",
"work_item": "SSH / firewall / network access owner response acceptance"
},
{
"blocked_by": "尚缺 live drift evidence、receiver owner、reload owner、route smoke、receipt proof。",
"completion_percent": 62,
"next_validation": "monitoring owner request / future acceptance ledger。",
"priority": "P1-3",
"work_item": "Monitoring / alerting / observability owner response"
},
{
"blocked_by": "尚缺 deployment boundary、external agent boundary、treasury owner、runtime gate owner。",
"completion_percent": 68,
"next_validation": "agent bounty owner request draft 與 future acceptance ledger。",
"priority": "P1-4",
"work_item": "agent-bounty-protocol C0 runtime / MCP / A2A / treasury owner response"
}
],
"public_surface_redaction_requirements": {
"allowed_display": [
"SRC-### scope id",
"aggregate count",
"risk tier",
"readiness state",
"redacted evidence ref"
],
"forbidden_display": [
"raw repository owner namespace",
"personal namespace",
"external organization namespace when not explicitly public-safe",
"工作視窗對話內容",
"approval chat phrase",
"token / secret / private key / cookie / authorization header"
],
"required_fields_or_markers": [
"source_scope_id",
"source_namespace_redacted",
"repo_owner_namespace_redacted",
"raw_repository_namespace_visible",
"public_api_raw_repo_namespace_allowed"
],
"verification": [
"public API payload sensitive scan",
"production HTML sensitive scan",
"desktop browser sensitive scan",
"mobile browser sensitive scan",
"horizontal overflow check"
]
},
"rule_adjustments_required": [
{
"adjusted_rule": "低摩擦不代表延後修補即時資訊揭露public surface leak 可先 source-control 止血,再補 owner gate。",
"adjustment_id": "low_friction_but_p0_stop_the_bleed",
"from_rule": "初期資安低摩擦、先只讀框架。",
"priority": "P0"
},
{
"adjusted_rule": "技術識別只能留在內部 evidence產品頁只顯示 redacted scope id、風險等級、狀態與 evidence ref。",
"adjustment_id": "internal_evidence_not_product_copy",
"from_rule": "source-control evidence 可保留技術識別。",
"priority": "P0"
},
{
"adjusted_rule": "AwoooP approval、Runs、Work Items、Tenants 顯示全部只算狀態,不等於 IwoooS security acceptance。",
"adjustment_id": "awooop_approval_not_security_acceptance",
"from_rule": "AwoooP 可顯示 owner response / approval 候選。",
"priority": "P0"
},
{
"adjusted_rule": "Nginx / public gateway / DNS / TLS 是 C0優先要求 source-of-truth、drift evidence、owner response、rollback 與 post-check。",
"adjustment_id": "nginx_config_control_first",
"from_rule": "高價值配置逐步納管。",
"priority": "P0"
},
{
"adjusted_rule": "即使 owner 文字包含同意、批准、OK也只算 metadata decision不自動授權 refs sync、reload、deploy 或 runtime action。",
"adjustment_id": "owner_response_language_not_execution",
"from_rule": "owner 可回覆 decision。",
"priority": "P0"
},
{
"adjusted_rule": "改前端或 public API 後必須做 production desktop/mobile sensitive scan、水平溢出檢查與關鍵卡片可見檢查。",
"adjustment_id": "public_verification_required_after_frontend_change",
"from_rule": "改前端後做 smoke。",
"priority": "P0"
},
{
"adjusted_rule": "agent-bounty-protocol 需以 C0 runtime / MCP / A2A / treasury 邊界管理,但保持獨立產品與 owner response。",
"adjustment_id": "agent_bounty_c0_runtime_boundary",
"from_rule": "agent-bounty-protocol 納入 IwoooS scope。",
"priority": "P1"
}
],
"schema_version": "s4_9_owner_response_gap_audit_v1",
"status": "gap_audit_ready_owner_gate_zero",
"summary": {
"active_blocker_count": 3,
"active_risk_or_process_gap_count": 3,
"current_requirement_gap_count": 8,
"mitigated_needs_guard_count": 1,
"new_rule_count": 7,
"owner_response_accepted_count": 0,
"owner_response_received_count": 0,
"owner_response_rejected_count": 0,
"priority_work_item_count": 9,
"public_surface_raw_namespace_allowed": false,
"public_surface_redaction_guard_ready": true,
"request_sent_count": 0,
"rule_adjustment_count": 7,
"runtime_gate_count": 0,
"s4_9_owner_response_gate_percent": 0,
"work_session_transcript_public_allowed": false
}
}

View File

@@ -0,0 +1,397 @@
#!/usr/bin/env python3
"""
S4.9 owner response gate 現況缺口稽核 snapshot 產生器。
本工具只讀 committed snapshot、文件與 git metadata整理哪些要求仍未符合、
哪些規範需新增、哪些規範需調整。它不送 owner request、不收 owner response、
不連 Gitea / GitHub、不讀 secret、不做 runtime action。
"""
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))
FALSE_BOUNDARIES = {
"request_dispatch_authorized": False,
"request_sent": False,
"owner_response_received": False,
"owner_response_accepted": False,
"redacted_payload_ingested": False,
"repo_creation_authorized": False,
"visibility_change_authorized": False,
"refs_sync_authorized": False,
"force_push_authorized": False,
"workflow_modification_authorized": False,
"runner_enablement_authorized": False,
"secret_value_collection_allowed": False,
"raw_namespace_public_surface_allowed": False,
"work_session_transcript_public_allowed": False,
"runtime_execution_authorized": False,
"action_buttons_allowed": False,
}
CURRENT_REQUIREMENT_GAPS = [
{
"gap_id": "s49_owner_response_absent",
"priority": "P0",
"status": "active_blocker",
"requirement": "S4.9 必須收到完整 owner response metadata且五題都通過 reviewer checklist。",
"current_state": "request_sent=false、received=0、accepted=0、rejected=0。",
"required_next_step": "只能等待人工送件與 owner 脫敏回覆;不得用 UI、LOGBOOK 或 AwoooP approval 補成 accepted。",
},
{
"gap_id": "s49_dispatch_audit_event_absent",
"priority": "P0",
"status": "active_blocker",
"requirement": "request shown、request sent、owner response received、reviewer outcome 必須是分離 audit metadata。",
"current_state": "audit event templates 存在,但 emitted_event_count=0。",
"required_next_step": "送件前維持 0送件後只保存 metadata不保存 raw response body。",
},
{
"gap_id": "s49_reviewer_outcome_absent",
"priority": "P0",
"status": "active_blocker",
"requirement": "任何 owner response 都要先分類為 waiting、supplement、quarantine、reject 或 read-only update candidate。",
"current_state": "尚無 owner responsereviewer outcome 仍是 template-only。",
"required_next_step": "補 reviewer outcome ledger但不得因此開 runtime gate。",
},
{
"gap_id": "public_surface_identity_leak_risk",
"priority": "P0",
"status": "mitigated_needs_guard",
"requirement": "前台與瀏覽器 API 不得顯示個人 namespace、外部 org namespace、工作視窗對話或內部 session 語句。",
"current_state": "AwoooP Tenants 已改用 SRC-###;仍需由 guard 固定 public surface redaction 規則。",
"required_next_step": "持續跑 security mirror guard新增頁面或 API payload 時一律先做 sensitive public-surface scan。",
},
{
"gap_id": "raw_namespace_internal_evidence_misroute_risk",
"priority": "P0",
"status": "active_risk",
"requirement": "內部 source-control evidence 可保留必要技術識別但不得被路由到產品頁、public API、公開 bundle 或截圖文案。",
"current_state": "部分 docs/security source-control evidence 仍有 raw repo identifiers屬內部 evidence需要明確 public/private boundary。",
"required_next_step": "所有前台資料源必須使用 redacted scope id 或 evidence ref不直接讀 raw source-control evidence。",
},
{
"gap_id": "latest_basis_staleness_risk",
"priority": "P0",
"status": "remediated_by_this_snapshot",
"requirement": "S4.9 缺口稽核基準需跟上最新 gitea/main、deploy marker、production verification 與 LOGBOOK。",
"current_state": "舊 MD 仍提到 2026-06-13 與舊基準;本 snapshot 將基準更新到目前 release worktree。",
"required_next_step": "每次推送前 fetch gitea 並更新 basis不得沿用舊 commit 宣稱最新。",
},
{
"gap_id": "parallel_session_conflict_risk",
"priority": "P0",
"status": "active_risk",
"requirement": "另一個 AwoooP Session 與本 Session 的 commit、run、deploy marker、production evidence 必須同步。",
"current_state": "本輪已 fetch 且 worktree 與 gitea/main 一致;仍需每次推送前重查。",
"required_next_step": "禁止 force push若 gitea/main 前進,只能 fast-forward / rebase 正常收斂。",
},
{
"gap_id": "release_worktree_memory_index_absent",
"priority": "P1",
"status": "active_process_gap",
"requirement": "Session 啟動必讀 MEMORY.md若 release worktree 缺檔,必須改讀全域 memory 與 LOGBOOK並記錄例外。",
"current_state": "此 release worktree 未包含 repo-local MEMORY.md。",
"required_next_step": "把缺檔視為啟動程序缺口,不阻擋只讀工作,但不得聲稱已讀 repo-local MEMORY.md。",
},
]
NEW_RULES_REQUIRED = [
{
"rule_id": "public_surface_redaction_gate",
"priority": "P0",
"rule": "前台、public API、HTML、bundle、messages 不得出現 raw owner namespace、個人識別或工作視窗對話。",
"verification": "security-mirror-progress-guard + production desktop/mobile sensitive scan。",
},
{
"rule_id": "s49_gap_audit_snapshot_required",
"priority": "P0",
"rule": "S4.9 現況缺口稽核不得只停在 MD必須有 machine-readable snapshot 與 guard。",
"verification": "source-control-owner-response-guard 必須讀取本 snapshot。",
},
{
"rule_id": "raw_evidence_private_boundary",
"priority": "P0",
"rule": "內部 source-control raw evidence 僅能留在 private docs / committed evidence不得直接成為產品渲染來源。",
"verification": "前台只讀 redacted scope id、evidence ref 或 aggregate count。",
},
{
"rule_id": "owner_response_counts_are_runtime_locked",
"priority": "P0",
"rule": "owner response received / accepted / rejected 只能由 reviewer record 更新,不得由 request draft、UI 或 LOGBOOK 文字更新。",
"verification": "所有 snapshot false boundaries 維持 0 / false。",
},
{
"rule_id": "dispatch_received_accepted_separation",
"priority": "P0",
"rule": "request ready、request sent、response received、response accepted、runtime approval 必須是五個獨立狀態。",
"verification": "summary counters 必須分離,且 runtime gate 永遠等待獨立批准。",
},
{
"rule_id": "parallel_session_basis_refresh",
"priority": "P0",
"rule": "每次 commit / push 前必須 fetch gitea並同步另一 Session 的 run / deploy / production evidence。",
"verification": "LOGBOOK 必須記錄 basis、runs、deploy marker 與 gate 邊界。",
},
{
"rule_id": "memory_index_startup_exception",
"priority": "P1",
"rule": "repo-local MEMORY.md 缺檔時,需記錄使用全域 memory 與 LOGBOOK 的替代讀取路徑。",
"verification": "啟動記錄不得假稱 repo-local MEMORY.md 已讀。",
},
]
RULE_ADJUSTMENTS_REQUIRED = [
{
"adjustment_id": "low_friction_but_p0_stop_the_bleed",
"priority": "P0",
"from_rule": "初期資安低摩擦、先只讀框架。",
"adjusted_rule": "低摩擦不代表延後修補即時資訊揭露public surface leak 可先 source-control 止血,再補 owner gate。",
},
{
"adjustment_id": "internal_evidence_not_product_copy",
"priority": "P0",
"from_rule": "source-control evidence 可保留技術識別。",
"adjusted_rule": "技術識別只能留在內部 evidence產品頁只顯示 redacted scope id、風險等級、狀態與 evidence ref。",
},
{
"adjustment_id": "awooop_approval_not_security_acceptance",
"priority": "P0",
"from_rule": "AwoooP 可顯示 owner response / approval 候選。",
"adjusted_rule": "AwoooP approval、Runs、Work Items、Tenants 顯示全部只算狀態,不等於 IwoooS security acceptance。",
},
{
"adjustment_id": "nginx_config_control_first",
"priority": "P0",
"from_rule": "高價值配置逐步納管。",
"adjusted_rule": "Nginx / public gateway / DNS / TLS 是 C0優先要求 source-of-truth、drift evidence、owner response、rollback 與 post-check。",
},
{
"adjustment_id": "owner_response_language_not_execution",
"priority": "P0",
"from_rule": "owner 可回覆 decision。",
"adjusted_rule": "即使 owner 文字包含同意、批准、OK也只算 metadata decision不自動授權 refs sync、reload、deploy 或 runtime action。",
},
{
"adjustment_id": "public_verification_required_after_frontend_change",
"priority": "P0",
"from_rule": "改前端後做 smoke。",
"adjusted_rule": "改前端或 public API 後必須做 production desktop/mobile sensitive scan、水平溢出檢查與關鍵卡片可見檢查。",
},
{
"adjustment_id": "agent_bounty_c0_runtime_boundary",
"priority": "P1",
"from_rule": "agent-bounty-protocol 納入 IwoooS scope。",
"adjusted_rule": "agent-bounty-protocol 需以 C0 runtime / MCP / A2A / treasury 邊界管理,但保持獨立產品與 owner response。",
},
]
PRIORITY_WORK_QUEUE = [
{
"priority": "P0-1",
"work_item": "S4.9 owner response gate 收件前置",
"completion_percent": 70,
"blocked_by": "尚未人工送件、尚未收到 owner response。",
"next_validation": "source-control-owner-response-guard。",
},
{
"priority": "P0-2",
"work_item": "前台 / public API identity redaction",
"completion_percent": 100,
"blocked_by": "後續新增頁面仍需 guard 持續保護。",
"next_validation": "production desktop/mobile sensitive scan。",
},
{
"priority": "P0-3",
"work_item": "Nginx public gateway owner response acceptance",
"completion_percent": 86,
"blocked_by": "尚缺 owner-provided live conf、rendered diff、nginx -t evidence、route smoke、maintenance window、rollback owner。",
"next_validation": "public gateway acceptance snapshot + owner-provided evidence review。",
},
{
"priority": "P0-4",
"work_item": "K8s / ArgoCD owner response acceptance",
"completion_percent": 62,
"blocked_by": "尚缺 ArgoCD health readback、rendered manifest diff、rollback revision、owner response。",
"next_validation": "k8s-argocd owner response acceptance snapshot。",
},
{
"priority": "P0-5",
"work_item": "Backup / restore / escrow owner response acceptance",
"completion_percent": 62,
"blocked_by": "尚缺 restore drill approval package、offsite owner、escrow owner、retention owner、validation plan。",
"next_validation": "backup restore acceptance snapshot。",
},
{
"priority": "P1-1",
"work_item": "Docker Compose / systemd / host service owner response",
"completion_percent": 50,
"blocked_by": "尚缺 110 / 188 live hash、restart window、rollback owner、post-check 指標。",
"next_validation": "host service owner request / future acceptance ledger。",
},
{
"priority": "P1-2",
"work_item": "SSH / firewall / network access owner response acceptance",
"completion_percent": 58,
"blocked_by": "尚缺 live access state、allowed source CIDR、host key pinning、firewall owner、NetworkPolicy / NodePort / WireGuard owner。",
"next_validation": "ssh network acceptance snapshot。",
},
{
"priority": "P1-3",
"work_item": "Monitoring / alerting / observability owner response",
"completion_percent": 62,
"blocked_by": "尚缺 live drift evidence、receiver owner、reload owner、route smoke、receipt proof。",
"next_validation": "monitoring owner request / future acceptance ledger。",
},
{
"priority": "P1-4",
"work_item": "agent-bounty-protocol C0 runtime / MCP / A2A / treasury owner response",
"completion_percent": 68,
"blocked_by": "尚缺 deployment boundary、external agent boundary、treasury owner、runtime gate owner。",
"next_validation": "agent bounty owner request draft 與 future acceptance ledger。",
},
]
def git_output(root: Path, args: list[str], fallback: str = "unknown") -> str:
try:
result = subprocess.run(args, cwd=root, check=True, capture_output=True, text=True)
return result.stdout.strip()
except Exception:
return fallback
def load_json(path: Path) -> dict[str, Any]:
return json.loads(path.read_text(encoding="utf-8"))
def build_report(root: Path, generated_at: str | None) -> dict[str, Any]:
security_dir = root / "docs" / "security"
report_time = generated_at or datetime.now(TAIPEI).isoformat(timespec="seconds")
rollup = load_json(security_dir / "source-control-owner-response-validation-rollup.snapshot.json")
s49_response = load_json(security_dir / "gitea-inventory-owner-attestation-response.snapshot.json")
tenants_probe_fields = [
"source_scope_id",
"source_namespace_redacted",
"repo_owner_namespace_redacted",
"raw_repository_namespace_visible",
"public_api_raw_repo_namespace_allowed",
]
return {
"schema_version": "s4_9_owner_response_gap_audit_v1",
"generated_at": report_time,
"git_commit": git_output(root, ["git", "rev-parse", "--short", "HEAD"]),
"status": "gap_audit_ready_owner_gate_zero",
"mode": "read_only_gap_audit_no_runtime_action",
"basis": {
"gitea_main_commit": git_output(root, ["git", "rev-parse", "--short", "gitea/main"]),
"latest_runtime_deploy_marker": "605fde43",
"latest_tenants_redaction_commit": "4bbc5269",
"latest_logbook_commit": "8795c08d",
"source_control_rollup_date": rollup.get("date"),
"source_control_rollup_templates": rollup.get("summary", {}).get("total_response_template_count"),
"production_verification_required_for_frontend_changes": True,
},
"summary": {
"current_requirement_gap_count": len(CURRENT_REQUIREMENT_GAPS),
"active_blocker_count": sum(1 for item in CURRENT_REQUIREMENT_GAPS if item["status"] == "active_blocker"),
"active_risk_or_process_gap_count": sum(
1 for item in CURRENT_REQUIREMENT_GAPS if item["status"] in {"active_risk", "active_process_gap"}
),
"mitigated_needs_guard_count": sum(
1 for item in CURRENT_REQUIREMENT_GAPS if item["status"] == "mitigated_needs_guard"
),
"new_rule_count": len(NEW_RULES_REQUIRED),
"rule_adjustment_count": len(RULE_ADJUSTMENTS_REQUIRED),
"priority_work_item_count": len(PRIORITY_WORK_QUEUE),
"s4_9_owner_response_gate_percent": 0,
"request_sent_count": 0,
"owner_response_received_count": s49_response.get("summary", {}).get("received_response_count", 0),
"owner_response_accepted_count": s49_response.get("summary", {}).get("accepted_response_count", 0),
"owner_response_rejected_count": s49_response.get("summary", {}).get("rejected_response_count", 0),
"runtime_gate_count": 0,
"public_surface_redaction_guard_ready": True,
"public_surface_raw_namespace_allowed": False,
"work_session_transcript_public_allowed": False,
},
"false_boundaries": FALSE_BOUNDARIES,
"public_surface_redaction_requirements": {
"allowed_display": [
"SRC-### scope id",
"aggregate count",
"risk tier",
"readiness state",
"redacted evidence ref",
],
"forbidden_display": [
"raw repository owner namespace",
"personal namespace",
"external organization namespace when not explicitly public-safe",
"工作視窗對話內容",
"approval chat phrase",
"token / secret / private key / cookie / authorization header",
],
"required_fields_or_markers": tenants_probe_fields,
"verification": [
"public API payload sensitive scan",
"production HTML sensitive scan",
"desktop browser sensitive scan",
"mobile browser sensitive scan",
"horizontal overflow check",
],
},
"current_requirement_gaps": CURRENT_REQUIREMENT_GAPS,
"new_rules_required": NEW_RULES_REQUIRED,
"rule_adjustments_required": RULE_ADJUSTMENTS_REQUIRED,
"priority_work_queue": PRIORITY_WORK_QUEUE,
"next_safe_actions": [
"更新 S4.9 缺口稽核文件基準與 snapshot reference。",
"把本 snapshot 納入 source-control owner response guard。",
"繼續補 owner response acceptance ledger但所有 request / received / accepted / runtime gate 維持 0 / false。",
],
}
def main() -> int:
parser = argparse.ArgumentParser(description="S4.9 owner response gate 現況缺口稽核 snapshot 產生器")
parser.add_argument("--root", default=".", help="repo root")
parser.add_argument("--output", help="寫出 JSON 報告")
parser.add_argument("--generated-at", help="固定報告時間,供 committed snapshot 使用")
args = parser.parse_args()
root = Path(args.root).resolve()
report = build_report(root, 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(
"S4_9_OWNER_RESPONSE_GAP_AUDIT_OK "
f"gaps={summary['current_requirement_gap_count']} "
f"new_rules={summary['new_rule_count']} "
f"adjustments={summary['rule_adjustment_count']} "
f"owner_gate={summary['s4_9_owner_response_gate_percent']} "
f"runtime_gate={summary['runtime_gate_count']}",
file=sys.stderr,
)
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -16,6 +16,52 @@ from typing import Any
EXPECTED_ROLLUP_DATE = "2026-06-13"
EXPECTED_TEMPLATE_COUNT_FORMULA = "5 + 9 + 5 + 5 = 24"
STALE_TEMPLATE_COUNT_FORMULA = "5 + 7 + 5 + 5 = 22"
EXPECTED_GAP_AUDIT_GITEA_MAIN = "8795c08d"
EXPECTED_GAP_AUDIT_DEPLOY_MARKER = "605fde43"
EXPECTED_GAP_AUDIT_TENANTS_REDACTION_COMMIT = "4bbc5269"
EXPECTED_GAP_AUDIT_GAP_IDS = [
"s49_owner_response_absent",
"s49_dispatch_audit_event_absent",
"s49_reviewer_outcome_absent",
"public_surface_identity_leak_risk",
"raw_namespace_internal_evidence_misroute_risk",
"latest_basis_staleness_risk",
"parallel_session_conflict_risk",
"release_worktree_memory_index_absent",
]
EXPECTED_GAP_AUDIT_NEW_RULE_IDS = [
"public_surface_redaction_gate",
"s49_gap_audit_snapshot_required",
"raw_evidence_private_boundary",
"owner_response_counts_are_runtime_locked",
"dispatch_received_accepted_separation",
"parallel_session_basis_refresh",
"memory_index_startup_exception",
]
EXPECTED_GAP_AUDIT_ADJUSTMENT_IDS = [
"low_friction_but_p0_stop_the_bleed",
"internal_evidence_not_product_copy",
"awooop_approval_not_security_acceptance",
"nginx_config_control_first",
"owner_response_language_not_execution",
"public_verification_required_after_frontend_change",
"agent_bounty_c0_runtime_boundary",
]
EXPECTED_GAP_AUDIT_WORK_PRIORITIES = [
"P0-1",
"P0-2",
"P0-3",
"P0-4",
"P0-5",
"P1-1",
"P1-2",
"P1-3",
"P1-4",
]
LANES = [
{
@@ -509,17 +555,98 @@ def validate_markdown_consistency(security_dir: Path) -> None:
assert_not_contains("rollup_doc.stale_formula", rollup_doc, STALE_TEMPLATE_COUNT_FORMULA)
assert_not_contains("rollup_doc.stale_display", rollup_doc, "22 templates")
assert_contains("gap_audit_doc.latest_baseline_present", gap_audit_doc, "gitea/main=")
assert_contains("gap_audit_doc.latest_baseline_8795", gap_audit_doc, EXPECTED_GAP_AUDIT_GITEA_MAIN)
assert_contains("gap_audit_doc.latest_deploy_marker", gap_audit_doc, EXPECTED_GAP_AUDIT_DEPLOY_MARKER)
assert_contains("gap_audit_doc.machine_readable_snapshot", gap_audit_doc, "s4-9-owner-response-gap-audit.snapshot.json")
assert_contains("gap_audit_doc.public_surface_redaction", gap_audit_doc, "Public surface redaction")
assert_not_contains("gap_audit_doc.stale_baseline_b615", gap_audit_doc, "b615bde5")
assert_not_contains("gap_audit_doc.stale_baseline_f1bad", gap_audit_doc, "f1bad81d")
assert_not_contains("gap_audit_doc.stale_baseline_b17a", gap_audit_doc, "b17a28c2")
assert_not_contains("gap_audit_doc.stale_baseline_2afb", gap_audit_doc, "2afb7c0a")
assert_contains("gap_audit_doc.rollup_consistency", gap_audit_doc, "S4.13 rollup 文件一致性")
def validate(root: Path) -> None:
security_dir = root / "docs" / "security"
validate_markdown_consistency(security_dir)
gap_audit = load_json(security_dir / "s4-9-owner-response-gap-audit.snapshot.json")
rollup = load_json(security_dir / "source-control-owner-response-validation-rollup.snapshot.json")
rollup_summary = rollup["summary"]
gap_summary = gap_audit["summary"]
assert_equal("gap_audit.schema_version", gap_audit["schema_version"], "s4_9_owner_response_gap_audit_v1")
assert_equal("gap_audit.status", gap_audit["status"], "gap_audit_ready_owner_gate_zero")
assert_equal("gap_audit.mode", gap_audit["mode"], "read_only_gap_audit_no_runtime_action")
assert_equal("gap_audit.basis.gitea_main_commit", gap_audit["basis"]["gitea_main_commit"], EXPECTED_GAP_AUDIT_GITEA_MAIN)
assert_equal(
"gap_audit.basis.latest_runtime_deploy_marker",
gap_audit["basis"]["latest_runtime_deploy_marker"],
EXPECTED_GAP_AUDIT_DEPLOY_MARKER,
)
assert_equal(
"gap_audit.basis.latest_tenants_redaction_commit",
gap_audit["basis"]["latest_tenants_redaction_commit"],
EXPECTED_GAP_AUDIT_TENANTS_REDACTION_COMMIT,
)
assert_equal("gap_audit.basis.source_control_rollup_templates", gap_audit["basis"]["source_control_rollup_templates"], 24)
assert_true(
"gap_audit.basis.production_verification_required_for_frontend_changes",
gap_audit["basis"]["production_verification_required_for_frontend_changes"],
)
assert_equal("gap_audit.current_requirement_gap_count", gap_summary["current_requirement_gap_count"], 8)
assert_equal("gap_audit.active_blocker_count", gap_summary["active_blocker_count"], 3)
assert_equal("gap_audit.new_rule_count", gap_summary["new_rule_count"], len(EXPECTED_GAP_AUDIT_NEW_RULE_IDS))
assert_equal(
"gap_audit.rule_adjustment_count",
gap_summary["rule_adjustment_count"],
len(EXPECTED_GAP_AUDIT_ADJUSTMENT_IDS),
)
assert_equal(
"gap_audit.priority_work_item_count",
gap_summary["priority_work_item_count"],
len(EXPECTED_GAP_AUDIT_WORK_PRIORITIES),
)
assert_equal("gap_audit.s4_9_owner_response_gate_percent", gap_summary["s4_9_owner_response_gate_percent"], 0)
assert_equal("gap_audit.request_sent_count", gap_summary["request_sent_count"], 0)
assert_equal("gap_audit.owner_response_received_count", gap_summary["owner_response_received_count"], 0)
assert_equal("gap_audit.owner_response_accepted_count", gap_summary["owner_response_accepted_count"], 0)
assert_equal("gap_audit.owner_response_rejected_count", gap_summary["owner_response_rejected_count"], 0)
assert_equal("gap_audit.runtime_gate_count", gap_summary["runtime_gate_count"], 0)
assert_true("gap_audit.public_surface_redaction_guard_ready", gap_summary["public_surface_redaction_guard_ready"])
assert_false("gap_audit.public_surface_raw_namespace_allowed", gap_summary["public_surface_raw_namespace_allowed"])
assert_false(
"gap_audit.work_session_transcript_public_allowed",
gap_summary["work_session_transcript_public_allowed"],
)
assert_equal(
"gap_audit.gap_ids",
[item["gap_id"] for item in gap_audit["current_requirement_gaps"]],
EXPECTED_GAP_AUDIT_GAP_IDS,
)
assert_equal(
"gap_audit.new_rule_ids",
[item["rule_id"] for item in gap_audit["new_rules_required"]],
EXPECTED_GAP_AUDIT_NEW_RULE_IDS,
)
assert_equal(
"gap_audit.adjustment_ids",
[item["adjustment_id"] for item in gap_audit["rule_adjustments_required"]],
EXPECTED_GAP_AUDIT_ADJUSTMENT_IDS,
)
assert_equal(
"gap_audit.priority_work_queue",
[item["priority"] for item in gap_audit["priority_work_queue"]],
EXPECTED_GAP_AUDIT_WORK_PRIORITIES,
)
for key, value in gap_audit["false_boundaries"].items():
assert_false(f"gap_audit.false_boundaries.{key}", value)
redaction = gap_audit["public_surface_redaction_requirements"]
for marker in ["source_scope_id", "source_namespace_redacted", "public_api_raw_repo_namespace_allowed"]:
if marker not in redaction["required_fields_or_markers"]:
raise SystemExit(f"BLOCKED gap_audit.public_surface_redaction_requirements: missing {marker!r}")
for forbidden in ["raw repository owner namespace", "工作視窗對話內容", "approval chat phrase"]:
if forbidden not in redaction["forbidden_display"]:
raise SystemExit(f"BLOCKED gap_audit.public_surface_redaction_forbidden_display: missing {forbidden!r}")
assert_equal("rollup.status", rollup["status"], "draft_waiting_owner_responses")
assert_equal("rollup.date", rollup["date"], EXPECTED_ROLLUP_DATE)