fix(security): route Wazuh to canonical executor
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m32s
CD Pipeline / build-and-deploy (push) Failing after 15m21s
CD Pipeline / post-deploy-checks (push) Has been skipped

This commit is contained in:
ogt
2026-07-15 13:11:47 +08:00
parent b2deba5e84
commit 89aee21570
5 changed files with 153 additions and 2 deletions

View File

@@ -389,7 +389,12 @@ def resolve_typed_alert_target(
_text_token(target_resource)
== "sentry-self-hosted-snuba-profiling-functions-consumer-1"
)
if not exact_sentry_consumer:
exact_registry_catalog_target = bool(
domain == "host_systemd"
and _text_token(target_resource)
== _text_token(str(identity.get("service_name") or ""))
)
if not (exact_sentry_consumer or exact_registry_catalog_target):
catalog_ids = []
stateful_level = str(identity.get("stateful_level") or "")
risk = (

View File

@@ -181,3 +181,35 @@ def test_typed_target_preview_is_no_write_and_fail_closed() -> None:
assert agent99_payload["route"]["agent99_bridge"][
"dispatch_allowed"
] is True
def test_wazuh_typed_target_preview_is_bounded_and_public_safe() -> None:
app = FastAPI()
app.include_router(router, prefix="/api/v1")
client = TestClient(app)
response = client.post(
"/api/v1/agents/controlled-alert-target-preview",
json={
"alertname": "WazuhSecurityEvent",
"target_resource": "wazuh-manager",
"namespace": "awoooi",
"labels": {"service": "wazuh-manager", "tool": "wazuh"},
"alert_category": "security",
},
)
assert response.status_code == 200
payload = response.json()
route = payload["route"]
assert payload["preview_only"] is True
assert payload["dispatch_performed"] is False
assert payload["runtime_closure_verified"] is False
assert route["resolution_status"] == "resolved"
assert route["canonical_asset_id"] == "service:wazuh-manager"
assert route["host"] == "host:kali-readonly"
assert route["allowed_catalog_ids"] == [
"ansible:wazuh-manager-posture-readback"
]
assert route["allowed_inventory_hosts"] == ["host_112"]
assert route["cross_domain_fallback_allowed"] is False

View File

@@ -47,6 +47,7 @@ PLAYBOOK = (
)
SENTRY_CONTAINER = "sentry-self-hosted-snuba-profiling-functions-consumer-1"
SENTRY_CATALOG = "ansible:110-sentry-profiling-consumer-recovery"
WAZUH_CATALOG = "ansible:wazuh-manager-posture-readback"
def _sentry_incident() -> dict:
@@ -110,6 +111,49 @@ def test_sentry_container_resolves_to_exact_host110_domain_route() -> None:
assert route["reasoning_contract"]["paid_call_allowed"] is False
def test_wazuh_manager_exact_service_resolves_to_host112_posture_lane() -> None:
registry = ServiceRegistryClient(REGISTRY)
route = resolve_typed_alert_target(
alertname="WazuhSecurityEvent",
target_resource="wazuh-manager",
namespace="awoooi",
labels={"service": "wazuh-manager", "tool": "wazuh"},
alert_category="security",
registry=registry,
)
identity = registry.resolve_identity("wazuh-manager")
assert identity["resolution_status"] == "resolved"
assert identity["canonical_id"] == "service:wazuh-manager"
assert identity["allowed_catalog_ids"] == [WAZUH_CATALOG]
assert route["resolution_status"] == "resolved"
assert route["target_kind"] == "host_systemd"
assert route["canonical_asset_id"] == "service:wazuh-manager"
assert route["executor"] == "host_ansible_executor"
assert route["verifier"] == "iwooos_wazuh_controlled_executor_runtime"
assert route["allowed_catalog_ids"] == [WAZUH_CATALOG]
assert route["allowed_inventory_hosts"] == ["host_112"]
assert route["controlled_apply_allowed"] is True
assert route["critical_break_glass_required"] is False
assert route["cross_domain_fallback_allowed"] is False
def test_wazuh_systemd_alias_cannot_inherit_execution_catalog() -> None:
route = resolve_typed_alert_target(
alertname="SystemdUnitUnavailable",
target_resource="wazuh-manager.service",
namespace="awoooi",
labels={},
alert_category="security",
registry=ServiceRegistryClient(REGISTRY),
)
assert route["resolution_status"] == "resolved"
assert route["canonical_asset_id"] == "service:wazuh-manager"
assert route["allowed_catalog_ids"] == []
assert route["cross_domain_fallback_allowed"] is False
def test_sentry_incident_cannot_fall_to_host188_or_full_convergence() -> None:
hints = _catalog_hints(_sentry_incident(), None)
@@ -363,6 +407,48 @@ def test_sentry_candidate_reaches_bounded_check_mode_with_exact_scope() -> None:
assert claim["controlled_apply_allowed"] is True
def test_wazuh_incident_reaches_bounded_host112_check_mode() -> None:
class Incident:
incident_id = "INC-WAZUH-TYPED-ROUTE"
project_id = "awoooi"
alertname = "WazuhSecurityEvent"
alert_category = "security"
notification_type = "TYPE-2"
severity = None
affected_services = ["wazuh-manager"]
signals = [
{
"alert_name": "WazuhSecurityEvent",
"labels": {
"service": "wazuh-manager",
"tool": "wazuh",
"namespace": "awoooi",
},
}
]
payload = build_ansible_decision_audit_payload(
incident=Incident(),
proposal_data={"source": "test", "risk_level": "medium"},
decision_path="repair_candidate_controlled_queue",
not_used_reason="test",
)
assert payload is not None
claim = build_ansible_check_mode_claim_input(
source_candidate_op_id="00000000-0000-0000-0000-000000112112",
candidate_input=payload["input"],
)
assert claim["catalog_id"] == WAZUH_CATALOG
assert claim["inventory_hosts"] == ["host_112"]
assert claim["typed_domain"] == "host_systemd"
assert claim["canonical_asset_id"] == "service:wazuh-manager"
assert claim["target_scope_validated"] is True
assert claim["cross_domain_fallback_allowed"] is False
assert claim["controlled_apply_allowed"] is True
def test_sentry_playbook_and_post_verifier_are_exact_container_bounded() -> None:
payload = yaml.safe_load(PLAYBOOK.read_text(encoding="utf-8"))
source = PLAYBOOK.read_text(encoding="utf-8")

View File

@@ -9,7 +9,7 @@ metadata:
app: awoooi
component: service-registry
annotations:
awoooi.wooo.work/source-sha256: "1662532ccf9c574e9853291a6f2881377c1a5b2519c4123ae05caf45be904121"
awoooi.wooo.work/source-sha256: "5548d19a6060900d51810cb3b1c3e1dc5f2fbb2b7c77df20227499cdb68599fc"
data:
service-registry.yaml: |
# ops/config/service-registry.yaml
@@ -165,6 +165,20 @@ data:
containers: ["alertmanager"]
# ─── AUTO無狀態允許自動修復 ──────────────────────────────────────
- name: wazuh-manager
canonical_id: "service:wazuh-manager"
display_name: "Wazuh Manager (host_112)"
host: "192.168.0.112"
stateful_level: AUTO
asset_domain: host_systemd
reason: "Only the bounded no-write posture catalog is enabled; active response and arbitrary service mutation remain unavailable"
executor: host_ansible_executor
verifier: iwooos_wazuh_controlled_executor_runtime
aliases: ["wazuh-manager.service"]
containers: []
allowed_catalog_ids:
- ansible:wazuh-manager-posture-readback
- name: nginx
display_name: "Nginx (反向代理)"
host: "192.168.0.110"

View File

@@ -151,6 +151,20 @@ services:
containers: ["alertmanager"]
# ─── AUTO無狀態允許自動修復 ──────────────────────────────────────
- name: wazuh-manager
canonical_id: "service:wazuh-manager"
display_name: "Wazuh Manager (host_112)"
host: "192.168.0.112"
stateful_level: AUTO
asset_domain: host_systemd
reason: "Only the bounded no-write posture catalog is enabled; active response and arbitrary service mutation remain unavailable"
executor: host_ansible_executor
verifier: iwooos_wazuh_controlled_executor_runtime
aliases: ["wazuh-manager.service"]
containers: []
allowed_catalog_ids:
- ansible:wazuh-manager-posture-readback
- name: nginx
display_name: "Nginx (反向代理)"
host: "192.168.0.110"