fix(iwooos): expose security runtime gaps truthfully
Some checks failed
CD Pipeline / select-latest-carrier (push) Successful in 58s
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m53s
CD Pipeline / revalidate-deploy-carrier (push) Successful in 38s
CD Pipeline / revalidate-post-deploy-carrier (push) Has been cancelled
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled
Some checks failed
CD Pipeline / select-latest-carrier (push) Successful in 58s
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m53s
CD Pipeline / revalidate-deploy-carrier (push) Successful in 38s
CD Pipeline / revalidate-post-deploy-carrier (push) Has been cancelled
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled
This commit is contained in:
@@ -33,6 +33,104 @@ _WINDOW_HOURS = 24
|
||||
_STRICT_RUNTIME_SCHEMA_VERSION = "ai_agent_strict_runtime_completion_v2"
|
||||
_STRICT_RUNTIME_SOURCE_ID = "autonomous_strict_runtime"
|
||||
|
||||
_WORK_ITEM_ORDER = {
|
||||
"source_health": 0,
|
||||
"asset_discovery": 10,
|
||||
"asset_scope": 20,
|
||||
"asset_ownership": 30,
|
||||
"automation_coverage": 40,
|
||||
"telemetry_detection": 50,
|
||||
"siem_pipeline": 60,
|
||||
"endpoint_xdr_wazuh": 70,
|
||||
"incident_response_soar": 80,
|
||||
"vulnerability_exposure": 90,
|
||||
"identity_zero_trust": 100,
|
||||
"data_secrets_privacy": 110,
|
||||
"backup_dr_resilience": 120,
|
||||
"siem_soc_threat_intel": 130,
|
||||
"security_audit": 140,
|
||||
"ai_security_automation": 150,
|
||||
"supply_chain_policy": 160,
|
||||
"certificate_live_verification": 170,
|
||||
"network_dns_tls": 180,
|
||||
"appsec_api": 190,
|
||||
"asset_relationship": 200,
|
||||
"audit_integrity": 210,
|
||||
}
|
||||
|
||||
_SECURITY_DOMAIN_WORK_ITEMS: tuple[tuple[str, str, str, str, str], ...] = (
|
||||
(
|
||||
"endpoint_xdr_wazuh",
|
||||
"AIA-P0-006-07",
|
||||
"P0",
|
||||
"接通 Wazuh / XDR 全資產 runtime 證據",
|
||||
"把 manager、agent、host、service 與事件 identity 接入資產圖,驗證偵測、隔離候選、postcheck 與復原證據。",
|
||||
),
|
||||
(
|
||||
"incident_response_soar",
|
||||
"AIA-P0-007-02",
|
||||
"P0",
|
||||
"封閉事件應變與 SOAR 處置",
|
||||
"將 open incident 串接 owner、decision、bounded apply、獨立 verifier、rollback 與 durable closure receipt。",
|
||||
),
|
||||
(
|
||||
"vulnerability_exposure",
|
||||
"AIA-P0-006-08",
|
||||
"P0",
|
||||
"接入 CVE 與外部暴露面驗證",
|
||||
"以 SBOM、映像掃描、DAST 與 public exposure verifier 產生可追溯 finding、修復與複驗。",
|
||||
),
|
||||
(
|
||||
"identity_zero_trust",
|
||||
"AIA-P0-006-09",
|
||||
"P0",
|
||||
"建立 IAM 與 Zero Trust runtime 稽核",
|
||||
"盤點人員、服務與 Agent identity,驗證最小權限、存取審查、失效權限與 break-glass 使用紀錄。",
|
||||
),
|
||||
(
|
||||
"data_secrets_privacy",
|
||||
"AIA-P0-006-10",
|
||||
"P0",
|
||||
"建立資料、Secret 與隱私控制證據",
|
||||
"驗證 secret rotation、at-rest/in-transit encryption、敏感資料流與資料保留;不得讀取 secret value。",
|
||||
),
|
||||
(
|
||||
"telemetry_detection",
|
||||
"AIA-P0-006-11",
|
||||
"P0",
|
||||
"補齊全資產監控與偵測覆蓋",
|
||||
"將每項資產綁定 telemetry、alert rule、owner、SLO 與可驗證的失效告警 receipt。",
|
||||
),
|
||||
(
|
||||
"backup_dr_resilience",
|
||||
"AIA-P0-006-12",
|
||||
"P0",
|
||||
"完成備份、還原演練與 DR 證據",
|
||||
"把 backup target、freshness、checksum、restore drill、RPO/RTO 與獨立 verifier 接入資產圖。",
|
||||
),
|
||||
(
|
||||
"siem_soc_threat_intel",
|
||||
"AIA-P0-007-03",
|
||||
"P0",
|
||||
"完成 SIEM / SOC 威脅情報閉環",
|
||||
"將 threat intel、規則命中、case、處置、驗證與 learning receipt 綁在同一事件與同一 run。",
|
||||
),
|
||||
(
|
||||
"network_dns_tls",
|
||||
"AIA-P1-006-13",
|
||||
"P1",
|
||||
"封閉網路、DNS 與 TLS 控制缺口",
|
||||
"對 public route、DNS、certificate chain、expiry 與 network policy 建立持續驗證與受控修復。",
|
||||
),
|
||||
(
|
||||
"appsec_api",
|
||||
"AIA-P1-006-14",
|
||||
"P1",
|
||||
"完成 AppSec、API 與 DAST 證據鏈",
|
||||
"把 SAST、DAST、API contract、dependency finding、修復 commit 與 production verifier 串成同一證據鏈。",
|
||||
),
|
||||
)
|
||||
|
||||
_ASSET_TYPES = (
|
||||
"host",
|
||||
"container",
|
||||
@@ -684,8 +782,10 @@ def _work_item(
|
||||
title: str,
|
||||
gap_count: int,
|
||||
next_action: str,
|
||||
*,
|
||||
gap_percent: int | None = None,
|
||||
) -> dict[str, Any]:
|
||||
return {
|
||||
item = {
|
||||
"work_item_id": work_item_id,
|
||||
"priority": priority,
|
||||
"control_id": control_id,
|
||||
@@ -693,7 +793,11 @@ def _work_item(
|
||||
"gap_count": gap_count,
|
||||
"status": "open",
|
||||
"next_action": next_action,
|
||||
"order": _WORK_ITEM_ORDER.get(control_id, 999),
|
||||
}
|
||||
if gap_percent is not None:
|
||||
item["gap_percent"] = max(0, min(100, gap_percent))
|
||||
return item
|
||||
|
||||
|
||||
def _strict_runtime_completion_projection(row: Any) -> dict[str, Any]:
|
||||
@@ -1283,7 +1387,38 @@ def build_iwooos_security_asset_control_plane(
|
||||
)
|
||||
)
|
||||
|
||||
work_items.sort(key=lambda item: (item["priority"], item["work_item_id"]))
|
||||
domain_by_id = {
|
||||
str(domain["domain_id"]): domain for domain in security_program_domains
|
||||
}
|
||||
active_control_ids = {str(item["control_id"]) for item in work_items}
|
||||
for (
|
||||
domain_id,
|
||||
work_item_id,
|
||||
priority,
|
||||
title,
|
||||
next_action,
|
||||
) in _SECURITY_DOMAIN_WORK_ITEMS:
|
||||
domain = domain_by_id.get(domain_id)
|
||||
if not domain or int(domain.get("controlled_percent", 0)) >= 100:
|
||||
continue
|
||||
if domain_id in active_control_ids:
|
||||
continue
|
||||
work_items.append(
|
||||
_work_item(
|
||||
work_item_id,
|
||||
priority,
|
||||
domain_id,
|
||||
title,
|
||||
1,
|
||||
next_action,
|
||||
gap_percent=max(0, 100 - int(domain.get("controlled_percent", 0))),
|
||||
)
|
||||
)
|
||||
active_control_ids.add(domain_id)
|
||||
|
||||
work_items.sort(
|
||||
key=lambda item: (item["priority"], item["order"], item["work_item_id"])
|
||||
)
|
||||
overall_control_percent = round(
|
||||
sum(function["controlled_percent"] for function in control_functions)
|
||||
/ len(control_functions)
|
||||
@@ -1829,8 +1964,7 @@ async def _read_strict_runtime_source() -> tuple[dict[str, Any], dict[str, Any]]
|
||||
readback
|
||||
)
|
||||
if (
|
||||
strict_runtime.get("schema_version")
|
||||
!= _STRICT_RUNTIME_SCHEMA_VERSION
|
||||
strict_runtime.get("schema_version") != _STRICT_RUNTIME_SCHEMA_VERSION
|
||||
or strict_runtime.get("runtime_contract_schema_version")
|
||||
!= AI_AUTOMATION_RUNTIME_CONTRACT_SCHEMA_VERSION
|
||||
):
|
||||
@@ -2056,21 +2190,45 @@ class IwoooSSecurityAssetControlPlaneService:
|
||||
source_id="security_compliance",
|
||||
statement=_sql(
|
||||
"""
|
||||
WITH recent AS MATERIALIZED (
|
||||
SELECT snapshot_id, asset_id, dimension, status, detected_at
|
||||
FROM asset_compliance_snapshot
|
||||
ORDER BY snapshot_id DESC
|
||||
LIMIT 100000
|
||||
), latest AS (
|
||||
SELECT DISTINCT ON (asset_id, dimension)
|
||||
asset_id, dimension, status
|
||||
FROM recent
|
||||
ORDER BY asset_id, dimension, detected_at DESC
|
||||
WITH dimensions(dimension) AS (
|
||||
SELECT unnest(ARRAY[
|
||||
'ssl_cert_valid', 'cve_scan', 'secret_rotated',
|
||||
'backup_tested', 'audit_log_enabled',
|
||||
'access_reviewed', 'encryption_at_rest'
|
||||
]::text[])
|
||||
)
|
||||
SELECT dimension, status, count(*) AS cnt
|
||||
FROM latest
|
||||
GROUP BY dimension, status
|
||||
ORDER BY dimension, status
|
||||
SELECT
|
||||
dimensions.dimension,
|
||||
CASE
|
||||
WHEN latest.detected_at IS NULL
|
||||
OR latest.detected_at < NOW() - INTERVAL '36 hours'
|
||||
THEN 'unknown'
|
||||
ELSE latest.status
|
||||
END AS status,
|
||||
count(*) AS cnt
|
||||
FROM asset_inventory asset
|
||||
CROSS JOIN dimensions
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT snapshot.status, snapshot.detected_at
|
||||
FROM asset_compliance_snapshot snapshot
|
||||
WHERE snapshot.asset_id = asset.asset_id
|
||||
AND snapshot.dimension = dimensions.dimension
|
||||
ORDER BY snapshot.detected_at DESC, snapshot.snapshot_id DESC
|
||||
LIMIT 1
|
||||
) latest ON true
|
||||
WHERE asset.lifecycle_state = 'active'
|
||||
GROUP BY dimensions.dimension, CASE
|
||||
WHEN latest.detected_at IS NULL
|
||||
OR latest.detected_at < NOW() - INTERVAL '36 hours'
|
||||
THEN 'unknown'
|
||||
ELSE latest.status
|
||||
END
|
||||
ORDER BY dimensions.dimension, CASE
|
||||
WHEN latest.detected_at IS NULL
|
||||
OR latest.detected_at < NOW() - INTERVAL '36 hours'
|
||||
THEN 'unknown'
|
||||
ELSE latest.status
|
||||
END
|
||||
"""
|
||||
),
|
||||
result_mode="all",
|
||||
@@ -2225,30 +2383,36 @@ class IwoooSSecurityAssetControlPlaneService:
|
||||
source_id="audit_runtime",
|
||||
statement=_sql(
|
||||
"""
|
||||
WITH k8s AS (
|
||||
SELECT
|
||||
count(*) AS total,
|
||||
count(*) FILTER (WHERE success IS FALSE) AS failed
|
||||
FROM audit_logs
|
||||
WHERE project_id = 'awoooi'
|
||||
AND created_at >= NOW() - INTERVAL '24 hours'
|
||||
), mcp AS (
|
||||
SELECT
|
||||
count(*) AS total,
|
||||
count(*) FILTER (WHERE success IS FALSE) AS failed
|
||||
FROM mcp_audit_log
|
||||
WHERE created_at >= NOW() - INTERVAL '24 hours'
|
||||
), asset_changes AS (
|
||||
SELECT
|
||||
count(*) AS total,
|
||||
count(*) FILTER (WHERE ai_analysis IS NOT NULL) AS analyzed
|
||||
FROM asset_change_event
|
||||
WHERE detected_at >= NOW() - INTERVAL '24 hours'
|
||||
)
|
||||
SELECT
|
||||
(SELECT count(*) FROM audit_logs
|
||||
WHERE project_id = 'awoooi'
|
||||
AND created_at >= NOW() - INTERVAL '24 hours')
|
||||
AS k8s_audit_count_24h,
|
||||
(SELECT count(*) FROM audit_logs
|
||||
WHERE project_id = 'awoooi'
|
||||
AND created_at >= NOW() - INTERVAL '24 hours'
|
||||
AND success IS FALSE)
|
||||
AS k8s_audit_failure_count_24h,
|
||||
(SELECT count(*) FROM mcp_audit_log
|
||||
WHERE created_at >= NOW() - INTERVAL '24 hours')
|
||||
AS mcp_audit_count_24h,
|
||||
(SELECT count(*) FROM mcp_audit_log
|
||||
WHERE created_at >= NOW() - INTERVAL '24 hours'
|
||||
AND success IS FALSE)
|
||||
AS mcp_audit_failure_count_24h,
|
||||
(SELECT count(*) FROM asset_change_event
|
||||
WHERE detected_at >= NOW() - INTERVAL '24 hours')
|
||||
AS asset_change_count_24h,
|
||||
(SELECT count(*) FROM asset_change_event
|
||||
WHERE detected_at >= NOW() - INTERVAL '24 hours'
|
||||
AND ai_analysis IS NOT NULL)
|
||||
AS asset_change_ai_analysis_count_24h
|
||||
k8s.total AS k8s_audit_count_24h,
|
||||
k8s.failed AS k8s_audit_failure_count_24h,
|
||||
mcp.total AS mcp_audit_count_24h,
|
||||
mcp.failed AS mcp_audit_failure_count_24h,
|
||||
asset_changes.total AS asset_change_count_24h,
|
||||
asset_changes.analyzed AS asset_change_ai_analysis_count_24h
|
||||
FROM k8s
|
||||
CROSS JOIN mcp
|
||||
CROSS JOIN asset_changes
|
||||
"""
|
||||
),
|
||||
result_mode="one",
|
||||
|
||||
@@ -71,6 +71,8 @@ def _ready_payload(
|
||||
*,
|
||||
discovery_status: str = "success",
|
||||
discovery_error: str | None = None,
|
||||
coverage_rows: list[SimpleNamespace] | None = None,
|
||||
compliance_rows: list[SimpleNamespace] | None = None,
|
||||
automation_rows: list[SimpleNamespace] | None = None,
|
||||
runtime_receipt_counts: dict[str, int] | None = None,
|
||||
strict_runtime: dict | None = None,
|
||||
@@ -98,30 +100,38 @@ def _ready_payload(
|
||||
_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",
|
||||
)
|
||||
]
|
||||
coverage = (
|
||||
coverage_rows
|
||||
if coverage_rows is not None
|
||||
else [
|
||||
_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 = (
|
||||
compliance_rows
|
||||
if compliance_rows is not None
|
||||
else [
|
||||
_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 = (
|
||||
automation_rows
|
||||
if automation_rows is not None
|
||||
@@ -226,6 +236,11 @@ def test_builds_live_asset_siem_audit_and_ai_control_plane_without_false_closure
|
||||
}
|
||||
assert domain_by_id["endpoint_xdr_wazuh"]["status"] == "not_evidenced"
|
||||
assert domain_by_id["siem_soc_threat_intel"]["controlled_percent"] == 50
|
||||
work_item_by_control = {item["control_id"]: item for item in payload["work_items"]}
|
||||
assert work_item_by_control["endpoint_xdr_wazuh"]["priority"] == "P0"
|
||||
assert work_item_by_control["endpoint_xdr_wazuh"]["gap_count"] == 1
|
||||
assert work_item_by_control["endpoint_xdr_wazuh"]["gap_percent"] == 100
|
||||
assert payload["work_items"][0]["order"] <= payload["work_items"][1]["order"]
|
||||
assert len(payload["siem"]["pipeline"]) == 8
|
||||
assert payload["security_audit"]["mcp_tool_audit_count_24h"] == 11
|
||||
assert payload["summary"]["package_digest_unpinned_count"] == 0
|
||||
@@ -256,6 +271,36 @@ def test_builds_live_asset_siem_audit_and_ai_control_plane_without_false_closure
|
||||
assert 'secret_value_collection_allowed": true' not in public_text.lower()
|
||||
|
||||
|
||||
def test_uncovered_security_domains_are_explicit_ordered_p0_work_items() -> None:
|
||||
payload = _ready_payload(coverage_rows=[], compliance_rows=[])
|
||||
|
||||
work_item_by_control = {item["control_id"]: item for item in payload["work_items"]}
|
||||
for control_id in (
|
||||
"endpoint_xdr_wazuh",
|
||||
"incident_response_soar",
|
||||
"identity_zero_trust",
|
||||
"data_secrets_privacy",
|
||||
"vulnerability_exposure",
|
||||
"telemetry_detection",
|
||||
"backup_dr_resilience",
|
||||
"siem_soc_threat_intel",
|
||||
):
|
||||
assert work_item_by_control[control_id]["priority"] == "P0"
|
||||
|
||||
p0_orders = [
|
||||
item["order"] for item in payload["work_items"] if item["priority"] == "P0"
|
||||
]
|
||||
assert p0_orders == sorted(p0_orders)
|
||||
assert all(item["order"] < 999 for item in payload["work_items"])
|
||||
assert [item["control_id"] for item in payload["work_items"][:5]] == [
|
||||
"asset_scope",
|
||||
"asset_ownership",
|
||||
"automation_coverage",
|
||||
"telemetry_detection",
|
||||
"endpoint_xdr_wazuh",
|
||||
]
|
||||
|
||||
|
||||
def test_projects_canonical_runtime_receipts_without_false_same_run_closure() -> None:
|
||||
payload = _ready_payload(
|
||||
automation_rows=[
|
||||
@@ -318,8 +363,7 @@ def test_projects_exact_authoritative_same_run_runtime_closure() -> None:
|
||||
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"]
|
||||
item["work_item_id"] != "AIA-P0-008-01" for item in payload["work_items"]
|
||||
)
|
||||
assert payload["completion"]["overall_percent"] == round(
|
||||
sum(
|
||||
@@ -372,8 +416,7 @@ def test_strict_runtime_projection_fails_closed_on_contract_or_receipt_drift() -
|
||||
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"]
|
||||
item["work_item_id"] == "AIA-P0-008-01" for item in payload["work_items"]
|
||||
)
|
||||
|
||||
|
||||
@@ -886,8 +929,14 @@ def test_service_bounds_source_concurrency_for_database_budget(monkeypatch) -> N
|
||||
for statement in statements
|
||||
if "asset_compliance_snapshot" in statement
|
||||
)
|
||||
assert "ORDER BY snapshot_id DESC" in compliance_query
|
||||
assert "LIMIT 100000" in compliance_query
|
||||
assert "CROSS JOIN dimensions" in compliance_query
|
||||
assert "LEFT JOIN LATERAL" in compliance_query
|
||||
assert (
|
||||
"ORDER BY snapshot.detected_at DESC, snapshot.snapshot_id DESC"
|
||||
in compliance_query
|
||||
)
|
||||
assert "latest.detected_at < NOW() - INTERVAL '36 hours'" in compliance_query
|
||||
assert "THEN 'unknown'" in compliance_query
|
||||
inventory_query = next(
|
||||
statement for statement in statements if "FROM asset_inventory" in statement
|
||||
)
|
||||
@@ -908,6 +957,12 @@ def test_service_bounds_source_concurrency_for_database_budget(monkeypatch) -> N
|
||||
assert "executor_returncode_trusted" in siem_query
|
||||
assert "learning_writeback_count_24h" in siem_query
|
||||
assert "ansible_learning_writeback_recorded" in siem_query
|
||||
audit_query = next(
|
||||
statement for statement in statements if "WITH k8s AS" in statement
|
||||
)
|
||||
assert "count(*) FILTER (WHERE success IS FALSE)" in audit_query
|
||||
assert "CROSS JOIN mcp" in audit_query
|
||||
assert "CROSS JOIN asset_changes" in audit_query
|
||||
assert "repository_readback_verified" in siem_query
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user