Merge remote-tracking branch 'origin/main' into codex/sre-typed-automation-20260715

# Conflicts:
#	apps/api/tests/test_executor_trust_boundary_readback.py
This commit is contained in:
ogt
2026-07-15 16:09:12 +08:00
38 changed files with 5361 additions and 116 deletions

View File

@@ -16,6 +16,7 @@ from src.services.ai_agent_autonomous_runtime_control import (
_RUNTIME_TIMELINE_COUNTS_SQL,
_runtime_stage_receipt_has_required_proof,
build_ai_agent_autonomous_runtime_control,
build_ai_agent_strict_runtime_completion_from_readback,
build_runtime_receipt_readback_from_rows,
classify_deploy_control_plane_observation,
)
@@ -1882,6 +1883,9 @@ def test_ai_agent_autonomous_runtime_control_uses_current_owner_directive():
assert strict["metadata_only_counts_as_completion"] is False
assert strict["historical_aggregate_fallback_allowed"] is False
assert len(strict["stage_contracts"]) == len(AI_AUTOMATION_REQUIRED_LOOP_STAGES)
assert build_ai_agent_strict_runtime_completion_from_readback(
data["runtime_receipt_readback"]
) == strict
assert data["current_policy"]["low_risk_controlled_apply_allowed"] is True
assert data["current_policy"]["medium_risk_controlled_apply_allowed"] is True
assert data["current_policy"]["high_risk_controlled_apply_allowed"] is True

View File

@@ -349,8 +349,8 @@ def test_executor_trust_boundary_requires_broker_secret_isolation() -> None:
def test_executor_trust_boundary_requires_live_connection_headroom() -> None:
receipt = _verified_receipt()
receipt["worker_active_role_connection_count"] = "7"
receipt["worker_available_connection_headroom"] = "1"
receipt["worker_active_role_connection_count"] = "8"
receipt["worker_available_connection_headroom"] = "0"
readback = build_executor_trust_boundary_readback(
receipt,
@@ -382,6 +382,24 @@ def test_executor_trust_boundary_requires_api_null_pool_concurrency_cap() -> Non
)
def test_executor_trust_boundary_does_not_double_count_used_budget() -> None:
receipt = _verified_receipt()
receipt["worker_active_role_connection_count"] = "3"
receipt["worker_available_connection_headroom"] = "5"
readback = build_executor_trust_boundary_readback(
receipt,
deployed_source_sha="abc123",
)
database_boundary = readback["database_identity_boundary"]
assert readback["full_workload_boundary_verified"] is True
assert database_boundary["connection_budget_verified"] is True
assert "worker_connection_budget_not_verified" not in (
database_boundary["active_blockers"]
)
def test_executor_trust_boundary_binds_budget_and_verifier_contract() -> None:
wrong_budget = _verified_receipt()
wrong_budget["worker_required_connection_budget"] = "4"

View File

