Files
awoooi/apps/api/tests/test_iwooos_security_asset_control_plane.py
ogt f00217593a
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 2m34s
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled
fix(iwooos): bound security source concurrency
2026-07-11 20:29:49 +08:00

409 lines
14 KiB
Python

from __future__ import annotations
# ruff: noqa: E402, I001
import asyncio
import json
import os
from datetime import UTC, datetime, timedelta
from types import SimpleNamespace
os.environ.setdefault("DATABASE_URL", "postgresql+asyncpg://test:test@localhost/test")
from fastapi import FastAPI
from fastapi.testclient import TestClient
from src.api.v1.iwooos import router
from src.services.iwooos_security_asset_control_plane import (
IwoooSSecurityAssetControlPlaneService,
_read_public_source,
build_iwooos_security_asset_control_plane,
build_unavailable_iwooos_security_asset_control_plane,
)
def _row(**values):
return SimpleNamespace(**values)
def _ready_payload(source_health: list[dict] | None = None) -> dict:
now = datetime(2026, 7, 11, 4, 0, tzinfo=UTC)
discovery = _row(
latest_status="success",
latest_scan_depth="full",
latest_started_at=now - timedelta(minutes=31),
latest_ended_at=now - timedelta(minutes=30),
latest_success_ended_at=now - timedelta(minutes=30),
latest_total_assets=24,
latest_new_assets=2,
latest_modified_assets=1,
latest_disappeared_assets=0,
)
inventory = [
_row(asset_type="host", cnt=3, unowned_count=1, stale_count=0),
_row(asset_type="k8s_workload", cnt=5, unowned_count=0, stale_count=1),
_row(asset_type="website", cnt=2, unowned_count=0, stale_count=0),
_row(asset_type="api_endpoint", cnt=4, unowned_count=0, stale_count=0),
_row(asset_type="database", cnt=2, unowned_count=0, stale_count=0),
_row(asset_type="log_stream", cnt=4, unowned_count=0, stale_count=0),
_row(asset_type="monitoring_target", cnt=3, unowned_count=0, stale_count=0),
_row(asset_type="ai_agent", cnt=1, unowned_count=0, stale_count=0),
]
coverage = [
_row(dimension=dimension, status="green", cnt=20)
for dimension in (
"auto_monitoring",
"auto_alerting",
"auto_rule_creation",
"auto_rule_matching",
"auto_playbook",
"auto_remediation",
"auto_km_creation",
)
]
compliance = [
_row(dimension=dimension, status="compliant", cnt=20)
for dimension in (
"ssl_cert_valid",
"cve_scan",
"secret_rotated",
"backup_tested",
"audit_log_enabled",
"access_reviewed",
"encryption_at_rest",
)
]
automation = [
_row(operation_type="asset_discovered", status="success", cnt=1),
_row(operation_type="rule_matched", status="success", cnt=3),
_row(operation_type="rule_created", status="success", cnt=2),
_row(operation_type="ansible_check_mode_executed", status="dry_run", cnt=2),
_row(operation_type="ansible_apply_executed", status="success", cnt=1),
_row(operation_type="remediation_verified", status="success", cnt=1),
_row(operation_type="km_created", status="success", cnt=1),
_row(operation_type="ansible_apply_executed", status="failed", cnt=1),
]
return build_iwooos_security_asset_control_plane(
discovery_row=discovery,
inventory_rows=inventory,
coverage_rows=coverage,
relationship_row=_row(relationship_count=21, orphan_asset_count=3),
compliance_rows=compliance,
automation_rows=automation,
ai_trace_row=_row(trace_count=4, accepted_trace_count=3),
siem_row=_row(
rule_total=12,
approved_rule_count=10,
fired_rule_count=8,
noisy_rule_count=1,
ai_generated_rule_count=3,
incident_total_24h=5,
open_incident_count_24h=2,
resolved_incident_count_24h=3,
decision_chain_count_24h=5,
normalized_event_count_24h=18,
mttr_minutes_24h=14.25,
),
audit_row=_row(
k8s_audit_count_24h=2,
k8s_audit_failure_count_24h=0,
mcp_audit_count_24h=11,
mcp_audit_failure_count_24h=1,
asset_change_count_24h=4,
asset_change_ai_analysis_count_24h=3,
),
source_health=source_health,
generated_at=now,
)
def test_builds_live_asset_siem_audit_and_ai_control_plane_without_false_closure() -> (
None
):
payload = _ready_payload()
assert payload["schema_version"] == "iwooos_security_asset_control_plane_v1"
assert payload["status"] == "ready"
assert payload["source_status"] == "live_database_aggregate"
assert payload["summary"]["managed_asset_count"] == 24
assert payload["summary"]["present_asset_type_count"] == 8
assert payload["summary"]["siem_stage_coverage_percent"] == 100
assert payload["summary"]["ai_loop_stage_coverage_percent"] == 100
assert payload["summary"]["verified_remediation_receipt_count_24h"] == 1
assert payload["discovery"]["fresh"] is True
assert payload["ai_automation"]["same_run_closed_loop_proven"] is False
assert payload["ai_automation"]["same_run_closed_loop_count"] == 0
assert len(payload["nist_csf_functions"]) == 6
assert payload["summary"]["security_program_domain_count"] == 16
assert len(payload["security_program_domains"]) == 16
domain_by_id = {
domain["domain_id"]: domain for domain in payload["security_program_domains"]
}
assert domain_by_id["endpoint_xdr_wazuh"]["status"] == "not_evidenced"
assert domain_by_id["siem_soc_threat_intel"]["controlled_percent"] == 50
assert len(payload["siem"]["pipeline"]) == 8
assert payload["security_audit"]["mcp_tool_audit_count_24h"] == 11
assert any(
item["work_item_id"] == "AIA-P0-006-02" for item in payload["work_items"]
)
assert any(
item["work_item_id"] == "AIA-P1-001-01" for item in payload["work_items"]
)
public_text = json.dumps(payload, ensure_ascii=False)
assert "192.168." not in public_text
assert "postgresql://" not in public_text
assert "target_resource" not in public_text
assert '"event_payload":' not in public_text
assert 'secret_value_collection_allowed": true' not in public_text.lower()
def test_unknown_coverage_and_compliance_create_p0_work_items() -> None:
now = datetime(2026, 7, 11, 4, 0, tzinfo=UTC)
payload = build_iwooos_security_asset_control_plane(
discovery_row=_row(
latest_status="success",
latest_scan_depth="shallow",
latest_started_at=now - timedelta(minutes=10),
latest_ended_at=now - timedelta(minutes=9),
latest_success_ended_at=now - timedelta(minutes=9),
latest_total_assets=1,
),
inventory_rows=[
_row(asset_type="host", cnt=1, unowned_count=1, stale_count=0),
],
coverage_rows=[
_row(dimension="auto_monitoring", status="unknown", cnt=1),
],
relationship_row=_row(relationship_count=0, orphan_asset_count=1),
compliance_rows=[
_row(dimension="cve_scan", status="unknown", cnt=1),
],
automation_rows=[],
ai_trace_row=_row(trace_count=0, accepted_trace_count=0),
siem_row=_row(),
audit_row=_row(),
generated_at=now,
)
assert payload["summary"]["automation_coverage_green_percent"] == 0
assert payload["summary"]["automation_coverage_unknown_count"] == 1
assert payload["summary"]["compliance_unknown_count"] == 1
assert payload["summary"]["siem_observed_stage_count"] == 0
assert payload["summary"]["ai_loop_observed_stage_count"] == 0
work_item_ids = {item["work_item_id"] for item in payload["work_items"]}
assert {
"AIA-P0-006-02",
"AIA-P0-006-03",
"AIA-P0-006-04",
"AIA-P0-006-05",
"AIA-P0-006-06",
"AIA-P0-007-01",
"AIA-P0-008-01",
} <= work_item_ids
def test_partial_source_failure_is_visible_without_erasing_core_inventory() -> None:
source_health = [
{"source_id": "asset_discovery", "status": "ready", "reason_code": None},
{"source_id": "asset_inventory", "status": "ready", "reason_code": None},
{
"source_id": "audit_runtime",
"status": "unavailable",
"reason_code": "audit_runtime_query_failed",
},
]
payload = _ready_payload(source_health)
assert payload["status"] == "degraded"
assert payload["source_status"] == "live_database_partial"
assert payload["summary"]["managed_asset_count"] == 24
assert payload["summary"]["ready_source_count"] == 2
assert payload["summary"]["unavailable_source_count"] == 1
assert payload["source_health"] == source_health
assert payload["work_items"][0]["work_item_id"] == "AIA-P0-006-00"
def test_read_public_source_returns_redacted_reason_code_on_query_failure(
monkeypatch,
) -> None:
class FailingDb:
async def execute(self, statement):
raise RuntimeError("private table detail")
class DbContext:
async def __aenter__(self):
return FailingDb()
async def __aexit__(self, exc_type, exc, traceback):
return False
monkeypatch.setattr(
"src.services.iwooos_security_asset_control_plane.get_db_context",
lambda project_id: DbContext(),
)
value, health = asyncio.run(
_read_public_source(
project_id="awoooi",
limiter=asyncio.Semaphore(1),
source_id="audit_runtime",
statement="SELECT 1",
result_mode="one",
default={},
)
)
assert value == {}
assert health == {
"source_id": "audit_runtime",
"status": "unavailable",
"reason_code": "audit_runtime_query_failed",
}
def test_unavailable_payload_is_fixed_degraded_contract_without_raw_error() -> None:
payload = build_unavailable_iwooos_security_asset_control_plane(
"database_query_failed"
)
assert payload["status"] == "degraded"
assert payload["source_status"] == "live_database_unavailable"
assert payload["reason_code"] == "database_query_failed"
assert payload["summary"]["managed_asset_count"] == 0
assert payload["discovery"]["fresh"] is False
assert payload["boundaries"]["raw_asset_identity_returned"] is False
assert payload["boundaries"]["raw_event_payload_returned"] is False
def test_service_redacts_database_exception_details(monkeypatch) -> None:
service = IwoooSSecurityAssetControlPlaneService()
async def fail_load():
raise RuntimeError("postgresql://operator:raw-secret@private-host/runtime")
monkeypatch.setattr(service, "_load_snapshot", fail_load)
payload = asyncio.run(service.get_snapshot())
text = json.dumps(payload)
assert payload["reason_code"] == "database_query_failed"
assert "raw-secret" not in text
assert "private-host" not in text
def test_service_reuses_short_lived_public_aggregate_cache(monkeypatch) -> None:
service = IwoooSSecurityAssetControlPlaneService()
calls = 0
expected = _ready_payload()
async def load_once():
nonlocal calls
calls += 1
return expected
monkeypatch.setattr(service, "_load_snapshot", load_once)
async def read_twice():
first = await service.get_snapshot()
second = await service.get_snapshot()
return first, second
first, second = asyncio.run(read_twice())
assert calls == 1
assert first is expected
assert second is expected
def test_service_uses_canonical_awoooi_project_scope(monkeypatch) -> None:
service = IwoooSSecurityAssetControlPlaneService()
requested_projects: list[str] = []
class FailingContext:
async def __aenter__(self):
raise RuntimeError("stop after project scope capture")
async def __aexit__(self, exc_type, exc, traceback):
return False
def fake_db_context(project_id: str):
requested_projects.append(project_id)
return FailingContext()
monkeypatch.setattr(
"src.services.iwooos_security_asset_control_plane.get_db_context",
fake_db_context,
)
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
def test_service_bounds_source_concurrency_for_database_budget(monkeypatch) -> None:
service = IwoooSSecurityAssetControlPlaneService()
concurrency = {"active": 0, "maximum": 0}
class EmptyResult:
def fetchall(self):
return []
def one(self):
return {}
def one_or_none(self):
return None
class SlowDb:
async def execute(self, statement):
concurrency["active"] += 1
concurrency["maximum"] = max(concurrency["maximum"], concurrency["active"])
await asyncio.sleep(0.02)
concurrency["active"] -= 1
return EmptyResult()
class DbContext:
async def __aenter__(self):
return SlowDb()
async def __aexit__(self, exc_type, exc, traceback):
return False
monkeypatch.setattr(
"src.services.iwooos_security_asset_control_plane.get_db_context",
lambda project_id: DbContext(),
)
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"]["unavailable_source_count"] == 0
def test_public_api_returns_live_aggregate(monkeypatch) -> None:
payload = _ready_payload()
class FakeService:
async def get_snapshot(self):
return payload
monkeypatch.setattr(
"src.api.v1.iwooos.get_iwooos_security_asset_control_plane_service",
lambda: FakeService(),
)
app = FastAPI()
app.include_router(router)
response = TestClient(app).get("/api/v1/iwooos/security-asset-control-plane")
assert response.status_code == 200
data = response.json()
assert data["schema_version"] == "iwooos_security_asset_control_plane_v1"
assert data["summary"]["managed_asset_count"] == 24
assert data["summary"]["siem_stage_coverage_percent"] == 100
assert data["ai_automation"]["same_run_closed_loop_proven"] is False
assert "192.168." not in response.text
assert "raw-secret" not in response.text