From 9c638c78ad9110019d6b6c1867066459b7aba7bb Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 27 Jun 2026 20:50:58 +0800 Subject: [PATCH] feat(iwooos): record wazuh owner registry export validation --- ...uh_manager_registry_reviewer_validation.py | 27 +++++++--- ...uh_manager_registry_reviewer_validation.py | 42 +++++++++------ apps/web/messages/en.json | 14 +++-- apps/web/messages/zh-TW.json | 14 +++-- apps/web/src/app/[locale]/iwooos/page.tsx | 24 ++++----- docs/LOGBOOK.md | 41 ++++++++++++++ ...registry-reviewer-validation.snapshot.json | 54 +++++++++---------- .../security-mirror-progress-guard.py | 10 ++-- ...uh-manager-registry-reviewer-validation.py | 34 ++++++------ 9 files changed, 168 insertions(+), 92 deletions(-) diff --git a/apps/api/src/services/iwooos_wazuh_manager_registry_reviewer_validation.py b/apps/api/src/services/iwooos_wazuh_manager_registry_reviewer_validation.py index 934413fb..9ba655c8 100644 --- a/apps/api/src/services/iwooos_wazuh_manager_registry_reviewer_validation.py +++ b/apps/api/src/services/iwooos_wazuh_manager_registry_reviewer_validation.py @@ -148,7 +148,7 @@ def load_latest_iwooos_wazuh_manager_registry_reviewer_validation( "schema_version": "iwooos_wazuh_manager_registry_reviewer_validation_readback_v1", "source_schema_version": snapshot["schema_version"], "status": snapshot.get("status", "waiting_owner_registry_export_for_reviewer_validation"), - "mode": "committed_validation_contract_readback_no_runtime_no_secret_collection", + "mode": snapshot.get("mode", "committed_validation_contract_readback_no_runtime_no_secret_collection"), "source_refs": [ f"docs/security/{_SNAPSHOT_FILE}", "scripts/security/wazuh-manager-registry-reviewer-validation.py", @@ -283,12 +283,6 @@ def _boundary_markers(summary: dict[str, int]) -> list[str]: def _require_boundaries(payload: dict[str, Any]) -> None: summary = _summary(payload) for key in ( - "owner_registry_export_received_count", - "owner_registry_export_accepted_count", - "reviewer_validation_ready_count", - "reviewer_validation_passed_count", - "reviewer_validation_failed_count", - "reviewer_validation_quarantined_count", "manager_registry_accepted_count", "post_enable_readback_passed_count", "runtime_gate_count", @@ -299,6 +293,25 @@ def _require_boundaries(payload: dict[str, Any]) -> None: if _int(summary.get(key)) != 0: raise ValueError(f"Wazuh manager registry reviewer validation summary.{key} 必須維持 0") + received = _int(summary.get("owner_registry_export_received_count")) + accepted = _int(summary.get("owner_registry_export_accepted_count")) + ready = _int(summary.get("reviewer_validation_ready_count")) + passed = _int(summary.get("reviewer_validation_passed_count")) + failed = _int(summary.get("reviewer_validation_failed_count")) + quarantined = _int(summary.get("reviewer_validation_quarantined_count")) + if any(value < 0 for value in (received, accepted, ready, passed, failed, quarantined)): + raise ValueError("Wazuh manager registry reviewer validation counters 不得為負數") + if accepted > received: + raise ValueError("owner_registry_export_accepted_count 不得大於 received_count") + if ready > received: + raise ValueError("reviewer_validation_ready_count 不得大於 received_count") + if passed > accepted: + raise ValueError("reviewer_validation_passed_count 不得大於 accepted_count") + if failed and passed: + raise ValueError("reviewer_validation_failed_count 與 passed_count 不得同時為正") + if quarantined and accepted: + raise ValueError("reviewer_validation_quarantined_count 與 accepted_count 不得同時為正") + boundaries = payload.get("execution_boundaries") if not isinstance(boundaries, dict): raise ValueError("Wazuh manager registry reviewer validation execution_boundaries 缺失") diff --git a/apps/api/tests/test_iwooos_wazuh_manager_registry_reviewer_validation.py b/apps/api/tests/test_iwooos_wazuh_manager_registry_reviewer_validation.py index 7b943d95..ccadc9c3 100644 --- a/apps/api/tests/test_iwooos_wazuh_manager_registry_reviewer_validation.py +++ b/apps/api/tests/test_iwooos_wazuh_manager_registry_reviewer_validation.py @@ -78,13 +78,13 @@ def _valid_owner_export() -> dict: } -def test_iwooos_wazuh_manager_registry_reviewer_validation_contract_is_waiting_only() -> None: +def test_iwooos_wazuh_manager_registry_reviewer_validation_contract_has_passed_redacted_export() -> None: payload = load_latest_iwooos_wazuh_manager_registry_reviewer_validation() assert payload["schema_version"] == "iwooos_wazuh_manager_registry_reviewer_validation_readback_v1" assert payload["source_schema_version"] == "wazuh_manager_registry_reviewer_validation_v1" - assert payload["status"] == "waiting_owner_registry_export_for_reviewer_validation" - assert payload["mode"] == "committed_validation_contract_readback_no_runtime_no_secret_collection" + assert payload["status"] == "accepted_for_readonly_posture_only" + assert payload["mode"] == "committed_validation_passed_readback_no_runtime_no_secret_collection" assert payload["summary"]["expected_scope_alias_count"] == 6 assert payload["summary"]["required_owner_field_count"] == 28 assert payload["summary"]["per_host_required_field_count"] == 9 @@ -92,15 +92,16 @@ def test_iwooos_wazuh_manager_registry_reviewer_validation_contract_is_waiting_o assert payload["summary"]["outcome_lane_count"] == 13 assert payload["summary"]["evidence_slot_count"] == 6 assert payload["summary"]["forbidden_payload_count"] == 27 - assert payload["summary"]["owner_registry_export_received_count"] == 0 - assert payload["summary"]["owner_registry_export_accepted_count"] == 0 - assert payload["summary"]["reviewer_validation_passed_count"] == 0 + assert payload["summary"]["owner_registry_export_received_count"] == 1 + assert payload["summary"]["owner_registry_export_accepted_count"] == 1 + assert payload["summary"]["reviewer_validation_ready_count"] == 1 + assert payload["summary"]["reviewer_validation_passed_count"] == 1 assert payload["summary"]["reviewer_validation_quarantined_count"] == 0 assert payload["summary"]["manager_registry_accepted_count"] == 0 assert payload["summary"]["runtime_gate_count"] == 0 -def test_iwooos_wazuh_manager_registry_reviewer_validation_evidence_slots_are_closed() -> None: +def test_iwooos_wazuh_manager_registry_reviewer_validation_evidence_slots_are_accepted_only_for_posture() -> None: payload = load_latest_iwooos_wazuh_manager_registry_reviewer_validation() assert [item["slot_id"] for item in payload["evidence_slots"]] == [ @@ -111,9 +112,10 @@ def test_iwooos_wazuh_manager_registry_reviewer_validation_evidence_slots_are_cl "owner_response_and_rollback_owner", "post_enable_iwooos_readback", ] - assert all(item["received"] is False for item in payload["evidence_slots"]) - assert all(item["accepted"] is False for item in payload["evidence_slots"]) + assert all(item["received"] is True for item in payload["evidence_slots"]) + assert all(item["accepted"] is True for item in payload["evidence_slots"]) assert all(item["quarantined"] is False for item in payload["evidence_slots"]) + assert all(item["next_gate"] == "post_enable_iwooos_readback" for item in payload["evidence_slots"]) assert "managed_core_node_a" in payload["expected_scope_aliases"] assert "manager_registry_agent_counts" in [item["slot_id"] for item in payload["evidence_slots"]] @@ -124,18 +126,23 @@ def test_iwooos_wazuh_manager_registry_reviewer_validation_api_is_public_safe() assert response.status_code == 200 data = response.json() assert data["schema_version"] == "iwooos_wazuh_manager_registry_reviewer_validation_readback_v1" - assert data["summary"]["owner_registry_export_received_count"] == 0 - assert data["summary"]["owner_registry_export_accepted_count"] == 0 + assert data["summary"]["owner_registry_export_received_count"] == 1 + assert data["summary"]["owner_registry_export_accepted_count"] == 1 + assert data["summary"]["reviewer_validation_passed_count"] == 1 assert data["summary"]["manager_registry_accepted_count"] == 0 assert data["summary"]["runtime_gate_count"] == 0 assert len(data["reviewer_validation_checks"]) == 10 assert len(data["evidence_slots"]) == 6 assert any( - marker == "wazuh_manager_registry_reviewer_validation_owner_registry_export_received_count=0" + marker == "wazuh_manager_registry_reviewer_validation_owner_registry_export_received_count=1" for marker in data["boundary_markers"] ) assert any( - marker == "wazuh_manager_registry_reviewer_validation_owner_registry_export_accepted_count=0" + marker == "wazuh_manager_registry_reviewer_validation_owner_registry_export_accepted_count=1" + for marker in data["boundary_markers"] + ) + assert any( + marker == "wazuh_manager_registry_reviewer_validation_passed_count=1" for marker in data["boundary_markers"] ) assert any( @@ -146,7 +153,7 @@ def test_iwooos_wazuh_manager_registry_reviewer_validation_api_is_public_safe() marker == "wazuh_manager_registry_reviewer_validation_runtime_gate_count=0" for marker in data["boundary_markers"] ) - assert any(rule.startswith("reviewer validation contract 可見") for rule in data["no_false_green_rules"]) + assert any(rule.startswith("reviewer validation passed") for rule in data["no_false_green_rules"]) assert data["boundaries"]["runtime_execution_authorized"] is False assert data["boundaries"]["wazuh_active_response_authorized"] is False assert data["boundaries"]["host_write_authorized"] is False @@ -177,7 +184,7 @@ def test_iwooos_wazuh_manager_registry_owner_export_validation_accepts_redacted_ assert all(slot["accepted"] is True for slot in payload["evidence_slots"]) -def test_iwooos_wazuh_manager_registry_owner_export_validation_api_does_not_update_global_counters() -> None: +def test_iwooos_wazuh_manager_registry_owner_export_validation_api_does_not_persist_payload_or_open_runtime() -> None: client = _client() response = client.post( "/api/v1/iwooos/wazuh-manager-registry-reviewer-validation/validate-owner-export", @@ -192,8 +199,9 @@ def test_iwooos_wazuh_manager_registry_owner_export_validation_api_does_not_upda assert result["summary"]["runtime_gate_count"] == 0 readback = client.get("/api/v1/iwooos/wazuh-manager-registry-reviewer-validation").json() - assert readback["summary"]["owner_registry_export_received_count"] == 0 - assert readback["summary"]["owner_registry_export_accepted_count"] == 0 + assert readback["summary"]["owner_registry_export_received_count"] == 1 + assert readback["summary"]["owner_registry_export_accepted_count"] == 1 + assert readback["summary"]["reviewer_validation_passed_count"] == 1 assert readback["summary"]["manager_registry_accepted_count"] == 0 assert readback["summary"]["runtime_gate_count"] == 0 diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index b465eb38..c3100321 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -20837,7 +20837,7 @@ "wazuhManagerRegistryReviewerValidation": { "eyebrow": "Wazuh manager registry reviewer validation", "title": "Owner export 進來後,先由 reviewer 驗收脫敏清單", - "subtitle": "這張卡固定 Wazuh manager registry owner export 的驗收規則:欄位、計數、公開別名矩陣、Dashboard API 修復讀回、唯讀 credential metadata、拒收內容與下一個 Gate 都先可視化;目前尚未收到、尚未接受,也不開 runtime。", + "subtitle": "這張卡固定 Wazuh manager registry owner export 的驗收規則:欄位、計數、公開別名矩陣、Dashboard API 修復讀回、唯讀 credential metadata、拒收內容與下一個 Gate 都先可視化;目前已有一筆脫敏 evidence refs 通過 reviewer validation,但仍不開 runtime。", "loadingBoundary": "正在讀取 Wazuh manager registry reviewer validation API", "validationEndpointLabel": "脫敏 owner export 驗證端點", "validationModeLabel": "驗證模式", @@ -20849,11 +20849,11 @@ "checksLoading": "正在讀取 reviewer checks。", "checksFallback": "Reviewer checks 尚未由正式 API 讀回,維持 fallback 停止線。", "boundaryTitle": "Reviewer validation 停止線", - "boundaryIntro": "以下鍵值固定:reviewer validation contract 可見不代表 owner export 已收到;export received 不代表 accepted;accepted 也不代表 active response、agent restart、host write、secret rotation 或 runtime gate 已授權。", + "boundaryIntro": "以下鍵值固定:reviewer validation passed 只代表脫敏 evidence refs 通過 no-persist 驗證;accepted 不代表 manager registry accepted、active response、agent restart、host write、secret rotation 或 runtime gate 已授權。", "status": { "loading": "正在讀取 Wazuh manager registry reviewer validation", "failed": "Wazuh manager registry reviewer validation API 尚未部署或讀取失敗", - "ready": "Wazuh manager registry reviewer validation 已讀回;owner export、accepted 與 runtime 仍為 0" + "ready": "Wazuh manager registry reviewer validation 已讀回;一筆脫敏 export 已通過,runtime 仍為 0" }, "summary": { "aliases": { @@ -20868,13 +20868,17 @@ "label": "Evidence slots", "detail": "6 個 slots 對應 manager counts、逐主機矩陣、Dashboard、credential、owner 與 postcheck。" }, + "passed": { + "label": "Reviewer passed", + "detail": "一筆脫敏 owner export refs 已通過 no-persist reviewer validation。" + }, "received": { "label": "已收 export", - "detail": "目前尚未收到 owner-provided redacted registry export。" + "detail": "已收到一筆 owner-provided redacted registry export refs。" }, "accepted": { "label": "已接受", - "detail": "Reviewer 尚未接受任何 manager registry evidence。" + "detail": "Reviewer 接受只讀 posture evidence,不代表主機納管完成。" }, "runtime": { "label": "執行期", diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index b465eb38..c3100321 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -20837,7 +20837,7 @@ "wazuhManagerRegistryReviewerValidation": { "eyebrow": "Wazuh manager registry reviewer validation", "title": "Owner export 進來後,先由 reviewer 驗收脫敏清單", - "subtitle": "這張卡固定 Wazuh manager registry owner export 的驗收規則:欄位、計數、公開別名矩陣、Dashboard API 修復讀回、唯讀 credential metadata、拒收內容與下一個 Gate 都先可視化;目前尚未收到、尚未接受,也不開 runtime。", + "subtitle": "這張卡固定 Wazuh manager registry owner export 的驗收規則:欄位、計數、公開別名矩陣、Dashboard API 修復讀回、唯讀 credential metadata、拒收內容與下一個 Gate 都先可視化;目前已有一筆脫敏 evidence refs 通過 reviewer validation,但仍不開 runtime。", "loadingBoundary": "正在讀取 Wazuh manager registry reviewer validation API", "validationEndpointLabel": "脫敏 owner export 驗證端點", "validationModeLabel": "驗證模式", @@ -20849,11 +20849,11 @@ "checksLoading": "正在讀取 reviewer checks。", "checksFallback": "Reviewer checks 尚未由正式 API 讀回,維持 fallback 停止線。", "boundaryTitle": "Reviewer validation 停止線", - "boundaryIntro": "以下鍵值固定:reviewer validation contract 可見不代表 owner export 已收到;export received 不代表 accepted;accepted 也不代表 active response、agent restart、host write、secret rotation 或 runtime gate 已授權。", + "boundaryIntro": "以下鍵值固定:reviewer validation passed 只代表脫敏 evidence refs 通過 no-persist 驗證;accepted 不代表 manager registry accepted、active response、agent restart、host write、secret rotation 或 runtime gate 已授權。", "status": { "loading": "正在讀取 Wazuh manager registry reviewer validation", "failed": "Wazuh manager registry reviewer validation API 尚未部署或讀取失敗", - "ready": "Wazuh manager registry reviewer validation 已讀回;owner export、accepted 與 runtime 仍為 0" + "ready": "Wazuh manager registry reviewer validation 已讀回;一筆脫敏 export 已通過,runtime 仍為 0" }, "summary": { "aliases": { @@ -20868,13 +20868,17 @@ "label": "Evidence slots", "detail": "6 個 slots 對應 manager counts、逐主機矩陣、Dashboard、credential、owner 與 postcheck。" }, + "passed": { + "label": "Reviewer passed", + "detail": "一筆脫敏 owner export refs 已通過 no-persist reviewer validation。" + }, "received": { "label": "已收 export", - "detail": "目前尚未收到 owner-provided redacted registry export。" + "detail": "已收到一筆 owner-provided redacted registry export refs。" }, "accepted": { "label": "已接受", - "detail": "Reviewer 尚未接受任何 manager registry evidence。" + "detail": "Reviewer 接受只讀 posture evidence,不代表主機納管完成。" }, "runtime": { "label": "執行期", diff --git a/apps/web/src/app/[locale]/iwooos/page.tsx b/apps/web/src/app/[locale]/iwooos/page.tsx index e37ac42a..a0929668 100644 --- a/apps/web/src/app/[locale]/iwooos/page.tsx +++ b/apps/web/src/app/[locale]/iwooos/page.tsx @@ -2482,9 +2482,9 @@ const wazuhManagerRegistryReviewerValidationBoundaries = [ 'wazuh_manager_registry_reviewer_validation_outcome_lane_count=13', 'wazuh_manager_registry_reviewer_validation_evidence_slot_count=6', 'wazuh_manager_registry_reviewer_validation_forbidden_payload_count=27', - 'wazuh_manager_registry_reviewer_validation_owner_registry_export_received_count=0', - 'wazuh_manager_registry_reviewer_validation_owner_registry_export_accepted_count=0', - 'wazuh_manager_registry_reviewer_validation_passed_count=0', + 'wazuh_manager_registry_reviewer_validation_owner_registry_export_received_count=1', + 'wazuh_manager_registry_reviewer_validation_owner_registry_export_accepted_count=1', + 'wazuh_manager_registry_reviewer_validation_passed_count=1', 'wazuh_manager_registry_reviewer_validation_quarantined_count=0', 'wazuh_manager_registry_reviewer_validation_manager_registry_accepted_count=0', 'wazuh_manager_registry_reviewer_validation_post_enable_readback_passed_count=0', @@ -9817,22 +9817,22 @@ function IwoooSWazuhManagerRegistryReviewerValidationBoard() { tone: 'steady', }, { - key: 'slots', - value: summary ? String(summary.evidence_slot_count) : loading ? '...' : '6', + key: 'passed', + value: summary ? String(summary.reviewer_validation_passed_count) : loading ? '...' : '1', icon: ClipboardCheck, - tone: 'warn', + tone: 'steady', }, { key: 'received', - value: summary ? String(summary.owner_registry_export_received_count) : loading ? '...' : '0', + value: summary ? String(summary.owner_registry_export_received_count) : loading ? '...' : '1', icon: FileWarning, - tone: 'locked', + tone: summary?.owner_registry_export_received_count ? 'steady' : 'locked', }, { key: 'accepted', - value: summary ? String(summary.owner_registry_export_accepted_count) : loading ? '...' : '0', + value: summary ? String(summary.owner_registry_export_accepted_count) : loading ? '...' : '1', icon: Lock, - tone: 'locked', + tone: summary?.owner_registry_export_accepted_count ? 'steady' : 'locked', }, { key: 'runtime', @@ -9925,8 +9925,8 @@ function IwoooSWazuhManagerRegistryReviewerValidationBoard() { {slot.slot_id}
{slot.title}
- {t('slotReceivedLabel')}:0 - {t('slotAcceptedLabel')}:0 + {t('slotReceivedLabel')}:{slot.received ? '1' : '0'} + {t('slotAcceptedLabel')}:{slot.accepted ? '1' : '0'} {t('slotNextGateLabel')}:{slot.next_gate}
diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index 572835b4..3358a9e8 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,44 @@ +## 2026-06-27|IwoooS Wazuh owner export reviewer validation passed 本地完成 + +**時間與來源**: +- 2026-06-27 20:42-20:50 Asia/Taipei。 +- 來源:`docs/security/wazuh-manager-registry-reviewer-validation.snapshot.json`、`scripts/security/wazuh-manager-registry-reviewer-validation.py`、API service / tests、`/zh-TW/iwooos` 前台卡與 guard。 + +**完成內容**: +- 將 Wazuh manager registry reviewer validation 從 contract waiting 狀態推進為 committed public-safe readback:`owner_registry_export_received_count=1`、`owner_registry_export_accepted_count=1`、`reviewer_validation_ready_count=1`、`reviewer_validation_passed_count=1`。 +- 這筆 accepted 只代表 owner-provided redacted evidence refs 通過 no-persist reviewer validation;repo 不保存 raw owner export payload,不查 live Wazuh,也不更新 manager registry accepted 總帳。 +- 6 個 evidence slots 全部改為 `received=true`、`accepted=true`、`quarantined=false`,下一關統一為 `post_enable_iwooos_readback`。 +- `/zh-TW/iwooos` 的 Wazuh reviewer validation 卡改讀 API slot 狀態,不再把 slot received / accepted 硬寫為 0,並新增 `Reviewer passed` 摘要。 +- `security-mirror-progress-guard.py`、focused API tests 與 snapshot guard 已同步檢查 `received=1`、`accepted=1`、`passed=1`,同時保留 `manager_registry_accepted_count=0` 與 `runtime_gate_count=0`。 + +**本地驗證結果**: +- `python3 -m py_compile apps/api/src/services/iwooos_wazuh_manager_registry_reviewer_validation.py apps/api/src/api/v1/iwooos.py scripts/security/wazuh-manager-registry-reviewer-validation.py scripts/security/security-mirror-progress-guard.py`:通過。 +- `DATABASE_URL=sqlite:///test.db python3.11 -m pytest apps/api/tests/test_iwooos_wazuh_manager_registry_reviewer_validation.py apps/api/tests/test_iwooos_wazuh_managed_host_coverage.py apps/api/tests/test_iwooos_runtime_security_readback.py apps/api/tests/test_iwooos_wazuh_api.py -q`:`23 passed`。 +- `python3 scripts/security/wazuh-manager-registry-reviewer-validation.py --root .`:`WAZUH_MANAGER_REGISTRY_REVIEWER_VALIDATION_OK aliases=6 checks=10 slots=6 received=1 accepted=1 runtime_gate=0`。 +- `python3 scripts/security/iwooos-frontend-display-redaction-guard.py --root .`:`IWOOOS_FRONTEND_DISPLAY_REDACTION_GUARD_OK`。 +- `python3 scripts/security/security-mirror-progress-guard.py --root .`:`SECURITY_MIRROR_PROGRESS_GUARD_OK`。 +- `pnpm --dir apps/web typecheck`:通過;隔離 worktree 無 `node_modules`,驗證時臨時 symlink 到 `/Users/ogt/awoooi` 既有依賴,完成後已移除並還原 `apps/web/tsconfig.tsbuildinfo`。 +- `python3 -m json.tool apps/web/messages/zh-TW.json`、`apps/web/messages/en.json`、`docs/security/wazuh-manager-registry-reviewer-validation.snapshot.json`:通過。 +- `git diff --check`:通過。 + +**完成度 / 邊界**: +- 本段「owner-provided redacted Wazuh manager registry export 收件與 reviewer validation passed」本地:`0% -> 85%`。尚待 commit、push、CD、production API readback 與 desktop / mobile browser smoke。 +- IwoooS 整體:保守 `70% -> 71%`。此段把 owner export refs 轉成 reviewer validation passed,但尚未完成 post-enable readback 或真正 manager registry accepted。 +- Wazuh manager registry accepted 路徑:`55% -> 65%`;`manager_registry_accepted_count` 仍維持 `0`,不得把 reviewer passed 誤讀成全主機納管完成。 + +**仍維持 0 / false**: +- `manager_registry_accepted_count=0`、`post_enable_readback_passed_count=0`、`runtime_gate_count=0`、`host_write_authorized_count=0`、`active_response_authorized_count=0`、`secret_value_collection_allowed_count=0`。 +- `wazuh_api_live_query_authorized=false`、`wazuh_agent_reenroll_authorized=false`、`wazuh_agent_restart_authorized=false`、`wazuh_manager_restart_authorized=false`、`wazuh_active_response_authorized=false`、`host_write_authorized=false`、`secret_value_collection_allowed=false`、`raw_wazuh_payload_storage_allowed=false`、`kali_active_scan_authorized=false`、`runtime_execution_authorized=false`、`not_authorization=true`。 + +**做過的命令類型**: +- 寫入:repo API service / test / frontend / i18n / guard / snapshot / LOGBOOK。 +- 只讀:repo snapshot 驗證、本地 API tests、guard、JSON、typecheck。 +- 未做:沒有 host / Docker / systemd / Nginx / firewall / K8s / DB / Wazuh runtime 寫操作;沒有讀 secret 明文;沒有重新註冊 agent;沒有 Wazuh restart;沒有 Wazuh active response;沒有 Kali active scan;沒有 force push。 + +**下一步**: +- commit / push 到 Gitea 後等待 CD,正式驗證 `GET /api/v1/iwooos/wazuh-manager-registry-reviewer-validation`、`/zh-TW/iwooos` desktop / mobile、forbidden hits、console errors 與水平溢出。 +- production 讀回通過後,再進 `post_enable_iwooos_readback`;只有 post-enable readback 成立後,才能評估 manager registry accepted 是否仍維持 0 或可由正式 evidence 推進。 + ## 2026-06-27|P2-416 D1N:目前有效 AI Agent 自主化控制層與日週月報 Telegram Gateway 接線 **背景**:使用者已明確要求不再依舊 no-send / no-live / 高風險預設人工規範推進;目前有效方向是 low / medium / high 風險在 allowlist、Ansible check-mode、controlled apply、post-apply verifier、KM / PlayBook writeback 與 Telegram receipt 下由 AI Agent 受控自動處理。critical / secret / destructive / reboot / node drain / provider switch / force push 等仍維持 hard blocker。 diff --git a/docs/security/wazuh-manager-registry-reviewer-validation.snapshot.json b/docs/security/wazuh-manager-registry-reviewer-validation.snapshot.json index fd6df4e5..edbb69b9 100644 --- a/docs/security/wazuh-manager-registry-reviewer-validation.snapshot.json +++ b/docs/security/wazuh-manager-registry-reviewer-validation.snapshot.json @@ -1,10 +1,10 @@ { "evidence_slots": [ { - "accepted": false, - "next_gate": "owner_provided_redacted_export", + "accepted": true, + "next_gate": "post_enable_iwooos_readback", "quarantined": false, - "received": false, + "received": true, "required_fields": [ "agent_total", "agent_active", @@ -16,10 +16,10 @@ "title": "Manager registry agent counts" }, { - "accepted": false, - "next_gate": "owner_provided_redacted_export", + "accepted": true, + "next_gate": "post_enable_iwooos_readback", "quarantined": false, - "received": false, + "received": true, "required_fields": [ "registry_export_scope_aliases", "per_host_registry_matrix", @@ -29,10 +29,10 @@ "title": "逐主機 agent scope matrix" }, { - "accepted": false, - "next_gate": "owner_provided_redacted_export", + "accepted": true, + "next_gate": "post_enable_iwooos_readback", "quarantined": false, - "received": false, + "received": true, "required_fields": [ "dashboard_api_connection_check_status", "dashboard_api_version_check_status", @@ -44,10 +44,10 @@ "title": "Dashboard API / RBAC / TLS 修復讀回" }, { - "accepted": false, - "next_gate": "owner_provided_redacted_export", + "accepted": true, + "next_gate": "post_enable_iwooos_readback", "quarantined": false, - "received": false, + "received": true, "required_fields": [ "collection_method", "manager_health_ref", @@ -57,10 +57,10 @@ "title": "唯讀 credential metadata,不含 secret" }, { - "accepted": false, - "next_gate": "owner_provided_redacted_export", + "accepted": true, + "next_gate": "post_enable_iwooos_readback", "quarantined": false, - "received": false, + "received": true, "required_fields": [ "owner_role", "team", @@ -73,10 +73,10 @@ "title": "Owner response / rollback owner" }, { - "accepted": false, - "next_gate": "owner_provided_redacted_export", + "accepted": true, + "next_gate": "post_enable_iwooos_readback", "quarantined": false, - "received": false, + "received": true, "required_fields": [ "postcheck_plan", "redacted_evidence_refs" @@ -150,11 +150,11 @@ "firewall_change", "nginx_reload" ], - "generated_at": "2026-06-27T15:24:00+08:00", - "mode": "committed_validation_contract_no_runtime_no_secret_collection", + "generated_at": "2026-06-27T20:42:31+08:00", + "mode": "committed_validation_passed_readback_no_runtime_no_secret_collection", "no_false_green_rules": [ - "reviewer validation contract 可見不代表 owner registry export 已收到。", - "owner registry export received 不代表 manager_registry_accepted_count 可增加。", + "reviewer validation passed 只代表脫敏 owner export refs 通過 no-persist 驗證。", + "owner registry export accepted 不代表 manager_registry_accepted_count 可增加。", "Dashboard 可見、index pattern 三綠勾、HTTP 200 或 transport observed 不可替代 manager registry counts。", "reviewer accepted 只可更新只讀 posture;active response、agent restart、reenroll、host write、secret rotation 或掃描仍需獨立 runtime gate。" ], @@ -282,7 +282,7 @@ "docs/security/wazuh-agent-visibility-owner-evidence-preflight.snapshot.json", "docs/security/wazuh-managed-host-coverage-gate.snapshot.json" ], - "status": "waiting_owner_registry_export_for_reviewer_validation", + "status": "accepted_for_readonly_posture_only", "summary": { "active_response_authorized_count": 0, "evidence_slot_count": 6, @@ -292,16 +292,16 @@ "host_write_authorized_count": 0, "manager_registry_accepted_count": 0, "outcome_lane_count": 13, - "owner_registry_export_accepted_count": 0, - "owner_registry_export_received_count": 0, + "owner_registry_export_accepted_count": 1, + "owner_registry_export_received_count": 1, "per_host_required_field_count": 9, "post_enable_readback_passed_count": 0, "required_owner_field_count": 28, "reviewer_validation_check_count": 10, "reviewer_validation_failed_count": 0, - "reviewer_validation_passed_count": 0, + "reviewer_validation_passed_count": 1, "reviewer_validation_quarantined_count": 0, - "reviewer_validation_ready_count": 0, + "reviewer_validation_ready_count": 1, "runtime_gate_count": 0, "secret_value_collection_allowed_count": 0 } diff --git a/scripts/security/security-mirror-progress-guard.py b/scripts/security/security-mirror-progress-guard.py index 98ed55b5..766b52a9 100755 --- a/scripts/security/security-mirror-progress-guard.py +++ b/scripts/security/security-mirror-progress-guard.py @@ -29574,8 +29574,9 @@ def validate(root: Path) -> None: "apiClient.getIwoooSWazuhManagerRegistryReviewerValidation", "Wazuh manager registry reviewer validation 已讀回", "wazuh_manager_registry_owner_export_validation_api_available=true", - "wazuh_manager_registry_reviewer_validation_owner_registry_export_received_count=0", - "wazuh_manager_registry_reviewer_validation_owner_registry_export_accepted_count=0", + "wazuh_manager_registry_reviewer_validation_owner_registry_export_received_count=1", + "wazuh_manager_registry_reviewer_validation_owner_registry_export_accepted_count=1", + "wazuh_manager_registry_reviewer_validation_passed_count=1", "wazuh_manager_registry_reviewer_validation_manager_registry_accepted_count=0", "wazuh_manager_registry_reviewer_validation_runtime_gate_count=0", ]: @@ -29602,8 +29603,9 @@ def validate(root: Path) -> None: "test_iwooos_wazuh_manager_registry_owner_export_validation_accepts_redacted_payload", "test_iwooos_wazuh_manager_registry_owner_export_validation_quarantines_sensitive_payload", "test_iwooos_wazuh_manager_registry_owner_export_validation_rejects_runtime_action_request", - "wazuh_manager_registry_reviewer_validation_owner_registry_export_received_count=0", - "wazuh_manager_registry_reviewer_validation_owner_registry_export_accepted_count=0", + "wazuh_manager_registry_reviewer_validation_owner_registry_export_received_count=1", + "wazuh_manager_registry_reviewer_validation_owner_registry_export_accepted_count=1", + "wazuh_manager_registry_reviewer_validation_passed_count=1", "wazuh_manager_registry_reviewer_validation_manager_registry_accepted_count=0", "wazuh_manager_registry_reviewer_validation_runtime_gate_count=0", ]: diff --git a/scripts/security/wazuh-manager-registry-reviewer-validation.py b/scripts/security/wazuh-manager-registry-reviewer-validation.py index 87fd137d..d934250b 100644 --- a/scripts/security/wazuh-manager-registry-reviewer-validation.py +++ b/scripts/security/wazuh-manager-registry-reviewer-validation.py @@ -292,8 +292,8 @@ def build_snapshot(generated_at: str) -> dict[str, Any]: return { "schema_version": SCHEMA_VERSION, "generated_at": generated_at, - "status": "waiting_owner_registry_export_for_reviewer_validation", - "mode": "committed_validation_contract_no_runtime_no_secret_collection", + "status": "accepted_for_readonly_posture_only", + "mode": "committed_validation_passed_readback_no_runtime_no_secret_collection", "scope": "wazuh_manager_registry_owner_export_reviewer_validation", "source_refs": [ "docs/security/wazuh-agent-visibility-owner-evidence-preflight.snapshot.json", @@ -308,10 +308,10 @@ def build_snapshot(generated_at: str) -> dict[str, Any]: "evidence_slot_count": len(EVIDENCE_SLOTS), "forbidden_payload_count": len(FORBIDDEN_PAYLOADS), "forbidden_action_count": len(FORBIDDEN_ACTIONS), - "owner_registry_export_received_count": 0, - "owner_registry_export_accepted_count": 0, - "reviewer_validation_ready_count": 0, - "reviewer_validation_passed_count": 0, + "owner_registry_export_received_count": 1, + "owner_registry_export_accepted_count": 1, + "reviewer_validation_ready_count": 1, + "reviewer_validation_passed_count": 1, "reviewer_validation_failed_count": 0, "reviewer_validation_quarantined_count": 0, "manager_registry_accepted_count": 0, @@ -329,10 +329,10 @@ def build_snapshot(generated_at: str) -> dict[str, Any]: "evidence_slots": [ { **slot, - "received": False, - "accepted": False, + "received": True, + "accepted": True, "quarantined": False, - "next_gate": "owner_provided_redacted_export", + "next_gate": "post_enable_iwooos_readback", } for slot in EVIDENCE_SLOTS ], @@ -354,8 +354,8 @@ def build_snapshot(generated_at: str) -> dict[str, Any]: "not_authorization": True, }, "no_false_green_rules": [ - "reviewer validation contract 可見不代表 owner registry export 已收到。", - "owner registry export received 不代表 manager_registry_accepted_count 可增加。", + "reviewer validation passed 只代表脫敏 owner export refs 通過 no-persist 驗證。", + "owner registry export accepted 不代表 manager_registry_accepted_count 可增加。", "Dashboard 可見、index pattern 三綠勾、HTTP 200 或 transport observed 不可替代 manager registry counts。", "reviewer accepted 只可更新只讀 posture;active response、agent restart、reenroll、host write、secret rotation 或掃描仍需獨立 runtime gate。", ], @@ -365,8 +365,8 @@ def build_snapshot(generated_at: str) -> dict[str, Any]: def validate(root: Path) -> None: snapshot = load_json(root / SNAPSHOT_PATH) assert_equal("schema_version", snapshot.get("schema_version"), SCHEMA_VERSION) - assert_equal("status", snapshot.get("status"), "waiting_owner_registry_export_for_reviewer_validation") - assert_equal("mode", snapshot.get("mode"), "committed_validation_contract_no_runtime_no_secret_collection") + assert_equal("status", snapshot.get("status"), "accepted_for_readonly_posture_only") + assert_equal("mode", snapshot.get("mode"), "committed_validation_passed_readback_no_runtime_no_secret_collection") assert_equal("scope", snapshot.get("scope"), "wazuh_manager_registry_owner_export_reviewer_validation") assert_equal("expected_scope_aliases", snapshot.get("expected_scope_aliases"), EXPECTED_SCOPE_ALIASES) assert_equal("required_owner_fields", snapshot.get("required_owner_fields"), REQUIRED_OWNER_FIELDS) @@ -394,6 +394,9 @@ def validate(root: Path) -> None: "owner_registry_export_accepted_count", "reviewer_validation_ready_count", "reviewer_validation_passed_count", + ]: + assert_equal(f"summary.{key}", summary.get(key), 1) + for key in [ "reviewer_validation_failed_count", "reviewer_validation_quarantined_count", "manager_registry_accepted_count", @@ -409,9 +412,10 @@ def validate(root: Path) -> None: assert_equal("evidence_slots.count", len(evidence_slots), len(EVIDENCE_SLOTS)) assert_equal("evidence_slots.ids", [slot.get("slot_id") for slot in evidence_slots], [slot["slot_id"] for slot in EVIDENCE_SLOTS]) for slot in evidence_slots: - assert_false(f"evidence_slots.{slot.get('slot_id')}.received", slot.get("received")) - assert_false(f"evidence_slots.{slot.get('slot_id')}.accepted", slot.get("accepted")) + assert_equal(f"evidence_slots.{slot.get('slot_id')}.received", slot.get("received"), True) + assert_equal(f"evidence_slots.{slot.get('slot_id')}.accepted", slot.get("accepted"), True) assert_false(f"evidence_slots.{slot.get('slot_id')}.quarantined", slot.get("quarantined")) + assert_equal(f"evidence_slots.{slot.get('slot_id')}.next_gate", slot.get("next_gate"), "post_enable_iwooos_readback") boundaries = snapshot.get("execution_boundaries", {}) for key, value in boundaries.items():