@@ -3,6 +3,7 @@ from __future__ import annotations
# ruff: noqa: E402, I001
import asyncio
import copy
import json
import os
from datetime import UTC, datetime, timedelta
@@ -20,12 +21,51 @@ from src.services.iwooos_security_asset_control_plane import (
build_iwooos_security_asset_control_plane,
build_unavailable_iwooos_security_asset_control_plane,
)
from src.services.ai_automation_runtime_contract import (
AI_AUTOMATION_REQUIRED_LOOP_STAGES,
AI_AUTOMATION_RUNTIME_CONTRACT_SCHEMA_VERSION,
)
def _row(**values):
return SimpleNamespace(**values)
def _closed_strict_runtime() -> dict:
return {
"schema_version": "ai_agent_strict_runtime_completion_v2",
"runtime_contract_schema_version": (
AI_AUTOMATION_RUNTIME_CONTRACT_SCHEMA_VERSION
),
"completion_percent": 100,
"required_stage_count": len(AI_AUTOMATION_REQUIRED_LOOP_STAGES),
"present_stage_count": len(AI_AUTOMATION_REQUIRED_LOOP_STAGES),
"missing_stage_ids": [],
"latest_flow_closed": True,
"latest_loop_closed": True,
"execution_loop_closed": True,
"same_run_correlation": True,
"full_trace_same_run_correlation_proven": True,
"automation_run_id": "internal-run-identity",
"run_id_mismatch_stage_ids": [],
"uncorrelated_stage_ids": [],
"stage_contracts": [
{
"stage_id": stage_id,
"evidence_present": True,
"same_run_correlation_proven": True,
"completion_eligible": True,
"evidence_source": "same_run_runtime_stage_receipt",
}
for stage_id in AI_AUTOMATION_REQUIRED_LOOP_STAGES
],
"closed": True,
"same_run_correlation_required": True,
"metadata_only_counts_as_completion": False,
"historical_aggregate_fallback_allowed": False,
}
def _ready_payload(
source_health: list[dict] | None = None,
*,
@@ -33,6 +73,7 @@ def _ready_payload(
discovery_error: str | None = None,
automation_rows: list[SimpleNamespace] | None = None,
runtime_receipt_counts: dict[str, int] | None = None,
strict_runtime: dict | None = None,
) -> dict:
now = datetime(2026, 7, 11, 4, 0, tzinfo=UTC)
discovery = _row(
@@ -124,6 +165,7 @@ def _ready_payload(
learning_writeback_count_24h=runtime_counts.get("learn", 0),
mttr_minutes_24h=14.25,
),
strict_runtime_row=strict_runtime,
audit_row=_row(
k8s_audit_count_24h=2,
k8s_audit_failure_count_24h=0,
@@ -249,6 +291,92 @@ def test_projects_canonical_runtime_receipts_without_false_same_run_closure() ->
assert work_items["AIA-P0-008-01"]["gap_count"] == 1
def test_projects_exact_authoritative_same_run_runtime_closure() -> None:
payload = _ready_payload(strict_runtime=_closed_strict_runtime())
strict = payload["ai_automation"]["strict_runtime_completion"]
assert strict == {
"schema_version": "ai_agent_strict_runtime_completion_v2",
"runtime_contract_schema_version": (
AI_AUTOMATION_RUNTIME_CONTRACT_SCHEMA_VERSION
),
"contract_compatible": True,
"completion_percent": 100,
"required_stage_count": len(AI_AUTOMATION_REQUIRED_LOOP_STAGES),
"present_stage_count": len(AI_AUTOMATION_REQUIRED_LOOP_STAGES),
"missing_stage_count": 0,
"same_run_correlation": True,
"full_trace_same_run_correlation_proven": True,
"execution_loop_closed": True,
"closed": True,
"reason_code": None,
"cache_fallback_active": False,
"raw_run_identity_returned": False,
"raw_stage_receipts_returned": False,
}
assert payload["completion"]["strict_runtime_closure_percent"] == 100
assert payload["ai_automation"]["same_run_closed_loop_proven"] is True
assert payload["ai_automation"]["same_run_closed_loop_count"] == 1
assert all(
item["work_item_id"] != "AIA-P0-008-01"
for item in payload["work_items"]
)
assert payload["completion"]["overall_percent"] == round(
sum(
dimension["completion_percent"]
for dimension in payload["completion"]["dimensions"]
)
/ payload["completion"]["dimension_count"]
)
public_text = json.dumps(payload, ensure_ascii=False)
assert "internal-run-identity" not in public_text
assert '"automation_run_id"' not in public_text
assert '"stage_contracts"' not in public_text
def test_strict_runtime_projection_fails_closed_on_contract_or_receipt_drift() -> None:
variants: list[dict] = []
bad_schema = _closed_strict_runtime()
bad_schema["schema_version"] = "ai_agent_strict_runtime_completion_v1"
variants.append(bad_schema)
missing_stage = _closed_strict_runtime()
missing_stage["present_stage_count"] -= 1
missing_stage["missing_stage_ids"] = [AI_AUTOMATION_REQUIRED_LOOP_STAGES[-1]]
variants.append(missing_stage)
cross_run = _closed_strict_runtime()
cross_run["same_run_correlation"] = False
cross_run["run_id_mismatch_stage_ids"] = ["telegram_receipt"]
variants.append(cross_run)
no_run_identity = _closed_strict_runtime()
no_run_identity["automation_run_id"] = ""
variants.append(no_run_identity)
metadata_only = _closed_strict_runtime()
metadata_only["metadata_only_counts_as_completion"] = True
variants.append(metadata_only)
invalid_stage_contract = copy.deepcopy(_closed_strict_runtime())
invalid_stage_contract["stage_contracts"][0]["completion_eligible"] = False
variants.append(invalid_stage_contract)
for strict_runtime in variants:
payload = _ready_payload(strict_runtime=strict_runtime)
strict = payload["ai_automation"]["strict_runtime_completion"]
assert strict["closed"] is False
assert strict["completion_percent"] == 0
assert payload["completion"]["strict_runtime_closure_percent"] == 0
assert payload["ai_automation"]["same_run_closed_loop_proven"] is False
assert any(
item["work_item_id"] == "AIA-P0-008-01"
for item in payload["work_items"]
)
def test_discovery_failure_exposes_only_allowlisted_collector_ids() -> None:
raw_error = (
"RuntimeError: asset_collector_failures=domain_tls_inventory,"
@@ -612,6 +740,9 @@ def test_unavailable_payload_is_fixed_degraded_contract_without_raw_error() -> N
assert payload["summary"]["overall_security_completion_percent"] == 0
assert payload["completion"]["overall_percent"] == 0
assert payload["completion"]["strict_runtime_closure_percent"] == 0
assert payload["summary"]["source_count"] == 10
assert payload["summary"]["unavailable_source_count"] == 10
assert payload["ai_automation"]["strict_runtime_completion"]["closed"] is False
assert payload["discovery"]["fresh"] is False
assert payload["boundaries"]["raw_asset_identity_returned"] is False
assert payload["boundaries"]["raw_event_payload_returned"] is False
@@ -676,12 +807,25 @@ def test_service_uses_canonical_awoooi_project_scope(monkeypatch) -> None:
"src.services.iwooos_security_asset_control_plane.get_db_context",
fake_db_context,
)
async def strict_runtime_unavailable():
return {}, {
"source_id": "autonomous_strict_runtime",
"status": "unavailable",
"reason_code": "autonomous_strict_runtime_query_failed",
}
monkeypatch.setattr(
"src.services.iwooos_security_asset_control_plane._read_strict_runtime_source",
strict_runtime_unavailable,
)
payload = asyncio.run(service.get_snapshot())
assert requested_projects == ["awoooi"] * 9
assert payload["status"] == "degraded"
assert payload["source_status"] == "live_database_unavailable"
assert payload["summary"]["unavailable_source_count"] == 9
assert payload["summary"]["source_count"] == 10
assert payload["summary"]["unavailable_source_count"] == 10
def test_service_bounds_source_concurrency_for_database_budget(monkeypatch) -> None:
@@ -719,11 +863,23 @@ def test_service_bounds_source_concurrency_for_database_budget(monkeypatch) -> N
"src.services.iwooos_security_asset_control_plane.get_db_context",
lambda project_id: DbContext(),
)
async def strict_runtime_ready():
return _closed_strict_runtime(), {
"source_id": "autonomous_strict_runtime",
"status": "ready",
"reason_code": None,
}
monkeypatch.setattr(
"src.services.iwooos_security_asset_control_plane._read_strict_runtime_source",
strict_runtime_ready,
)
payload = asyncio.run(service._load_snapshot())
assert concurrency["maximum"] == 3
assert payload["summary"]["source_count"] == 9
assert payload["summary"]["ready_source_count"] == 9
assert payload["summary"]["source_count"] == 10
assert payload["summary"]["ready_source_count"] == 10
assert payload["summary"]["unavailable_source_count"] == 0
compliance_query = next(
statement

View File

@@ -1,5 +1,7 @@
from __future__ import annotations
# ruff: noqa: E402, I001
import os
from contextlib import asynccontextmanager
from datetime import UTC, datetime
@@ -90,6 +92,30 @@ def test_wazuh_runtime_readback_closes_only_with_complete_same_run_receipts() ->
assert payload["boundaries"]["command_output_returned"] is False
def test_wazuh_runtime_readback_prefers_ingress_convergence_semantics() -> None:
row = _complete_row()
row["catalog_id"] = "ansible:wazuh-alertmanager-integration"
row["work_item_id"] = "P0-03-WAZUH-ALERT-INGRESS"
payload = build_iwooos_wazuh_controlled_executor_runtime_readback(
row,
executor_enabled=True,
)
assert payload["status"] == "wazuh_alert_ingress_same_run_runtime_closed"
assert payload["work_item_id"] == "P0-03-WAZUH-ALERT-INGRESS"
assert payload["summary"]["selected_catalog_id"] == (
"ansible:wazuh-alertmanager-integration"
)
assert payload["summary"]["bounded_posture_execution_passed_count"] == 0
assert payload["summary"]["bounded_ingress_convergence_passed_count"] == 1
assert payload["summary"]["host_write_performed_count"] == 1
assert payload["boundaries"]["bounded_no_write_posture_probe"] is False
assert payload["boundaries"]["bounded_alert_ingress_convergence"] is True
assert payload["boundaries"]["sanitized_alert_ingress_configured"] is True
assert payload["boundaries"]["raw_wazuh_payload_persisted"] is False
def test_wazuh_runtime_readback_keeps_partial_execution_open() -> None:
row = _complete_row()
row["stage_ids"] = [

View File

@@ -0,0 +1,418 @@
from __future__ import annotations
# ruff: noqa: E402, I001
import importlib.util
import json
import os
from contextlib import asynccontextmanager
from datetime import UTC, datetime
from pathlib import Path
from unittest.mock import AsyncMock, MagicMock
import pytest
import yaml
os.environ.setdefault("DATABASE_URL", "postgresql+asyncpg://test:test@localhost/test")
from src.services.awooop_ansible_audit_service import (
_catalog_hints,
get_ansible_catalog_item,
)
from src.services.awooop_ansible_post_verifier import postconditions_for_catalog
from src.services.awooop_ansible_check_mode_service import (
build_ansible_apply_command,
build_ansible_check_mode_command,
)
from src.core.config import settings
from src.services.controlled_alert_target_router import resolve_typed_alert_target
from src.services.incident_service import classify_alert_early
ROOT = Path(__file__).resolve().parents[3]
SCRIPT = (
ROOT
/ "infra"
/ "ansible"
/ "files"
/ "wazuh"
/ "custom-awoooi-alertmanager.py"
)
PLAYBOOK = (
ROOT
/ "infra"
/ "ansible"
/ "playbooks"
/ "wazuh-alertmanager-integration.yml"
)
BROKER_DEPLOYMENT = (
ROOT / "k8s" / "awoooi-prod" / "08-deployment-ansible-executor-broker.yaml"
)
WORKER_DEPLOYMENT = ROOT / "k8s" / "awoooi-prod" / "08-deployment-worker.yaml"
CATALOG_ID = "ansible:wazuh-alertmanager-integration"
def _load_bridge_module():
spec = importlib.util.spec_from_file_location("wazuh_awoooi_bridge", SCRIPT)
assert spec is not None and spec.loader is not None
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
def _alert(*, agent_id: str = "017") -> dict:
return {
"timestamp": "2026-07-15T05:30:00Z",
"manager": {"name": "wazuh-manager-internal"},
"agent": {
"id": agent_id,
"name": "private-endpoint-name",
"ip": "192.168.0.55",
},
"rule": {
"id": "5710",
"level": 12,
"description": "private security evidence",
"groups": ["authentication_failures", "sshd"],
"mitre": {"id": ["T1110", "not-a-technique"]},
},
"full_log": "raw source event must remain in Wazuh",
"data": {"srcip": "203.0.113.7"},
}
def test_wazuh_bridge_emits_only_public_safe_stable_metadata() -> None:
bridge = _load_bridge_module()
payload = bridge.build_alertmanager_payload(
_alert(),
now=datetime(2026, 7, 15, 5, 30, tzinfo=UTC),
)
encoded = json.dumps(payload, sort_keys=True)
labels = payload["alerts"][0]["labels"]
assert labels["alertname"] == "WazuhSecurityEvent_5710"
assert labels["component"] == "wazuh-manager"
assert labels["severity"] == "critical"
assert labels["wazuh_rule_groups"] == "authentication_failures,sshd"
assert labels["mitre_techniques"] == "T1110"
assert labels["deployment"].startswith("wazuh-agent-")
assert labels["raw_payload_persisted"] == "false"
assert labels["active_response_requested"] == "false"
for forbidden in (
"private-endpoint-name",
"192.168.0.55",
"203.0.113.7",
"private security evidence",
"raw source event must remain in Wazuh",
"wazuh-manager-internal",
):
assert forbidden not in encoded
def test_wazuh_bridge_fingerprint_clusters_same_rule_and_agent() -> None:
bridge = _load_bridge_module()
first = bridge.build_alertmanager_payload(_alert(agent_id="017"))
second = bridge.build_alertmanager_payload(_alert(agent_id="017"))
other_agent = bridge.build_alertmanager_payload(_alert(agent_id="018"))
assert first["groupKey"] == second["groupKey"]
assert first["groupKey"] != other_agent["groupKey"]
assert (
first["alerts"][0]["labels"]["deployment"]
!= other_agent["alerts"][0]["labels"]["deployment"]
)
@pytest.mark.parametrize(
"url",
[
"http://awoooi.wooo.work/api/v1/webhooks/alertmanager",
"https://example.com/api/v1/webhooks/alertmanager",
"https://awoooi.wooo.work/api/v1/webhooks/alertmanager?raw=1",
"https://user:pass@awoooi.wooo.work/api/v1/webhooks/alertmanager",
],
)
def test_wazuh_bridge_rejects_non_allowlisted_hook_urls(url: str) -> None:
bridge = _load_bridge_module()
with pytest.raises(ValueError, match="hook_url_not_allowlisted"):
bridge._validated_hook_url(url)
def test_wazuh_integration_catalog_and_rollback_contract_are_bounded() -> None:
catalog = get_ansible_catalog_item(CATALOG_ID)
playbook = yaml.safe_load(PLAYBOOK.read_text(encoding="utf-8"))
text = PLAYBOOK.read_text(encoding="utf-8")
conditions = postconditions_for_catalog(CATALOG_ID)
assert catalog is not None
assert catalog["inventory_hosts"] == ["host_112"]
assert catalog["risk_level"] == "high"
assert catalog["auto_apply_enabled"] is True
assert catalog["approval_required"] is False
assert catalog["supports_check_mode"] is True
assert playbook[0]["hosts"] == "host_112"
assert "backup: true" in text
assert "remote_src: true" in text
assert "wazuh_privileged_convergence_capability_missing" in text
assert "/var/lib/awoooi-wazuh-alert-ingress/receipt.env" in text
assert "raw_payload_persisted=0" in text
assert "active_response_enabled=0" in text
assert "wazuh_alertmanager_integration_rolled_back" in text
assert "slurp:" not in text
assert "api_key>" not in text
assert "ansible_become_pass" not in text
assert "raw.githubusercontent.com" not in text
assert {condition.condition_id for condition in conditions} == {
"host_112_wazuh_alertmanager_script",
"host_112_wazuh_alertmanager_config",
"host_112_wazuh_manager_runtime_after_ingress_convergence",
"host_112_wazuh_integrator_runtime",
"host_112_awoooi_alertmanager_ingress_reachable",
}
def test_wazuh_become_password_projection_is_path_only_and_optional(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
password_file = tmp_path / "become-password"
password_file.write_text("test-only-secret-value\n", encoding="utf-8")
monkeypatch.setattr(
settings,
"AWOOOP_ANSIBLE_BECOME_PASSWORD_FILE",
str(password_file),
)
spec = build_ansible_check_mode_command(
playbook_path="infra/ansible/playbooks/wazuh-alertmanager-integration.yml",
inventory_hosts=("host_112",),
playbook_root=ROOT / "infra" / "ansible",
check_mode_ssh_key_path=tmp_path / "ssh-key",
check_mode_known_hosts_path=tmp_path / "known-hosts",
)
manifest = yaml.safe_load(BROKER_DEPLOYMENT.read_text(encoding="utf-8"))
volume = next(
item
for item in manifest["spec"]["template"]["spec"]["volumes"]
if item["name"] == "host112-become-password"
)
assert spec.env["ANSIBLE_BECOME_PASSWORD_FILE"] == str(password_file)
assert "test-only-secret-value" not in " ".join(spec.command)
assert volume["secret"]["optional"] is True
assert volume["secret"]["items"] == [
{"key": "HOST112_ANSIBLE_BECOME_PASSWORD", "path": "password"}
]
assert "test-only-secret-value" not in BROKER_DEPLOYMENT.read_text(
encoding="utf-8"
)
apply_spec = build_ansible_apply_command(
playbook_path="infra/ansible/playbooks/wazuh-alertmanager-integration.yml",
inventory_hosts=("host_112",),
playbook_root=ROOT / "infra" / "ansible",
check_mode_ssh_key_path=tmp_path / "ssh-key",
check_mode_known_hosts_path=tmp_path / "known-hosts",
)
assert apply_spec.env["ANSIBLE_BECOME_PASSWORD_FILE"] == str(password_file)
assert "test-only-secret-value" not in " ".join(apply_spec.command)
unrelated_spec = build_ansible_check_mode_command(
playbook_path="infra/ansible/playbooks/wazuh-manager-posture-readback.yml",
inventory_hosts=("host_112",),
playbook_root=ROOT / "infra" / "ansible",
check_mode_ssh_key_path=tmp_path / "ssh-key",
check_mode_known_hosts_path=tmp_path / "known-hosts",
)
assert "ANSIBLE_BECOME_PASSWORD_FILE" not in unrelated_spec.env
def test_wazuh_ingress_convergence_uses_only_the_mutating_catalog() -> None:
route = resolve_typed_alert_target(
alertname="WazuhAlertmanagerIntegrationConvergence",
target_resource="wazuh-manager",
namespace="awoooi",
labels={"service": "wazuh-manager", "tool": "wazuh"},
)
hints = _catalog_hints(
{
"incident_id": "IWZ-INGRESS-2026071500",
"alertname": "WazuhAlertmanagerIntegrationConvergence",
"alert_category": "security",
"affected_services": ["wazuh-manager", "siem"],
"signals": [
{
"alert_name": "WazuhAlertmanagerIntegrationConvergence",
"labels": {
"service": "wazuh-manager",
"component": "wazuh-manager",
"tool": "wazuh",
},
}
],
},
None,
)
assert route["canonical_asset_id"] == "service:wazuh-manager"
assert route["allowed_catalog_ids"] == [CATALOG_ID]
assert [item["catalog_id"] for item in hints["candidates"]] == [CATALOG_ID]
@pytest.mark.asyncio
async def test_wazuh_ingress_scheduler_records_one_high_risk_controlled_candidate(
monkeypatch: pytest.MonkeyPatch,
) -> None:
from src.jobs import awooop_ansible_candidate_backfill_job as job
class _Mappings:
def first(self):
return None
class _Result:
def mappings(self):
return _Mappings()
class _Db:
async def execute(self, _statement, params):
assert json.loads(params["catalog_match"]) == [
{"catalog_id": CATALOG_ID}
]
return _Result()
@asynccontextmanager
async def fake_db_context(project_id: str):
assert project_id == "awoooi"
yield _Db()
recorder = AsyncMock(return_value=True)
monkeypatch.setattr(job, "get_db_context", fake_db_context)
monkeypatch.setattr(
job.settings,
"ENABLE_IWOOOS_WAZUH_MANAGER_POSTURE_EXECUTOR",
True,
)
monkeypatch.setattr(
job.settings,
"IWOOOS_WAZUH_MANAGER_POSTURE_FRESHNESS_HOURS",
6,
)
monkeypatch.setattr(
job,
"now_taipei",
MagicMock(return_value=datetime.fromisoformat("2026-07-15T05:59:59+08:00")),
)
result = await job.enqueue_iwooos_wazuh_alertmanager_integration_candidate_once(
recorder=recorder,
evidence_collector=AsyncMock(return_value=MagicMock(snapshot_id="wazuh-ingress")),
evidence_verifier=AsyncMock(return_value=True),
)
assert result["status"] == "queued_for_controlled_executor"
assert result["work_item_id"] == "P0-03-WAZUH-ALERT-INGRESS"
recorded = recorder.await_args.kwargs
assert recorded["incident"]["alertname"] == (
"WazuhAlertmanagerIntegrationConvergence"
)
assert recorded["incident"]["incident_id"] == "IWZ-INGRESS-2026071500"
assert len(recorded["incident"]["incident_id"]) <= 30
assert recorded["proposal_data"]["risk_level"] == "high"
assert recorded["proposal_data"]["execution_priority"] == 0
assert recorded["incident"]["source_receipt_ref"] == (
"scheduled-wazuh-alert-ingress:2026071500"
)
write_not_acknowledged = (
await job.enqueue_iwooos_wazuh_alertmanager_integration_candidate_once(
recorder=AsyncMock(return_value=False),
evidence_collector=AsyncMock(
return_value=MagicMock(snapshot_id="wazuh-ingress")
),
evidence_verifier=AsyncMock(return_value=True),
)
)
assert write_not_acknowledged["status"] == "candidate_write_not_acknowledged"
assert write_not_acknowledged["existing"] == 0
assert write_not_acknowledged["active_blockers"] == [
"candidate_write_not_acknowledged"
]
@pytest.mark.asyncio
async def test_wazuh_ingress_scheduler_reports_unresolved_payload_before_recording(
monkeypatch: pytest.MonkeyPatch,
) -> None:
from src.jobs import awooop_ansible_candidate_backfill_job as job
class _Mappings:
def first(self):
return None
class _Result:
def mappings(self):
return _Mappings()
class _Db:
async def execute(self, _statement, _params):
return _Result()
@asynccontextmanager
async def fake_db_context(_project_id: str):
yield _Db()
recorder = AsyncMock(return_value=False)
monkeypatch.setattr(job, "get_db_context", fake_db_context)
monkeypatch.setattr(
job.settings,
"ENABLE_IWOOOS_WAZUH_MANAGER_POSTURE_EXECUTOR",
True,
)
monkeypatch.setattr(
job,
"build_ansible_decision_audit_payload",
MagicMock(return_value=None),
)
result = await job.enqueue_iwooos_wazuh_alertmanager_integration_candidate_once(
recorder=recorder,
evidence_collector=AsyncMock(return_value=MagicMock(snapshot_id="wazuh-ingress")),
evidence_verifier=AsyncMock(return_value=True),
)
assert result["status"] == "blocked_canonical_asset_or_ansible_catalog_unresolved"
assert result["existing"] == 0
assert result["active_blockers"] == [
"canonical_asset_or_ansible_catalog_unresolved"
]
recorder.assert_not_awaited()
def test_wazuh_ingress_scheduler_worker_mounts_canonical_service_registry() -> None:
deployment = yaml.safe_load(WORKER_DEPLOYMENT.read_text(encoding="utf-8"))
pod_spec = deployment["spec"]["template"]["spec"]
container = pod_spec["containers"][0]
mount = next(
item for item in container["volumeMounts"] if item["name"] == "service-registry"
)
volume = next(item for item in pod_spec["volumes"] if item["name"] == "service-registry")
assert mount == {
"name": "service-registry",
"mountPath": "/app/ops/config/service-registry.yaml",
"subPath": "service-registry.yaml",
"readOnly": True,
}
assert volume["configMap"]["name"] == "service-registry"
def test_wazuh_security_event_uses_secops_lifecycle() -> None:
assert classify_alert_early(
"WazuhSecurityEvent_5710",
"critical",
{"tool": "wazuh"},
) == ("secops", "TYPE-5S")