From 2b8654704a0d493d3e5164d3aafa3858043ae2ae Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 15 Jun 2026 18:57:27 +0800 Subject: [PATCH] =?UTF-8?q?feat(iwooos):=20=E6=96=B0=E5=A2=9E=20AI=20provi?= =?UTF-8?q?der=20owner=20response=20=E9=A9=97=E6=94=B6=20gate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/messages/en.json | 2 +- apps/web/messages/zh-TW.json | 2 +- apps/web/src/app/[locale]/iwooos/page.tsx | 22 +- docs/ai/AI-MODEL-CARDS.md | 94 +- .../iwooos_posture_projection_v1.schema.json | 124 +- .../AI-PROVIDER-OWNER-RESPONSE-ACCEPTANCE.md | 111 + .../HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md | 13 +- .../IWOOOS-CONFIG-CONTROL-INVENTORY.md | 10 +- docs/security/IWOOOS-POSTURE-PROJECTION.md | 1 + .../SECURITY-SUPPLY-CHAIN-PROGRESS.md | 10 +- ...er-owner-response-acceptance.snapshot.json | 2261 +++++++++++++++++ ...alue-config-control-coverage.snapshot.json | 33 +- .../iwooos-posture-projection.snapshot.json | 36 +- .../ai-provider-owner-response-acceptance.py | 553 ++++ .../high-value-config-control-coverage.py | 14 +- .../security/iwooos-config-control-guard.py | 36 +- .../security-mirror-progress-guard.py | 295 ++- 17 files changed, 3528 insertions(+), 89 deletions(-) create mode 100644 docs/security/AI-PROVIDER-OWNER-RESPONSE-ACCEPTANCE.md create mode 100644 docs/security/ai-provider-owner-response-acceptance.snapshot.json create mode 100644 scripts/security/ai-provider-owner-response-acceptance.py diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 842cd71d9..0ef3576cc 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -17938,7 +17938,7 @@ }, "aiProvider": { "title": "AI 供應商 / 模型路由", - "body": "供應商、Ollama 代理、回退順序、成本與隱私邊界已納入高價值配置矩陣;目前成熟度 60%,下一步需要供應商負責人、乾跑、基準測試、成本審查、隱私審查與回復負責人,不直接切正式環境。" + "body": "供應商、Ollama 代理、回退順序、成本與隱私邊界已新增 owner response acceptance 帳本;目前成熟度 64%,8 個候選、24 個審查檢查項、10 條結果分流、38 類禁止動作,供應商回覆、乾跑、基準測試、成本審查、隱私審查、provider 切換、外部呼叫、付費呼叫、prompt 送出與 runtime gate 仍全部為 0。" }, "sshNetwork": { "title": "SSH / network / firewall", diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index 842cd71d9..0ef3576cc 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -17938,7 +17938,7 @@ }, "aiProvider": { "title": "AI 供應商 / 模型路由", - "body": "供應商、Ollama 代理、回退順序、成本與隱私邊界已納入高價值配置矩陣;目前成熟度 60%,下一步需要供應商負責人、乾跑、基準測試、成本審查、隱私審查與回復負責人,不直接切正式環境。" + "body": "供應商、Ollama 代理、回退順序、成本與隱私邊界已新增 owner response acceptance 帳本;目前成熟度 64%,8 個候選、24 個審查檢查項、10 條結果分流、38 類禁止動作,供應商回覆、乾跑、基準測試、成本審查、隱私審查、provider 切換、外部呼叫、付費呼叫、prompt 送出與 runtime gate 仍全部為 0。" }, "sshNetwork": { "title": "SSH / network / firewall", diff --git a/apps/web/src/app/[locale]/iwooos/page.tsx b/apps/web/src/app/[locale]/iwooos/page.tsx index 62d849a18..3cb2a7be0 100644 --- a/apps/web/src/app/[locale]/iwooos/page.tsx +++ b/apps/web/src/app/[locale]/iwooos/page.tsx @@ -2093,8 +2093,8 @@ const highValueConfigControlCoverageSummary = [ const highValueConfigControlCoverageItems: HighValueConfigControlCoverageItem[] = [ { key: 'dockerSystemd', rank: 'P1-1', value: '62%', icon: Server, tone: 'warn' }, - { key: 'aiProvider', rank: 'P1-2', value: '60%', icon: Cloud, tone: 'warn' }, - { key: 'sshNetwork', rank: 'P1-3', value: '62%', icon: Network, tone: 'warn' }, + { key: 'sshNetwork', rank: 'P1-2', value: '62%', icon: Network, tone: 'warn' }, + { key: 'aiProvider', rank: 'P1-3', value: '64%', icon: Cloud, tone: 'warn' }, { key: 'k8sGitops', rank: 'P1-4', value: '64%', icon: Workflow, tone: 'warn' }, ] @@ -2120,6 +2120,24 @@ const highValueConfigControlCoverageBoundaries = [ 'secret_metadata_coverage_percent=68', 'gitea_workflow_runner_source_control_coverage_percent=72', 'public_admin_api_runtime_config_coverage_percent=66', + 'ai_provider_model_routing_coverage_percent=64', + 'ai_provider_owner_response_acceptance_candidate_count=8', + 'ai_provider_owner_response_acceptance_write_capable_candidate_count=5', + 'ai_provider_owner_response_acceptance_required_owner_field_count=24', + 'ai_provider_owner_response_acceptance_reviewer_check_count=24', + 'ai_provider_owner_response_acceptance_outcome_lane_count=10', + 'ai_provider_owner_response_acceptance_blocked_action_count=38', + 'ai_provider_owner_response_acceptance_owner_response_received_count=0', + 'ai_provider_owner_response_acceptance_owner_response_accepted_count=0', + 'ai_provider_owner_response_acceptance_dry_run_result_accepted_count=0', + 'ai_provider_owner_response_acceptance_benchmark_result_accepted_count=0', + 'ai_provider_owner_response_acceptance_cost_review_accepted_count=0', + 'ai_provider_owner_response_acceptance_privacy_review_accepted_count=0', + 'ai_provider_owner_response_acceptance_provider_switch_authorized_count=0', + 'ai_provider_owner_response_acceptance_external_provider_call_authorized_count=0', + 'ai_provider_owner_response_acceptance_paid_provider_call_authorized_count=0', + 'ai_provider_owner_response_acceptance_prompt_send_authorized_count=0', + 'ai_provider_owner_response_acceptance_runtime_gate_count=0', 'public_frontend_sensitive_surface_guard_file_count=225', 'public_frontend_sensitive_surface_guard_forbidden_pattern_count=12', 'public_frontend_sensitive_surface_guard_violation_count=0', diff --git a/docs/ai/AI-MODEL-CARDS.md b/docs/ai/AI-MODEL-CARDS.md index b0a26ff16..829742495 100644 --- a/docs/ai/AI-MODEL-CARDS.md +++ b/docs/ai/AI-MODEL-CARDS.md @@ -7,6 +7,8 @@ > **資料來源**: `apps/api/models.json` v1.3.0、`feedback_ai_model_config.md` > **維護**: 每次更換主力模型後更新;費用變更須統帥批准(`feedback_cost_change_approval.md`) +> **2026-06-15 資安修訂**:本文件只能保存模型治理 metadata。端點一律使用脫敏 alias,不保存內網位址、secret、API key、raw prompt、raw log 或可直接連線的 live URL。任何 provider / fallback / cost / privacy 變更都必須先通過 IwoooS owner response acceptance,不得直接切 production。 + --- ## 模型路由架構 @@ -39,16 +41,16 @@ AIRouter(ADR-052) | 屬性 | 值 | |------|---| -| **Model ID** | `deepseek-r1:14b` | -| **Provider** | Ollama(本地)| -| **Endpoint** | `http://192.168.0.111:11434` | -| **Priority** | 1(最優先)| -| **硬體** | 188 主機,NVIDIA GPU | -| **Cost** | $0(完全離線)| +| **模型 ID** | `deepseek-r1:14b` | +| **供應者** | Ollama(本地)| +| **端點(脫敏)** | `host:ai-local-fallback:11434` | +| **優先序** | 1(最優先)| +| **硬體** | 本地 AI 主機,NVIDIA GPU | +| **成本** | $0(完全離線)| **用途(purposes)** -| Purpose Key | 說明 | +| 用途鍵 | 說明 | |-------------|------| | `rca` | Root Cause Analysis — 告警根因分析 | | `diagnose` | 深度診斷(含 log 關聯) | @@ -60,7 +62,7 @@ AIRouter(ADR-052) - 14B 參數,P95 延遲 ~8-15s(依硬體負載) **限制** -- 僅在 188 主機可用;188 離線時全部 fallback 至 Gemini +- 僅在本地 AI 主機可用;本地 AI 主機離線時全部 fallback 至 Gemini - 無 Tool Calling 能力(使用 structured prompt 替代) - 高負載時延遲可能超過 25s LLM timeout → Expert System 降級 @@ -74,15 +76,15 @@ AIRouter(ADR-052) | 屬性 | 值 | |------|---| -| **Model ID** | `qwen2.5:7b-instruct` | -| **Provider** | Ollama(本地)| -| **Endpoint** | `http://192.168.0.111:11434` | -| **Priority** | 1(與 deepseek-r1 同層,purpose 分工)| -| **Cost** | $0(完全離線)| +| **模型 ID** | `qwen2.5:7b-instruct` | +| **供應者** | Ollama(本地)| +| **端點(脫敏)** | `host:ai-local-fallback:11434` | +| **優先序** | 1(與 deepseek-r1 同層,purpose 分工)| +| **成本** | $0(完全離線)| **用途(purposes)** -| Purpose Key | 說明 | +| 用途鍵 | 說明 | |-------------|------| | `drift_summary` | 配置漂移摘要 | | `rag_generate` | RAG 知識庫生成回答 | @@ -96,7 +98,7 @@ AIRouter(ADR-052) **限制** - 推理深度不如 deepseek-r1;複雜 RCA 不使用此模型 -- 同在 188 主機;與 deepseek 共享 GPU 資源,高負載時互相競爭 +- 同在本地 AI 主機;與 deepseek 共享 GPU 資源,高負載時互相競爭 --- @@ -104,15 +106,15 @@ AIRouter(ADR-052) | 屬性 | 值 | |------|---| -| **Model ID** | `nomic-embed-text:latest` | -| **Provider** | Ollama(本地)| -| **Endpoint** | `http://192.168.0.111:11434` | -| **Priority** | 1(embedding 專用)| -| **Cost** | $0(完全離線)| +| **模型 ID** | `nomic-embed-text:latest` | +| **供應者** | Ollama(本地)| +| **端點(脫敏)** | `host:ai-local-fallback:11434` | +| **優先序** | 1(embedding 專用)| +| **成本** | $0(完全離線)| **用途(purposes)** -| Purpose Key | 說明 | +| 用途鍵 | 說明 | |-------------|------| | `embedding` | 文字向量化(KM 搜尋、RAG 索引)| @@ -131,15 +133,15 @@ AIRouter(ADR-052) | 屬性 | 值 | |------|---| -| **Model ID** | `qwen2.5-coder:7b` | -| **Provider** | Ollama(本地)| -| **Endpoint** | `http://192.168.0.111:11434` | -| **Priority** | 1(code_review 專用)| -| **Cost** | $0(完全離線)| +| **模型 ID** | `qwen2.5-coder:7b` | +| **供應者** | Ollama(本地)| +| **端點(脫敏)** | `host:ai-local-fallback:11434` | +| **優先序** | 1(code_review 專用)| +| **成本** | $0(完全離線)| **用途(purposes)** -| Purpose Key | 說明 | +| 用途鍵 | 說明 | |-------------|------| | `code_review` | 程式碼審查(CI/CD Pipeline 整合)| @@ -153,15 +155,15 @@ AIRouter(ADR-052) | 屬性 | 值 | |------|---| -| **Model ID** | `gemini-2.0-flash` | -| **Provider** | Google Gemini API(雲端)| -| **Priority** | 2(Ollama 失敗時 fallback)| -| **Daily Limit** | 70,000 tokens/day | -| **Cost** | 免費額度內 $0;超出計費 | +| **模型 ID** | `gemini-2.0-flash` | +| **供應者** | Google Gemini API(雲端)| +| **優先序** | 2(Ollama 失敗時 fallback)| +| **每日上限** | 70,000 tokens/day | +| **成本** | 免費額度內 $0;超出計費 | **用途(purposes)** -| Purpose Key | 說明 | +| 用途鍵 | 說明 | |-------------|------| | `rca` | Ollama 失敗時的 RCA fallback | | `summary` | 事件摘要 fallback | @@ -187,15 +189,15 @@ AIRouter(ADR-052) | 屬性 | 值 | |------|---| -| **Model ID** | `claude-3-haiku-20240307` | -| **Provider** | Anthropic API(雲端)| -| **Priority** | 3(Gemini 失敗或超限時 fallback)| -| **Daily Limit** | 35,000 tokens/day | -| **Cost** | 按用量計費($0.25/1M input tokens)| +| **模型 ID** | `claude-3-haiku-20240307` | +| **供應者** | Anthropic API(雲端)| +| **優先序** | 3(Gemini 失敗或超限時 fallback)| +| **每日上限** | 35,000 tokens/day | +| **成本** | 按用量計費($0.25/1M input tokens)| **用途(purposes)** -| Purpose Key | 說明 | +| 用途鍵 | 說明 | |-------------|------| | `rca` | 緊急 fallback(Ollama+Gemini 均失效)| | `summary` | 緊急 fallback | @@ -219,15 +221,15 @@ AIRouter(ADR-052) | 屬性 | 值 | |------|---| -| **Model ID** | `nvidia/nemotron-mini-4b-instruct` | -| **Provider** | NVIDIA NIM API(雲端)| -| **Priority** | 4(特殊場景專用)| -| **Accuracy** | 83.3%(`nemoclaw` 任務)| -| **Cost** | 按用量計費 | +| **模型 ID** | `nvidia/nemotron-mini-4b-instruct` | +| **供應者** | NVIDIA NIM API(雲端)| +| **優先序** | 4(特殊場景專用)| +| **準確率** | 83.3%(`nemoclaw` 任務)| +| **成本** | 按用量計費 | **用途(purposes)** -| Purpose Key | 說明 | +| 用途鍵 | 說明 | |-------------|------| | `nemoclaw` | Tool Calling(OpenClaw 整合)| | `tool_calling` | 結構化函式呼叫 | @@ -267,7 +269,7 @@ nemoclaw N/A → N/A → N/A → nemotron | 指標 | 來源 | 告警閾值 | |------|------|---------| -| Ollama 可用性 | Prometheus scrape 188:9090 | 失效 > 30s → Telegram | +| Ollama 可用性 | owner-provided monitoring ref | 失效 > 30s → Telegram | | Gemini 日用量 | Langfuse `provider=gemini` | > 60K tokens/day | | Claude 日用量 | Langfuse `provider=claude` | > 25K tokens/day | | LLM P95 延遲 | SLO-2(< 20s for P95) | 超過 25s → Expert System 降級 | diff --git a/docs/schemas/iwooos_posture_projection_v1.schema.json b/docs/schemas/iwooos_posture_projection_v1.schema.json index 8d5c80697..8c72c4e0f 100644 --- a/docs/schemas/iwooos_posture_projection_v1.schema.json +++ b/docs/schemas/iwooos_posture_projection_v1.schema.json @@ -623,11 +623,11 @@ }, "high_value_config_control_coverage_average_percent": { "type": "integer", - "const": 67 + "const": 70 }, "high_value_config_control_coverage_needs_live_evidence_count": { "type": "integer", - "const": 7 + "const": 10 }, "high_value_config_control_coverage_owner_response_required_count": { "type": "integer", @@ -1401,6 +1401,126 @@ "public_gateway_preflight_coverage_percent_after_preflight": { "type": "integer", "const": 84 + }, + "ai_provider_owner_response_acceptance_candidate_count": { + "type": "integer", + "const": 8 + }, + "ai_provider_owner_response_acceptance_write_capable_candidate_count": { + "type": "integer", + "const": 5 + }, + "ai_provider_owner_response_acceptance_paid_provider_related_candidate_count": { + "type": "integer", + "const": 5 + }, + "ai_provider_owner_response_acceptance_data_egress_candidate_count": { + "type": "integer", + "const": 6 + }, + "ai_provider_owner_response_acceptance_live_evidence_required_candidate_count": { + "type": "integer", + "const": 6 + }, + "ai_provider_owner_response_acceptance_acceptance_field_count": { + "type": "integer", + "const": 37 + }, + "ai_provider_owner_response_acceptance_required_owner_field_count": { + "type": "integer", + "const": 24 + }, + "ai_provider_owner_response_acceptance_reviewer_check_count": { + "type": "integer", + "const": 24 + }, + "ai_provider_owner_response_acceptance_outcome_lane_count": { + "type": "integer", + "const": 10 + }, + "ai_provider_owner_response_acceptance_blocked_action_count": { + "type": "integer", + "const": 38 + }, + "ai_provider_owner_response_acceptance_owner_response_received_count": { + "type": "integer", + "const": 0 + }, + "ai_provider_owner_response_acceptance_owner_response_accepted_count": { + "type": "integer", + "const": 0 + }, + "ai_provider_owner_response_acceptance_dry_run_result_accepted_count": { + "type": "integer", + "const": 0 + }, + "ai_provider_owner_response_acceptance_benchmark_result_accepted_count": { + "type": "integer", + "const": 0 + }, + "ai_provider_owner_response_acceptance_cost_review_accepted_count": { + "type": "integer", + "const": 0 + }, + "ai_provider_owner_response_acceptance_privacy_review_accepted_count": { + "type": "integer", + "const": 0 + }, + "ai_provider_owner_response_acceptance_fallback_order_accepted_count": { + "type": "integer", + "const": 0 + }, + "ai_provider_owner_response_acceptance_prompt_redaction_accepted_count": { + "type": "integer", + "const": 0 + }, + "ai_provider_owner_response_acceptance_secret_handling_accepted_count": { + "type": "integer", + "const": 0 + }, + "ai_provider_owner_response_acceptance_quality_gate_accepted_count": { + "type": "integer", + "const": 0 + }, + "ai_provider_owner_response_acceptance_rollback_owner_accepted_count": { + "type": "integer", + "const": 0 + }, + "ai_provider_owner_response_acceptance_provider_switch_authorized_count": { + "type": "integer", + "const": 0 + }, + "ai_provider_owner_response_acceptance_external_provider_call_authorized_count": { + "type": "integer", + "const": 0 + }, + "ai_provider_owner_response_acceptance_paid_provider_call_authorized_count": { + "type": "integer", + "const": 0 + }, + "ai_provider_owner_response_acceptance_prompt_send_authorized_count": { + "type": "integer", + "const": 0 + }, + "ai_provider_owner_response_acceptance_live_endpoint_probe_authorized_count": { + "type": "integer", + "const": 0 + }, + "ai_provider_owner_response_acceptance_secret_value_collection_allowed_count": { + "type": "integer", + "const": 0 + }, + "ai_provider_owner_response_acceptance_runtime_gate_count": { + "type": "integer", + "const": 0 + }, + "ai_provider_owner_response_acceptance_coverage_percent_after_acceptance": { + "type": "integer", + "const": 64 + }, + "ai_provider_model_routing_coverage_percent": { + "type": "integer", + "const": 64 } }, "additionalProperties": false diff --git a/docs/security/AI-PROVIDER-OWNER-RESPONSE-ACCEPTANCE.md b/docs/security/AI-PROVIDER-OWNER-RESPONSE-ACCEPTANCE.md new file mode 100644 index 000000000..7f9c44b38 --- /dev/null +++ b/docs/security/AI-PROVIDER-OWNER-RESPONSE-ACCEPTANCE.md @@ -0,0 +1,111 @@ +# AI Provider / Model Routing Owner Response Acceptance + +| 項目 | 內容 | +|------|------| +| 日期 | 2026-06-15 | +| 狀態 | `owner_response_acceptance_ledger_ready_no_runtime_action` | +| 工具 | `scripts/security/ai-provider-owner-response-acceptance.py` | +| Snapshot | `docs/security/ai-provider-owner-response-acceptance.snapshot.json` | +| Schema | `ai_provider_owner_response_acceptance_v1` | +| runtime gate | `0` | + +## 1. 目的 + +AI provider、模型路由、Ollama proxy、fallback order、成本與隱私邊界已是 C1 高價值配置。這份文件把它們從「只知道要管」推進成可重跑 owner response acceptance 帳本,讓任何 provider 切換、fallback 調整、付費 provider 使用、外部 API 呼叫、prompt 外送、模型版本更新或 agent replacement 都先走只讀證據驗收。 + +本階段仍只做 source-control 文件、snapshot 與 guard,不呼叫任何模型、不讀 live endpoint、不切 provider、不改 Nginx、不送 prompt、不增加付費 provider 呼叫、不讀 secret、不安裝 SDK、不啟動 shadow / canary、不部署 production。 + +## 2. 驗收候選 + +| Surface | 範圍 | 風險 | 狀態 | +|---------|------|------|------| +| AI router provider policy / purpose mapping | purpose routing、provider priority、degraded mode | route drift 會造成外部 provider 誤用、成本上升、資料外送或品質下降 | `waiting_owner_response` | +| Ollama proxy gateway / local fallback boundary | proxy route、local fallback、gateway health | proxy drift 會造成 fallback 失效或錯誤 upstream | `waiting_owner_response` | +| Fallback order / circuit breaker | fallback order、timeout、circuit breaker | 只剩雲端或跳過本地 fallback 會造成成本與隱私風險 | `waiting_owner_response` | +| Cost budget / quota / paid provider stop condition | quota、token budget、cost alert、stop condition | 付費 provider 失控、告警不足或未設停損 | `waiting_owner_response` | +| Privacy / data egress / prompt redaction boundary | prompt redaction、資料分級、外部 provider 資料外送 | raw prompt、raw log、incident context 或 secrets 被外送 | `waiting_owner_response` | +| Dry-run / benchmark / replay pack | dry-run、benchmark、fixture replay、quality gate | 未經 replay / benchmark 就替換模型或 agent | `waiting_owner_response` | +| Model card / model version inventory | model card、version freshness、source-of-truth、redacted endpoint | 模型卡片含 raw endpoint 或版本來源漂移 | `waiting_owner_response` | +| Agent replacement / NemoTron / Hermes / OpenClaw candidate boundary | agent candidate、promotion gate、shadow/canary boundary | 未授權 SDK、外部呼叫、shadow/canary 或 production replacement | `waiting_owner_response` | + +## 3. 固定數字 + +| 指標 | 目前值 | +|------|--------| +| acceptance candidates | `8` | +| write-capable candidates | `5` | +| paid-provider related candidates | `5` | +| data-egress candidates | `6` | +| live-evidence required candidates | `6` | +| acceptance fields | `37` | +| required owner fields | `24` | +| reviewer checks | `24` | +| outcome lanes | `10` | +| blocked actions | `38` | +| owner response received / accepted | `0 / 0` | +| dry-run / benchmark / cost / privacy accepted | `0 / 0 / 0 / 0` | +| fallback order / rollback owner accepted | `0 / 0` | +| runtime gate | `0` | + +## 4. 必填 owner response + +每筆 AI provider owner response 必須至少包含: + +1. owner role / team、provider owner、decision、decision reason、affected scope。 +2. fallback order ref、dry-run result ref、benchmark result ref、quality gate ref。 +3. cost review ref、quota budget ref、privacy review ref、data classification ref。 +4. prompt redaction ref、secret handling ref、latency / timeout / circuit breaker SLO ref。 +5. rollback owner、rollback plan ref、maintenance window、postcheck evidence refs。 +6. redacted evidence refs、followup owner、no-secret-value attestation。 + +缺欄位只能要求補件,不得標記 accepted。 + +## 5. 拒收與隔離 + +以下內容一律拒收或隔離: + +- raw prompt、raw log、raw incident payload、未脫敏截圖。 +- raw live endpoint、內網位址、可直接連線 URL、API key、token、cookie、private key、env dump、secret value、secret hash 或 partial token。 +- 夾帶 provider switch、fallback order change、Ollama proxy change、Nginx reload、env change、production deploy、workflow dispatch、external provider call、paid provider call、prompt send、SDK install、model download、agent runtime enable、shadow / canary enable。 +- 只用 provider route `200`、dashboard up、模型成功回覆一次或 UI 可見來宣稱 routing / cost / privacy / quality 已驗收。 + +## 6. Outcome lanes + +| Lane | 意義 | +|------|------| +| `waiting_owner_response` | 尚未收到 AI provider owner response,全部 accepted / runtime count 維持 0 | +| `quarantine_secret_or_raw_payload` | 收到 secret、raw prompt、raw log、raw endpoint 或未脫敏內容時隔離 | +| `reject_execution_request` | 夾帶 provider switch、外部呼叫、prompt send、Nginx reload、env change 或 deploy 要求時拒收 | +| `request_fallback_supplement` | 缺 fallback order、degraded mode、circuit breaker 或 rollback 時要求補件 | +| `request_cost_privacy_supplement` | 缺 cost、quota、privacy、data classification 或 prompt redaction 時要求補件 | +| `request_benchmark_supplement` | 缺 dry-run、benchmark、fixture replay、quality gate 或 incumbent baseline 時要求補件 | +| `legacy_model_card_redaction_required` | 舊模型卡、runbook 或報表含 raw endpoint / 主機識別時,先改成脫敏 alias | +| `ready_for_ai_provider_review` | metadata 合格後,只能進 AI provider reviewer review | +| `owner_review_only_update` | 只允許更新只讀 owner review ledger,不切 provider、不呼叫模型、不改 proxy | +| `waiting_runtime_gate` | 即使 owner response accepted,runtime gate 仍需獨立人工批准 | + +## 7. 完成度 + +| 工作 | 完成度 | 說明 | +|------|--------|------| +| AI provider owner response acceptance ledger | `100%` | 已新增可重跑 script、snapshot、reviewer checks、outcome lanes 與 blocked actions | +| AI provider / model routing 只讀成熟度 | `60% -> 64%` | 從分類政策推進到 owner response acceptance;仍未收到 owner response | +| owner response received / accepted | `0%` | 不得假性提高 | +| runtime / provider 切換 | `0%` | 不呼叫模型、不切 provider、不改 proxy、不外送資料、不增加付費呼叫 | + +## 8. 指令 + +```bash +python3 scripts/security/ai-provider-owner-response-acceptance.py \ + --root . \ + --output docs/security/ai-provider-owner-response-acceptance.snapshot.json +``` + +固定 committed snapshot 時間: + +```bash +python3 scripts/security/ai-provider-owner-response-acceptance.py \ + --root . \ + --generated-at 2026-06-15T19:35:00+08:00 \ + --output docs/security/ai-provider-owner-response-acceptance.snapshot.json +``` diff --git a/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md b/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md index 0b8251d97..b9687479b 100644 --- a/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md +++ b/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md @@ -90,6 +90,12 @@ 固定數字為 `change_evidence_candidate_count=14`、`write_capable_change_evidence_candidate_count=6`、`policy_or_exposure_candidate_count=5`、`change_evidence_field_count=40`、`required_evidence_field_count=21`、`reviewer_check_count=21`、`outcome_lane_count=9`、`blocked_action_count=28`、`change_evidence_received_count=0`、`change_evidence_accepted_count=0`、`service_health_impact_accepted_count=0`、`operator_notification_accepted_count=0`、`firewall_change_authorized_count=0`、`port_close_authorized_count=0`、`port_open_authorized_count=0`、`runtime_gate_count=0`。此更新讓 `ssh_firewall_network_access` 從 `58%` 推進到 `62%`;它補齊端口 / 防火牆變更與事故回補的 actor、before / after state、service dependency、customer impact、service health impact、operator notification、cross-project sync、rollback 與 post-check evidence 驗收規則,不代表 SSH、live firewall read、firewall change、port close / open、route smoke、host restart、production write 或 runtime gate 已授權。 +## 1.7a 2026-06-15 AI provider / model routing owner response acceptance 只讀帳本 + +已新增 `docs/security/AI-PROVIDER-OWNER-RESPONSE-ACCEPTANCE.md` 與 `docs/security/ai-provider-owner-response-acceptance.snapshot.json`,將 AI router provider policy、Ollama proxy gateway、fallback order / circuit breaker、cost budget / quota、privacy / data egress、benchmark / dry-run、model card / version inventory 與 agent replacement candidate boundary 轉成 metadata-only owner response acceptance 帳本。 + +固定數字為 `acceptance_candidate_count=8`、`write_capable_acceptance_candidate_count=5`、`paid_provider_related_candidate_count=5`、`data_egress_candidate_count=6`、`live_evidence_required_candidate_count=6`、`acceptance_field_count=37`、`required_owner_field_count=24`、`reviewer_check_count=24`、`outcome_lane_count=10`、`blocked_action_count=38`。此更新讓 `ai_provider_model_routing` 從 `60%` 推進到 `64%`;provider owner、fallback order、dry-run、benchmark、cost review、privacy review、data classification、prompt redaction、secret handling、quota budget、quality gate、rollback owner、post-check evidence、owner response received / accepted、provider switch、external provider call、paid provider call、prompt send、live endpoint probe、secret value collection、runtime gate 與 action button 仍全部為 `0 / false`。 + ## 1.8 2026-06-15 高價值配置集中 Guard 已新增 `docs/security/IWOOOS-CONFIG-CONTROL-GUARD.md` 與 `scripts/security/iwooos-config-control-guard.py`,把 14 類高價值配置、C0 類別、evidence refs、owner response / change evidence 帳本、supply-chain contract manifest 與 `0 / false` 邊界串成集中驗證。 @@ -117,9 +123,9 @@ | 優先 | 類別 | 目前成熟度 | 下一步 | |------|------|------------|--------| -| P1-1 | AI provider / model routing / Ollama proxy / cost and privacy | `60%` | provider、model routing、Ollama proxy 與 fallback order 已納入高價值配置分類;仍缺 provider owner、fallback order、cost review、privacy review、benchmark、dry-run 結果與 rollback owner,不切 production | -| P1-2 | Docker Compose / systemd / host service config | `62%` | repo-only 清冊、owner response acceptance 與 host service change evidence acceptance 已納入 9 個 surface;重啟 actor、before / after、Docker daemon、compose / systemd、failed unit、port binding、dependency、cold-start、route recovery、operator notification、cross-project sync 與 no-false-green 已納入;仍缺 owner response、live hash、change evidence、maintenance / restart window、rollback owner、post-check plan、disable switch 與 no-secret-value evidence | -| P1-3 | SSH / sudoers / known_hosts / firewall / WireGuard / NodePort | `62%` | repo-only 清冊已納入 16 個 SSH / network access surface,owner request draft、owner response acceptance 與事故型端口 / 防火牆變更證據驗收 ledger 已完成;仍缺 owner-provided change / incident ref、actor、before / after state、health impact、notification、cross-project sync、maintenance window、rollback owner 與 post-check evidence | +| P1-1 | Docker Compose / systemd / host service config | `62%` | repo-only 清冊、owner response acceptance 與 host service change evidence acceptance 已納入 9 個 surface;重啟 actor、before / after、Docker daemon、compose / systemd、failed unit、port binding、dependency、cold-start、route recovery、operator notification、cross-project sync 與 no-false-green 已納入;仍缺 owner response、live hash、change evidence、maintenance / restart window、rollback owner、post-check plan、disable switch 與 no-secret-value evidence | +| P1-2 | SSH / sudoers / known_hosts / firewall / WireGuard / NodePort | `62%` | repo-only 清冊已納入 16 個 SSH / network access surface,owner request draft、owner response acceptance 與事故型端口 / 防火牆變更證據驗收 ledger 已完成;仍缺 owner-provided change / incident ref、actor、before / after state、health impact、notification、cross-project sync、maintenance window、rollback owner 與 post-check evidence | +| P1-3 | AI provider / model routing / Ollama proxy / cost and privacy | `64%` | 已新增 owner response acceptance 帳本,固定 8 個候選、24 個 owner 必填欄位、24 個 reviewer checks、10 條 outcome lanes、38 類 blocked actions;仍缺 provider owner、fallback order、dry-run、benchmark、cost review、privacy review、data classification、prompt redaction、quality gate、rollback owner 與 post-check evidence,不切 production | | P1-4 | K8s / ArgoCD / production manifests | `64%` | manifest inventory、owner response acceptance 與 GitOps change evidence acceptance 已完成;仍缺 proposed commit ref、rendered manifest diff、ArgoCD app / sync revision、health before / after、rollout、route smoke、metrics / alert、blast radius、rollback revision、maintenance window 與 post-check owner | | P1-5 | Backup / restore / escrow / retention | `64%` | repo-only 清冊已納入 38 個 surface,owner request draft 與 owner response acceptance ledger 已完成,並補 restore recovery、freshness SLO、隔離還原目標、remote delete guard、retention runway、credential recovery metadata-only 與 no-false-green backup health Gate;仍缺 owner response、restore drill approval package、offsite / escrow owner、rollback owner、validation plan 與 no-secret-value evidence | | P1-6 | Prometheus / Alertmanager / Grafana / SigNoz / Sentry / Langfuse | `68%` | repo-only 清冊已納入 60 個 monitoring / alerting / observability surface,owner response acceptance 已補 no-false-green 回補 Gate;仍缺 owner response、live drift evidence、reload owner、receiver owner、receipt proof、stale / silence review、post-reload readback、route smoke plan 與 noise budget | @@ -256,6 +262,7 @@ python3 scripts/security/iwooos-config-control-guard.py --root . | Public / Admin / API runtime config 變更證據驗收 | `100%` | 已新增 `public_runtime_config_change_evidence_acceptance_v1` 與前台 source / messages 防洩漏 guard;6 個 candidate、5 個 C0、21 個 reviewer checks、8 條 outcome lanes、32 類 blocked action,另掃 225 個前端檔案、12 類禁字、違規 0;public/admin/API runtime config 成熟度 `62% -> 66%`,raw namespace / repo slug / 內部狀態碼 / 內部協作內容外洩列為拒收或隔離條件 | | Backup / restore / escrow owner response acceptance backfill | `100%` | 已將 `backup_restore_owner_response_acceptance_v1` 補強為 38 個 candidate、27 個 write-capable、23 個 owner 必填欄位、22 個 reviewer checks、9 條 outcome lanes、31 類 blocked action;backup / restore / credential 成熟度 `62% -> 64%` | | Monitoring / alerting / observability owner response acceptance backfill | `100%` | 已將 `monitoring_owner_response_acceptance_v1` 補強為 60 個 candidate、11 個 write-capable、38 個 acceptance fields、23 個 reviewer checks、12 條 outcome lanes、34 類 blocked action;monitoring / alerting / observability 成熟度 `66% -> 68%` | +| AI provider / model routing owner response acceptance | `100%` | 已新增 `ai_provider_owner_response_acceptance_v1`,8 個 candidate、5 個 write-capable、24 個 owner 必填欄位、24 個 reviewer checks、10 條 outcome lanes、38 類 blocked action;AI provider / model routing 成熟度 `60% -> 64%` | | owner response 收件 | `0%` | 尚未收到或接受任何 owner response | | live evidence collection | `0%` | 未 SSH、未 live probe、未 active scan | | runtime gate | `0%` | 未開啟任何執行期閘門 | diff --git a/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md b/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md index e7de25ccf..e6fb55e9c 100644 --- a/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md +++ b/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md @@ -133,6 +133,12 @@ 此更新只表示未來 host service 事故或變更證據已有收件驗收規則;change evidence received / accepted、Docker daemon state accepted、compose stack state accepted、systemd unit state accepted、failed unit review accepted、port binding accepted、route recovery accepted、operator notification accepted、live host read、SSH、Docker / systemd、repair-bot、Ansible、route smoke、host write、runtime gate 仍全部為 `0 / false`。 +### 0.8b 2026-06-15 AI provider / model routing owner response acceptance 只讀帳本 + +`ai_provider_owner_response_acceptance_v1` 已把 AI router provider policy、Ollama proxy gateway、fallback order / circuit breaker、cost budget / quota、privacy / data egress、benchmark / dry-run、model card / version inventory 與 agent replacement candidate boundary 轉成 metadata-only owner response acceptance 帳本。固定 `candidates=8`、`write_capable=5`、`paid_provider_related=5`、`data_egress=6`、`live_evidence_required=6`、`acceptance_fields=37`、`required_owner_fields=24`、`reviewer_checks=24`、`outcome_lanes=10`、`blocked_actions=38`,讓 AI provider / model routing 類別成熟度從 `60%` 推進到 `64%`。 + +此更新只表示未來 provider、fallback、cost、privacy、benchmark、dry-run、模型卡片與 agent replacement 證據已有收件驗收規則;owner response received / accepted、dry-run accepted、benchmark accepted、cost review accepted、privacy review accepted、fallback order accepted、provider switch、external provider call、paid provider call、prompt send、live endpoint probe、secret collection、SDK install、model download、shadow / canary、production deploy、runtime gate 仍全部為 `0 / false`。 + ## 1. 目前已不符合新要求的項目 | 優先 | 項目 | 現況 | 風險 | 本階段處置 | @@ -147,7 +153,7 @@ | P0 | DNS / TLS / certbot | 已有 domain / certificate path 清冊、owner confirmation request 與 owner response acceptance 只讀帳本,但仍缺 owner-provided coverage metadata、expiry metadata、renewal owner、ACME route owner、maintenance window 與 rollback owner | 憑證過期、錯誤 cert path、ACME challenge 被覆蓋會造成公開服務中斷 | 維持 C0;下一步只收脫敏 metadata ref,不做 DNS query、TLS probe、certbot renew 或 reload | | P1 | workflow / runner / deploy key / secret name | 已有 Gitea / GitHub readiness 盤點,但尚未把配置變更和 IwoooS 高價值配置共用 gate 合併 | workflow 或 runner 改錯會直接影響部署與 secret 注入 | 納入 C0,維持只讀 owner response,不收 secret value | | P1 | Docker Compose / systemd live config | 已有 repo-only inventory、owner request draft 與 owner response acceptance 只讀帳本,但仍缺 owner-provided live hash、maintenance / restart window、rollback owner、post-check plan、disable switch 與 no-secret-value evidence | restart policy、port、volume、env 改動會影響 Harbor、Sentry、Langfuse、Gitea 與代理賞金協議 runtime | 下一步只收脫敏 owner response / live hash metadata,不主動 SSH、不重啟、不跑 repair-bot | -| P1 | AI provider / Ollama proxy | 110 Nginx proxy、GCP-A/B、111 fallback、API provider route 多處配置 | provider route drift 會造成成本、可用性、資料外送與模型品質風險 | 納入 C1,任何切換仍需 dry-run / benchmark / owner gate | +| P1 | AI provider / Ollama proxy | Nginx proxy template、API provider route、fallback order、模型治理卡與 agent replacement 候選 | provider route drift 會造成成本、可用性、資料外送與模型品質風險 | 納入 C1,owner response acceptance 已固定;任何切換仍需 dry-run / benchmark / cost / privacy / rollback owner gate | | P1 | agent-bounty-protocol runtime / treasury / A2A / MCP | 已納入只讀範圍,但尚未有 production host、compose、domain、TLS、rollback owner 完整資料 | 外部 agent、claim / submit、payout 或 webhook 若未控管,風險高於一般網站 | 納入 C2,仍不改該 repo、不讀 `.env`、不部署 | ## 2. Nginx 控管機制 @@ -202,7 +208,7 @@ Nginx 是目前必須最先資安控管的配置,原因是它同時控制公 | P1 | Docker Compose / systemd | `docker-compose.yml`、`ops/*/docker-compose.yml`、`scripts/reboot-recovery/*.service`、`docs/security/HOST-SERVICE-OWNER-REQUEST-DRAFT.md`、`docs/security/HOST-SERVICE-OWNER-RESPONSE-ACCEPTANCE.md` | 110 / 188 / agent-bounty hosts | live hash metadata、port / volume / env diff、maintenance / restart window、rollback owner、post-check plan、disable switch;不得 restart / apply | | P1 | SSH / sudoers / known_hosts | Ansible inventory、ops scripts、runner scripts | host owners | owner request draft 已固定;下一步只收脫敏 live access state、known_hosts / host-key policy、target whitelist 與 rollback owner | | P1 | Firewall / WireGuard / NodePort / VIP | K8s service / network policy、Kali / wg-easy docs、`docs/security/PORT-FIREWALL-CHANGE-EVIDENCE-ACCEPTANCE.md` | network owner | owner request draft、owner response acceptance 與 change evidence acceptance 已固定;下一步只收 actor、before / after state、impact、cross-project sync、maintenance window、rollback owner 與 post-check evidence;no unreviewed port exposure | -| P1 | AI provider / model routing | `apps/api/src/services/ai_providers/*`、Ollama runbooks、Nginx proxy | AI owner | dry-run、benchmark、cost / privacy review、fallback order gate | +| P1 | AI provider / model routing | `apps/api/src/services/ai_providers/*`、`apps/api/src/services/ai_router.py`、`docs/ai/AI-MODEL-CARDS.md`、`docs/security/AI-PROVIDER-OWNER-RESPONSE-ACCEPTANCE.md`、`docs/security/ai-provider-owner-response-acceptance.snapshot.json` | AI owner | owner response acceptance、dry-run、benchmark、cost / privacy review、fallback order、prompt redaction、rollback owner;不得 provider switch、外部呼叫、付費呼叫、prompt send 或 live endpoint probe | | P1 | Kali 112 scanner config | `docs/security/KALI-112-MAINTENANCE-WINDOW-DRAFT.md`、Kali snapshots | Kali owner | maintenance window、no active scan、no `/execute`、hardening dry-run | | P2 | AWOOOI / AwoooP / IwoooS frontend runtime config | `apps/web/next.config.js`、`apps/web/src/lib/config.ts`、i18n | web owner | NEXT_PUBLIC public-domain only、no internal transcript, desktop/mobile smoke | | P2 | VibeWork product boundary | VibeWork owner docs / future evidence refs | VibeWork owner | independent product boundary、repo / deploy / admin / backup scope | diff --git a/docs/security/IWOOOS-POSTURE-PROJECTION.md b/docs/security/IWOOOS-POSTURE-PROJECTION.md index f3fa3923d..0222d8494 100644 --- a/docs/security/IWOOOS-POSTURE-PROJECTION.md +++ b/docs/security/IWOOOS-POSTURE-PROJECTION.md @@ -102,6 +102,7 @@ IwoooS 首版只讀取或對齊以下已提交 evidence: 56. 16 個 SSH / network access repo-only inventory surfaces、owner response acceptance 與端口 / 防火牆變更證據驗收只讀帳本,顯示 SSH target、known_hosts workflow、CI deploy SSH、monitoring SSH、backup SSH capture、sudoers wrapper、NetworkPolicy、NodePort、WireGuard runbook 與 alert SSH action catalog 的第一層清冊;write-capable surface `6`、NetworkPolicy `2`、NodePort `2`、sudoers `1`、WireGuard `1`,acceptance candidate `16`、change evidence candidate `14`、reviewer check `21`、outcome lane `9`、blocked action `28`,讓 SSH / network 類別成熟度從 `58%` 推進到 `62%`;owner response、change evidence、actor、before / after state、service health impact、operator notification、cross-project sync、post-check evidence、maintenance window、rollback owner、runtime gate 與 action button 仍全部為 `0`,不代表 SSH、sudo、firewall、port close / open、NetworkPolicy、NodePort、WireGuard、route smoke 或 known_hosts patch 已授權。 56a. 4 個 K8s / ArgoCD GitOps 變更證據驗收候選,顯示 production manifests、ArgoCD app、Velero、monitoring manifests 的 proposed commit、rendered manifest diff、ArgoCD app / sync revision、health before / after、rollout、route smoke、metrics / alert、secret metadata parity、blast radius、maintenance window、rollback revision 與 postcheck owner 收件規則;C0 candidate `3`、write-capable candidate `4`、reviewer check `18`、outcome lane `8`、blocked action `28`,讓 K8s / ArgoCD 類別成熟度從 `62%` 推進到 `64%`;change evidence、runtime approval package、ArgoCD API read、ArgoCD sync、kubectl action、Helm upgrade、NetworkPolicy / NodePort / RBAC change、production write、runtime gate 與 action button 仍全部為 `0`。 56b. 5 個 CD / Runner / Secret 注入變更證據驗收候選,顯示 CD pipeline、程式碼審查、部署通知、執行器證明與 repository secret name parity / injection owner 的 metadata-only 收件規則;C0 candidate `4`、write-capable candidate `5`、local workflow file `33`、referenced secret name `42`、runner label `5`、reviewer check `19`、outcome lane `8`、blocked action `32`,讓 secret metadata 類別成熟度從 `66%` 推進到 `68%`,讓 Gitea workflow / runner 類別成熟度從 `70%` 推進到 `72%`;workflow diff、runner attestation、secret name parity、secret injection route、deploy marker readback、guard result、postcheck evidence、runtime approval package、workflow modification、runner change、repo secret change、secret rotation、Gitea action dispatch、production deploy、runtime gate 與 action button 仍全部為 `0`。 +56c. 8 個 AI provider / model routing owner response acceptance 候選,顯示 AI router provider policy、Ollama proxy gateway、fallback order / circuit breaker、cost budget / quota、privacy / data egress、benchmark / dry-run、model card / version inventory 與 agent replacement candidate boundary 的 metadata-only 收件規則;write-capable candidate `5`、paid-provider candidate `5`、data-egress candidate `6`、owner field `24`、reviewer check `24`、outcome lane `10`、blocked action `38`,讓 AI provider / model routing 類別成熟度從 `60%` 推進到 `64%`;owner response、fallback order、dry-run、benchmark、cost review、privacy review、prompt redaction、quality gate、provider switch、external provider call、paid provider call、prompt send、live endpoint probe、secret collection、SDK install、shadow / canary、runtime gate 與 action button 仍全部為 `0`。 57. 38 個 Backup / restore / escrow / retention repo-only inventory surfaces,顯示 backup orchestration、service backup scripts、restic retention、offsite sync、credential escrow、Velero restore drill、backup health alert 與 cold-start / DR runbook 的第一層清冊;write-capable surface `27`、restore drill surface `4`、offsite / escrow surface `8`,owner response、live evidence、restore drill、offsite sync、credential escrow、retention change、runtime gate 與 action button 仍全部為 `0`,不代表 backup、restore、offsite sync、remote delete、restic prune、escrow marker write、rclone config 或 Velero restore 已授權。 57a. 38 個 Backup / restore / escrow owner response acceptance backfill,顯示 restore recovery、freshness SLO、隔離 restore target、backup dependency map、data classification、remote delete guard、retention runway、restore observer / stop condition、credential recovery non-secret proof 與 backup health no-false-green review 收件規則;owner field `23`、reviewer check `22`、outcome lane `9`、blocked action `31`,讓 backup / restore / credential 類別成熟度從 `62%` 推進到 `64%`;owner response、freshness SLO accepted、restore target isolation accepted、remote delete guard accepted、retention runway accepted、credential recovery drill accepted、backup run、restore run、offsite sync、remote delete、retention change、secret collection、runtime gate 與 action button 仍全部為 `0`。 58. 60 個 Monitoring / alerting / observability repo-only inventory surfaces,顯示 Prometheus、Alertmanager、Grafana、SigNoz、Sentry、Langfuse、OTEL、Telegram / notification policy、deploy / reload scripts 與 alert chain smoke scripts 的第一層清冊;write-capable surface `11`、alert rule surface `13`、deploy / reload surface `6`,owner response、live evidence、reload owner、receiver owner、route smoke、runtime gate 與 action button 仍全部為 `0`,不代表 Prometheus reload、Alertmanager reload、Grafana import、SigNoz apply、Sentry deploy、Telegram send、live alert fire 或 alert chain smoke 已授權。 diff --git a/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md b/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md index e0021f793..76d355720 100644 --- a/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md +++ b/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md @@ -3,13 +3,13 @@ | 項目 | 內容 | |------|------| | 日期 | 2026-06-15 | -| 狀態 | IwoooS 64% 只讀治理推進中;高價值配置集中 guard、Package / Docker 供應鏈 repo-only baseline 與 Package / Docker 供應鏈 owner policy gate 已完成;Frontend public sensitive surface guard、Backup / Restore / Escrow owner response acceptance backfill、Monitoring / Alerting / Observability no-false-green owner response acceptance、Host Service change evidence acceptance、CD / Runner / Secret 注入變更證據驗收與 Public / Admin / API runtime config 變更證據驗收只讀帳本已本地完成;端口 / 防火牆變更證據驗收、主機服務事故回補與 K8s / ArgoCD GitOps 變更證據驗收已正式部署驗證;S4.9 owner response gate 仍是第一優先 | +| 狀態 | IwoooS 64% 只讀治理推進中;高價值配置集中 guard、Package / Docker 供應鏈 repo-only baseline 與 Package / Docker 供應鏈 owner policy gate 已完成;Frontend public sensitive surface guard、Backup / Restore / Escrow owner response acceptance backfill、Monitoring / Alerting / Observability no-false-green owner response acceptance、Host Service change evidence acceptance、AI provider / model routing owner response acceptance、CD / Runner / Secret 注入變更證據驗收與 Public / Admin / API runtime config 變更證據驗收只讀帳本已本地完成;端口 / 防火牆變更證據驗收、主機服務事故回補與 K8s / ArgoCD GitOps 變更證據驗收已正式部署驗證;S4.9 owner response gate 仍是第一優先 | | 本階段完成 | 資安供應鏈 contract manifest + Source Control Approval Board + Draft Reconcile Plan + Ref Detail Diff + Ref Truth Classification + Source Control Ref Truth Owner Response 收件包 + GitHub Primary Readiness Gate + GitHub Primary Rollback ADR + GitHub Target Owner Decision Response 收件包 + Gitea 認證清冊匯出請求 + Gitea 認證清冊匯入驗收契約 + Gitea 清冊覆蓋 Owner Attestation + Gitea Owner Attestation Approval Lane 對齊 + Gitea Owner Attestation Response 收件包 + Workflow / Secret Name Inventory + Workflow / Secret Name Local Evidence + Workflow / Secret Name Redacted Export Request + Workflow / Secret Name Owner Response 收件包 + Source Control Owner Response Validation Rollup + Kali 112 live integration status + Security Finding contract + Kali scan scope approval package + Security Approval Queue + S3 人工批准 Gate + S3 人工決策紀錄 + S3 人工審查封包 + S3 人工決策狀態轉移 + S3 後續 runtime gate 準備契約 + 鏡像 readiness index + 鏡像接收計畫 + 鏡像事件信封 + 鏡像路由矩陣 + 鏡像驗收契約 + 鏡像隔離契約 + 鏡像 dry-run 報告契約 + 鏡像狀態彙整契約 + IwoooS 前端態勢入口 + IwoooS posture projection contract + IwoooS 既有前端資安頁面整合 + IwoooS 覆蓋與邊界矩陣 + IwoooS 只讀資安處理旅程 + IwoooS owner evidence readiness board + IwoooS host coverage view + IwoooS host action gate matrix + IwoooS host evidence readiness board + IwoooS host evidence collection order + IwoooS host evidence intake preflight + IwoooS host evidence review outcome lanes + IwoooS host evidence review handoff packets + IwoooS host evidence reviewer checklist + IwoooS host evidence reviewer outcome lanes + IwoooS host owner decision candidate packets + IwoooS host owner decision review checklist + IwoooS host owner decision review outcome lanes + IwoooS host owner decision record draft packets + IwoooS host owner decision record draft review checklist + IwoooS host owner decision record draft review outcome lanes + IwoooS host owner decision record write-up packets + IwoooS host owner decision record write-up review checklist + IwoooS host owner decision record write-up review outcome lanes + IwoooS host owner decision record formal candidate packets + IwoooS host owner decision record formal candidate review checklist + IwoooS host owner decision record formal candidate review outcome lanes + IwoooS host owner decision record formal record queue packets + IwoooS host owner decision record formal record queue review checklist + IwoooS host owner decision record formal record queue review outcome lanes + IwoooS host owner decision record human handoff readiness packets + IwoooS host owner decision record human handoff readiness review checklist + IwoooS host owner decision record human handoff readiness review outcome lanes + IwoooS host owner decision record human record owner review candidate packets + IwoooS host owner decision record human record owner review candidate checklist + IwoooS host owner decision record human record owner review candidate outcome lanes + IwoooS host owner decision record human record owner review preparation packets + IwoooS host owner decision record human record owner review preparation checklist + IwoooS progress acceleration lanes + IwoooS owner response next-action focus + IwoooS S4.9 owner response preflight + IwoooS S4.9 owner response request templates + IwoooS progress hold movement gates + IwoooS AwoooP read-only landing readiness + IwoooS AwoooP cross-session handoff packets + AwoooP 首頁 IwoooS 資安鏡像候選 + AwoooP 工作鏈路 IwoooS 資安鏡像候選 + AwoooP 審批佇列 IwoooS owner response 只讀焦點 | | 本階段追加 | AwoooP 合約儀表板 IwoooS 資安契約只讀候選 + AwoooP 租戶管理 IwoooS 資安租戶範圍只讀候選 + AwoooP 執行監控 IwoooS 執行狀態只讀候選 + 既有安全 / 合規頁面 IwoooS 只讀反向橋接 + 告警 / 錯誤 / 授權 / 治理頁面 IwoooS 只讀反向橋接 + 稽核 / 工程審查頁面 IwoooS 深色只讀反向橋接 + IwoooS 前端資安頁面連接狀態板 + IwoooS GitHub 主要來源就緒度只讀狀態板 + AwoooP 工作鏈路 GitHub 主要來源就緒度只讀工作項 + AwoooP 合約儀表板 GitHub 主要來源就緒度合約只讀候選 + AwoooP 審批佇列 GitHub 主要來源就緒度審批邊界 + AwoooP 首頁 GitHub 主要來源就緒度只讀摘要 + AwoooP 租戶管理 GitHub 主要來源就緒度租戶範圍 + AwoooP 執行監控 GitHub 主要來源就緒度執行邊界 + IwoooS / AwoooP 資安可視區塊繁體中文呈現防護檢查 + AwoooP 執行詳情 / 審批詳情繁體中文呈現防護檢查 + AwoooP 首頁負責人回覆驗收總覽 + AwoooP 工作鏈路負責人回覆驗收只讀工作項 + AwoooP 合約儀表板負責人回覆驗收契約只讀候選 + AwoooP 審批佇列負責人回覆驗收只讀審查邊界 + AwoooP 租戶管理負責人回覆驗收租戶範圍 + AwoooP 執行監控負責人回覆驗收執行邊界 + AwoooP 執行詳情負責人回覆驗收詳情邊界 + AwoooP 審批決策負責人回覆驗收審批邊界 + IwoooS AwoooP 資安入口覆蓋狀態板 + IwoooS 階段式資安收斂節奏圖 + IwoooS 下一步人工收件作戰板 + IwoooS 人工回覆安全驗收閘道 + IwoooS 人工回覆審查結果分流 + IwoooS 人工決策準備佇列 + IwoooS 人工決策紀錄草稿防誤用 + IwoooS 人工決策正式紀錄負責人指派確認準備包 + IwoooS 人工決策正式紀錄負責人指派確認清單 + IwoooS 人工決策正式紀錄負責人指派確認結果分流 + IwoooS 人工決策正式紀錄負責人指派決策準備包 + IwoooS 人工決策正式紀錄負責人指派決策檢查清單 + IwoooS S4.9 負責人回覆封套欄位 + IwoooS S4.9 負責人回覆封套送件前檢查 + IwoooS S4.9 負責人回覆封套送件前結果分流 + IwoooS S4.9 負責人回覆送件請求草稿 + IwoooS S4.9 負責人回覆送件鏈路摘要 + IwoooS 低摩擦分階段收斂主控 + IwoooS 低摩擦下一步行動邊界 + IwoooS 64% 進度移動訊號驗收條 + IwoooS 第一個進度解鎖路徑 + IwoooS 第一解鎖證據包 + IwoooS 第一解鎖證據包預檢分流 + IwoooS 第一解鎖證據包補件路徑 + IwoooS 第一解鎖證據包補件送審前檢查 + IwoooS 第一解鎖證據包補件送審結果分流 + IwoooS 第一解鎖證據包 reviewer 指派準備包 + IwoooS 第一解鎖證據包 reviewer 指派前檢查 + IwoooS 第一解鎖證據包 reviewer 指派前檢查結果分流 + IwoooS 正式只讀 landing 與 Kali 112 只讀證據進度重估 | | 本階段追加補充 | IwoooS 目前具體工作地圖 + IwoooS 目前具體交付清單 + IwoooS 目前阻塞與解除條件 + IwoooS 三軸進度與全產品套用範圍 + IwoooS 全產品分階段套用台帳 + IwoooS 全產品 rollout 波次驗收門檻 + IwoooS 全產品 rollout 驗收結果分流 + IwoooS 全產品證據接線地圖 + IwoooS 全產品證據接線預檢 + IwoooS 全產品證據接線預檢結果分流 + IwoooS 全產品預檢補件回收台帳 + IwoooS 全產品補件重試門檻 + IwoooS 全產品重試結果分流 + IwoooS 全產品人工審查候選準備 + IwoooS 全產品人工審查候選預檢 + IwoooS 全產品人工審查候選預檢結果分流 + IwoooS 全產品人工審查候選預檢補件回收台帳 + IwoooS 全產品人工審查候選預檢補件重試門檻 + IwoooS 全產品只讀套用快照 + P2-145 owner response acceptance gate 正式驗證完成 | | P0 追加 | IwoooS P0 配置控管優先序前台正式驗證完成;Nginx public gateway、DNS / TLS / certbot、K8s / ArgoCD / production manifests、Workflow / runner / secret metadata、Public / admin / API runtime config、agent-bounty runtime / treasury 六類先列為即時風險配置;高價值配置 Gate 已補上 `k8s/nginx/**`、`scripts/ops/**/*cert*`、`scripts/ops/**/*tls*`,sample 從 `matched=0 / C0=0` 收斂到 `matched=3 / C0=2`;Gate 預設工作樹 preflight 已可讀取 staged / unstaged / untracked,本地 smoke 對臨時 `k8s/nginx/*` 檔命中 C0;Owner Packet snapshot 已同步為 `packets=3 / c0=2`,Coverage snapshot 已同步最新 patterns;IwoooS / AwoooP 前台 Owner Packet 摘要已正式驗證 `packet=3 / c0=2`,feature commit `e999c16b`、deploy marker `16c6b983`、Gitea code-review `2973` / CD `2972` success;IwoooS posture projection snapshot / schema / guard 已同步 `packet=3 / c0=2`,不再保留舊 `1 / 0` 口徑;高價值配置 Owner Packet 收件預檢已新增 `checks=9 / lanes=5 / required_fields=27 / blocked_requests=16`;高價值配置 Owner Request 草稿包已新增 `drafts=3 / handoff_fields=11 / forbidden_payloads=12 / sent=0`;Public Gateway live conf 匯出請求包已新增 `requests=3 / c0=2 / redaction_rules=8 / received=0`;Public Gateway redacted export 收件預檢已新增 `candidates=3 / c0=2 / checks=10 / rejection_guards=12 / received=0 / accepted=0`;Public Gateway rendered diff / nginx gate 草稿已新增 `candidates=3 / c0=2 / stages=7 / blocked=14 / rendered_diff=0 / runtime=0`;Public Gateway owner response acceptance 只讀帳本已新增 `candidates=3 / c0=2 / fields=33 / checks=22 / lanes=8 / blocked=28 / accepted=0 / runtime=0`,並補上手動 / 緊急 gateway 變更的 intent、approval / break-glass、route health、rollback validation 與 post-change monitoring 必填 ref;DNS / TLS / certbot Owner Confirmation Request 已新增 `requests=4 / c0=4 / fields=9 / questions=5 / guards=12 / received=0 / accepted=0`;K8s / ArgoCD manifest repo-only 清冊已新增 `files=49 / c0=36 / yaml=45 / kinds=20 / blocked=13 / runtime=0`;K8s / ArgoCD Owner Request Draft 已新增 `drafts=4 / c0=3 / fields=11 / sent=0 / runtime=0`;K8s / ArgoCD owner response acceptance 只讀帳本已新增 `candidates=4 / c0=3 / fields=11 / checks=12 / lanes=7 / blocked=18 / accepted=0 / runtime=0`;K8s / ArgoCD GitOps 變更證據驗收已新增 `candidates=4 / c0=3 / write_capable=4 / evidence_fields=18 / checks=18 / lanes=8 / blocked=28 / accepted=0 / runtime=0`;CD / Runner / Secret 注入變更證據驗收已新增 `candidates=5 / c0=4 / write_capable=5 / workflow_files=33 / secret_names=42 / runner_labels=5 / evidence_fields=19 / checks=19 / lanes=8 / blocked=32 / accepted=0 / runtime=0`;Public / Admin / API runtime config 變更證據驗收已新增 `candidates=6 / c0=5 / write_capable=6 / source_refs=20 / evidence_fields=21 / checks=21 / lanes=8 / blocked=32 / accepted=0 / runtime=0`,並把 raw namespace、repo slug、內部狀態碼與內部協作內容外洩列為拒收 / 隔離;Frontend public sensitive surface guard 已新增 `files=225 / patterns=12 / allowlisted=2 / violations=0 / runtime=0`,讓 public runtime config 成熟度 `64% -> 66%`、高價值配置平均 `69% -> 70%`;Backup / Restore / Escrow owner response acceptance 只讀帳本已更新為 `candidates=38 / write_capable=27 / fields=33 / owner_fields=23 / reviewer_checks=22 / lanes=9 / blocked=31 / accepted=0 / runtime=0`;SSH / Firewall / Network Access owner response acceptance 只讀帳本已新增 `candidates=16 / write_capable=6 / fields=13 / checks=15 / lanes=7 / blocked=22 / accepted=0 / runtime=0`;端口 / 防火牆變更證據驗收只讀帳本已新增 `candidates=14 / write_capable=6 / policy_or_exposure=5 / evidence_fields=16 / checks=16 / lanes=8 / blocked=24 / accepted=0 / runtime=0`;owner response / live evidence / runtime gate / action buttons 仍全部為 0 | | P0 agent-bounty 追加 | agent-bounty-protocol Owner Request Draft 已新增 `drafts=11 / control=4 / surface=7 / write_capable=8 / treasury=4 / mcp_a2a=5 / fields=22 / forbidden_inputs=25 / blocked=28 / sent=0 / runtime=0`;這是 repo / refs、deployment、data classification、MCP / A2A、cron / daemon、admin / treasury、webhook / traffic 的人工送件前草稿,不是 owner response、repo push、refs sync、workflow 修改、secret 收集、deploy、compose restart、DB migration、claim / submit、payout / withdrawal、cron / daemon、external send、host write 或 runtime gate | -| P1 追加 | Docker / systemd / Host Service Owner Request Draft 已新增 `drafts=9 / write_capable=3 / fields=12 / blocked=14 / sent=0 / runtime=0`;Docker / systemd / Host Service Owner Response Acceptance 已更新為 `candidates=9 / write_capable=3 / live_evidence_required=8 / fields=34 / owner_fields=18 / reviewer_checks=21 / lanes=8 / blocked=27 / accepted=0 / runtime=0`;Docker / systemd / Host Service Change Evidence Acceptance 已新增 `candidates=9 / write_capable=3 / live_evidence_required=8 / evidence_fields=45 / required_fields=25 / reviewer_checks=26 / lanes=10 / blocked=39 / accepted=0 / runtime=0`;SSH / Firewall / Network Access Owner Request Draft 已新增 `drafts=16 / write_capable=6 / fields=13 / blocked=16 / sent=0 / runtime=0`;Backup / Restore / Escrow Owner Request Draft 已新增 `drafts=38 / write_capable=27 / fields=14 / blocked=18 / sent=0 / runtime=0`;Backup / Restore / Escrow Owner Response Acceptance 已更新為 `candidates=38 / write_capable=27 / owner_fields=23 / reviewer_checks=22 / lanes=9 / blocked=31 / accepted=0 / runtime=0`;Monitoring / Alerting / Observability Owner Request Draft 已新增 `drafts=60 / write_capable=11 / fields=14 / blocked=24 / sent=0 / runtime=0`;Monitoring / Alerting / Observability Owner Response Acceptance 已更新為 `candidates=60 / write_capable=11 / live_evidence_required=60 / fields=38 / owner_fields=14 / reviewer_checks=23 / lanes=12 / blocked=34 / accepted=0 / runtime=0`,並補 incident context、receiver receipt、stale alert、silence / dedup、post-reload readback 與 false-green risk review;上述全部仍是人工送件前草稿或只讀 acceptance 帳本,不是 owner response、change evidence accepted、live evidence、reload、restart、backup、restore、Telegram send、alert smoke、host write 或 runtime gate | +| P1 追加 | Docker / systemd / Host Service Owner Request Draft 已新增 `drafts=9 / write_capable=3 / fields=12 / blocked=14 / sent=0 / runtime=0`;Docker / systemd / Host Service Owner Response Acceptance 已更新為 `candidates=9 / write_capable=3 / live_evidence_required=8 / fields=34 / owner_fields=18 / reviewer_checks=21 / lanes=8 / blocked=27 / accepted=0 / runtime=0`;Docker / systemd / Host Service Change Evidence Acceptance 已新增 `candidates=9 / write_capable=3 / live_evidence_required=8 / evidence_fields=45 / required_fields=25 / reviewer_checks=26 / lanes=10 / blocked=39 / accepted=0 / runtime=0`;AI provider / Model Routing Owner Response Acceptance 已新增 `candidates=8 / write_capable=5 / paid_provider=5 / data_egress=6 / fields=37 / owner_fields=24 / reviewer_checks=24 / lanes=10 / blocked=38 / accepted=0 / runtime=0`;SSH / Firewall / Network Access Owner Request Draft 已新增 `drafts=16 / write_capable=6 / fields=13 / blocked=16 / sent=0 / runtime=0`;Backup / Restore / Escrow Owner Request Draft 已新增 `drafts=38 / write_capable=27 / fields=14 / blocked=18 / sent=0 / runtime=0`;Backup / Restore / Escrow Owner Response Acceptance 已更新為 `candidates=38 / write_capable=27 / owner_fields=23 / reviewer_checks=22 / lanes=9 / blocked=31 / accepted=0 / runtime=0`;Monitoring / Alerting / Observability Owner Request Draft 已新增 `drafts=60 / write_capable=11 / fields=14 / blocked=24 / sent=0 / runtime=0`;Monitoring / Alerting / Observability Owner Response Acceptance 已更新為 `candidates=60 / write_capable=11 / live_evidence_required=60 / fields=38 / owner_fields=14 / reviewer_checks=23 / lanes=12 / blocked=34 / accepted=0 / runtime=0`,並補 incident context、receiver receipt、stale alert、silence / dedup、post-reload readback 與 false-green risk review;上述全部仍是人工送件前草稿或只讀 acceptance 帳本,不是 owner response、change evidence accepted、live evidence、provider switch、外部 provider call、付費呼叫、prompt send、reload、restart、backup、restore、Telegram send、alert smoke、host write 或 runtime gate | | P2 供應鏈追加 | Package / Docker 供應鏈 repo-only baseline 已新增 `package_json=6 / pyproject=4 / requirements=2 / dockerfiles=2 / compose=6 / gaps=5 / runtime=0`;Package / Docker 供應鏈 owner policy gate 已新增 `requests=6 / c0=2 / fields=8 / checks=12 / blocked=20 / sent=0 / accepted=0 / runtime=0`;缺口為 Python lockfile 缺席、requirements 未 pin、Docker base image 未全數 digest pinning、Docker `COPY --from` 外部 image 未 digest pinning、compose image 未 digest pinning,以及 CVE / license / SBOM window 未定;目前尚未列入 36 個正式 AwoooP 消費 contract,後續若要前台消費需同步 manifest / readiness / route / rollup / dry-run / posture projection / guard count;本輪不 install、不 upgrade、不跑 CVE、不 pull / build / push image、不改 tag、不登入 registry、不部署 | | 原則 | 低摩擦分階段;文件、schema、read-only evidence 優先;不做 runtime enforcement、不切 primary | | P0 主控板 | `docs/workplans/2026-06-04-iwooos-security-governance-p0.md` | @@ -20,6 +20,12 @@ 同步邊界:IwoooS headline 維持 `64%`,active runtime gate 維持 `0`;change evidence、Docker daemon state、compose stack state、systemd unit state、failed unit review、port binding、route recovery、operator notification、postcheck evidence、runtime gate 與 action buttons 全部仍為 `0 / false`。本段只更新文件、snapshot、guard、覆蓋矩陣與前端 marker,不 SSH、不讀 live host、不碰 Docker daemon、systemd、repair-bot、Ansible、route smoke、Nginx、firewall、iptables 或主機。 +## 0.00aaaaaa1 2026-06-15 AI provider / Model Routing owner response acceptance + +本輪把 AI router provider policy、Ollama proxy gateway、fallback order / circuit breaker、cost budget / quota、privacy / data egress、benchmark / dry-run、model card / version inventory 與 agent replacement candidate boundary 從 policy-ready 推進到 owner response acceptance 只讀帳本:`ai_provider_owner_response_acceptance_v1` 固定 `candidates=8`、`write_capable=5`、`paid_provider=5`、`data_egress=6`、`live_evidence_required=6`、`acceptance_fields=37`、`owner_fields=24`、`reviewer_checks=24`、`outcome_lanes=10`、`blocked_actions=38`,並讓 `ai_provider_model_routing` 只讀治理成熟度 `60% -> 64%`。 + +同步邊界:IwoooS headline 維持 `64%`,active runtime gate 維持 `0`;owner response、fallback order、dry-run、benchmark、cost review、privacy review、prompt redaction、quality gate、provider switch、external provider call、paid provider call、prompt send、live endpoint probe、secret collection、SDK install、model download、shadow / canary、production deploy、runtime gate 與 action buttons 全部仍為 `0 / false`。本段只更新文件、snapshot、guard、覆蓋矩陣、模型卡片脫敏與前端 marker,不呼叫模型、不切 provider、不改 proxy、不新增付費呼叫、不外送資料。 + ## 0.00aaaaaa 2026-06-15 Monitoring / Alerting / Observability owner response acceptance 本輪把 Prometheus、Alertmanager、Grafana、SigNoz、Sentry、Langfuse、OTEL、receiver route、silence policy、Telegram Bot 與 alert chain smoke 從 owner request draft 推進到 owner response acceptance 只讀帳本:`monitoring_owner_response_acceptance_v1` 固定 `candidates=60`、`write_capable=11`、`live_evidence_required=60`、`acceptance_fields=38`、`owner_fields=14`、`reviewer_checks=23`、`outcome_lanes=12`、`blocked_actions=34`,並讓 `monitoring_alerting_observability` 只讀治理成熟度 `62% -> 68%`。這是 owner response 收件驗收與 no-false-green 回補帳本,不是 owner response received / accepted / rejected、Prometheus reload、Alertmanager reload、Grafana import、SigNoz apply、Sentry deploy、Langfuse change、OTEL reload、receiver route change、silence change、Telegram send、live alert fire、alert chain smoke、runtime approval package 或 runtime gate。 diff --git a/docs/security/ai-provider-owner-response-acceptance.snapshot.json b/docs/security/ai-provider-owner-response-acceptance.snapshot.json new file mode 100644 index 000000000..cc24c308f --- /dev/null +++ b/docs/security/ai-provider-owner-response-acceptance.snapshot.json @@ -0,0 +1,2261 @@ +{ + "schema_version": "ai_provider_owner_response_acceptance_v1", + "status": "owner_response_acceptance_ledger_ready_no_runtime_action", + "generated_at": "2026-06-15T19:35:00+08:00", + "git_sha": "403b29df", + "source_paths": [ + "docs/HARD_RULES.md", + "docs/ai/AI-MODEL-CARDS.md", + "docs/runbooks/OPENCLAW-REPLACEMENT-EVALUATION.md", + "scripts/security/ai-provider-owner-response-acceptance.py", + "scripts/security/high-value-config-control-coverage.py" + ], + "summary": { + "acceptance_candidate_count": 8, + "write_capable_acceptance_candidate_count": 5, + "paid_provider_related_candidate_count": 5, + "data_egress_candidate_count": 6, + "live_evidence_required_candidate_count": 6, + "acceptance_field_count": 37, + "required_owner_field_count": 24, + "reviewer_check_count": 24, + "outcome_lane_count": 10, + "blocked_action_count": 38, + "owner_response_received_count": 0, + "owner_response_accepted_count": 0, + "owner_response_rejected_count": 0, + "owner_response_quarantined_count": 0, + "supplement_requested_count": 0, + "fallback_order_accepted_count": 0, + "dry_run_result_accepted_count": 0, + "benchmark_result_accepted_count": 0, + "cost_review_accepted_count": 0, + "privacy_review_accepted_count": 0, + "data_classification_accepted_count": 0, + "prompt_redaction_accepted_count": 0, + "secret_handling_accepted_count": 0, + "quota_budget_accepted_count": 0, + "latency_slo_accepted_count": 0, + "quality_gate_accepted_count": 0, + "rollback_owner_accepted_count": 0, + "maintenance_window_accepted_count": 0, + "postcheck_evidence_accepted_count": 0, + "provider_switch_authorized_count": 0, + "external_provider_call_authorized_count": 0, + "paid_provider_call_authorized_count": 0, + "prompt_send_authorized_count": 0, + "live_endpoint_probe_authorized_count": 0, + "secret_value_collection_allowed_count": 0, + "runtime_gate_count": 0, + "action_button_count": 0, + "coverage_percent_before_acceptance": 60, + "coverage_percent_after_acceptance": 64 + }, + "acceptance_fields": [ + "acceptance_candidate_id", + "surface_id", + "label", + "expected_scope", + "config_kind", + "control_tier", + "source_refs", + "source_ref_sha256", + "write_capable_surface", + "paid_provider_related", + "data_egress_related", + "requires_live_evidence", + "owner_response_ref", + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "provider_owner", + "fallback_order_ref", + "dry_run_result_ref", + "benchmark_result_ref", + "cost_review_ref", + "privacy_review_ref", + "data_classification_ref", + "prompt_redaction_ref", + "secret_handling_ref", + "quota_budget_ref", + "latency_slo_ref", + "quality_gate_ref", + "rollback_owner", + "rollback_plan_ref", + "maintenance_window", + "postcheck_evidence_refs", + "redacted_evidence_refs", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "required_owner_fields": [ + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "provider_owner", + "fallback_order_ref", + "dry_run_result_ref", + "benchmark_result_ref", + "cost_review_ref", + "privacy_review_ref", + "data_classification_ref", + "prompt_redaction_ref", + "secret_handling_ref", + "quota_budget_ref", + "latency_slo_ref", + "quality_gate_ref", + "rollback_owner", + "rollback_plan_ref", + "maintenance_window", + "postcheck_evidence_refs", + "redacted_evidence_refs", + "followup_owner", + "not_approval", + "no_secret_value_attestation" + ], + "reviewer_checks": [ + { + "check_id": "owner_identity_present", + "instruction": "owner role / team 與 provider owner 必須可追溯。" + }, + { + "check_id": "decision_reason_present", + "instruction": "decision 與 decision reason 必須同時存在。" + }, + { + "check_id": "affected_scope_matches_surface", + "instruction": "affected scope 必須能對回既有 AI provider surface。" + }, + { + "check_id": "redacted_refs_only", + "instruction": "evidence 只能是脫敏 ref、hash、ticket、commit 或 artifact pointer。" + }, + { + "check_id": "secret_value_absent", + "instruction": "不得出現 API key、token、cookie、private key、env dump、完整 DSN 或 partial secret。" + }, + { + "check_id": "live_endpoint_absent", + "instruction": "不得保存 raw live endpoint、內網位址或可直接連線 URL。" + }, + { + "check_id": "fallback_order_present", + "instruction": "必須提供 fallback order 與 degraded mode ref,不接受憑印象切 provider。" + }, + { + "check_id": "dry_run_result_present", + "instruction": "必須有 dry-run 結果或明確不適用理由;dry-run 不得呼叫 production LLM。" + }, + { + "check_id": "benchmark_result_present", + "instruction": "必須有 benchmark / replay / fixture 結果與評分方法 ref。" + }, + { + "check_id": "cost_review_present", + "instruction": "涉及雲端或付費 provider 時必須有成本上限、quota、告警與停損 ref。" + }, + { + "check_id": "privacy_review_present", + "instruction": "涉及外部 provider、prompt、log 或 embedding 時必須有資料外送與脫敏審查 ref。" + }, + { + "check_id": "data_classification_present", + "instruction": "必須標示可送出、不可送出、需遮罩與只能本地處理的資料分類。" + }, + { + "check_id": "prompt_redaction_present", + "instruction": "prompt / log / incident context 需有 redaction proof,不接受 raw prompt 或 raw log。" + }, + { + "check_id": "secret_handling_metadata_only", + "instruction": "secret handling 只能描述注入路徑與 owner,不得貼 secret value / hash / partial token。" + }, + { + "check_id": "quota_budget_present", + "instruction": "付費 provider、雲端 provider 或外部 API 必須有 quota budget 與 stop condition。" + }, + { + "check_id": "latency_slo_present", + "instruction": "需要 latency / timeout / circuit breaker / degradation SLO ref。" + }, + { + "check_id": "quality_gate_present", + "instruction": "模型切換或 agent replacement 必須有品質門檻與 incumbent baseline。" + }, + { + "check_id": "rollback_owner_present", + "instruction": "rollback owner 與 rollback plan 必須存在。" + }, + { + "check_id": "maintenance_window_present", + "instruction": "provider route、proxy、env 或 model change 必須另有維護窗口。" + }, + { + "check_id": "postcheck_evidence_present", + "instruction": "post-check 必須覆蓋 provider route、fallback、cost、privacy、observability 與 rollback stop condition。" + }, + { + "check_id": "no_runtime_request", + "instruction": "夾帶 provider switch、Nginx reload、env change、external call、prompt send、benchmark live call 或 deploy 時拒收。" + }, + { + "check_id": "no_false_green_provider_health", + "instruction": "不得把 provider route 200、dashboard up、模型回覆一次成功當成 routing / privacy / cost 已驗收。" + }, + { + "check_id": "cross_project_sync_present", + "instruction": "影響 AwoooP、IwoooS、agent-bounty、code review、StockPlatform 或公開網站時需有跨專案同步 ref。" + }, + { + "check_id": "counts_transition_safe", + "instruction": "只有 reviewer record 可更新 received / accepted;不得同時開 runtime gate。" + } + ], + "outcome_lanes": [ + { + "lane_id": "waiting_owner_response", + "meaning": "尚未收到 AI provider owner response;所有 accepted / runtime count 維持 0。" + }, + { + "lane_id": "quarantine_secret_or_raw_payload", + "meaning": "收到 secret、raw prompt、raw log、raw endpoint、未脫敏截圖或 env dump 時隔離。" + }, + { + "lane_id": "reject_execution_request", + "meaning": "夾帶 provider switch、外部呼叫、prompt send、Nginx reload、env change 或 deploy 要求時拒收。" + }, + { + "lane_id": "request_fallback_supplement", + "meaning": "缺 fallback order、degraded mode、circuit breaker 或 rollback 時要求補件。" + }, + { + "lane_id": "request_cost_privacy_supplement", + "meaning": "缺 cost / quota / privacy / data classification / prompt redaction 時要求補件。" + }, + { + "lane_id": "request_benchmark_supplement", + "meaning": "缺 dry-run、benchmark、fixture replay、quality gate 或 incumbent baseline 時要求補件。" + }, + { + "lane_id": "legacy_model_card_redaction_required", + "meaning": "舊模型卡、runbook 或報表含 raw endpoint / 主機識別時,先改成脫敏 alias。" + }, + { + "lane_id": "ready_for_ai_provider_review", + "meaning": "metadata 合格後,只能進 AI provider reviewer review。" + }, + { + "lane_id": "owner_review_only_update", + "meaning": "只允許更新只讀 owner review ledger,不切 provider、不呼叫模型、不改 proxy。" + }, + { + "lane_id": "waiting_runtime_gate", + "meaning": "即使 owner response accepted,runtime gate 仍需獨立人工批准。" + } + ], + "blocked_actions": [ + "provider_switch", + "model_route_change", + "fallback_order_change", + "ollama_proxy_change", + "nginx_reload", + "env_change", + "runtime_config_change", + "external_provider_call", + "paid_provider_call", + "prompt_send", + "raw_prompt_storage", + "raw_log_storage", + "raw_endpoint_storage", + "live_endpoint_probe", + "benchmark_live_call", + "dry_run_external_call", + "quota_increase", + "cost_limit_change", + "privacy_boundary_change", + "data_egress_change", + "secret_value_collection", + "secret_hash_collection", + "partial_token_collection", + "api_key_rotation", + "secret_store_read", + "model_download", + "sdk_install", + "agent_runtime_enable", + "shadow_or_canary_enable", + "production_deploy", + "workflow_dispatch", + "host_write", + "ssh_read", + "ssh_write", + "active_scan", + "mark_owner_response_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button" + ], + "acceptance_candidates": [ + { + "acceptance_candidate_id": "ai_provider_owner_response_acceptance:ai_router_provider_policy", + "status": "waiting_owner_response", + "surface_id": "ai_router_provider_policy", + "label": "AI router provider policy / purpose mapping", + "expected_scope": "purpose routing、provider priority、degraded mode", + "config_kind": "provider_policy", + "control_tier": "C1", + "source_refs": [ + "apps/api/src/services/ai_router.py", + "apps/api/src/services/ai_provider_route_matrix.py", + "apps/api/models.json", + "docs/ai/AI-MODEL-CARDS.md" + ], + "source_ref_sha256": "fdfb8489a1b92feeb7a540c6a4c4810c3d72df2831691831e7347ad9bb86e351", + "write_capable_surface": true, + "paid_provider_related": true, + "data_egress_related": true, + "requires_live_evidence": true, + "owner_response_ref": null, + "owner_role_or_team": "pending_owner_response", + "decision": "pending_owner_response", + "decision_reason": "pending_owner_response", + "affected_scope": "pending_owner_response", + "provider_owner": "pending_owner_response", + "fallback_order_ref": null, + "dry_run_result_ref": null, + "benchmark_result_ref": null, + "cost_review_ref": null, + "privacy_review_ref": null, + "data_classification_ref": null, + "prompt_redaction_ref": null, + "secret_handling_ref": null, + "quota_budget_ref": null, + "latency_slo_ref": null, + "quality_gate_ref": null, + "rollback_owner": "pending_owner_response", + "rollback_plan_ref": null, + "maintenance_window": "pending_owner_response", + "postcheck_evidence_refs": [], + "redacted_evidence_refs": [], + "reviewer_outcome": "waiting_owner_response", + "followup_owner": "pending_owner_response", + "acceptance_fields": [ + "acceptance_candidate_id", + "surface_id", + "label", + "expected_scope", + "config_kind", + "control_tier", + "source_refs", + "source_ref_sha256", + "write_capable_surface", + "paid_provider_related", + "data_egress_related", + "requires_live_evidence", + "owner_response_ref", + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "provider_owner", + "fallback_order_ref", + "dry_run_result_ref", + "benchmark_result_ref", + "cost_review_ref", + "privacy_review_ref", + "data_classification_ref", + "prompt_redaction_ref", + "secret_handling_ref", + "quota_budget_ref", + "latency_slo_ref", + "quality_gate_ref", + "rollback_owner", + "rollback_plan_ref", + "maintenance_window", + "postcheck_evidence_refs", + "redacted_evidence_refs", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "required_owner_fields": [ + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "provider_owner", + "fallback_order_ref", + "dry_run_result_ref", + "benchmark_result_ref", + "cost_review_ref", + "privacy_review_ref", + "data_classification_ref", + "prompt_redaction_ref", + "secret_handling_ref", + "quota_budget_ref", + "latency_slo_ref", + "quality_gate_ref", + "rollback_owner", + "rollback_plan_ref", + "maintenance_window", + "postcheck_evidence_refs", + "redacted_evidence_refs", + "followup_owner", + "not_approval", + "no_secret_value_attestation" + ], + "reviewer_checks": [ + "owner_identity_present", + "decision_reason_present", + "affected_scope_matches_surface", + "redacted_refs_only", + "secret_value_absent", + "live_endpoint_absent", + "fallback_order_present", + "dry_run_result_present", + "benchmark_result_present", + "cost_review_present", + "privacy_review_present", + "data_classification_present", + "prompt_redaction_present", + "secret_handling_metadata_only", + "quota_budget_present", + "latency_slo_present", + "quality_gate_present", + "rollback_owner_present", + "maintenance_window_present", + "postcheck_evidence_present", + "no_runtime_request", + "no_false_green_provider_health", + "cross_project_sync_present", + "counts_transition_safe" + ], + "outcome_lanes": [ + "waiting_owner_response", + "quarantine_secret_or_raw_payload", + "reject_execution_request", + "request_fallback_supplement", + "request_cost_privacy_supplement", + "request_benchmark_supplement", + "legacy_model_card_redaction_required", + "ready_for_ai_provider_review", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "blocked_actions": [ + "provider_switch", + "model_route_change", + "fallback_order_change", + "ollama_proxy_change", + "nginx_reload", + "env_change", + "runtime_config_change", + "external_provider_call", + "paid_provider_call", + "prompt_send", + "raw_prompt_storage", + "raw_log_storage", + "raw_endpoint_storage", + "live_endpoint_probe", + "benchmark_live_call", + "dry_run_external_call", + "quota_increase", + "cost_limit_change", + "privacy_boundary_change", + "data_egress_change", + "secret_value_collection", + "secret_hash_collection", + "partial_token_collection", + "api_key_rotation", + "secret_store_read", + "model_download", + "sdk_install", + "agent_runtime_enable", + "shadow_or_canary_enable", + "production_deploy", + "workflow_dispatch", + "host_write", + "ssh_read", + "ssh_write", + "active_scan", + "mark_owner_response_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button" + ], + "not_approval": true, + "request_sent": false, + "recipient_confirmed": false, + "owner_response_received": false, + "owner_response_accepted": false, + "owner_response_rejected": false, + "owner_response_quarantined": false, + "supplement_requested": false, + "fallback_order_accepted": false, + "dry_run_result_accepted": false, + "benchmark_result_accepted": false, + "cost_review_accepted": false, + "privacy_review_accepted": false, + "data_classification_accepted": false, + "prompt_redaction_accepted": false, + "secret_handling_accepted": false, + "quota_budget_accepted": false, + "latency_slo_accepted": false, + "quality_gate_accepted": false, + "rollback_owner_accepted": false, + "maintenance_window_accepted": false, + "postcheck_evidence_accepted": false, + "provider_switch_authorized": false, + "model_route_change_authorized": false, + "fallback_order_change_authorized": false, + "ollama_proxy_change_authorized": false, + "nginx_reload_authorized": false, + "env_change_authorized": false, + "external_provider_call_authorized": false, + "paid_provider_call_authorized": false, + "prompt_send_authorized": false, + "live_endpoint_probe_authorized": false, + "benchmark_live_call_authorized": false, + "dry_run_external_call_authorized": false, + "quota_increase_authorized": false, + "cost_limit_change_authorized": false, + "privacy_boundary_change_authorized": false, + "data_egress_change_authorized": false, + "secret_value_collection_allowed": false, + "secret_hash_collection_allowed": false, + "partial_token_collection_allowed": false, + "api_key_rotation_authorized": false, + "secret_store_read_authorized": false, + "model_download_authorized": false, + "sdk_install_authorized": false, + "agent_runtime_enable_authorized": false, + "shadow_or_canary_enable_authorized": false, + "production_deploy_authorized": false, + "workflow_dispatch_authorized": false, + "host_write_authorized": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "active_scan_authorized": false, + "runtime_gate": false, + "action_buttons_allowed": false + }, + { + "acceptance_candidate_id": "ai_provider_owner_response_acceptance:ollama_proxy_gateway", + "status": "waiting_owner_response", + "surface_id": "ollama_proxy_gateway", + "label": "Ollama proxy gateway / local fallback boundary", + "expected_scope": "proxy route、local fallback、gateway health", + "config_kind": "proxy_gateway", + "control_tier": "C1", + "source_refs": [ + "infra/ansible/roles/nginx/templates/110-ollama-proxy.conf.j2", + "apps/api/src/services/ollama_endpoint_resolver.py", + "apps/api/src/services/ollama_failover_manager.py", + "apps/api/src/services/provider_proxy.py" + ], + "source_ref_sha256": "7eb65ad1c985886cad9add02894440995d4ca936f46831dce53995ba668632e5", + "write_capable_surface": true, + "paid_provider_related": false, + "data_egress_related": false, + "requires_live_evidence": true, + "owner_response_ref": null, + "owner_role_or_team": "pending_owner_response", + "decision": "pending_owner_response", + "decision_reason": "pending_owner_response", + "affected_scope": "pending_owner_response", + "provider_owner": "pending_owner_response", + "fallback_order_ref": null, + "dry_run_result_ref": null, + "benchmark_result_ref": null, + "cost_review_ref": null, + "privacy_review_ref": null, + "data_classification_ref": null, + "prompt_redaction_ref": null, + "secret_handling_ref": null, + "quota_budget_ref": null, + "latency_slo_ref": null, + "quality_gate_ref": null, + "rollback_owner": "pending_owner_response", + "rollback_plan_ref": null, + "maintenance_window": "pending_owner_response", + "postcheck_evidence_refs": [], + "redacted_evidence_refs": [], + "reviewer_outcome": "waiting_owner_response", + "followup_owner": "pending_owner_response", + "acceptance_fields": [ + "acceptance_candidate_id", + "surface_id", + "label", + "expected_scope", + "config_kind", + "control_tier", + "source_refs", + "source_ref_sha256", + "write_capable_surface", + "paid_provider_related", + "data_egress_related", + "requires_live_evidence", + "owner_response_ref", + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "provider_owner", + "fallback_order_ref", + "dry_run_result_ref", + "benchmark_result_ref", + "cost_review_ref", + "privacy_review_ref", + "data_classification_ref", + "prompt_redaction_ref", + "secret_handling_ref", + "quota_budget_ref", + "latency_slo_ref", + "quality_gate_ref", + "rollback_owner", + "rollback_plan_ref", + "maintenance_window", + "postcheck_evidence_refs", + "redacted_evidence_refs", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "required_owner_fields": [ + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "provider_owner", + "fallback_order_ref", + "dry_run_result_ref", + "benchmark_result_ref", + "cost_review_ref", + "privacy_review_ref", + "data_classification_ref", + "prompt_redaction_ref", + "secret_handling_ref", + "quota_budget_ref", + "latency_slo_ref", + "quality_gate_ref", + "rollback_owner", + "rollback_plan_ref", + "maintenance_window", + "postcheck_evidence_refs", + "redacted_evidence_refs", + "followup_owner", + "not_approval", + "no_secret_value_attestation" + ], + "reviewer_checks": [ + "owner_identity_present", + "decision_reason_present", + "affected_scope_matches_surface", + "redacted_refs_only", + "secret_value_absent", + "live_endpoint_absent", + "fallback_order_present", + "dry_run_result_present", + "benchmark_result_present", + "cost_review_present", + "privacy_review_present", + "data_classification_present", + "prompt_redaction_present", + "secret_handling_metadata_only", + "quota_budget_present", + "latency_slo_present", + "quality_gate_present", + "rollback_owner_present", + "maintenance_window_present", + "postcheck_evidence_present", + "no_runtime_request", + "no_false_green_provider_health", + "cross_project_sync_present", + "counts_transition_safe" + ], + "outcome_lanes": [ + "waiting_owner_response", + "quarantine_secret_or_raw_payload", + "reject_execution_request", + "request_fallback_supplement", + "request_cost_privacy_supplement", + "request_benchmark_supplement", + "legacy_model_card_redaction_required", + "ready_for_ai_provider_review", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "blocked_actions": [ + "provider_switch", + "model_route_change", + "fallback_order_change", + "ollama_proxy_change", + "nginx_reload", + "env_change", + "runtime_config_change", + "external_provider_call", + "paid_provider_call", + "prompt_send", + "raw_prompt_storage", + "raw_log_storage", + "raw_endpoint_storage", + "live_endpoint_probe", + "benchmark_live_call", + "dry_run_external_call", + "quota_increase", + "cost_limit_change", + "privacy_boundary_change", + "data_egress_change", + "secret_value_collection", + "secret_hash_collection", + "partial_token_collection", + "api_key_rotation", + "secret_store_read", + "model_download", + "sdk_install", + "agent_runtime_enable", + "shadow_or_canary_enable", + "production_deploy", + "workflow_dispatch", + "host_write", + "ssh_read", + "ssh_write", + "active_scan", + "mark_owner_response_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button" + ], + "not_approval": true, + "request_sent": false, + "recipient_confirmed": false, + "owner_response_received": false, + "owner_response_accepted": false, + "owner_response_rejected": false, + "owner_response_quarantined": false, + "supplement_requested": false, + "fallback_order_accepted": false, + "dry_run_result_accepted": false, + "benchmark_result_accepted": false, + "cost_review_accepted": false, + "privacy_review_accepted": false, + "data_classification_accepted": false, + "prompt_redaction_accepted": false, + "secret_handling_accepted": false, + "quota_budget_accepted": false, + "latency_slo_accepted": false, + "quality_gate_accepted": false, + "rollback_owner_accepted": false, + "maintenance_window_accepted": false, + "postcheck_evidence_accepted": false, + "provider_switch_authorized": false, + "model_route_change_authorized": false, + "fallback_order_change_authorized": false, + "ollama_proxy_change_authorized": false, + "nginx_reload_authorized": false, + "env_change_authorized": false, + "external_provider_call_authorized": false, + "paid_provider_call_authorized": false, + "prompt_send_authorized": false, + "live_endpoint_probe_authorized": false, + "benchmark_live_call_authorized": false, + "dry_run_external_call_authorized": false, + "quota_increase_authorized": false, + "cost_limit_change_authorized": false, + "privacy_boundary_change_authorized": false, + "data_egress_change_authorized": false, + "secret_value_collection_allowed": false, + "secret_hash_collection_allowed": false, + "partial_token_collection_allowed": false, + "api_key_rotation_authorized": false, + "secret_store_read_authorized": false, + "model_download_authorized": false, + "sdk_install_authorized": false, + "agent_runtime_enable_authorized": false, + "shadow_or_canary_enable_authorized": false, + "production_deploy_authorized": false, + "workflow_dispatch_authorized": false, + "host_write_authorized": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "active_scan_authorized": false, + "runtime_gate": false, + "action_buttons_allowed": false + }, + { + "acceptance_candidate_id": "ai_provider_owner_response_acceptance:fallback_order_and_circuit_breaker", + "status": "waiting_owner_response", + "surface_id": "fallback_order_and_circuit_breaker", + "label": "Fallback order / circuit breaker", + "expected_scope": "GCP / local / cloud fallback order、timeout、circuit breaker", + "config_kind": "routing_guard", + "control_tier": "C1", + "source_refs": [ + "apps/api/src/services/ollama_endpoint_circuit_breaker.py", + "apps/api/src/services/ollama_health_monitor.py", + "apps/api/src/services/failover_alerter.py", + "apps/web/messages/zh-TW.json" + ], + "source_ref_sha256": "909d508008b3660c9fcd3617e0571f18e38fc6a71894a12c48f94b8cc22d02dd", + "write_capable_surface": true, + "paid_provider_related": true, + "data_egress_related": true, + "requires_live_evidence": true, + "owner_response_ref": null, + "owner_role_or_team": "pending_owner_response", + "decision": "pending_owner_response", + "decision_reason": "pending_owner_response", + "affected_scope": "pending_owner_response", + "provider_owner": "pending_owner_response", + "fallback_order_ref": null, + "dry_run_result_ref": null, + "benchmark_result_ref": null, + "cost_review_ref": null, + "privacy_review_ref": null, + "data_classification_ref": null, + "prompt_redaction_ref": null, + "secret_handling_ref": null, + "quota_budget_ref": null, + "latency_slo_ref": null, + "quality_gate_ref": null, + "rollback_owner": "pending_owner_response", + "rollback_plan_ref": null, + "maintenance_window": "pending_owner_response", + "postcheck_evidence_refs": [], + "redacted_evidence_refs": [], + "reviewer_outcome": "waiting_owner_response", + "followup_owner": "pending_owner_response", + "acceptance_fields": [ + "acceptance_candidate_id", + "surface_id", + "label", + "expected_scope", + "config_kind", + "control_tier", + "source_refs", + "source_ref_sha256", + "write_capable_surface", + "paid_provider_related", + "data_egress_related", + "requires_live_evidence", + "owner_response_ref", + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "provider_owner", + "fallback_order_ref", + "dry_run_result_ref", + "benchmark_result_ref", + "cost_review_ref", + "privacy_review_ref", + "data_classification_ref", + "prompt_redaction_ref", + "secret_handling_ref", + "quota_budget_ref", + "latency_slo_ref", + "quality_gate_ref", + "rollback_owner", + "rollback_plan_ref", + "maintenance_window", + "postcheck_evidence_refs", + "redacted_evidence_refs", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "required_owner_fields": [ + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "provider_owner", + "fallback_order_ref", + "dry_run_result_ref", + "benchmark_result_ref", + "cost_review_ref", + "privacy_review_ref", + "data_classification_ref", + "prompt_redaction_ref", + "secret_handling_ref", + "quota_budget_ref", + "latency_slo_ref", + "quality_gate_ref", + "rollback_owner", + "rollback_plan_ref", + "maintenance_window", + "postcheck_evidence_refs", + "redacted_evidence_refs", + "followup_owner", + "not_approval", + "no_secret_value_attestation" + ], + "reviewer_checks": [ + "owner_identity_present", + "decision_reason_present", + "affected_scope_matches_surface", + "redacted_refs_only", + "secret_value_absent", + "live_endpoint_absent", + "fallback_order_present", + "dry_run_result_present", + "benchmark_result_present", + "cost_review_present", + "privacy_review_present", + "data_classification_present", + "prompt_redaction_present", + "secret_handling_metadata_only", + "quota_budget_present", + "latency_slo_present", + "quality_gate_present", + "rollback_owner_present", + "maintenance_window_present", + "postcheck_evidence_present", + "no_runtime_request", + "no_false_green_provider_health", + "cross_project_sync_present", + "counts_transition_safe" + ], + "outcome_lanes": [ + "waiting_owner_response", + "quarantine_secret_or_raw_payload", + "reject_execution_request", + "request_fallback_supplement", + "request_cost_privacy_supplement", + "request_benchmark_supplement", + "legacy_model_card_redaction_required", + "ready_for_ai_provider_review", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "blocked_actions": [ + "provider_switch", + "model_route_change", + "fallback_order_change", + "ollama_proxy_change", + "nginx_reload", + "env_change", + "runtime_config_change", + "external_provider_call", + "paid_provider_call", + "prompt_send", + "raw_prompt_storage", + "raw_log_storage", + "raw_endpoint_storage", + "live_endpoint_probe", + "benchmark_live_call", + "dry_run_external_call", + "quota_increase", + "cost_limit_change", + "privacy_boundary_change", + "data_egress_change", + "secret_value_collection", + "secret_hash_collection", + "partial_token_collection", + "api_key_rotation", + "secret_store_read", + "model_download", + "sdk_install", + "agent_runtime_enable", + "shadow_or_canary_enable", + "production_deploy", + "workflow_dispatch", + "host_write", + "ssh_read", + "ssh_write", + "active_scan", + "mark_owner_response_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button" + ], + "not_approval": true, + "request_sent": false, + "recipient_confirmed": false, + "owner_response_received": false, + "owner_response_accepted": false, + "owner_response_rejected": false, + "owner_response_quarantined": false, + "supplement_requested": false, + "fallback_order_accepted": false, + "dry_run_result_accepted": false, + "benchmark_result_accepted": false, + "cost_review_accepted": false, + "privacy_review_accepted": false, + "data_classification_accepted": false, + "prompt_redaction_accepted": false, + "secret_handling_accepted": false, + "quota_budget_accepted": false, + "latency_slo_accepted": false, + "quality_gate_accepted": false, + "rollback_owner_accepted": false, + "maintenance_window_accepted": false, + "postcheck_evidence_accepted": false, + "provider_switch_authorized": false, + "model_route_change_authorized": false, + "fallback_order_change_authorized": false, + "ollama_proxy_change_authorized": false, + "nginx_reload_authorized": false, + "env_change_authorized": false, + "external_provider_call_authorized": false, + "paid_provider_call_authorized": false, + "prompt_send_authorized": false, + "live_endpoint_probe_authorized": false, + "benchmark_live_call_authorized": false, + "dry_run_external_call_authorized": false, + "quota_increase_authorized": false, + "cost_limit_change_authorized": false, + "privacy_boundary_change_authorized": false, + "data_egress_change_authorized": false, + "secret_value_collection_allowed": false, + "secret_hash_collection_allowed": false, + "partial_token_collection_allowed": false, + "api_key_rotation_authorized": false, + "secret_store_read_authorized": false, + "model_download_authorized": false, + "sdk_install_authorized": false, + "agent_runtime_enable_authorized": false, + "shadow_or_canary_enable_authorized": false, + "production_deploy_authorized": false, + "workflow_dispatch_authorized": false, + "host_write_authorized": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "active_scan_authorized": false, + "runtime_gate": false, + "action_buttons_allowed": false + }, + { + "acceptance_candidate_id": "ai_provider_owner_response_acceptance:cost_budget_and_quota", + "status": "waiting_owner_response", + "surface_id": "cost_budget_and_quota", + "label": "Cost budget / quota / paid provider stop condition", + "expected_scope": "quota、token budget、cost alert、paid provider stop condition", + "config_kind": "cost_policy", + "control_tier": "C1", + "source_refs": [ + "docs/ai/AI-MODEL-CARDS.md", + "apps/api/src/services/ai_rate_limiter.py", + "apps/api/src/services/ai_slo_calculator.py", + "apps/web/messages/zh-TW.json" + ], + "source_ref_sha256": "9cab1f216749d36b76cfb8da06e324b0bf4bcd12424657bc8e40c2bf64c03af7", + "write_capable_surface": false, + "paid_provider_related": true, + "data_egress_related": true, + "requires_live_evidence": true, + "owner_response_ref": null, + "owner_role_or_team": "pending_owner_response", + "decision": "pending_owner_response", + "decision_reason": "pending_owner_response", + "affected_scope": "pending_owner_response", + "provider_owner": "pending_owner_response", + "fallback_order_ref": null, + "dry_run_result_ref": null, + "benchmark_result_ref": null, + "cost_review_ref": null, + "privacy_review_ref": null, + "data_classification_ref": null, + "prompt_redaction_ref": null, + "secret_handling_ref": null, + "quota_budget_ref": null, + "latency_slo_ref": null, + "quality_gate_ref": null, + "rollback_owner": "pending_owner_response", + "rollback_plan_ref": null, + "maintenance_window": "pending_owner_response", + "postcheck_evidence_refs": [], + "redacted_evidence_refs": [], + "reviewer_outcome": "waiting_owner_response", + "followup_owner": "pending_owner_response", + "acceptance_fields": [ + "acceptance_candidate_id", + "surface_id", + "label", + "expected_scope", + "config_kind", + "control_tier", + "source_refs", + "source_ref_sha256", + "write_capable_surface", + "paid_provider_related", + "data_egress_related", + "requires_live_evidence", + "owner_response_ref", + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "provider_owner", + "fallback_order_ref", + "dry_run_result_ref", + "benchmark_result_ref", + "cost_review_ref", + "privacy_review_ref", + "data_classification_ref", + "prompt_redaction_ref", + "secret_handling_ref", + "quota_budget_ref", + "latency_slo_ref", + "quality_gate_ref", + "rollback_owner", + "rollback_plan_ref", + "maintenance_window", + "postcheck_evidence_refs", + "redacted_evidence_refs", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "required_owner_fields": [ + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "provider_owner", + "fallback_order_ref", + "dry_run_result_ref", + "benchmark_result_ref", + "cost_review_ref", + "privacy_review_ref", + "data_classification_ref", + "prompt_redaction_ref", + "secret_handling_ref", + "quota_budget_ref", + "latency_slo_ref", + "quality_gate_ref", + "rollback_owner", + "rollback_plan_ref", + "maintenance_window", + "postcheck_evidence_refs", + "redacted_evidence_refs", + "followup_owner", + "not_approval", + "no_secret_value_attestation" + ], + "reviewer_checks": [ + "owner_identity_present", + "decision_reason_present", + "affected_scope_matches_surface", + "redacted_refs_only", + "secret_value_absent", + "live_endpoint_absent", + "fallback_order_present", + "dry_run_result_present", + "benchmark_result_present", + "cost_review_present", + "privacy_review_present", + "data_classification_present", + "prompt_redaction_present", + "secret_handling_metadata_only", + "quota_budget_present", + "latency_slo_present", + "quality_gate_present", + "rollback_owner_present", + "maintenance_window_present", + "postcheck_evidence_present", + "no_runtime_request", + "no_false_green_provider_health", + "cross_project_sync_present", + "counts_transition_safe" + ], + "outcome_lanes": [ + "waiting_owner_response", + "quarantine_secret_or_raw_payload", + "reject_execution_request", + "request_fallback_supplement", + "request_cost_privacy_supplement", + "request_benchmark_supplement", + "legacy_model_card_redaction_required", + "ready_for_ai_provider_review", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "blocked_actions": [ + "provider_switch", + "model_route_change", + "fallback_order_change", + "ollama_proxy_change", + "nginx_reload", + "env_change", + "runtime_config_change", + "external_provider_call", + "paid_provider_call", + "prompt_send", + "raw_prompt_storage", + "raw_log_storage", + "raw_endpoint_storage", + "live_endpoint_probe", + "benchmark_live_call", + "dry_run_external_call", + "quota_increase", + "cost_limit_change", + "privacy_boundary_change", + "data_egress_change", + "secret_value_collection", + "secret_hash_collection", + "partial_token_collection", + "api_key_rotation", + "secret_store_read", + "model_download", + "sdk_install", + "agent_runtime_enable", + "shadow_or_canary_enable", + "production_deploy", + "workflow_dispatch", + "host_write", + "ssh_read", + "ssh_write", + "active_scan", + "mark_owner_response_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button" + ], + "not_approval": true, + "request_sent": false, + "recipient_confirmed": false, + "owner_response_received": false, + "owner_response_accepted": false, + "owner_response_rejected": false, + "owner_response_quarantined": false, + "supplement_requested": false, + "fallback_order_accepted": false, + "dry_run_result_accepted": false, + "benchmark_result_accepted": false, + "cost_review_accepted": false, + "privacy_review_accepted": false, + "data_classification_accepted": false, + "prompt_redaction_accepted": false, + "secret_handling_accepted": false, + "quota_budget_accepted": false, + "latency_slo_accepted": false, + "quality_gate_accepted": false, + "rollback_owner_accepted": false, + "maintenance_window_accepted": false, + "postcheck_evidence_accepted": false, + "provider_switch_authorized": false, + "model_route_change_authorized": false, + "fallback_order_change_authorized": false, + "ollama_proxy_change_authorized": false, + "nginx_reload_authorized": false, + "env_change_authorized": false, + "external_provider_call_authorized": false, + "paid_provider_call_authorized": false, + "prompt_send_authorized": false, + "live_endpoint_probe_authorized": false, + "benchmark_live_call_authorized": false, + "dry_run_external_call_authorized": false, + "quota_increase_authorized": false, + "cost_limit_change_authorized": false, + "privacy_boundary_change_authorized": false, + "data_egress_change_authorized": false, + "secret_value_collection_allowed": false, + "secret_hash_collection_allowed": false, + "partial_token_collection_allowed": false, + "api_key_rotation_authorized": false, + "secret_store_read_authorized": false, + "model_download_authorized": false, + "sdk_install_authorized": false, + "agent_runtime_enable_authorized": false, + "shadow_or_canary_enable_authorized": false, + "production_deploy_authorized": false, + "workflow_dispatch_authorized": false, + "host_write_authorized": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "active_scan_authorized": false, + "runtime_gate": false, + "action_buttons_allowed": false + }, + { + "acceptance_candidate_id": "ai_provider_owner_response_acceptance:privacy_data_egress_boundary", + "status": "waiting_owner_response", + "surface_id": "privacy_data_egress_boundary", + "label": "Privacy / data egress / prompt redaction boundary", + "expected_scope": "prompt redaction、資料分級、外部 provider 資料外送", + "config_kind": "privacy_policy", + "control_tier": "C1", + "source_refs": [ + "docs/HARD_RULES.md", + "docs/ai/AI-MODEL-CARDS.md", + "apps/api/src/services/ai_providers/permissions.py", + "apps/api/src/services/alertmanager_llm_guard.py" + ], + "source_ref_sha256": "c15c8a91861b12a72117e70a8a44cd18c96bc1494f90245c57b517d0509fe3ae", + "write_capable_surface": false, + "paid_provider_related": true, + "data_egress_related": true, + "requires_live_evidence": true, + "owner_response_ref": null, + "owner_role_or_team": "pending_owner_response", + "decision": "pending_owner_response", + "decision_reason": "pending_owner_response", + "affected_scope": "pending_owner_response", + "provider_owner": "pending_owner_response", + "fallback_order_ref": null, + "dry_run_result_ref": null, + "benchmark_result_ref": null, + "cost_review_ref": null, + "privacy_review_ref": null, + "data_classification_ref": null, + "prompt_redaction_ref": null, + "secret_handling_ref": null, + "quota_budget_ref": null, + "latency_slo_ref": null, + "quality_gate_ref": null, + "rollback_owner": "pending_owner_response", + "rollback_plan_ref": null, + "maintenance_window": "pending_owner_response", + "postcheck_evidence_refs": [], + "redacted_evidence_refs": [], + "reviewer_outcome": "waiting_owner_response", + "followup_owner": "pending_owner_response", + "acceptance_fields": [ + "acceptance_candidate_id", + "surface_id", + "label", + "expected_scope", + "config_kind", + "control_tier", + "source_refs", + "source_ref_sha256", + "write_capable_surface", + "paid_provider_related", + "data_egress_related", + "requires_live_evidence", + "owner_response_ref", + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "provider_owner", + "fallback_order_ref", + "dry_run_result_ref", + "benchmark_result_ref", + "cost_review_ref", + "privacy_review_ref", + "data_classification_ref", + "prompt_redaction_ref", + "secret_handling_ref", + "quota_budget_ref", + "latency_slo_ref", + "quality_gate_ref", + "rollback_owner", + "rollback_plan_ref", + "maintenance_window", + "postcheck_evidence_refs", + "redacted_evidence_refs", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "required_owner_fields": [ + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "provider_owner", + "fallback_order_ref", + "dry_run_result_ref", + "benchmark_result_ref", + "cost_review_ref", + "privacy_review_ref", + "data_classification_ref", + "prompt_redaction_ref", + "secret_handling_ref", + "quota_budget_ref", + "latency_slo_ref", + "quality_gate_ref", + "rollback_owner", + "rollback_plan_ref", + "maintenance_window", + "postcheck_evidence_refs", + "redacted_evidence_refs", + "followup_owner", + "not_approval", + "no_secret_value_attestation" + ], + "reviewer_checks": [ + "owner_identity_present", + "decision_reason_present", + "affected_scope_matches_surface", + "redacted_refs_only", + "secret_value_absent", + "live_endpoint_absent", + "fallback_order_present", + "dry_run_result_present", + "benchmark_result_present", + "cost_review_present", + "privacy_review_present", + "data_classification_present", + "prompt_redaction_present", + "secret_handling_metadata_only", + "quota_budget_present", + "latency_slo_present", + "quality_gate_present", + "rollback_owner_present", + "maintenance_window_present", + "postcheck_evidence_present", + "no_runtime_request", + "no_false_green_provider_health", + "cross_project_sync_present", + "counts_transition_safe" + ], + "outcome_lanes": [ + "waiting_owner_response", + "quarantine_secret_or_raw_payload", + "reject_execution_request", + "request_fallback_supplement", + "request_cost_privacy_supplement", + "request_benchmark_supplement", + "legacy_model_card_redaction_required", + "ready_for_ai_provider_review", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "blocked_actions": [ + "provider_switch", + "model_route_change", + "fallback_order_change", + "ollama_proxy_change", + "nginx_reload", + "env_change", + "runtime_config_change", + "external_provider_call", + "paid_provider_call", + "prompt_send", + "raw_prompt_storage", + "raw_log_storage", + "raw_endpoint_storage", + "live_endpoint_probe", + "benchmark_live_call", + "dry_run_external_call", + "quota_increase", + "cost_limit_change", + "privacy_boundary_change", + "data_egress_change", + "secret_value_collection", + "secret_hash_collection", + "partial_token_collection", + "api_key_rotation", + "secret_store_read", + "model_download", + "sdk_install", + "agent_runtime_enable", + "shadow_or_canary_enable", + "production_deploy", + "workflow_dispatch", + "host_write", + "ssh_read", + "ssh_write", + "active_scan", + "mark_owner_response_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button" + ], + "not_approval": true, + "request_sent": false, + "recipient_confirmed": false, + "owner_response_received": false, + "owner_response_accepted": false, + "owner_response_rejected": false, + "owner_response_quarantined": false, + "supplement_requested": false, + "fallback_order_accepted": false, + "dry_run_result_accepted": false, + "benchmark_result_accepted": false, + "cost_review_accepted": false, + "privacy_review_accepted": false, + "data_classification_accepted": false, + "prompt_redaction_accepted": false, + "secret_handling_accepted": false, + "quota_budget_accepted": false, + "latency_slo_accepted": false, + "quality_gate_accepted": false, + "rollback_owner_accepted": false, + "maintenance_window_accepted": false, + "postcheck_evidence_accepted": false, + "provider_switch_authorized": false, + "model_route_change_authorized": false, + "fallback_order_change_authorized": false, + "ollama_proxy_change_authorized": false, + "nginx_reload_authorized": false, + "env_change_authorized": false, + "external_provider_call_authorized": false, + "paid_provider_call_authorized": false, + "prompt_send_authorized": false, + "live_endpoint_probe_authorized": false, + "benchmark_live_call_authorized": false, + "dry_run_external_call_authorized": false, + "quota_increase_authorized": false, + "cost_limit_change_authorized": false, + "privacy_boundary_change_authorized": false, + "data_egress_change_authorized": false, + "secret_value_collection_allowed": false, + "secret_hash_collection_allowed": false, + "partial_token_collection_allowed": false, + "api_key_rotation_authorized": false, + "secret_store_read_authorized": false, + "model_download_authorized": false, + "sdk_install_authorized": false, + "agent_runtime_enable_authorized": false, + "shadow_or_canary_enable_authorized": false, + "production_deploy_authorized": false, + "workflow_dispatch_authorized": false, + "host_write_authorized": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "active_scan_authorized": false, + "runtime_gate": false, + "action_buttons_allowed": false + }, + { + "acceptance_candidate_id": "ai_provider_owner_response_acceptance:benchmark_dry_run_pack", + "status": "waiting_owner_response", + "surface_id": "benchmark_dry_run_pack", + "label": "Dry-run / benchmark / replay pack", + "expected_scope": "dry-run、benchmark、fixture replay、quality gate", + "config_kind": "evaluation_pack", + "control_tier": "C1", + "source_refs": [ + "docs/runbooks/OPENCLAW-REPLACEMENT-EVALUATION.md", + "docs/ai/agent-replacement-candidates.v1.json", + "scripts/agents/run-agent-replacement-replay.py", + "scripts/agents/evaluate-agent-promotion-gate.py" + ], + "source_ref_sha256": "692a2417842c677b5282118efe43b74deb47c017f6a2a7a5f4bfd013e822992e", + "write_capable_surface": false, + "paid_provider_related": false, + "data_egress_related": true, + "requires_live_evidence": false, + "owner_response_ref": null, + "owner_role_or_team": "pending_owner_response", + "decision": "pending_owner_response", + "decision_reason": "pending_owner_response", + "affected_scope": "pending_owner_response", + "provider_owner": "pending_owner_response", + "fallback_order_ref": null, + "dry_run_result_ref": null, + "benchmark_result_ref": null, + "cost_review_ref": null, + "privacy_review_ref": null, + "data_classification_ref": null, + "prompt_redaction_ref": null, + "secret_handling_ref": null, + "quota_budget_ref": null, + "latency_slo_ref": null, + "quality_gate_ref": null, + "rollback_owner": "pending_owner_response", + "rollback_plan_ref": null, + "maintenance_window": "pending_owner_response", + "postcheck_evidence_refs": [], + "redacted_evidence_refs": [], + "reviewer_outcome": "waiting_owner_response", + "followup_owner": "pending_owner_response", + "acceptance_fields": [ + "acceptance_candidate_id", + "surface_id", + "label", + "expected_scope", + "config_kind", + "control_tier", + "source_refs", + "source_ref_sha256", + "write_capable_surface", + "paid_provider_related", + "data_egress_related", + "requires_live_evidence", + "owner_response_ref", + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "provider_owner", + "fallback_order_ref", + "dry_run_result_ref", + "benchmark_result_ref", + "cost_review_ref", + "privacy_review_ref", + "data_classification_ref", + "prompt_redaction_ref", + "secret_handling_ref", + "quota_budget_ref", + "latency_slo_ref", + "quality_gate_ref", + "rollback_owner", + "rollback_plan_ref", + "maintenance_window", + "postcheck_evidence_refs", + "redacted_evidence_refs", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "required_owner_fields": [ + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "provider_owner", + "fallback_order_ref", + "dry_run_result_ref", + "benchmark_result_ref", + "cost_review_ref", + "privacy_review_ref", + "data_classification_ref", + "prompt_redaction_ref", + "secret_handling_ref", + "quota_budget_ref", + "latency_slo_ref", + "quality_gate_ref", + "rollback_owner", + "rollback_plan_ref", + "maintenance_window", + "postcheck_evidence_refs", + "redacted_evidence_refs", + "followup_owner", + "not_approval", + "no_secret_value_attestation" + ], + "reviewer_checks": [ + "owner_identity_present", + "decision_reason_present", + "affected_scope_matches_surface", + "redacted_refs_only", + "secret_value_absent", + "live_endpoint_absent", + "fallback_order_present", + "dry_run_result_present", + "benchmark_result_present", + "cost_review_present", + "privacy_review_present", + "data_classification_present", + "prompt_redaction_present", + "secret_handling_metadata_only", + "quota_budget_present", + "latency_slo_present", + "quality_gate_present", + "rollback_owner_present", + "maintenance_window_present", + "postcheck_evidence_present", + "no_runtime_request", + "no_false_green_provider_health", + "cross_project_sync_present", + "counts_transition_safe" + ], + "outcome_lanes": [ + "waiting_owner_response", + "quarantine_secret_or_raw_payload", + "reject_execution_request", + "request_fallback_supplement", + "request_cost_privacy_supplement", + "request_benchmark_supplement", + "legacy_model_card_redaction_required", + "ready_for_ai_provider_review", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "blocked_actions": [ + "provider_switch", + "model_route_change", + "fallback_order_change", + "ollama_proxy_change", + "nginx_reload", + "env_change", + "runtime_config_change", + "external_provider_call", + "paid_provider_call", + "prompt_send", + "raw_prompt_storage", + "raw_log_storage", + "raw_endpoint_storage", + "live_endpoint_probe", + "benchmark_live_call", + "dry_run_external_call", + "quota_increase", + "cost_limit_change", + "privacy_boundary_change", + "data_egress_change", + "secret_value_collection", + "secret_hash_collection", + "partial_token_collection", + "api_key_rotation", + "secret_store_read", + "model_download", + "sdk_install", + "agent_runtime_enable", + "shadow_or_canary_enable", + "production_deploy", + "workflow_dispatch", + "host_write", + "ssh_read", + "ssh_write", + "active_scan", + "mark_owner_response_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button" + ], + "not_approval": true, + "request_sent": false, + "recipient_confirmed": false, + "owner_response_received": false, + "owner_response_accepted": false, + "owner_response_rejected": false, + "owner_response_quarantined": false, + "supplement_requested": false, + "fallback_order_accepted": false, + "dry_run_result_accepted": false, + "benchmark_result_accepted": false, + "cost_review_accepted": false, + "privacy_review_accepted": false, + "data_classification_accepted": false, + "prompt_redaction_accepted": false, + "secret_handling_accepted": false, + "quota_budget_accepted": false, + "latency_slo_accepted": false, + "quality_gate_accepted": false, + "rollback_owner_accepted": false, + "maintenance_window_accepted": false, + "postcheck_evidence_accepted": false, + "provider_switch_authorized": false, + "model_route_change_authorized": false, + "fallback_order_change_authorized": false, + "ollama_proxy_change_authorized": false, + "nginx_reload_authorized": false, + "env_change_authorized": false, + "external_provider_call_authorized": false, + "paid_provider_call_authorized": false, + "prompt_send_authorized": false, + "live_endpoint_probe_authorized": false, + "benchmark_live_call_authorized": false, + "dry_run_external_call_authorized": false, + "quota_increase_authorized": false, + "cost_limit_change_authorized": false, + "privacy_boundary_change_authorized": false, + "data_egress_change_authorized": false, + "secret_value_collection_allowed": false, + "secret_hash_collection_allowed": false, + "partial_token_collection_allowed": false, + "api_key_rotation_authorized": false, + "secret_store_read_authorized": false, + "model_download_authorized": false, + "sdk_install_authorized": false, + "agent_runtime_enable_authorized": false, + "shadow_or_canary_enable_authorized": false, + "production_deploy_authorized": false, + "workflow_dispatch_authorized": false, + "host_write_authorized": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "active_scan_authorized": false, + "runtime_gate": false, + "action_buttons_allowed": false + }, + { + "acceptance_candidate_id": "ai_provider_owner_response_acceptance:model_card_and_version_inventory", + "status": "waiting_owner_response", + "surface_id": "model_card_and_version_inventory", + "label": "Model card / model version inventory", + "expected_scope": "model card、version freshness、source-of-truth、redacted endpoint", + "config_kind": "model_metadata", + "control_tier": "C1", + "source_refs": [ + "docs/ai/AI-MODEL-CARDS.md", + "apps/api/src/services/model_registry.py", + "apps/api/src/services/model_version_tracker.py", + "apps/api/src/services/model_version_probe.py" + ], + "source_ref_sha256": "d5f5fce37c4c1cdb61b2fe60357b7f43bcb771372a9984fbff4647067c3c11f9", + "write_capable_surface": true, + "paid_provider_related": false, + "data_egress_related": false, + "requires_live_evidence": false, + "owner_response_ref": null, + "owner_role_or_team": "pending_owner_response", + "decision": "pending_owner_response", + "decision_reason": "pending_owner_response", + "affected_scope": "pending_owner_response", + "provider_owner": "pending_owner_response", + "fallback_order_ref": null, + "dry_run_result_ref": null, + "benchmark_result_ref": null, + "cost_review_ref": null, + "privacy_review_ref": null, + "data_classification_ref": null, + "prompt_redaction_ref": null, + "secret_handling_ref": null, + "quota_budget_ref": null, + "latency_slo_ref": null, + "quality_gate_ref": null, + "rollback_owner": "pending_owner_response", + "rollback_plan_ref": null, + "maintenance_window": "pending_owner_response", + "postcheck_evidence_refs": [], + "redacted_evidence_refs": [], + "reviewer_outcome": "waiting_owner_response", + "followup_owner": "pending_owner_response", + "acceptance_fields": [ + "acceptance_candidate_id", + "surface_id", + "label", + "expected_scope", + "config_kind", + "control_tier", + "source_refs", + "source_ref_sha256", + "write_capable_surface", + "paid_provider_related", + "data_egress_related", + "requires_live_evidence", + "owner_response_ref", + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "provider_owner", + "fallback_order_ref", + "dry_run_result_ref", + "benchmark_result_ref", + "cost_review_ref", + "privacy_review_ref", + "data_classification_ref", + "prompt_redaction_ref", + "secret_handling_ref", + "quota_budget_ref", + "latency_slo_ref", + "quality_gate_ref", + "rollback_owner", + "rollback_plan_ref", + "maintenance_window", + "postcheck_evidence_refs", + "redacted_evidence_refs", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "required_owner_fields": [ + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "provider_owner", + "fallback_order_ref", + "dry_run_result_ref", + "benchmark_result_ref", + "cost_review_ref", + "privacy_review_ref", + "data_classification_ref", + "prompt_redaction_ref", + "secret_handling_ref", + "quota_budget_ref", + "latency_slo_ref", + "quality_gate_ref", + "rollback_owner", + "rollback_plan_ref", + "maintenance_window", + "postcheck_evidence_refs", + "redacted_evidence_refs", + "followup_owner", + "not_approval", + "no_secret_value_attestation" + ], + "reviewer_checks": [ + "owner_identity_present", + "decision_reason_present", + "affected_scope_matches_surface", + "redacted_refs_only", + "secret_value_absent", + "live_endpoint_absent", + "fallback_order_present", + "dry_run_result_present", + "benchmark_result_present", + "cost_review_present", + "privacy_review_present", + "data_classification_present", + "prompt_redaction_present", + "secret_handling_metadata_only", + "quota_budget_present", + "latency_slo_present", + "quality_gate_present", + "rollback_owner_present", + "maintenance_window_present", + "postcheck_evidence_present", + "no_runtime_request", + "no_false_green_provider_health", + "cross_project_sync_present", + "counts_transition_safe" + ], + "outcome_lanes": [ + "waiting_owner_response", + "quarantine_secret_or_raw_payload", + "reject_execution_request", + "request_fallback_supplement", + "request_cost_privacy_supplement", + "request_benchmark_supplement", + "legacy_model_card_redaction_required", + "ready_for_ai_provider_review", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "blocked_actions": [ + "provider_switch", + "model_route_change", + "fallback_order_change", + "ollama_proxy_change", + "nginx_reload", + "env_change", + "runtime_config_change", + "external_provider_call", + "paid_provider_call", + "prompt_send", + "raw_prompt_storage", + "raw_log_storage", + "raw_endpoint_storage", + "live_endpoint_probe", + "benchmark_live_call", + "dry_run_external_call", + "quota_increase", + "cost_limit_change", + "privacy_boundary_change", + "data_egress_change", + "secret_value_collection", + "secret_hash_collection", + "partial_token_collection", + "api_key_rotation", + "secret_store_read", + "model_download", + "sdk_install", + "agent_runtime_enable", + "shadow_or_canary_enable", + "production_deploy", + "workflow_dispatch", + "host_write", + "ssh_read", + "ssh_write", + "active_scan", + "mark_owner_response_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button" + ], + "not_approval": true, + "request_sent": false, + "recipient_confirmed": false, + "owner_response_received": false, + "owner_response_accepted": false, + "owner_response_rejected": false, + "owner_response_quarantined": false, + "supplement_requested": false, + "fallback_order_accepted": false, + "dry_run_result_accepted": false, + "benchmark_result_accepted": false, + "cost_review_accepted": false, + "privacy_review_accepted": false, + "data_classification_accepted": false, + "prompt_redaction_accepted": false, + "secret_handling_accepted": false, + "quota_budget_accepted": false, + "latency_slo_accepted": false, + "quality_gate_accepted": false, + "rollback_owner_accepted": false, + "maintenance_window_accepted": false, + "postcheck_evidence_accepted": false, + "provider_switch_authorized": false, + "model_route_change_authorized": false, + "fallback_order_change_authorized": false, + "ollama_proxy_change_authorized": false, + "nginx_reload_authorized": false, + "env_change_authorized": false, + "external_provider_call_authorized": false, + "paid_provider_call_authorized": false, + "prompt_send_authorized": false, + "live_endpoint_probe_authorized": false, + "benchmark_live_call_authorized": false, + "dry_run_external_call_authorized": false, + "quota_increase_authorized": false, + "cost_limit_change_authorized": false, + "privacy_boundary_change_authorized": false, + "data_egress_change_authorized": false, + "secret_value_collection_allowed": false, + "secret_hash_collection_allowed": false, + "partial_token_collection_allowed": false, + "api_key_rotation_authorized": false, + "secret_store_read_authorized": false, + "model_download_authorized": false, + "sdk_install_authorized": false, + "agent_runtime_enable_authorized": false, + "shadow_or_canary_enable_authorized": false, + "production_deploy_authorized": false, + "workflow_dispatch_authorized": false, + "host_write_authorized": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "active_scan_authorized": false, + "runtime_gate": false, + "action_buttons_allowed": false + }, + { + "acceptance_candidate_id": "ai_provider_owner_response_acceptance:agent_replacement_candidate_runtime_boundary", + "status": "waiting_owner_response", + "surface_id": "agent_replacement_candidate_runtime_boundary", + "label": "Agent replacement / NemoTron / Hermes / OpenClaw candidate boundary", + "expected_scope": "agent candidate、promotion gate、shadow/canary boundary", + "config_kind": "agent_runtime_boundary", + "control_tier": "C1", + "source_refs": [ + "docs/runbooks/OPENCLAW-REPLACEMENT-EVALUATION.md", + "docs/ai/agent-market-watch-sources.v1.json", + "docs/ai/agent-replacement-candidates.v1.json", + "apps/api/src/services/ai_agent_tool_adoption_approval_package.py" + ], + "source_ref_sha256": "de3de57ea5fb5cbe9d47fab30167110521165e3680bb4dba449035f9a7a29845", + "write_capable_surface": true, + "paid_provider_related": true, + "data_egress_related": true, + "requires_live_evidence": true, + "owner_response_ref": null, + "owner_role_or_team": "pending_owner_response", + "decision": "pending_owner_response", + "decision_reason": "pending_owner_response", + "affected_scope": "pending_owner_response", + "provider_owner": "pending_owner_response", + "fallback_order_ref": null, + "dry_run_result_ref": null, + "benchmark_result_ref": null, + "cost_review_ref": null, + "privacy_review_ref": null, + "data_classification_ref": null, + "prompt_redaction_ref": null, + "secret_handling_ref": null, + "quota_budget_ref": null, + "latency_slo_ref": null, + "quality_gate_ref": null, + "rollback_owner": "pending_owner_response", + "rollback_plan_ref": null, + "maintenance_window": "pending_owner_response", + "postcheck_evidence_refs": [], + "redacted_evidence_refs": [], + "reviewer_outcome": "waiting_owner_response", + "followup_owner": "pending_owner_response", + "acceptance_fields": [ + "acceptance_candidate_id", + "surface_id", + "label", + "expected_scope", + "config_kind", + "control_tier", + "source_refs", + "source_ref_sha256", + "write_capable_surface", + "paid_provider_related", + "data_egress_related", + "requires_live_evidence", + "owner_response_ref", + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "provider_owner", + "fallback_order_ref", + "dry_run_result_ref", + "benchmark_result_ref", + "cost_review_ref", + "privacy_review_ref", + "data_classification_ref", + "prompt_redaction_ref", + "secret_handling_ref", + "quota_budget_ref", + "latency_slo_ref", + "quality_gate_ref", + "rollback_owner", + "rollback_plan_ref", + "maintenance_window", + "postcheck_evidence_refs", + "redacted_evidence_refs", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "required_owner_fields": [ + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "provider_owner", + "fallback_order_ref", + "dry_run_result_ref", + "benchmark_result_ref", + "cost_review_ref", + "privacy_review_ref", + "data_classification_ref", + "prompt_redaction_ref", + "secret_handling_ref", + "quota_budget_ref", + "latency_slo_ref", + "quality_gate_ref", + "rollback_owner", + "rollback_plan_ref", + "maintenance_window", + "postcheck_evidence_refs", + "redacted_evidence_refs", + "followup_owner", + "not_approval", + "no_secret_value_attestation" + ], + "reviewer_checks": [ + "owner_identity_present", + "decision_reason_present", + "affected_scope_matches_surface", + "redacted_refs_only", + "secret_value_absent", + "live_endpoint_absent", + "fallback_order_present", + "dry_run_result_present", + "benchmark_result_present", + "cost_review_present", + "privacy_review_present", + "data_classification_present", + "prompt_redaction_present", + "secret_handling_metadata_only", + "quota_budget_present", + "latency_slo_present", + "quality_gate_present", + "rollback_owner_present", + "maintenance_window_present", + "postcheck_evidence_present", + "no_runtime_request", + "no_false_green_provider_health", + "cross_project_sync_present", + "counts_transition_safe" + ], + "outcome_lanes": [ + "waiting_owner_response", + "quarantine_secret_or_raw_payload", + "reject_execution_request", + "request_fallback_supplement", + "request_cost_privacy_supplement", + "request_benchmark_supplement", + "legacy_model_card_redaction_required", + "ready_for_ai_provider_review", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "blocked_actions": [ + "provider_switch", + "model_route_change", + "fallback_order_change", + "ollama_proxy_change", + "nginx_reload", + "env_change", + "runtime_config_change", + "external_provider_call", + "paid_provider_call", + "prompt_send", + "raw_prompt_storage", + "raw_log_storage", + "raw_endpoint_storage", + "live_endpoint_probe", + "benchmark_live_call", + "dry_run_external_call", + "quota_increase", + "cost_limit_change", + "privacy_boundary_change", + "data_egress_change", + "secret_value_collection", + "secret_hash_collection", + "partial_token_collection", + "api_key_rotation", + "secret_store_read", + "model_download", + "sdk_install", + "agent_runtime_enable", + "shadow_or_canary_enable", + "production_deploy", + "workflow_dispatch", + "host_write", + "ssh_read", + "ssh_write", + "active_scan", + "mark_owner_response_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button" + ], + "not_approval": true, + "request_sent": false, + "recipient_confirmed": false, + "owner_response_received": false, + "owner_response_accepted": false, + "owner_response_rejected": false, + "owner_response_quarantined": false, + "supplement_requested": false, + "fallback_order_accepted": false, + "dry_run_result_accepted": false, + "benchmark_result_accepted": false, + "cost_review_accepted": false, + "privacy_review_accepted": false, + "data_classification_accepted": false, + "prompt_redaction_accepted": false, + "secret_handling_accepted": false, + "quota_budget_accepted": false, + "latency_slo_accepted": false, + "quality_gate_accepted": false, + "rollback_owner_accepted": false, + "maintenance_window_accepted": false, + "postcheck_evidence_accepted": false, + "provider_switch_authorized": false, + "model_route_change_authorized": false, + "fallback_order_change_authorized": false, + "ollama_proxy_change_authorized": false, + "nginx_reload_authorized": false, + "env_change_authorized": false, + "external_provider_call_authorized": false, + "paid_provider_call_authorized": false, + "prompt_send_authorized": false, + "live_endpoint_probe_authorized": false, + "benchmark_live_call_authorized": false, + "dry_run_external_call_authorized": false, + "quota_increase_authorized": false, + "cost_limit_change_authorized": false, + "privacy_boundary_change_authorized": false, + "data_egress_change_authorized": false, + "secret_value_collection_allowed": false, + "secret_hash_collection_allowed": false, + "partial_token_collection_allowed": false, + "api_key_rotation_authorized": false, + "secret_store_read_authorized": false, + "model_download_authorized": false, + "sdk_install_authorized": false, + "agent_runtime_enable_authorized": false, + "shadow_or_canary_enable_authorized": false, + "production_deploy_authorized": false, + "workflow_dispatch_authorized": false, + "host_write_authorized": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "active_scan_authorized": false, + "runtime_gate": false, + "action_buttons_allowed": false + } + ], + "boundaries": { + "not_authorization": true, + "runtime_execution_authorized": false, + "provider_switch_authorized": false, + "model_route_change_authorized": false, + "fallback_order_change_authorized": false, + "ollama_proxy_change_authorized": false, + "nginx_reload_authorized": false, + "external_provider_call_authorized": false, + "paid_provider_call_authorized": false, + "prompt_send_authorized": false, + "live_endpoint_probe_authorized": false, + "secret_value_collection_allowed": false, + "raw_prompt_storage_allowed": false, + "raw_endpoint_storage_allowed": false, + "sdk_install_authorized": false, + "agent_runtime_enable_authorized": false, + "shadow_or_canary_enable_authorized": false, + "production_deploy_authorized": false, + "host_write_authorized": false, + "active_scan_authorized": false, + "runtime_gate": false, + "action_buttons_allowed": false + } +} diff --git a/docs/security/high-value-config-control-coverage.snapshot.json b/docs/security/high-value-config-control-coverage.snapshot.json index 176d7bbc8..280ffd239 100644 --- a/docs/security/high-value-config-control-coverage.snapshot.json +++ b/docs/security/high-value-config-control-coverage.snapshot.json @@ -458,15 +458,17 @@ "action_buttons_allowed": false, "category_id": "ai_provider_model_routing", "control_tier": "C1", - "coverage_percent": 60, - "coverage_status": "policy_ready_needs_dry_run_pack", - "current_gap": "模型 / provider / Ollama proxy 切換需 dry-run、benchmark、成本與 privacy review;目前不切 production。", + "coverage_percent": 64, + "coverage_status": "owner_response_acceptance_ready_needs_provider_owner_evidence", + "current_gap": "已固定 AI provider / model routing owner response acceptance 帳本;provider owner、fallback order、dry-run、benchmark、成本、privacy、data classification、prompt redaction、rollback 與 post-check evidence 仍全部為 0,目前不切 production。", "evidence_refs": [ "docs/HARD_RULES.md", - "docs/ai" + "docs/ai", + "docs/security/AI-PROVIDER-OWNER-RESPONSE-ACCEPTANCE.md", + "docs/security/ai-provider-owner-response-acceptance.snapshot.json" ], "label": "AI provider / model routing / Ollama proxy / cost and privacy", - "next_owner_action": "補 provider owner、fallback order、cost review、privacy review、benchmark 與 rollback owner。", + "next_owner_action": "補 provider owner、fallback order、dry-run result、benchmark result、cost review、privacy review、data classification、prompt redaction、quota budget、quality gate、rollback owner 與 post-check evidence。", "owner_response_accepted": false, "owner_response_received": false, "owner_response_required": true, @@ -637,16 +639,9 @@ "websocket_route_change_authorized": false, "workflow_modification_authorized": false }, - "generated_at": "2026-06-15T18:55:00+08:00", - "git_commit": "a9060b49", + "generated_at": "2026-06-11T21:30:00+08:00", + "git_commit": "403b29df", "lowest_coverage_categories": [ - { - "category_id": "ai_provider_model_routing", - "coverage_percent": 60, - "current_gap": "模型 / provider / Ollama proxy 切換需 dry-run、benchmark、成本與 privacy review;目前不切 production。", - "label": "AI provider / model routing / Ollama proxy / cost and privacy", - "next_owner_action": "補 provider owner、fallback order、cost review、privacy review、benchmark 與 rollback owner。" - }, { "category_id": "docker_compose_systemd_host_config", "coverage_percent": 62, @@ -667,6 +662,13 @@ "current_gap": "已固定 owner response acceptance 與 GitOps 變更證據驗收只讀帳本;proposed commit、rendered manifest diff、ArgoCD app / sync revision、health before / after、rollout、route smoke、metrics / alert、rollback、maintenance window 與 post-check evidence 仍全部為 0。", "label": "K8s / ArgoCD / production manifests", "next_owner_action": "補 GitOps owner 回覆、proposed commit ref、rendered manifest diff ref、ArgoCD app / sync revision ref、health before / after、rollout、route smoke、metrics / alert、blast radius、rollback revision、maintenance window 與 post-check owner。" + }, + { + "category_id": "backup_restore_credential", + "coverage_percent": 64, + "current_gap": "已固定 owner response acceptance、restore recovery backfill、remote delete guard、retention runway、credential recovery metadata-only 與 backup health no-false-green 只讀帳本;restore drill、offsite sync、credential escrow、retention change、live evidence 與 owner response 仍全部為 0。", + "label": "Backup / restore / escrow / retention", + "next_owner_action": "補 restore drill approval package、freshness SLO、隔離 restore target、依賴圖、資料分級、offsite remote delete guard、credential recovery non-secret proof、retention runway、observer / stop condition、rollback owner、validation plan 與 no-secret-value evidence。" } ], "next_collection_order": [ @@ -678,8 +680,9 @@ "public_admin_api_runtime_config", "agent_bounty_protocol_runtime", "docker_compose_systemd_host_config", - "monitoring_alerting_observability", "ssh_firewall_network_access", + "ai_provider_model_routing", + "monitoring_alerting_observability", "backup_restore_credential" ], "operator_interpretation": [ diff --git a/docs/security/iwooos-posture-projection.snapshot.json b/docs/security/iwooos-posture-projection.snapshot.json index c6e5b0ed5..e0da037a9 100644 --- a/docs/security/iwooos-posture-projection.snapshot.json +++ b/docs/security/iwooos-posture-projection.snapshot.json @@ -8424,7 +8424,9 @@ "docs/security/k8s-argocd-change-evidence-acceptance.snapshot.json", "docs/security/CD-RUNNER-SECRET-INJECTION-CHANGE-EVIDENCE-ACCEPTANCE.md", "docs/security/cd-runner-secret-injection-change-evidence-acceptance.snapshot.json", - "docs/security/public-frontend-sensitive-surface-guard.snapshot.json" + "docs/security/public-frontend-sensitive-surface-guard.snapshot.json", + "docs/security/AI-PROVIDER-OWNER-RESPONSE-ACCEPTANCE.md", + "docs/security/ai-provider-owner-response-acceptance.snapshot.json" ], "status": "draft", "summary": { @@ -9026,7 +9028,37 @@ "vibework_security_onboarding_runtime_gate_count": 0, "visual_command_dashboard_default_visible": false, "visual_command_dashboard_first_layer": true, - "visual_command_dashboard_widget_count": 14 + "visual_command_dashboard_widget_count": 14, + "ai_provider_owner_response_acceptance_candidate_count": 8, + "ai_provider_owner_response_acceptance_write_capable_candidate_count": 5, + "ai_provider_owner_response_acceptance_paid_provider_related_candidate_count": 5, + "ai_provider_owner_response_acceptance_data_egress_candidate_count": 6, + "ai_provider_owner_response_acceptance_live_evidence_required_candidate_count": 6, + "ai_provider_owner_response_acceptance_acceptance_field_count": 37, + "ai_provider_owner_response_acceptance_required_owner_field_count": 24, + "ai_provider_owner_response_acceptance_reviewer_check_count": 24, + "ai_provider_owner_response_acceptance_outcome_lane_count": 10, + "ai_provider_owner_response_acceptance_blocked_action_count": 38, + "ai_provider_owner_response_acceptance_owner_response_received_count": 0, + "ai_provider_owner_response_acceptance_owner_response_accepted_count": 0, + "ai_provider_owner_response_acceptance_dry_run_result_accepted_count": 0, + "ai_provider_owner_response_acceptance_benchmark_result_accepted_count": 0, + "ai_provider_owner_response_acceptance_cost_review_accepted_count": 0, + "ai_provider_owner_response_acceptance_privacy_review_accepted_count": 0, + "ai_provider_owner_response_acceptance_fallback_order_accepted_count": 0, + "ai_provider_owner_response_acceptance_prompt_redaction_accepted_count": 0, + "ai_provider_owner_response_acceptance_secret_handling_accepted_count": 0, + "ai_provider_owner_response_acceptance_quality_gate_accepted_count": 0, + "ai_provider_owner_response_acceptance_rollback_owner_accepted_count": 0, + "ai_provider_owner_response_acceptance_provider_switch_authorized_count": 0, + "ai_provider_owner_response_acceptance_external_provider_call_authorized_count": 0, + "ai_provider_owner_response_acceptance_paid_provider_call_authorized_count": 0, + "ai_provider_owner_response_acceptance_prompt_send_authorized_count": 0, + "ai_provider_owner_response_acceptance_live_endpoint_probe_authorized_count": 0, + "ai_provider_owner_response_acceptance_secret_value_collection_allowed_count": 0, + "ai_provider_owner_response_acceptance_runtime_gate_count": 0, + "ai_provider_owner_response_acceptance_coverage_percent_after_acceptance": 64, + "ai_provider_model_routing_coverage_percent": 64 }, "topology_atlas_lenses": [ { diff --git a/scripts/security/ai-provider-owner-response-acceptance.py b/scripts/security/ai-provider-owner-response-acceptance.py new file mode 100644 index 000000000..ac4eb6738 --- /dev/null +++ b/scripts/security/ai-provider-owner-response-acceptance.py @@ -0,0 +1,553 @@ +#!/usr/bin/env python3 +""" +IwoooS AI provider / model routing owner response acceptance 只讀帳本產生器。 + +本工具建立 AI provider、Ollama proxy、fallback order、cost、privacy、 +benchmark、dry-run 與 agent replacement candidate 的 metadata-only +acceptance ledger。它不呼叫任何模型、不讀 live endpoint、不切 provider、 +不改 Nginx、不送 prompt、不建立外部 API 呼叫、不收 secret value,也不開 +runtime gate。 +""" + +from __future__ import annotations + +import argparse +import hashlib +import json +import subprocess +import sys +from datetime import datetime, timedelta, timezone +from pathlib import Path +from typing import Any + + +TAIPEI = timezone(timedelta(hours=8)) + +ACCEPTANCE_FIELDS = [ + "acceptance_candidate_id", + "surface_id", + "label", + "expected_scope", + "config_kind", + "control_tier", + "source_refs", + "source_ref_sha256", + "write_capable_surface", + "paid_provider_related", + "data_egress_related", + "requires_live_evidence", + "owner_response_ref", + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "provider_owner", + "fallback_order_ref", + "dry_run_result_ref", + "benchmark_result_ref", + "cost_review_ref", + "privacy_review_ref", + "data_classification_ref", + "prompt_redaction_ref", + "secret_handling_ref", + "quota_budget_ref", + "latency_slo_ref", + "quality_gate_ref", + "rollback_owner", + "rollback_plan_ref", + "maintenance_window", + "postcheck_evidence_refs", + "redacted_evidence_refs", + "reviewer_outcome", + "followup_owner", + "not_approval", +] + +REQUIRED_OWNER_FIELDS = [ + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "provider_owner", + "fallback_order_ref", + "dry_run_result_ref", + "benchmark_result_ref", + "cost_review_ref", + "privacy_review_ref", + "data_classification_ref", + "prompt_redaction_ref", + "secret_handling_ref", + "quota_budget_ref", + "latency_slo_ref", + "quality_gate_ref", + "rollback_owner", + "rollback_plan_ref", + "maintenance_window", + "postcheck_evidence_refs", + "redacted_evidence_refs", + "followup_owner", + "not_approval", + "no_secret_value_attestation", +] + +REVIEWER_CHECKS = [ + {"check_id": "owner_identity_present", "instruction": "owner role / team 與 provider owner 必須可追溯。"}, + {"check_id": "decision_reason_present", "instruction": "decision 與 decision reason 必須同時存在。"}, + {"check_id": "affected_scope_matches_surface", "instruction": "affected scope 必須能對回既有 AI provider surface。"}, + {"check_id": "redacted_refs_only", "instruction": "evidence 只能是脫敏 ref、hash、ticket、commit 或 artifact pointer。"}, + {"check_id": "secret_value_absent", "instruction": "不得出現 API key、token、cookie、private key、env dump、完整 DSN 或 partial secret。"}, + {"check_id": "live_endpoint_absent", "instruction": "不得保存 raw live endpoint、內網位址或可直接連線 URL。"}, + {"check_id": "fallback_order_present", "instruction": "必須提供 fallback order 與 degraded mode ref,不接受憑印象切 provider。"}, + {"check_id": "dry_run_result_present", "instruction": "必須有 dry-run 結果或明確不適用理由;dry-run 不得呼叫 production LLM。"}, + {"check_id": "benchmark_result_present", "instruction": "必須有 benchmark / replay / fixture 結果與評分方法 ref。"}, + {"check_id": "cost_review_present", "instruction": "涉及雲端或付費 provider 時必須有成本上限、quota、告警與停損 ref。"}, + {"check_id": "privacy_review_present", "instruction": "涉及外部 provider、prompt、log 或 embedding 時必須有資料外送與脫敏審查 ref。"}, + {"check_id": "data_classification_present", "instruction": "必須標示可送出、不可送出、需遮罩與只能本地處理的資料分類。"}, + {"check_id": "prompt_redaction_present", "instruction": "prompt / log / incident context 需有 redaction proof,不接受 raw prompt 或 raw log。"}, + {"check_id": "secret_handling_metadata_only", "instruction": "secret handling 只能描述注入路徑與 owner,不得貼 secret value / hash / partial token。"}, + {"check_id": "quota_budget_present", "instruction": "付費 provider、雲端 provider 或外部 API 必須有 quota budget 與 stop condition。"}, + {"check_id": "latency_slo_present", "instruction": "需要 latency / timeout / circuit breaker / degradation SLO ref。"}, + {"check_id": "quality_gate_present", "instruction": "模型切換或 agent replacement 必須有品質門檻與 incumbent baseline。"}, + {"check_id": "rollback_owner_present", "instruction": "rollback owner 與 rollback plan 必須存在。"}, + {"check_id": "maintenance_window_present", "instruction": "provider route、proxy、env 或 model change 必須另有維護窗口。"}, + {"check_id": "postcheck_evidence_present", "instruction": "post-check 必須覆蓋 provider route、fallback、cost、privacy、observability 與 rollback stop condition。"}, + {"check_id": "no_runtime_request", "instruction": "夾帶 provider switch、Nginx reload、env change、external call、prompt send、benchmark live call 或 deploy 時拒收。"}, + {"check_id": "no_false_green_provider_health", "instruction": "不得把 provider route 200、dashboard up、模型回覆一次成功當成 routing / privacy / cost 已驗收。"}, + {"check_id": "cross_project_sync_present", "instruction": "影響 AwoooP、IwoooS、agent-bounty、code review、StockPlatform 或公開網站時需有跨專案同步 ref。"}, + {"check_id": "counts_transition_safe", "instruction": "只有 reviewer record 可更新 received / accepted;不得同時開 runtime gate。"}, +] + +OUTCOME_LANES = [ + {"lane_id": "waiting_owner_response", "meaning": "尚未收到 AI provider owner response;所有 accepted / runtime count 維持 0。"}, + {"lane_id": "quarantine_secret_or_raw_payload", "meaning": "收到 secret、raw prompt、raw log、raw endpoint、未脫敏截圖或 env dump 時隔離。"}, + {"lane_id": "reject_execution_request", "meaning": "夾帶 provider switch、外部呼叫、prompt send、Nginx reload、env change 或 deploy 要求時拒收。"}, + {"lane_id": "request_fallback_supplement", "meaning": "缺 fallback order、degraded mode、circuit breaker 或 rollback 時要求補件。"}, + {"lane_id": "request_cost_privacy_supplement", "meaning": "缺 cost / quota / privacy / data classification / prompt redaction 時要求補件。"}, + {"lane_id": "request_benchmark_supplement", "meaning": "缺 dry-run、benchmark、fixture replay、quality gate 或 incumbent baseline 時要求補件。"}, + {"lane_id": "legacy_model_card_redaction_required", "meaning": "舊模型卡、runbook 或報表含 raw endpoint / 主機識別時,先改成脫敏 alias。"}, + {"lane_id": "ready_for_ai_provider_review", "meaning": "metadata 合格後,只能進 AI provider reviewer review。"}, + {"lane_id": "owner_review_only_update", "meaning": "只允許更新只讀 owner review ledger,不切 provider、不呼叫模型、不改 proxy。"}, + {"lane_id": "waiting_runtime_gate", "meaning": "即使 owner response accepted,runtime gate 仍需獨立人工批准。"}, +] + +BLOCKED_ACTIONS = [ + "provider_switch", + "model_route_change", + "fallback_order_change", + "ollama_proxy_change", + "nginx_reload", + "env_change", + "runtime_config_change", + "external_provider_call", + "paid_provider_call", + "prompt_send", + "raw_prompt_storage", + "raw_log_storage", + "raw_endpoint_storage", + "live_endpoint_probe", + "benchmark_live_call", + "dry_run_external_call", + "quota_increase", + "cost_limit_change", + "privacy_boundary_change", + "data_egress_change", + "secret_value_collection", + "secret_hash_collection", + "partial_token_collection", + "api_key_rotation", + "secret_store_read", + "model_download", + "sdk_install", + "agent_runtime_enable", + "shadow_or_canary_enable", + "production_deploy", + "workflow_dispatch", + "host_write", + "ssh_read", + "ssh_write", + "active_scan", + "mark_owner_response_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", +] + +SURFACES = [ + { + "surface_id": "ai_router_provider_policy", + "label": "AI router provider policy / purpose mapping", + "expected_scope": "purpose routing、provider priority、degraded mode", + "config_kind": "provider_policy", + "source_refs": [ + "apps/api/src/services/ai_router.py", + "apps/api/src/services/ai_provider_route_matrix.py", + "apps/api/models.json", + "docs/ai/AI-MODEL-CARDS.md", + ], + "write_capable_surface": True, + "paid_provider_related": True, + "data_egress_related": True, + "requires_live_evidence": True, + }, + { + "surface_id": "ollama_proxy_gateway", + "label": "Ollama proxy gateway / local fallback boundary", + "expected_scope": "proxy route、local fallback、gateway health", + "config_kind": "proxy_gateway", + "source_refs": [ + "infra/ansible/roles/nginx/templates/110-ollama-proxy.conf.j2", + "apps/api/src/services/ollama_endpoint_resolver.py", + "apps/api/src/services/ollama_failover_manager.py", + "apps/api/src/services/provider_proxy.py", + ], + "write_capable_surface": True, + "paid_provider_related": False, + "data_egress_related": False, + "requires_live_evidence": True, + }, + { + "surface_id": "fallback_order_and_circuit_breaker", + "label": "Fallback order / circuit breaker", + "expected_scope": "GCP / local / cloud fallback order、timeout、circuit breaker", + "config_kind": "routing_guard", + "source_refs": [ + "apps/api/src/services/ollama_endpoint_circuit_breaker.py", + "apps/api/src/services/ollama_health_monitor.py", + "apps/api/src/services/failover_alerter.py", + "apps/web/messages/zh-TW.json", + ], + "write_capable_surface": True, + "paid_provider_related": True, + "data_egress_related": True, + "requires_live_evidence": True, + }, + { + "surface_id": "cost_budget_and_quota", + "label": "Cost budget / quota / paid provider stop condition", + "expected_scope": "quota、token budget、cost alert、paid provider stop condition", + "config_kind": "cost_policy", + "source_refs": [ + "docs/ai/AI-MODEL-CARDS.md", + "apps/api/src/services/ai_rate_limiter.py", + "apps/api/src/services/ai_slo_calculator.py", + "apps/web/messages/zh-TW.json", + ], + "write_capable_surface": False, + "paid_provider_related": True, + "data_egress_related": True, + "requires_live_evidence": True, + }, + { + "surface_id": "privacy_data_egress_boundary", + "label": "Privacy / data egress / prompt redaction boundary", + "expected_scope": "prompt redaction、資料分級、外部 provider 資料外送", + "config_kind": "privacy_policy", + "source_refs": [ + "docs/HARD_RULES.md", + "docs/ai/AI-MODEL-CARDS.md", + "apps/api/src/services/ai_providers/permissions.py", + "apps/api/src/services/alertmanager_llm_guard.py", + ], + "write_capable_surface": False, + "paid_provider_related": True, + "data_egress_related": True, + "requires_live_evidence": True, + }, + { + "surface_id": "benchmark_dry_run_pack", + "label": "Dry-run / benchmark / replay pack", + "expected_scope": "dry-run、benchmark、fixture replay、quality gate", + "config_kind": "evaluation_pack", + "source_refs": [ + "docs/runbooks/OPENCLAW-REPLACEMENT-EVALUATION.md", + "docs/ai/agent-replacement-candidates.v1.json", + "scripts/agents/run-agent-replacement-replay.py", + "scripts/agents/evaluate-agent-promotion-gate.py", + ], + "write_capable_surface": False, + "paid_provider_related": False, + "data_egress_related": True, + "requires_live_evidence": False, + }, + { + "surface_id": "model_card_and_version_inventory", + "label": "Model card / model version inventory", + "expected_scope": "model card、version freshness、source-of-truth、redacted endpoint", + "config_kind": "model_metadata", + "source_refs": [ + "docs/ai/AI-MODEL-CARDS.md", + "apps/api/src/services/model_registry.py", + "apps/api/src/services/model_version_tracker.py", + "apps/api/src/services/model_version_probe.py", + ], + "write_capable_surface": True, + "paid_provider_related": False, + "data_egress_related": False, + "requires_live_evidence": False, + }, + { + "surface_id": "agent_replacement_candidate_runtime_boundary", + "label": "Agent replacement / NemoTron / Hermes / OpenClaw candidate boundary", + "expected_scope": "agent candidate、promotion gate、shadow/canary boundary", + "config_kind": "agent_runtime_boundary", + "source_refs": [ + "docs/runbooks/OPENCLAW-REPLACEMENT-EVALUATION.md", + "docs/ai/agent-market-watch-sources.v1.json", + "docs/ai/agent-replacement-candidates.v1.json", + "apps/api/src/services/ai_agent_tool_adoption_approval_package.py", + ], + "write_capable_surface": True, + "paid_provider_related": True, + "data_egress_related": True, + "requires_live_evidence": True, + }, +] + + +def git_short_sha(root: Path) -> str: + try: + result = subprocess.run( + ["git", "rev-parse", "--short", "HEAD"], + cwd=root, + check=True, + capture_output=True, + text=True, + ) + return result.stdout.strip() + except Exception: + return "unknown" + + +def ref_digest(root: Path, refs: list[str]) -> str: + digest = hashlib.sha256() + for ref in refs: + path = root / ref + digest.update(ref.encode("utf-8")) + if path.is_file(): + digest.update(path.read_bytes()) + elif path.is_dir(): + digest.update(b"") + else: + digest.update(b"") + return digest.hexdigest() + + +def build_candidate(root: Path, surface: dict[str, Any]) -> dict[str, Any]: + return { + "acceptance_candidate_id": f"ai_provider_owner_response_acceptance:{surface['surface_id']}", + "status": "waiting_owner_response", + "surface_id": surface["surface_id"], + "label": surface["label"], + "expected_scope": surface["expected_scope"], + "config_kind": surface["config_kind"], + "control_tier": "C1", + "source_refs": surface["source_refs"], + "source_ref_sha256": ref_digest(root, surface["source_refs"]), + "write_capable_surface": surface["write_capable_surface"], + "paid_provider_related": surface["paid_provider_related"], + "data_egress_related": surface["data_egress_related"], + "requires_live_evidence": surface["requires_live_evidence"], + "owner_response_ref": None, + "owner_role_or_team": "pending_owner_response", + "decision": "pending_owner_response", + "decision_reason": "pending_owner_response", + "affected_scope": "pending_owner_response", + "provider_owner": "pending_owner_response", + "fallback_order_ref": None, + "dry_run_result_ref": None, + "benchmark_result_ref": None, + "cost_review_ref": None, + "privacy_review_ref": None, + "data_classification_ref": None, + "prompt_redaction_ref": None, + "secret_handling_ref": None, + "quota_budget_ref": None, + "latency_slo_ref": None, + "quality_gate_ref": None, + "rollback_owner": "pending_owner_response", + "rollback_plan_ref": None, + "maintenance_window": "pending_owner_response", + "postcheck_evidence_refs": [], + "redacted_evidence_refs": [], + "reviewer_outcome": "waiting_owner_response", + "followup_owner": "pending_owner_response", + "acceptance_fields": ACCEPTANCE_FIELDS, + "required_owner_fields": REQUIRED_OWNER_FIELDS, + "reviewer_checks": [item["check_id"] for item in REVIEWER_CHECKS], + "outcome_lanes": [item["lane_id"] for item in OUTCOME_LANES], + "blocked_actions": BLOCKED_ACTIONS, + "not_approval": True, + "request_sent": False, + "recipient_confirmed": False, + "owner_response_received": False, + "owner_response_accepted": False, + "owner_response_rejected": False, + "owner_response_quarantined": False, + "supplement_requested": False, + "fallback_order_accepted": False, + "dry_run_result_accepted": False, + "benchmark_result_accepted": False, + "cost_review_accepted": False, + "privacy_review_accepted": False, + "data_classification_accepted": False, + "prompt_redaction_accepted": False, + "secret_handling_accepted": False, + "quota_budget_accepted": False, + "latency_slo_accepted": False, + "quality_gate_accepted": False, + "rollback_owner_accepted": False, + "maintenance_window_accepted": False, + "postcheck_evidence_accepted": False, + "provider_switch_authorized": False, + "model_route_change_authorized": False, + "fallback_order_change_authorized": False, + "ollama_proxy_change_authorized": False, + "nginx_reload_authorized": False, + "env_change_authorized": False, + "external_provider_call_authorized": False, + "paid_provider_call_authorized": False, + "prompt_send_authorized": False, + "live_endpoint_probe_authorized": False, + "benchmark_live_call_authorized": False, + "dry_run_external_call_authorized": False, + "quota_increase_authorized": False, + "cost_limit_change_authorized": False, + "privacy_boundary_change_authorized": False, + "data_egress_change_authorized": False, + "secret_value_collection_allowed": False, + "secret_hash_collection_allowed": False, + "partial_token_collection_allowed": False, + "api_key_rotation_authorized": False, + "secret_store_read_authorized": False, + "model_download_authorized": False, + "sdk_install_authorized": False, + "agent_runtime_enable_authorized": False, + "shadow_or_canary_enable_authorized": False, + "production_deploy_authorized": False, + "workflow_dispatch_authorized": False, + "host_write_authorized": False, + "ssh_read_authorized": False, + "ssh_write_authorized": False, + "active_scan_authorized": False, + "runtime_gate": False, + "action_buttons_allowed": False, + } + + +def build_snapshot(root: Path, generated_at: str | None = None) -> dict[str, Any]: + generated = generated_at or datetime.now(TAIPEI).isoformat(timespec="seconds") + candidates = [build_candidate(root, surface) for surface in SURFACES] + summary = { + "acceptance_candidate_count": len(candidates), + "write_capable_acceptance_candidate_count": sum(1 for item in candidates if item["write_capable_surface"]), + "paid_provider_related_candidate_count": sum(1 for item in candidates if item["paid_provider_related"]), + "data_egress_candidate_count": sum(1 for item in candidates if item["data_egress_related"]), + "live_evidence_required_candidate_count": sum(1 for item in candidates if item["requires_live_evidence"]), + "acceptance_field_count": len(ACCEPTANCE_FIELDS), + "required_owner_field_count": len(REQUIRED_OWNER_FIELDS), + "reviewer_check_count": len(REVIEWER_CHECKS), + "outcome_lane_count": len(OUTCOME_LANES), + "blocked_action_count": len(BLOCKED_ACTIONS), + "owner_response_received_count": 0, + "owner_response_accepted_count": 0, + "owner_response_rejected_count": 0, + "owner_response_quarantined_count": 0, + "supplement_requested_count": 0, + "fallback_order_accepted_count": 0, + "dry_run_result_accepted_count": 0, + "benchmark_result_accepted_count": 0, + "cost_review_accepted_count": 0, + "privacy_review_accepted_count": 0, + "data_classification_accepted_count": 0, + "prompt_redaction_accepted_count": 0, + "secret_handling_accepted_count": 0, + "quota_budget_accepted_count": 0, + "latency_slo_accepted_count": 0, + "quality_gate_accepted_count": 0, + "rollback_owner_accepted_count": 0, + "maintenance_window_accepted_count": 0, + "postcheck_evidence_accepted_count": 0, + "provider_switch_authorized_count": 0, + "external_provider_call_authorized_count": 0, + "paid_provider_call_authorized_count": 0, + "prompt_send_authorized_count": 0, + "live_endpoint_probe_authorized_count": 0, + "secret_value_collection_allowed_count": 0, + "runtime_gate_count": 0, + "action_button_count": 0, + "coverage_percent_before_acceptance": 60, + "coverage_percent_after_acceptance": 64, + } + return { + "schema_version": "ai_provider_owner_response_acceptance_v1", + "status": "owner_response_acceptance_ledger_ready_no_runtime_action", + "generated_at": generated, + "git_sha": git_short_sha(root), + "source_paths": [ + "docs/HARD_RULES.md", + "docs/ai/AI-MODEL-CARDS.md", + "docs/runbooks/OPENCLAW-REPLACEMENT-EVALUATION.md", + "scripts/security/ai-provider-owner-response-acceptance.py", + "scripts/security/high-value-config-control-coverage.py", + ], + "summary": summary, + "acceptance_fields": ACCEPTANCE_FIELDS, + "required_owner_fields": REQUIRED_OWNER_FIELDS, + "reviewer_checks": REVIEWER_CHECKS, + "outcome_lanes": OUTCOME_LANES, + "blocked_actions": BLOCKED_ACTIONS, + "acceptance_candidates": candidates, + "boundaries": { + "not_authorization": True, + "runtime_execution_authorized": False, + "provider_switch_authorized": False, + "model_route_change_authorized": False, + "fallback_order_change_authorized": False, + "ollama_proxy_change_authorized": False, + "nginx_reload_authorized": False, + "external_provider_call_authorized": False, + "paid_provider_call_authorized": False, + "prompt_send_authorized": False, + "live_endpoint_probe_authorized": False, + "secret_value_collection_allowed": False, + "raw_prompt_storage_allowed": False, + "raw_endpoint_storage_allowed": False, + "sdk_install_authorized": False, + "agent_runtime_enable_authorized": False, + "shadow_or_canary_enable_authorized": False, + "production_deploy_authorized": False, + "host_write_authorized": False, + "active_scan_authorized": False, + "runtime_gate": False, + "action_buttons_allowed": False, + }, + } + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("--root", default=".") + parser.add_argument( + "--output", + default="docs/security/ai-provider-owner-response-acceptance.snapshot.json", + ) + parser.add_argument("--generated-at", default=None) + args = parser.parse_args() + + root = Path(args.root).resolve() + output = root / args.output + snapshot = build_snapshot(root, args.generated_at) + output.parent.mkdir(parents=True, exist_ok=True) + output.write_text(json.dumps(snapshot, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") + print( + "AI_PROVIDER_OWNER_RESPONSE_ACCEPTANCE_OK " + f"candidates={snapshot['summary']['acceptance_candidate_count']} " + f"checks={snapshot['summary']['reviewer_check_count']} " + f"lanes={snapshot['summary']['outcome_lane_count']} " + f"accepted={snapshot['summary']['owner_response_accepted_count']} " + f"runtime_gate={snapshot['summary']['runtime_gate_count']}" + ) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/security/high-value-config-control-coverage.py b/scripts/security/high-value-config-control-coverage.py index 11ce54f80..11ee8cde5 100644 --- a/scripts/security/high-value-config-control-coverage.py +++ b/scripts/security/high-value-config-control-coverage.py @@ -193,14 +193,16 @@ CONTROL_STATUS_BY_CATEGORY = { "next_owner_action": "補端口 / 防火牆變更的 change / incident ref、actor role / team、affected scope、before / after state、service dependency、customer impact、service health impact、operator notification、cross-project sync、rollback owner 與 post-check 指標。", }, "ai_provider_model_routing": { - "coverage_status": "policy_ready_needs_dry_run_pack", - "coverage_percent": 60, + "coverage_status": "owner_response_acceptance_ready_needs_provider_owner_evidence", + "coverage_percent": 64, "evidence_refs": [ "docs/HARD_RULES.md", "docs/ai", + "docs/security/AI-PROVIDER-OWNER-RESPONSE-ACCEPTANCE.md", + "docs/security/ai-provider-owner-response-acceptance.snapshot.json", ], - "current_gap": "模型 / provider / Ollama proxy 切換需 dry-run、benchmark、成本與 privacy review;目前不切 production。", - "next_owner_action": "補 provider owner、fallback order、cost review、privacy review、benchmark 與 rollback owner。", + "current_gap": "已固定 AI provider / model routing owner response acceptance 帳本;provider owner、fallback order、dry-run、benchmark、成本、privacy、data classification、prompt redaction、rollback 與 post-check evidence 仍全部為 0,目前不切 production。", + "next_owner_action": "補 provider owner、fallback order、dry-run result、benchmark result、cost review、privacy review、data classification、prompt redaction、quota budget、quality gate、rollback owner 與 post-check evidence。", }, "product_surface_runtime_routes": { "coverage_status": "scope_inventory_ready", @@ -394,6 +396,7 @@ def build_report(root: Path, generated_at: str | None) -> dict[str, Any]: "change_evidence_acceptance_ready_needs_host_service_owner_evidence", "policy_ready_needs_network_matrix", "policy_ready_needs_dry_run_pack", + "owner_response_acceptance_ready_needs_provider_owner_evidence", } ] average_coverage = round(sum(item["coverage_percent"] for item in categories) / len(categories)) @@ -442,8 +445,9 @@ def build_report(root: Path, generated_at: str | None) -> dict[str, Any]: "public_admin_api_runtime_config", "agent_bounty_protocol_runtime", "docker_compose_systemd_host_config", - "monitoring_alerting_observability", "ssh_firewall_network_access", + "ai_provider_model_routing", + "monitoring_alerting_observability", "backup_restore_credential", ], "operator_interpretation": [ diff --git a/scripts/security/iwooos-config-control-guard.py b/scripts/security/iwooos-config-control-guard.py index 3c93ad91f..c3bb2b554 100644 --- a/scripts/security/iwooos-config-control-guard.py +++ b/scripts/security/iwooos-config-control-guard.py @@ -28,7 +28,7 @@ EXPECTED_CATEGORIES = { "monitoring_alerting_observability": 68, "docker_compose_systemd_host_config": 62, "ssh_firewall_network_access": 62, - "ai_provider_model_routing": 60, + "ai_provider_model_routing": 64, "product_surface_runtime_routes": 72, "security_evidence_tooling": 86, } @@ -61,6 +61,7 @@ REQUIRED_CONTROL_DOCS = [ "docs/security/CD-RUNNER-SECRET-INJECTION-CHANGE-EVIDENCE-ACCEPTANCE.md", "docs/security/PUBLIC-RUNTIME-CONFIG-CHANGE-EVIDENCE-ACCEPTANCE.md", "docs/security/MONITORING-OWNER-REQUEST-DRAFT.md", + "docs/security/AI-PROVIDER-OWNER-RESPONSE-ACCEPTANCE.md", "docs/security/AGENT-BOUNTY-OWNER-REQUEST-DRAFT.md", "docs/security/SECURITY-SUPPLY-CHAIN-CONTRACT-MANIFEST.md", ] @@ -408,6 +409,39 @@ ARTIFACT_SPECS = [ "runtime_gate_count": 0, }, }, + { + "label": "ai provider owner response acceptance", + "path": "docs/security/ai-provider-owner-response-acceptance.snapshot.json", + "schema": "ai_provider_owner_response_acceptance_v1", + "status": "owner_response_acceptance_ledger_ready_no_runtime_action", + "list_counts": { + "acceptance_candidates": 8, + "blocked_actions": 38, + "reviewer_checks": 24, + "outcome_lanes": 10, + "required_owner_fields": 24, + }, + "summary_counts": { + "acceptance_candidate_count": 8, + "write_capable_acceptance_candidate_count": 5, + "paid_provider_related_candidate_count": 5, + "data_egress_candidate_count": 6, + "live_evidence_required_candidate_count": 6, + "acceptance_field_count": 37, + "required_owner_field_count": 24, + "reviewer_check_count": 24, + "outcome_lane_count": 10, + "blocked_action_count": 38, + "owner_response_received_count": 0, + "owner_response_accepted_count": 0, + "dry_run_result_accepted_count": 0, + "benchmark_result_accepted_count": 0, + "cost_review_accepted_count": 0, + "privacy_review_accepted_count": 0, + "fallback_order_accepted_count": 0, + "runtime_gate_count": 0, + }, + }, { "label": "agent bounty owner request draft", "path": "docs/security/agent-bounty-owner-request-draft.snapshot.json", diff --git a/scripts/security/security-mirror-progress-guard.py b/scripts/security/security-mirror-progress-guard.py index b15d8edab..1cf1f92f3 100755 --- a/scripts/security/security-mirror-progress-guard.py +++ b/scripts/security/security-mirror-progress-guard.py @@ -179,6 +179,9 @@ def validate(root: Path) -> None: monitoring_owner_response_acceptance = load_json( security_dir / "monitoring-owner-response-acceptance.snapshot.json" ) + ai_provider_owner_response_acceptance = load_json( + security_dir / "ai-provider-owner-response-acceptance.snapshot.json" + ) domain_tls_inventory = load_json(security_dir / "domain-tls-certbot-inventory.snapshot.json") domain_tls_owner_confirmation_request = load_json( security_dir / "domain-tls-certbot-owner-confirmation-request.snapshot.json" @@ -3222,6 +3225,32 @@ def validate(root: Path) -> None: ssh_network_category["evidence_refs"], evidence_ref, ) + ai_provider_category = next( + item + for item in high_value_config_coverage["coverage_categories"] + if item["category_id"] == "ai_provider_model_routing" + ) + assert_equal( + "high_value_config_coverage.coverage_categories.ai_provider.coverage_percent", + ai_provider_category["coverage_percent"], + 64, + ) + assert_equal( + "high_value_config_coverage.coverage_categories.ai_provider.coverage_status", + ai_provider_category["coverage_status"], + "owner_response_acceptance_ready_needs_provider_owner_evidence", + ) + for evidence_ref in [ + "docs/HARD_RULES.md", + "docs/ai", + "docs/security/AI-PROVIDER-OWNER-RESPONSE-ACCEPTANCE.md", + "docs/security/ai-provider-owner-response-acceptance.snapshot.json", + ]: + assert_contains( + "high_value_config_coverage.coverage_categories.ai_provider.evidence_refs", + ai_provider_category["evidence_refs"], + evidence_ref, + ) backup_restore_category = next( item for item in high_value_config_coverage["coverage_categories"] @@ -5567,6 +5596,192 @@ def validate(root: Path) -> None: f"monitoring_owner_response_acceptance.{item['acceptance_candidate_id']}.{false_key}", item[false_key], ) + assert_equal( + "ai_provider_owner_response_acceptance.schema", + ai_provider_owner_response_acceptance["schema_version"], + "ai_provider_owner_response_acceptance_v1", + ) + assert_equal( + "ai_provider_owner_response_acceptance.status", + ai_provider_owner_response_acceptance["status"], + "owner_response_acceptance_ledger_ready_no_runtime_action", + ) + expected_ai_provider_owner_response_acceptance_summary = { + "acceptance_candidate_count": 8, + "write_capable_acceptance_candidate_count": 5, + "paid_provider_related_candidate_count": 5, + "data_egress_candidate_count": 6, + "live_evidence_required_candidate_count": 6, + "acceptance_field_count": 37, + "required_owner_field_count": 24, + "reviewer_check_count": 24, + "outcome_lane_count": 10, + "blocked_action_count": 38, + "owner_response_received_count": 0, + "owner_response_accepted_count": 0, + "owner_response_rejected_count": 0, + "owner_response_quarantined_count": 0, + "supplement_requested_count": 0, + "fallback_order_accepted_count": 0, + "dry_run_result_accepted_count": 0, + "benchmark_result_accepted_count": 0, + "cost_review_accepted_count": 0, + "privacy_review_accepted_count": 0, + "data_classification_accepted_count": 0, + "prompt_redaction_accepted_count": 0, + "secret_handling_accepted_count": 0, + "quota_budget_accepted_count": 0, + "latency_slo_accepted_count": 0, + "quality_gate_accepted_count": 0, + "rollback_owner_accepted_count": 0, + "maintenance_window_accepted_count": 0, + "postcheck_evidence_accepted_count": 0, + "provider_switch_authorized_count": 0, + "external_provider_call_authorized_count": 0, + "paid_provider_call_authorized_count": 0, + "prompt_send_authorized_count": 0, + "live_endpoint_probe_authorized_count": 0, + "secret_value_collection_allowed_count": 0, + "runtime_gate_count": 0, + "action_button_count": 0, + "coverage_percent_after_acceptance": 64, + } + for key, expected in expected_ai_provider_owner_response_acceptance_summary.items(): + assert_equal( + f"ai_provider_owner_response_acceptance.summary.{key}", + ai_provider_owner_response_acceptance["summary"][key], + expected, + ) + for key, value in ai_provider_owner_response_acceptance["boundaries"].items(): + if key == "not_authorization": + assert_true(f"ai_provider_owner_response_acceptance.boundaries.{key}", value) + else: + assert_false(f"ai_provider_owner_response_acceptance.boundaries.{key}", value) + assert_equal( + "ai_provider_owner_response_acceptance.acceptance_candidates.count", + len(ai_provider_owner_response_acceptance["acceptance_candidates"]), + 8, + ) + expected_ai_provider_candidate_ids = [ + "ai_provider_owner_response_acceptance:ai_router_provider_policy", + "ai_provider_owner_response_acceptance:ollama_proxy_gateway", + "ai_provider_owner_response_acceptance:fallback_order_and_circuit_breaker", + "ai_provider_owner_response_acceptance:cost_budget_and_quota", + "ai_provider_owner_response_acceptance:privacy_data_egress_boundary", + "ai_provider_owner_response_acceptance:benchmark_dry_run_pack", + "ai_provider_owner_response_acceptance:model_card_and_version_inventory", + "ai_provider_owner_response_acceptance:agent_replacement_candidate_runtime_boundary", + ] + assert_equal( + "ai_provider_owner_response_acceptance.acceptance_candidates", + [item["acceptance_candidate_id"] for item in ai_provider_owner_response_acceptance["acceptance_candidates"]], + expected_ai_provider_candidate_ids, + ) + assert_equal( + "ai_provider_owner_response_acceptance.reviewer_checks.count", + len(ai_provider_owner_response_acceptance["reviewer_checks"]), + 24, + ) + assert_equal( + "ai_provider_owner_response_acceptance.outcome_lanes.count", + len(ai_provider_owner_response_acceptance["outcome_lanes"]), + 10, + ) + assert_equal( + "ai_provider_owner_response_acceptance.blocked_actions.count", + len(ai_provider_owner_response_acceptance["blocked_actions"]), + 38, + ) + for item in ai_provider_owner_response_acceptance["acceptance_candidates"]: + assert_equal( + f"ai_provider_owner_response_acceptance.{item['acceptance_candidate_id']}.acceptance_fields", + len(item["acceptance_fields"]), + 37, + ) + assert_equal( + f"ai_provider_owner_response_acceptance.{item['acceptance_candidate_id']}.required_owner_fields", + len(item["required_owner_fields"]), + 24, + ) + assert_equal( + f"ai_provider_owner_response_acceptance.{item['acceptance_candidate_id']}.reviewer_checks", + len(item["reviewer_checks"]), + 24, + ) + assert_equal( + f"ai_provider_owner_response_acceptance.{item['acceptance_candidate_id']}.outcome_lanes", + len(item["outcome_lanes"]), + 10, + ) + assert_equal( + f"ai_provider_owner_response_acceptance.{item['acceptance_candidate_id']}.blocked_actions", + len(item["blocked_actions"]), + 38, + ) + assert_true( + f"ai_provider_owner_response_acceptance.{item['acceptance_candidate_id']}.not_approval", + item["not_approval"], + ) + for false_key in [ + "request_sent", + "recipient_confirmed", + "owner_response_received", + "owner_response_accepted", + "owner_response_rejected", + "owner_response_quarantined", + "supplement_requested", + "fallback_order_accepted", + "dry_run_result_accepted", + "benchmark_result_accepted", + "cost_review_accepted", + "privacy_review_accepted", + "data_classification_accepted", + "prompt_redaction_accepted", + "secret_handling_accepted", + "quota_budget_accepted", + "latency_slo_accepted", + "quality_gate_accepted", + "rollback_owner_accepted", + "maintenance_window_accepted", + "postcheck_evidence_accepted", + "provider_switch_authorized", + "model_route_change_authorized", + "fallback_order_change_authorized", + "ollama_proxy_change_authorized", + "nginx_reload_authorized", + "env_change_authorized", + "external_provider_call_authorized", + "paid_provider_call_authorized", + "prompt_send_authorized", + "live_endpoint_probe_authorized", + "benchmark_live_call_authorized", + "dry_run_external_call_authorized", + "quota_increase_authorized", + "cost_limit_change_authorized", + "privacy_boundary_change_authorized", + "data_egress_change_authorized", + "secret_value_collection_allowed", + "secret_hash_collection_allowed", + "partial_token_collection_allowed", + "api_key_rotation_authorized", + "secret_store_read_authorized", + "model_download_authorized", + "sdk_install_authorized", + "agent_runtime_enable_authorized", + "shadow_or_canary_enable_authorized", + "production_deploy_authorized", + "workflow_dispatch_authorized", + "host_write_authorized", + "ssh_read_authorized", + "ssh_write_authorized", + "active_scan_authorized", + "runtime_gate", + "action_buttons_allowed", + ]: + assert_false( + f"ai_provider_owner_response_acceptance.{item['acceptance_candidate_id']}.{false_key}", + item[false_key], + ) assert_equal( "public_gateway_preflight_inventory.schema", public_gateway_preflight_inventory["schema_version"], @@ -6596,6 +6811,7 @@ def validate(root: Path) -> None: "public_frontend_sensitive_surface_guard_allowlisted_match_count": 2, "public_frontend_sensitive_surface_guard_violation_count": 0, "public_frontend_sensitive_surface_guard_runtime_gate_count": 0, + "ai_provider_model_routing_coverage_percent": 64, } for key, expected in expected_high_value_config_coverage_summary.items(): assert_equal( @@ -6603,6 +6819,43 @@ def validate(root: Path) -> None: iwooos_projection["summary"][key], expected, ) + expected_ai_provider_owner_response_projection_summary = { + "ai_provider_owner_response_acceptance_candidate_count": 8, + "ai_provider_owner_response_acceptance_write_capable_candidate_count": 5, + "ai_provider_owner_response_acceptance_paid_provider_related_candidate_count": 5, + "ai_provider_owner_response_acceptance_data_egress_candidate_count": 6, + "ai_provider_owner_response_acceptance_live_evidence_required_candidate_count": 6, + "ai_provider_owner_response_acceptance_acceptance_field_count": 37, + "ai_provider_owner_response_acceptance_required_owner_field_count": 24, + "ai_provider_owner_response_acceptance_reviewer_check_count": 24, + "ai_provider_owner_response_acceptance_outcome_lane_count": 10, + "ai_provider_owner_response_acceptance_blocked_action_count": 38, + "ai_provider_owner_response_acceptance_owner_response_received_count": 0, + "ai_provider_owner_response_acceptance_owner_response_accepted_count": 0, + "ai_provider_owner_response_acceptance_dry_run_result_accepted_count": 0, + "ai_provider_owner_response_acceptance_benchmark_result_accepted_count": 0, + "ai_provider_owner_response_acceptance_cost_review_accepted_count": 0, + "ai_provider_owner_response_acceptance_privacy_review_accepted_count": 0, + "ai_provider_owner_response_acceptance_fallback_order_accepted_count": 0, + "ai_provider_owner_response_acceptance_prompt_redaction_accepted_count": 0, + "ai_provider_owner_response_acceptance_secret_handling_accepted_count": 0, + "ai_provider_owner_response_acceptance_quality_gate_accepted_count": 0, + "ai_provider_owner_response_acceptance_rollback_owner_accepted_count": 0, + "ai_provider_owner_response_acceptance_provider_switch_authorized_count": 0, + "ai_provider_owner_response_acceptance_external_provider_call_authorized_count": 0, + "ai_provider_owner_response_acceptance_paid_provider_call_authorized_count": 0, + "ai_provider_owner_response_acceptance_prompt_send_authorized_count": 0, + "ai_provider_owner_response_acceptance_live_endpoint_probe_authorized_count": 0, + "ai_provider_owner_response_acceptance_secret_value_collection_allowed_count": 0, + "ai_provider_owner_response_acceptance_runtime_gate_count": 0, + "ai_provider_owner_response_acceptance_coverage_percent_after_acceptance": 64, + } + for key, expected in expected_ai_provider_owner_response_projection_summary.items(): + assert_equal( + f"iwooos_projection.summary.{key}", + iwooos_projection["summary"][key], + expected, + ) expected_host_service_projection_summary = { "host_service_config_inventory_first_layer": True, "host_service_config_inventory_surface_count": 9, @@ -16507,15 +16760,15 @@ def validate(root: Path) -> None: iwooos_projection_page, "{ key: 'dockerSystemd', rank: 'P1-1', value: '62%'", ) - assert_text_contains( - "iwooos_page.high_value_config_control_coverage_ai_provider_percent", - iwooos_projection_page, - "{ key: 'aiProvider', rank: 'P1-2', value: '60%'", - ) assert_text_contains( "iwooos_page.high_value_config_control_coverage_ssh_network_percent", iwooos_projection_page, - "{ key: 'sshNetwork', rank: 'P1-3', value: '62%'", + "{ key: 'sshNetwork', rank: 'P1-2', value: '62%'", + ) + assert_text_contains( + "iwooos_page.high_value_config_control_coverage_ai_provider_percent", + iwooos_projection_page, + "{ key: 'aiProvider', rank: 'P1-3', value: '64%'", ) assert_text_contains( "iwooos_page.high_value_config_control_coverage_k8s_gitops_percent", @@ -16550,6 +16803,24 @@ def validate(root: Path) -> None: "secret_metadata_coverage_percent=68", "gitea_workflow_runner_source_control_coverage_percent=72", "public_admin_api_runtime_config_coverage_percent=66", + "ai_provider_model_routing_coverage_percent=64", + "ai_provider_owner_response_acceptance_candidate_count=8", + "ai_provider_owner_response_acceptance_write_capable_candidate_count=5", + "ai_provider_owner_response_acceptance_required_owner_field_count=24", + "ai_provider_owner_response_acceptance_reviewer_check_count=24", + "ai_provider_owner_response_acceptance_outcome_lane_count=10", + "ai_provider_owner_response_acceptance_blocked_action_count=38", + "ai_provider_owner_response_acceptance_owner_response_received_count=0", + "ai_provider_owner_response_acceptance_owner_response_accepted_count=0", + "ai_provider_owner_response_acceptance_dry_run_result_accepted_count=0", + "ai_provider_owner_response_acceptance_benchmark_result_accepted_count=0", + "ai_provider_owner_response_acceptance_cost_review_accepted_count=0", + "ai_provider_owner_response_acceptance_privacy_review_accepted_count=0", + "ai_provider_owner_response_acceptance_provider_switch_authorized_count=0", + "ai_provider_owner_response_acceptance_external_provider_call_authorized_count=0", + "ai_provider_owner_response_acceptance_paid_provider_call_authorized_count=0", + "ai_provider_owner_response_acceptance_prompt_send_authorized_count=0", + "ai_provider_owner_response_acceptance_runtime_gate_count=0", "public_frontend_sensitive_surface_guard_file_count=225", "public_frontend_sensitive_surface_guard_forbidden_pattern_count=12", "public_frontend_sensitive_surface_guard_violation_count=0", @@ -17125,7 +17396,7 @@ def validate(root: Path) -> None: list(web_messages_en["iwooos"]["highValueConfigControlCoverage"]["summary"].keys()), key, ) - for key in ["dockerSystemd", "sshNetwork", "backupRestore", "monitoring"]: + for key in ["dockerSystemd", "sshNetwork", "aiProvider", "k8sGitops"]: assert_contains( "web_messages.zh-TW.iwooos.highValueConfigControlCoverage.items", list(web_messages_zh["iwooos"]["highValueConfigControlCoverage"]["items"].keys()), @@ -17136,6 +17407,16 @@ def validate(root: Path) -> None: list(web_messages_en["iwooos"]["highValueConfigControlCoverage"]["items"].keys()), key, ) + assert_text_contains( + "web_messages.zh-TW.iwooos.highValueConfigControlCoverage.items.aiProvider.body", + web_messages_zh["iwooos"]["highValueConfigControlCoverage"]["items"]["aiProvider"]["body"], + "8 個候選、24 個審查檢查項、10 條結果分流、38 類禁止動作", + ) + assert_text_contains( + "web_messages.en.iwooos.highValueConfigControlCoverage.items.aiProvider.body", + web_messages_en["iwooos"]["highValueConfigControlCoverage"]["items"]["aiProvider"]["body"], + "8 個候選、24 個審查檢查項、10 條結果分流、38 類禁止動作", + ) assert_text_contains( "web_messages.zh-TW.iwooos.highValueConfigControlCoverage.items.sshNetwork.body", web_messages_zh["iwooos"]["highValueConfigControlCoverage"]["items"]["sshNetwork"]["body"],