feat(iwooos): commit wazuh manager registry accepted readback [skip ci]

This commit is contained in:
Your Name
2026-06-28 08:44:53 +08:00
parent b170383463
commit d4c2cc6e20
14 changed files with 191 additions and 128 deletions

View File

@@ -183,10 +183,25 @@ def load_latest_iwooos_runtime_security_readback(
"lanes": [
_lane(
"wazuh_registry",
"blocked_waiting_manager_registry",
0,
"locked",
"管理器清單交叉驗收",
(
"manager_registry_readback_accepted_runtime_gate_closed"
if _int(wazuh_summary.get("manager_registry_accepted_count"))
>= _int(wazuh_summary.get("expected_host_scope_count"))
else "blocked_waiting_manager_registry"
),
(
35
if _int(wazuh_summary.get("manager_registry_accepted_count"))
>= _int(wazuh_summary.get("expected_host_scope_count"))
else 0
),
(
"steady"
if _int(wazuh_summary.get("manager_registry_accepted_count"))
>= _int(wazuh_summary.get("expected_host_scope_count"))
else "locked"
),
"管理器清單交叉驗收已讀回runtime gate 仍關閉",
{
"expected_hosts": wazuh_summary.get("expected_host_scope_count", 0),
"transport_observed": wazuh_summary.get("manager_transport_established_connection_count", 0),

View File

@@ -259,13 +259,21 @@ def _build_domains(snapshots: dict[str, dict[str, Any]]) -> list[dict[str, Any]]
"domain_id": "wazuh_managed_host_coverage",
"label": "Wazuh 主機納管與 manager registry",
"priority": "P0",
"coverage_percent": 0,
"coverage_percent": 70 if _as_int(wazuh_summary.get("manager_registry_accepted_count")) else 0,
"scope_count": _as_int(wazuh_summary.get("expected_host_scope_count")),
"write_capable_count": _as_int(wazuh_summary.get("agent_reenroll_authorized_count")),
"accepted_count": _as_int(wazuh_summary.get("manager_registry_accepted_count")),
"blocked_count": _as_int(wazuh_summary.get("expected_host_scope_count")),
"status": "waiting_manager_registry_readback",
"next_gate": "manager_registry_cross_check_all_expected_hosts",
"blocked_count": max(
_as_int(wazuh_summary.get("expected_host_scope_count"))
- _as_int(wazuh_summary.get("manager_registry_accepted_count")),
0,
),
"status": (
"manager_registry_readback_accepted_runtime_gate_closed"
if _as_int(wazuh_summary.get("manager_registry_accepted_count"))
else "waiting_manager_registry_readback"
),
"next_gate": "runtime_gate_owner_review_and_postcheck",
"source_refs": ["docs/security/wazuh-managed-host-coverage-gate.snapshot.json"],
},
{
@@ -323,7 +331,10 @@ def _build_summary(snapshots: dict[str, dict[str, Any]], domains: list[dict[str,
"owner_response_received_count": 0,
"owner_response_accepted_count": 0,
"live_evidence_accepted_count": 0,
"wazuh_manager_registry_accepted_count": 0,
"wazuh_manager_registry_accepted_count": _summary_int(
snapshots["wazuh_hosts"],
"manager_registry_accepted_count",
),
"active_scan_authorized_count": 0,
"active_response_authorized_count": 0,
"telegram_send_authorized_count": 0,

View File

@@ -32,15 +32,16 @@ _REQUIRED_FALSE_BOUNDARIES = {
}
_STATUS_LABELS = {
"agent_active_transport_observed": "代理服務與傳輸連線已觀察,仍待管理器清單驗收",
"no_agent_transport_observed": "未觀察到代理傳輸,需確認安裝、服務與負責人決策",
"ssh_readback_blocked": "合法只讀讀回仍受阻,需 owner export 或維護窗口",
"agent_active_transport_observed": "代理服務與傳輸連線已觀察,管理器清單 evidence 已驗收",
"no_agent_transport_observed": "管理器清單 evidence 已驗收,仍需 runtime/服務狀態獨立確認",
"ssh_readback_blocked": "管理器清單 evidence 已驗收,合法只讀讀回與 runtime postcheck 仍需獨立 gate",
}
_NEXT_GATE_LABELS = {
"manager_registry_cross_check": "補管理器清單交叉驗收",
"agent_install_or_service_owner_decision": "補代理安裝狀態或服務負責人決策",
"read_only_access_or_owner_export": "補只讀 access 或脫敏 owner export",
"runtime_gate_owner_review": "進 runtime gate owner review 與 postcheck",
}
@@ -116,7 +117,7 @@ def load_latest_iwooos_wazuh_managed_host_coverage(
"no_false_green_rules": [
"Wazuh Dashboard 可見不等於 manager registry 已恢復",
"transport 連線、agent service active 或 HTTP 200 不可替代逐主機 registry matrix",
"manager_registry_accepted_count 維持 0 時不得宣稱所有主機已納管",
"manager registry accepted 只代表 committed redacted evidence 覆蓋公開別名,不代表 runtime 授權",
"重新註冊、重啟、active response、主機寫入、Nginx、firewall、Kali 掃描與機密調整都不是此讀回授權",
],
}
@@ -165,8 +166,7 @@ def _host_scope_matrix(payload: dict[str, Any]) -> list[dict[str, Any]]:
next_gate = str(raw_item.get("next_gate", ""))
if not node_id.startswith("managed_"):
raise ValueError(f"Wazuh 受管主機覆蓋 node_id 必須維持公開別名:{node_id}")
if raw_item.get("manager_registry_accepted") is not False:
raise ValueError(f"Wazuh 受管主機覆蓋 {node_id} manager_registry_accepted 必須維持 false")
manager_registry_accepted = raw_item.get("manager_registry_accepted") is True
matrix.append(
{
"node_id": node_id,
@@ -175,7 +175,7 @@ def _host_scope_matrix(payload: dict[str, Any]) -> list[dict[str, Any]]:
"readback_status_label": _STATUS_LABELS.get(readback_status, "待補只讀讀回"),
"next_gate": next_gate,
"next_gate_label": _NEXT_GATE_LABELS.get(next_gate, "待補負責人驗收"),
"manager_registry_accepted": False,
"manager_registry_accepted": manager_registry_accepted,
}
)
return matrix
@@ -227,7 +227,6 @@ def _boundary_markers(summary: dict[str, int]) -> list[str]:
def _require_boundaries(payload: dict[str, Any]) -> None:
summary = _summary(payload)
for key in (
"manager_registry_accepted_count",
"live_metadata_env_enabled_count",
"active_response_authorized_count",
"host_write_authorized_count",
@@ -238,6 +237,23 @@ def _require_boundaries(payload: dict[str, Any]) -> None:
if _int(summary.get(key)) != 0:
raise ValueError(f"Wazuh 受管主機覆蓋 summary.{key} 必須維持 0")
expected_hosts = _int(summary.get("expected_host_scope_count"))
manager_accepted = _int(summary.get("manager_registry_accepted_count"))
if manager_accepted < 0:
raise ValueError("Wazuh 受管主機覆蓋 summary.manager_registry_accepted_count 不得為負數")
if manager_accepted > expected_hosts:
raise ValueError("Wazuh 受管主機覆蓋 summary.manager_registry_accepted_count 不得大於 expected_host_scope_count")
raw_matrix = payload.get("host_scope_matrix")
if isinstance(raw_matrix, list):
matrix_accepted = sum(
1
for item in raw_matrix
if isinstance(item, dict) and item.get("manager_registry_accepted") is True
)
if matrix_accepted != manager_accepted:
raise ValueError("Wazuh 受管主機覆蓋 manager registry accepted matrix/count 不一致")
boundaries = payload.get("execution_boundaries")
if not isinstance(boundaries, dict):
raise ValueError("Wazuh 受管主機覆蓋 execution_boundaries 缺失")

View File

@@ -317,7 +317,6 @@ def _boundary_markers(summary: dict[str, int]) -> list[str]:
def _require_boundaries(payload: dict[str, Any]) -> None:
summary = _summary(payload)
for key in (
"manager_registry_accepted_count",
"runtime_gate_count",
"host_write_authorized_count",
"active_response_authorized_count",
@@ -326,6 +325,8 @@ 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")
expected_aliases = _int(summary.get("expected_scope_alias_count"))
manager_accepted = _int(summary.get("manager_registry_accepted_count"))
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"))
@@ -349,9 +350,12 @@ def _require_boundaries(payload: dict[str, Any]) -> None:
acceptance_endpoint,
acceptance_received,
acceptance_ready,
manager_accepted,
)
):
raise ValueError("Wazuh manager registry reviewer validation counters 不得為負數")
if manager_accepted > expected_aliases:
raise ValueError("manager_registry_accepted_count 不得大於 expected_scope_alias_count")
if accepted > received:
raise ValueError("owner_registry_export_accepted_count 不得大於 received_count")
if ready > received:
@@ -366,8 +370,20 @@ def _require_boundaries(payload: dict[str, Any]) -> None:
raise ValueError(
"manager_registry_acceptance_evidence_review_ready_count 不得大於 received_count"
)
if acceptance_ready:
raise ValueError("manager_registry_acceptance_evidence_review_ready_count 目前不得在全域讀回中自動上修")
if manager_accepted and not all(
value > 0
for value in (
received,
accepted,
ready,
passed,
post_enable,
acceptance_endpoint,
acceptance_received,
acceptance_ready,
)
):
raise ValueError("manager_registry_accepted_count 上修前必須先有完整 committed acceptance evidence")
if failed and passed:
raise ValueError("reviewer_validation_failed_count 與 passed_count 不得同時為正")
if quarantined and accepted:

View File

@@ -25,7 +25,7 @@ def test_iwooos_runtime_security_readback_preserves_zero_runtime_gates() -> None
assert payload["summary"]["runtime_gate_count"] == 0
assert payload["summary"]["owner_response_received_count"] == 0
assert payload["summary"]["owner_response_accepted_count"] == 0
assert payload["summary"]["wazuh_manager_registry_accepted_count"] == 0
assert payload["summary"]["wazuh_manager_registry_accepted_count"] == 6
assert payload["summary"]["wazuh_live_status"] == "not_checked_by_snapshot_loader"
assert payload["summary"]["wazuh_live_route_degraded_count"] == 1
assert payload["summary"]["wazuh_live_readonly_api_enabled_count"] == 0
@@ -74,7 +74,7 @@ def test_iwooos_runtime_security_readback_lanes_are_candidate_only() -> None:
assert all(lane["next_gate"] for lane in payload["lanes"])
assert all(lane["source_refs"] for lane in payload["lanes"])
assert any(lane["completion_percent"] > 0 for lane in payload["lanes"])
assert all(lane["lane_id"] != "wazuh_registry" or lane["completion_percent"] == 0 for lane in payload["lanes"])
assert all(lane["lane_id"] != "wazuh_registry" or lane["completion_percent"] == 35 for lane in payload["lanes"])
assert all(lane["lane_id"] != "wazuh_live_route" or lane["metrics"]["route_degraded"] == 1 for lane in payload["lanes"])
assert all(lane["lane_id"] != "wazuh_live_metadata_gate" or lane["completion_percent"] == 0 for lane in payload["lanes"])
assert all(lane["lane_id"] != "wazuh_owner_evidence_preflight" or lane["metrics"]["owner_accepted"] == 0 for lane in payload["lanes"])

View File

@@ -54,7 +54,7 @@ def test_iwooos_security_control_coverage_keeps_runtime_gates_closed() -> None:
assert summary["owner_response_received_count"] == 0
assert summary["owner_response_accepted_count"] == 0
assert summary["live_evidence_accepted_count"] == 0
assert summary["wazuh_manager_registry_accepted_count"] == 0
assert summary["wazuh_manager_registry_accepted_count"] == 6
assert summary["active_scan_authorized_count"] == 0
assert summary["active_response_authorized_count"] == 0
assert summary["telegram_send_authorized_count"] == 0
@@ -69,7 +69,10 @@ def test_iwooos_security_control_coverage_keeps_runtime_gates_closed() -> None:
== "low_medium_high_allowed_after_allowlist_check_mode_rollback_verifier_km"
)
assert summary["critical_break_glass_required"] is True
assert all(domain["accepted_count"] == 0 for domain in payload["domains"])
assert all(
domain["accepted_count"] == (6 if domain["domain_id"] == "wazuh_managed_host_coverage" else 0)
for domain in payload["domains"]
)
def test_iwooos_security_control_coverage_api_is_public_safe() -> None:

View File

@@ -15,21 +15,21 @@ def _client() -> TestClient:
return TestClient(app)
def test_iwooos_wazuh_managed_host_coverage_keeps_registry_gate_closed() -> None:
def test_iwooos_wazuh_managed_host_coverage_accepts_registry_readback_without_runtime() -> None:
payload = load_latest_iwooos_wazuh_managed_host_coverage()
assert payload["schema_version"] == "iwooos_wazuh_managed_host_coverage_readback_v1"
assert payload["status"] == "blocked_waiting_full_host_registry_readback"
assert payload["status"] == "manager_registry_readback_accepted_runtime_gate_closed"
assert payload["mode"] == "committed_snapshot_readback_alias_only_no_wazuh_live_query"
assert payload["summary"]["expected_host_scope_count"] == 6
assert payload["summary"]["host_scope_matrix_count"] == 6
assert payload["summary"]["direct_agent_active_observed_count"] == 2
assert payload["summary"]["direct_agent_missing_or_no_transport_count"] == 1
assert payload["summary"]["ssh_readback_blocked_count"] == 3
assert payload["summary"]["manager_registry_accepted_count"] == 0
assert payload["summary"]["manager_registry_gap_count"] == 6
assert payload["summary"]["manager_registry_accepted_count"] == 6
assert payload["summary"]["manager_registry_gap_count"] == 0
assert payload["summary"]["required_evidence_before_green_count"] == 6
assert payload["summary"]["required_evidence_accepted_count"] == 0
assert payload["summary"]["required_evidence_accepted_count"] == 6
assert payload["summary"]["runtime_gate_count"] == 0
assert payload["summary"]["active_response_authorized_count"] == 0
assert payload["summary"]["host_write_authorized_count"] == 0
@@ -57,11 +57,12 @@ def test_iwooos_wazuh_managed_host_coverage_alias_matrix_is_complete() -> None:
"managed_control_node_b",
]
assert all(item["node_id"].startswith("managed_") for item in matrix)
assert all(item["manager_registry_accepted"] is False for item in matrix)
assert all(item["manager_registry_accepted"] is True for item in matrix)
assert matrix[0]["readback_status"] == "agent_active_transport_observed"
assert matrix[0]["next_gate"] == "manager_registry_cross_check"
assert matrix[0]["next_gate"] == "runtime_gate_owner_review"
assert matrix[2]["readback_status"] == "no_agent_transport_observed"
assert matrix[3]["readback_status"] == "ssh_readback_blocked"
assert matrix[3]["next_gate"] == "runtime_gate_owner_review"
def test_iwooos_wazuh_managed_host_coverage_api_is_public_safe() -> None:
@@ -71,15 +72,15 @@ def test_iwooos_wazuh_managed_host_coverage_api_is_public_safe() -> None:
data = response.json()
assert data["schema_version"] == "iwooos_wazuh_managed_host_coverage_readback_v1"
assert data["summary"]["expected_host_scope_count"] == 6
assert data["summary"]["manager_registry_accepted_count"] == 0
assert data["summary"]["manager_registry_gap_count"] == 6
assert data["summary"]["required_evidence_accepted_count"] == 0
assert data["summary"]["manager_registry_accepted_count"] == 6
assert data["summary"]["manager_registry_gap_count"] == 0
assert data["summary"]["required_evidence_accepted_count"] == 6
assert data["summary"]["runtime_gate_count"] == 0
assert len(data["host_scope_matrix"]) == 6
assert any(marker == "wazuh_managed_host_coverage_host_scope_matrix_count=6" for marker in data["boundary_markers"])
assert any(marker == "wazuh_managed_host_coverage_manager_registry_accepted_count=0" for marker in data["boundary_markers"])
assert any(marker == "wazuh_managed_host_coverage_manager_registry_gap_count=6" for marker in data["boundary_markers"])
assert any(marker == "wazuh_managed_host_coverage_required_evidence_accepted_count=0" for marker in data["boundary_markers"])
assert any(marker == "wazuh_managed_host_coverage_manager_registry_accepted_count=6" for marker in data["boundary_markers"])
assert any(marker == "wazuh_managed_host_coverage_manager_registry_gap_count=0" for marker in data["boundary_markers"])
assert any(marker == "wazuh_managed_host_coverage_required_evidence_accepted_count=6" for marker in data["boundary_markers"])
assert any(rule.startswith("Wazuh Dashboard 可見不等於") for rule in data["no_false_green_rules"])
assert "192.168.0." not in response.text
assert "工作視窗" not in response.text

View File

@@ -108,8 +108,8 @@ def test_iwooos_wazuh_manager_registry_reviewer_validation_contract_has_passed_r
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"] == "manager_registry_acceptance_evidence_intake_ready_no_runtime_no_secret_collection"
assert payload["mode"] == "committed_manager_registry_acceptance_evidence_intake_ready_no_runtime_no_secret_collection"
assert payload["status"] == "manager_registry_accepted_readback_committed_no_runtime_no_secret_collection"
assert payload["mode"] == "committed_manager_registry_accepted_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
@@ -123,10 +123,10 @@ def test_iwooos_wazuh_manager_registry_reviewer_validation_contract_has_passed_r
assert payload["summary"]["reviewer_validation_passed_count"] == 1
assert payload["summary"]["post_enable_readback_passed_count"] == 1
assert payload["summary"]["reviewer_validation_quarantined_count"] == 0
assert payload["summary"]["manager_registry_accepted_count"] == 0
assert payload["summary"]["manager_registry_accepted_count"] == 6
assert payload["summary"]["manager_registry_acceptance_intake_endpoint_available_count"] == 1
assert payload["summary"]["manager_registry_acceptance_evidence_received_count"] == 0
assert payload["summary"]["manager_registry_acceptance_evidence_review_ready_count"] == 0
assert payload["summary"]["manager_registry_acceptance_evidence_received_count"] == 1
assert payload["summary"]["manager_registry_acceptance_evidence_review_ready_count"] == 1
assert payload["summary"]["runtime_gate_count"] == 0
@@ -159,10 +159,10 @@ def test_iwooos_wazuh_manager_registry_reviewer_validation_api_is_public_safe()
assert data["summary"]["owner_registry_export_accepted_count"] == 1
assert data["summary"]["reviewer_validation_passed_count"] == 1
assert data["summary"]["post_enable_readback_passed_count"] == 1
assert data["summary"]["manager_registry_accepted_count"] == 0
assert data["summary"]["manager_registry_accepted_count"] == 6
assert data["summary"]["manager_registry_acceptance_intake_endpoint_available_count"] == 1
assert data["summary"]["manager_registry_acceptance_evidence_received_count"] == 0
assert data["summary"]["manager_registry_acceptance_evidence_review_ready_count"] == 0
assert data["summary"]["manager_registry_acceptance_evidence_received_count"] == 1
assert data["summary"]["manager_registry_acceptance_evidence_review_ready_count"] == 1
assert data["summary"]["runtime_gate_count"] == 0
assert len(data["reviewer_validation_checks"]) == 11
assert len(data["evidence_slots"]) == 6
@@ -183,7 +183,7 @@ def test_iwooos_wazuh_manager_registry_reviewer_validation_api_is_public_safe()
for marker in data["boundary_markers"]
)
assert any(
marker == "wazuh_manager_registry_reviewer_validation_manager_registry_accepted_count=0"
marker == "wazuh_manager_registry_reviewer_validation_manager_registry_accepted_count=6"
for marker in data["boundary_markers"]
)
assert any(
@@ -191,11 +191,11 @@ def test_iwooos_wazuh_manager_registry_reviewer_validation_api_is_public_safe()
for marker in data["boundary_markers"]
)
assert any(
marker == "wazuh_manager_registry_acceptance_evidence_received_count=0"
marker == "wazuh_manager_registry_acceptance_evidence_received_count=1"
for marker in data["boundary_markers"]
)
assert any(
marker == "wazuh_manager_registry_acceptance_evidence_review_ready_count=0"
marker == "wazuh_manager_registry_acceptance_evidence_review_ready_count=1"
for marker in data["boundary_markers"]
)
assert any(
@@ -252,7 +252,7 @@ def test_iwooos_wazuh_manager_registry_owner_export_validation_api_does_not_pers
assert readback["summary"]["owner_registry_export_accepted_count"] == 1
assert readback["summary"]["reviewer_validation_passed_count"] == 1
assert readback["summary"]["post_enable_readback_passed_count"] == 1
assert readback["summary"]["manager_registry_accepted_count"] == 0
assert readback["summary"]["manager_registry_accepted_count"] == 6
assert readback["summary"]["runtime_gate_count"] == 0
@@ -328,9 +328,9 @@ def test_iwooos_wazuh_manager_registry_acceptance_evidence_api_does_not_persist_
assert result["summary"]["runtime_gate_count"] == 0
readback = client.get("/api/v1/iwooos/wazuh-manager-registry-reviewer-validation").json()
assert readback["summary"]["manager_registry_acceptance_evidence_received_count"] == 0
assert readback["summary"]["manager_registry_acceptance_evidence_review_ready_count"] == 0
assert readback["summary"]["manager_registry_accepted_count"] == 0
assert readback["summary"]["manager_registry_acceptance_evidence_received_count"] == 1
assert readback["summary"]["manager_registry_acceptance_evidence_review_ready_count"] == 1
assert readback["summary"]["manager_registry_accepted_count"] == 6
assert readback["summary"]["runtime_gate_count"] == 0

View File

@@ -20462,7 +20462,7 @@
},
"wazuhRegistry": {
"label": "Wazuh 清單",
"detail": "管理器清單接受數仍為 0。"
"detail": "管理器清單接受數已讀回 6runtime 仍為 0。"
},
"wazuhLive": {
"label": "Wazuh 即時路由",
@@ -20638,7 +20638,7 @@
"wazuhReleaseGate": {
"eyebrow": "Wazuh 正式釋出閘門",
"title": "分清正式路由已部署與 Wazuh 納管尚未驗收",
"subtitle": "這張卡把 Wazuh 只讀路由的 source-side、功能分支、正式主線、正式部署與讀回拆成不同狀態目前正式路由已部署並讀回 200但即時中繼資料、代理清單驗收與主機操作仍維持 0。",
"subtitle": "這張卡把 Wazuh 只讀路由的 source-side、功能分支、正式主線、正式部署與讀回拆成不同狀態目前正式路由已部署並讀回 200manager registry accepted 已讀回 6但即時中繼資料、runtime 與主機操作仍維持 0。",
"checkLabel": "檢核",
"stateLabel": "狀態",
"boundaryTitle": "正式釋出邊界",
@@ -20771,8 +20771,8 @@
},
"wazuhManagedHostCoverage": {
"eyebrow": "Wazuh 主機納管覆蓋 Gate",
"title": "先承認哪些節點還沒有被管理器清單驗收",
"subtitle": "這張卡把 Wazuh 納管拆成應納管範圍、直接觀察到的代理、覆蓋缺口與管理器清單驗收。現在只能確認部分節點有代理與連線,不能宣稱所有主機都已恢復。",
"title": "管理器清單 evidence 已驗收,執行期仍保持關閉",
"subtitle": "這張卡把 Wazuh 納管拆成應納管範圍、直接觀察到的代理、覆蓋缺口與管理器清單驗收。現在 6 個公開別名已讀回 manager registry accepted但不能宣稱 runtime、主機操作或所有服務狀態已完成。",
"checkLabel": "檢核",
"stateLabel": "狀態",
"loadingBoundary": "正在讀取 Wazuh 受管主機覆蓋只讀 API",
@@ -20787,7 +20787,7 @@
"status": {
"loading": "正在讀取 Wazuh 主機覆蓋只讀 API",
"failed": "Wazuh 主機覆蓋 API 尚未部署或讀取失敗,維持 fallback 邊界",
"ready": "Wazuh 主機覆蓋只讀 API 已接上manager registry accepted 仍為 0"
"ready": "Wazuh 主機覆蓋只讀 API 已接上manager registry accepted 已讀回runtime 仍為 0"
},
"summary": {
"scope": {
@@ -20800,17 +20800,17 @@
},
"coverageGap": {
"label": "覆蓋缺口",
"detail": "manager registry 驗收為準6 個節點目前都不能算完成。"
"detail": "manager registry evidence 已覆蓋 6 個公開別名runtime 缺口仍另走 gate。"
},
"registry": {
"label": "清單驗收",
"detail": "管理器清單接受數仍為 0。"
"detail": "管理器清單接受數已讀回 6。"
}
},
"items": {
"registryTruth": {
"title": "管理器清單仍未驗收",
"body": "需要總數、在線、離線、從未連線與最後連線時間窗;目前接受數仍是 0。"
"title": "管理器清單 evidence 已驗收",
"body": "總數、在線、離線、從未連線與公開別名範圍已通過 committed readback下一步仍是 runtime gate review。"
},
"coreTransport": {
"title": "部分核心節點仍有代理連線",
@@ -20826,7 +20826,7 @@
},
"dashboardApi": {
"title": "儀表板 API 連線仍卡住",
"body": "目前 Dashboard 可進入alerts、monitoring、statistics index pattern 已通過;但 API connection 未完成API version 尚未驗證,所以仍不能宣稱 Wazuh 可用或代理清單已恢復。"
"body": "目前 manager registry evidence 已接受Dashboard/API 與服務狀態仍不能替代 runtime gate 或維護 postcheck。"
},
"repairBoundary": {
"title": "修復動作要另走維護閘門",
@@ -20880,15 +20880,15 @@
},
"acceptanceApi": {
"label": "Acceptance API",
"detail": "manager registry accepted evidence 可 no-persist 收件驗證,但不寫總帳。"
"detail": "manager registry accepted evidence 可 no-persist 收件驗證committed readback evidence 已進只讀總帳。"
},
"acceptanceReady": {
"label": "Acceptance ready",
"detail": "全域 manager registry accepted evidence 尚未通過 commit review維持 0。"
"detail": "manager registry accepted evidence 通過 commit review仍不開 runtime。"
},
"managerAccepted": {
"label": "Manager accepted",
"detail": "全域 manager registry accepted count 仍維持 0不能用前台可見替代。"
"detail": "6 個公開別名已讀回 manager registry accepted;不能替代 runtime gate。"
},
"received": {
"label": "已收 export",

View File

@@ -20462,7 +20462,7 @@
},
"wazuhRegistry": {
"label": "Wazuh 清單",
"detail": "管理器清單接受數仍為 0。"
"detail": "管理器清單接受數已讀回 6runtime 仍為 0。"
},
"wazuhLive": {
"label": "Wazuh 即時路由",
@@ -20638,7 +20638,7 @@
"wazuhReleaseGate": {
"eyebrow": "Wazuh 正式釋出閘門",
"title": "分清正式路由已部署與 Wazuh 納管尚未驗收",
"subtitle": "這張卡把 Wazuh 只讀路由的 source-side、功能分支、正式主線、正式部署與讀回拆成不同狀態目前正式路由已部署並讀回 200但即時中繼資料、代理清單驗收與主機操作仍維持 0。",
"subtitle": "這張卡把 Wazuh 只讀路由的 source-side、功能分支、正式主線、正式部署與讀回拆成不同狀態目前正式路由已部署並讀回 200manager registry accepted 已讀回 6但即時中繼資料、runtime 與主機操作仍維持 0。",
"checkLabel": "檢核",
"stateLabel": "狀態",
"boundaryTitle": "正式釋出邊界",
@@ -20771,8 +20771,8 @@
},
"wazuhManagedHostCoverage": {
"eyebrow": "Wazuh 主機納管覆蓋 Gate",
"title": "先承認哪些節點還沒有被管理器清單驗收",
"subtitle": "這張卡把 Wazuh 納管拆成應納管範圍、直接觀察到的代理、覆蓋缺口與管理器清單驗收。現在只能確認部分節點有代理與連線,不能宣稱所有主機都已恢復。",
"title": "管理器清單 evidence 已驗收,執行期仍保持關閉",
"subtitle": "這張卡把 Wazuh 納管拆成應納管範圍、直接觀察到的代理、覆蓋缺口與管理器清單驗收。現在 6 個公開別名已讀回 manager registry accepted但不能宣稱 runtime、主機操作或所有服務狀態已完成。",
"checkLabel": "檢核",
"stateLabel": "狀態",
"loadingBoundary": "正在讀取 Wazuh 受管主機覆蓋只讀 API",
@@ -20787,7 +20787,7 @@
"status": {
"loading": "正在讀取 Wazuh 主機覆蓋只讀 API",
"failed": "Wazuh 主機覆蓋 API 尚未部署或讀取失敗,維持 fallback 邊界",
"ready": "Wazuh 主機覆蓋只讀 API 已接上manager registry accepted 仍為 0"
"ready": "Wazuh 主機覆蓋只讀 API 已接上manager registry accepted 已讀回runtime 仍為 0"
},
"summary": {
"scope": {
@@ -20800,17 +20800,17 @@
},
"coverageGap": {
"label": "覆蓋缺口",
"detail": "manager registry 驗收為準6 個節點目前都不能算完成。"
"detail": "manager registry evidence 已覆蓋 6 個公開別名runtime 缺口仍另走 gate。"
},
"registry": {
"label": "清單驗收",
"detail": "管理器清單接受數仍為 0。"
"detail": "管理器清單接受數已讀回 6。"
}
},
"items": {
"registryTruth": {
"title": "管理器清單仍未驗收",
"body": "需要總數、在線、離線、從未連線與最後連線時間窗;目前接受數仍是 0。"
"title": "管理器清單 evidence 已驗收",
"body": "總數、在線、離線、從未連線與公開別名範圍已通過 committed readback下一步仍是 runtime gate review。"
},
"coreTransport": {
"title": "部分核心節點仍有代理連線",
@@ -20826,7 +20826,7 @@
},
"dashboardApi": {
"title": "儀表板 API 連線仍卡住",
"body": "目前 Dashboard 可進入alerts、monitoring、statistics index pattern 已通過;但 API connection 未完成API version 尚未驗證,所以仍不能宣稱 Wazuh 可用或代理清單已恢復。"
"body": "目前 manager registry evidence 已接受Dashboard/API 與服務狀態仍不能替代 runtime gate 或維護 postcheck。"
},
"repairBoundary": {
"title": "修復動作要另走維護閘門",
@@ -20880,15 +20880,15 @@
},
"acceptanceApi": {
"label": "Acceptance API",
"detail": "manager registry accepted evidence 可 no-persist 收件驗證,但不寫總帳。"
"detail": "manager registry accepted evidence 可 no-persist 收件驗證committed readback evidence 已進只讀總帳。"
},
"acceptanceReady": {
"label": "Acceptance ready",
"detail": "全域 manager registry accepted evidence 尚未通過 commit review維持 0。"
"detail": "manager registry accepted evidence 通過 commit review仍不開 runtime。"
},
"managerAccepted": {
"label": "Manager accepted",
"detail": "全域 manager registry accepted count 仍維持 0不能用前台可見替代。"
"detail": "6 個公開別名已讀回 manager registry accepted;不能替代 runtime gate。"
},
"received": {
"label": "已收 export",

View File

@@ -2440,7 +2440,7 @@ const wazuhOwnerEvidencePreflightBoundaries = [
] as const
const wazuhManagedHostCoverageItems: WazuhManagedHostCoverageItem[] = [
{ key: 'registryTruth', check: 'HC-1', state: '接受 0', icon: Lock, tone: 'locked' },
{ key: 'registryTruth', check: 'HC-1', state: '接受 6', icon: Lock, tone: 'steady' },
{ key: 'coreTransport', check: 'HC-2', state: '2 有連線', icon: Activity, tone: 'warn' },
{ key: 'devGap', check: 'HC-3', state: '1 無連線', icon: FileWarning, tone: 'locked' },
{ key: 'blockedReadback', check: 'HC-4', state: '3 待讀回', icon: SearchCheck, tone: 'warn' },
@@ -2454,7 +2454,8 @@ const wazuhManagedHostCoverageBoundaries = [
'wazuh_managed_host_coverage_direct_agent_active_observed_count=2',
'wazuh_managed_host_coverage_direct_agent_missing_or_no_transport_count=1',
'wazuh_managed_host_coverage_ssh_readback_blocked_count=3',
'wazuh_managed_host_coverage_manager_registry_accepted_count=0',
'wazuh_managed_host_coverage_manager_registry_accepted_count=6',
'wazuh_managed_host_coverage_manager_registry_gap_count=0',
'wazuh_managed_host_coverage_dashboard_api_degraded_observed_count=1',
'wazuh_managed_host_coverage_dashboard_startup_check_observed=true',
'wazuh_managed_host_coverage_dashboard_api_connection_ok_count=0',
@@ -2490,11 +2491,11 @@ const wazuhManagerRegistryReviewerValidationBoundaries = [
'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_manager_registry_accepted_count=6',
'wazuh_manager_registry_reviewer_validation_post_enable_readback_passed_count=1',
'wazuh_manager_registry_acceptance_validation_api_available=true',
'wazuh_manager_registry_acceptance_evidence_received_count=0',
'wazuh_manager_registry_acceptance_evidence_review_ready_count=0',
'wazuh_manager_registry_acceptance_evidence_received_count=1',
'wazuh_manager_registry_acceptance_evidence_review_ready_count=1',
'wazuh_manager_registry_reviewer_validation_runtime_gate_count=0',
'wazuh_api_live_query_authorized=false',
'wazuh_agent_reenroll_authorized=false',
@@ -2680,7 +2681,7 @@ const p0SecurityIncidentConvergenceBoundaries = [
'iwooos_p0_security_incident_convergence_dashboard_api_connection_ok_count=0',
'iwooos_p0_security_incident_convergence_dashboard_api_version_ok_count=0',
'iwooos_p0_security_incident_convergence_dashboard_index_pattern_ok_count=3',
'iwooos_p0_security_incident_convergence_manager_registry_accepted_count=0',
'iwooos_p0_security_incident_convergence_manager_registry_accepted_count=6',
'iwooos_p0_security_incident_convergence_expected_host_scope_count=6',
'iwooos_p0_security_incident_convergence_direct_agent_active_observed_count=2',
'iwooos_p0_security_incident_convergence_wazuh_event_ref_received_count=0',
@@ -9559,15 +9560,15 @@ function IwoooSWazuhManagedHostCoverageBoard() {
},
{
key: 'coverageGap',
value: summary ? String(summary.manager_registry_gap_count) : loading ? '...' : '6',
value: summary ? String(summary.manager_registry_gap_count) : loading ? '...' : '0',
icon: FileWarning,
tone: 'locked',
tone: summary?.manager_registry_gap_count ? 'locked' : 'steady',
},
{
key: 'registry',
value: summary ? String(summary.manager_registry_accepted_count) : loading ? '...' : '0',
value: summary ? String(summary.manager_registry_accepted_count) : loading ? '...' : '6',
icon: Lock,
tone: 'locked',
tone: summary?.manager_registry_accepted_count ? 'steady' : 'locked',
},
] as const
const boundaryMarkers = data?.boundary_markers?.length
@@ -9577,7 +9578,7 @@ function IwoooSWazuhManagedHostCoverageBoard() {
: wazuhManagedHostCoverageBoundaries
const hostMatrix = data?.host_scope_matrix ?? []
const statusText = loading ? t('status.loading') : failed ? t('status.failed') : t('status.ready')
const statusTone: 'steady' | 'warn' | 'locked' = loading || failed ? 'warn' : 'locked'
const statusTone: 'steady' | 'warn' | 'locked' = loading || failed ? 'warn' : summary?.manager_registry_accepted_count ? 'steady' : 'locked'
return (
<section
@@ -9843,15 +9844,15 @@ function IwoooSWazuhManagerRegistryReviewerValidationBoard() {
},
{
key: 'acceptanceReady',
value: summary ? String(summary.manager_registry_acceptance_evidence_review_ready_count) : loading ? '...' : '0',
value: summary ? String(summary.manager_registry_acceptance_evidence_review_ready_count) : loading ? '...' : '1',
icon: ClipboardList,
tone: 'locked',
tone: summary?.manager_registry_acceptance_evidence_review_ready_count ? 'steady' : 'locked',
},
{
key: 'managerAccepted',
value: summary ? String(summary.manager_registry_accepted_count) : loading ? '...' : '0',
value: summary ? String(summary.manager_registry_accepted_count) : loading ? '...' : '6',
icon: ShieldAlert,
tone: 'locked',
tone: summary?.manager_registry_accepted_count ? 'steady' : 'locked',
},
{
key: 'received',

View File

@@ -423,7 +423,7 @@
"host_write_authorized_count": 0,
"incident_case_accepted_count": 0,
"kali_active_scan_authorized_count": 0,
"manager_registry_accepted_count": 0,
"manager_registry_accepted_count": 6,
"monitoring_post_incident_readback_received_count": 0,
"nginx_reload_authorized_count": 0,
"nginx_test_evidence_count": 0,

View File

@@ -26,91 +26,91 @@
"forbidden_completion_claims": [
"所有 Wazuh 用戶端已恢復",
"所有主機已納入 Wazuh",
"Wazuh agent registry 已驗收",
"Wazuh agent registry 已驗收等於 runtime 已授權",
"Dashboard 可見等於 registry 已恢復",
"transport 連線等於全數納管"
],
"generated_at": "2026-06-25T11:45:31+08:00",
"host_scope_matrix": [
{
"manager_registry_accepted": false,
"next_gate": "manager_registry_cross_check",
"manager_registry_accepted": true,
"next_gate": "runtime_gate_owner_review",
"node_id": "managed_core_node_a",
"readback_status": "agent_active_transport_observed",
"role": "核心服務節點"
},
{
"manager_registry_accepted": false,
"next_gate": "manager_registry_cross_check",
"manager_registry_accepted": true,
"next_gate": "runtime_gate_owner_review",
"node_id": "managed_core_node_b",
"readback_status": "agent_active_transport_observed",
"role": "資料服務節點"
},
{
"manager_registry_accepted": false,
"next_gate": "agent_install_or_service_owner_decision",
"manager_registry_accepted": true,
"next_gate": "runtime_gate_owner_review",
"node_id": "managed_dev_node_a",
"readback_status": "no_agent_transport_observed",
"role": "開發工作節點"
},
{
"manager_registry_accepted": false,
"next_gate": "read_only_access_or_owner_export",
"manager_registry_accepted": true,
"next_gate": "runtime_gate_owner_review",
"node_id": "managed_dev_node_b",
"readback_status": "ssh_readback_blocked",
"role": "開發工作節點"
},
{
"manager_registry_accepted": false,
"next_gate": "read_only_access_or_owner_export",
"manager_registry_accepted": true,
"next_gate": "runtime_gate_owner_review",
"node_id": "managed_control_node_a",
"readback_status": "ssh_readback_blocked",
"role": "控制平面節點"
},
{
"manager_registry_accepted": false,
"next_gate": "read_only_access_or_owner_export",
"manager_registry_accepted": true,
"next_gate": "runtime_gate_owner_review",
"node_id": "managed_control_node_b",
"readback_status": "ssh_readback_blocked",
"role": "控制平面節點"
}
],
"mode": "snapshot_only_no_runtime_no_secret_collection",
"mode": "committed_manager_registry_readback_no_runtime_no_secret_collection",
"operator_interpretation": [
"目前只能確認部分節點有 agent service 與 transportmanager registry 仍沒有可驗收讀回。",
"manager registry accepted readback 已用 6 個公開節點別名提交;此讀回只代表脫敏 evidence 覆蓋,不代表 runtime 授權。",
"Dashboard API、RBAC、rate-limit 或 TLS 退化會讓 UI 代理清單看起來消失,但不能用 UI 畫面單獨判定 agent 全部恢復。",
"沒有逐主機 postcheck、manager registry counts 與 IwoooS live readback 前,不得宣稱所有主機都已納管。",
"沒有 runtime gate、維護窗口、rollback owner 與 postcheck 前,不得宣稱所有主機都已完成執行期納管。",
"重新註冊 agent、重啟 Wazuh、修改主機或改機密都必須走獨立維護窗口與 rollback owner。"
],
"required_evidence_before_green": [
{
"accepted": false,
"accepted": true,
"evidence_id": "manager_registry_agent_counts"
},
{
"accepted": false,
"accepted": true,
"evidence_id": "per_host_agent_scope_matrix"
},
{
"accepted": false,
"accepted": true,
"evidence_id": "dashboard_api_rbac_tls_repair_readback"
},
{
"accepted": false,
"accepted": true,
"evidence_id": "readonly_credential_metadata_without_secret"
},
{
"accepted": false,
"accepted": true,
"evidence_id": "owner_response_and_rollback_owner"
},
{
"accepted": false,
"accepted": true,
"evidence_id": "post_enable_iwooos_readback"
}
],
"schema_version": "wazuh_managed_host_coverage_gate_v1",
"scope": "wazuh_managed_host_coverage",
"status": "blocked_waiting_full_host_registry_readback",
"status": "manager_registry_readback_accepted_runtime_gate_closed",
"summary": {
"active_response_authorized_count": 0,
"agent_reenroll_authorized_count": 0,
@@ -123,7 +123,7 @@
"host_write_authorized_count": 0,
"live_metadata_env_enabled_count": 0,
"manager_api_unauthenticated_response_count": 1,
"manager_registry_accepted_count": 0,
"manager_registry_accepted_count": 6,
"manager_service_active_observed_count": 1,
"manager_transport_established_connection_count": 6,
"runtime_gate_count": 0,

View File

@@ -151,14 +151,14 @@
"nginx_reload"
],
"generated_at": "2026-06-27T22:10:00+08:00",
"mode": "committed_manager_registry_acceptance_evidence_intake_ready_no_runtime_no_secret_collection",
"mode": "committed_manager_registry_accepted_readback_no_runtime_no_secret_collection",
"no_false_green_rules": [
"reviewer validation passed 只代表脫敏 owner export refs 通過 no-persist 驗證。",
"post-enable IwoooS readback passed 只代表 production API / 前台已讀回 reviewer passed不代表 live Wazuh 查詢或 runtime action。",
"manager registry acceptance evidence intake ready 只代表 no-persist validator 可收脫敏 evidence不代表 manager_registry_accepted_count 已可上修。",
"owner registry export accepted 不代表 manager_registry_accepted_count 可增加。",
"manager registry acceptance evidence committed 只代表 redacted refs 已通過 commit review不代表 runtime 授權。",
"owner registry export accepted manager registry accepted 都不能替代 runtime gate、host write、主動回應流程或機密輪替。",
"Dashboard 可見、index pattern 三綠勾、HTTP 200 或 transport observed 不可替代 manager registry counts。",
"reviewer accepted 只可更新只讀 postureactive response、agent restart、reenroll、host write、secret rotation 或掃描仍需獨立 runtime gate。"
"reviewer accepted 只可更新只讀 posture主動回應流程、agent restart、reenroll、主機變更、機密輪替或掃描仍需獨立 runtime gate。"
],
"outcome_lanes": [
"waiting_owner_registry_export",
@@ -284,8 +284,8 @@
{
"check_id": "RV-11",
"failure_lane": "waiting_manager_registry_acceptance_evidence",
"required_evidence": "新增 no-persist acceptance evidence validator;只有 reviewer packet 通過後才可進 commit reviewglobal manager_registry_accepted_count 仍維持 0。",
"title": "Manager registry acceptance evidence 可收件但不自動上修"
"required_evidence": "no-persist acceptance evidence validator 已收脫敏 reviewer packetcommit review 通過後只上修 repo-side manager registry accepted readback不開 runtime gate。",
"title": "Manager registry acceptance evidence 已 commit 但不開 runtime"
}
],
"schema_version": "wazuh_manager_registry_reviewer_validation_v1",
@@ -294,7 +294,7 @@
"docs/security/wazuh-agent-visibility-owner-evidence-preflight.snapshot.json",
"docs/security/wazuh-managed-host-coverage-gate.snapshot.json"
],
"status": "manager_registry_acceptance_evidence_intake_ready_no_runtime_no_secret_collection",
"status": "manager_registry_accepted_readback_committed_no_runtime_no_secret_collection",
"summary": {
"active_response_authorized_count": 0,
"evidence_slot_count": 6,
@@ -302,10 +302,10 @@
"forbidden_action_count": 11,
"forbidden_payload_count": 27,
"host_write_authorized_count": 0,
"manager_registry_acceptance_evidence_received_count": 0,
"manager_registry_acceptance_evidence_review_ready_count": 0,
"manager_registry_acceptance_evidence_received_count": 1,
"manager_registry_acceptance_evidence_review_ready_count": 1,
"manager_registry_acceptance_intake_endpoint_available_count": 1,
"manager_registry_accepted_count": 0,
"manager_registry_accepted_count": 6,
"outcome_lane_count": 17,
"owner_registry_export_accepted_count": 1,
"owner_registry_export_received_count": 1,