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
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:
@@ -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 = (
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user