feat(iwooos): codify full security framework

This commit is contained in:
ogt
2026-07-11 19:52:54 +08:00
parent da508b89f1
commit a21567c991
5 changed files with 313 additions and 1 deletions

View File

@@ -349,6 +349,191 @@ def _build_control_functions(
]
def _build_security_program_domains(
*,
by_type: dict[str, int],
asset_scopes: list[dict[str, Any]],
coverage: list[dict[str, Any]],
compliance: list[dict[str, Any]],
control_functions: list[dict[str, Any]],
siem_stage_percent: int,
siem_evidence_count: int,
ai_stage_percent: int,
ai_evidence_count: int,
audit_evidence_count: int,
) -> list[dict[str, Any]]:
scope_by_id = {row["scope_id"]: row for row in asset_scopes}
function_by_id = {row["function_id"]: row for row in control_functions}
compliance_by_id = {row["dimension"]: row for row in compliance}
def function_percent(function_id: str) -> int:
return int(function_by_id.get(function_id, {}).get("controlled_percent", 0))
def scope_percent(scope_id: str) -> int:
return int(scope_by_id.get(scope_id, {}).get("type_coverage_percent", 0))
def scope_assets(scope_id: str) -> int:
return int(scope_by_id.get(scope_id, {}).get("managed_asset_count", 0))
def compliance_percent(dimension: str) -> int:
return int(compliance_by_id.get(dimension, {}).get("compliant_percent", 0))
def compliance_total(dimension: str) -> int:
return int(compliance_by_id.get(dimension, {}).get("total", 0))
def average(*values: int) -> int:
return round(sum(values) / len(values)) if values else 0
domain_values = (
(
"governance_risk",
"治理、風險與責任",
function_percent("govern"),
sum(by_type.values()),
"asset_owner_or_policy_evidence_missing",
),
(
"asset_attack_surface",
"資產與攻擊面",
function_percent("identify"),
sum(by_type.values()),
"asset_identity_or_relationship_gap",
),
(
"identity_zero_trust",
"IAM 與 Zero Trust",
compliance_percent("access_reviewed"),
compliance_total("access_reviewed"),
"access_review_runtime_evidence_missing",
),
(
"data_secrets_privacy",
"資料、Secret 與隱私",
average(
compliance_percent("secret_rotated"),
compliance_percent("encryption_at_rest"),
),
compliance_total("secret_rotated") + compliance_total("encryption_at_rest"),
"secret_rotation_or_encryption_evidence_missing",
),
(
"vulnerability_exposure",
"漏洞與暴露面",
average(
compliance_percent("cve_scan"),
compliance_percent("ssl_cert_valid"),
),
compliance_total("cve_scan") + compliance_total("ssl_cert_valid"),
"cve_or_external_exposure_verifier_missing",
),
(
"endpoint_xdr_wazuh",
"端點、XDR 與 Wazuh",
0,
0,
"wazuh_runtime_identity_not_joined_to_asset_graph",
),
(
"network_dns_tls",
"網路、DNS 與 TLS",
average(
100 if by_type.get("network", 0) > 0 else 0,
100 if by_type.get("certificate", 0) > 0 else 0,
compliance_percent("ssl_cert_valid"),
),
by_type.get("network", 0)
+ by_type.get("certificate", 0)
+ compliance_total("ssl_cert_valid"),
"network_dns_tls_runtime_evidence_missing",
),
(
"cloud_container_k8s",
"容器、K8s 與執行環境",
scope_percent("infrastructure"),
scope_assets("infrastructure"),
"infrastructure_scope_or_policy_evidence_missing",
),
(
"appsec_api",
"AppSec、API 與 DAST",
average(
scope_percent("products"),
compliance_percent("cve_scan"),
compliance_percent("ssl_cert_valid"),
),
scope_assets("products") + compliance_total("cve_scan"),
"appsec_sast_dast_api_evidence_missing",
),
(
"software_supply_chain",
"軟體供應鏈與 SBOM",
average(
scope_percent("supply_chain"),
compliance_percent("cve_scan"),
),
scope_assets("supply_chain") + compliance_total("cve_scan"),
"sbom_signature_dependency_evidence_missing",
),
(
"telemetry_detection",
"遙測、偵測與可觀測性",
function_percent("detect"),
by_type.get("log_stream", 0) + by_type.get("monitoring_target", 0),
"telemetry_or_detection_coverage_missing",
),
(
"siem_soc_threat_intel",
"SIEM、SOC 與威脅情報",
average(siem_stage_percent, 0),
siem_evidence_count,
"siem_stage_or_threat_intelligence_evidence_missing",
),
(
"incident_response_soar",
"事故應變、SOAR 與鑑識",
average(function_percent("respond"), function_percent("recover")),
siem_evidence_count,
"case_response_verifier_or_forensic_evidence_missing",
),
(
"backup_dr_resilience",
"備份、DR 與韌性",
compliance_percent("backup_tested"),
by_type.get("backup_target", 0) + compliance_total("backup_tested"),
"backup_restore_drill_evidence_missing",
),
(
"ai_security_automation",
"AI 安全與 Agent 自動化",
ai_stage_percent,
ai_evidence_count,
"same_run_ai_security_closure_missing",
),
(
"compliance_audit",
"合規、稽核與證據保存",
average(
compliance_percent("audit_log_enabled"),
100 if audit_evidence_count > 0 else 0,
),
audit_evidence_count + compliance_total("audit_log_enabled"),
"audit_control_or_immutable_retention_evidence_missing",
),
)
return [
{
"domain_id": domain_id,
"label": label,
"controlled_percent": percent,
"status": _status_for_percent(percent, has_evidence=evidence_count > 0),
"evidence_count": evidence_count,
"gap_code": None if percent >= 100 else gap_code,
}
for domain_id, label, percent, evidence_count, gap_code in domain_values
]
def _build_siem_pipeline(
*,
by_type: dict[str, int],
@@ -628,6 +813,23 @@ def build_iwooos_security_asset_control_plane(
"immutable_external_audit_store_evidenced": False,
}
security_program_domains = _build_security_program_domains(
by_type=by_type,
asset_scopes=asset_scopes,
coverage=coverage,
compliance=compliance,
control_functions=control_functions,
siem_stage_percent=_percent(siem_observed_stages, len(_SIEM_STAGES)),
siem_evidence_count=siem_observed_stages + siem["incident_total_24h"],
ai_stage_percent=_percent(observed_automation_stages, len(_AI_LOOP_STAGES)),
ai_evidence_count=accepted_ai_trace_count + verified_receipts,
audit_evidence_count=(
audit["k8s_execution_audit_count_24h"]
+ audit["mcp_tool_audit_count_24h"]
+ audit["automation_operation_count_24h"]
),
)
work_items: list[dict[str, Any]] = []
if asset_total == 0 or not discovery_fresh:
work_items.append(
@@ -737,6 +939,10 @@ def build_iwooos_security_asset_control_plane(
sum(function["controlled_percent"] for function in control_functions)
/ len(control_functions)
)
security_program_percent = round(
sum(domain["controlled_percent"] for domain in security_program_domains)
/ len(security_program_domains)
)
return {
"schema_version": _SCHEMA_VERSION,
@@ -763,6 +969,13 @@ def build_iwooos_security_asset_control_plane(
"compliance_violation_count": compliance_violations,
"compliance_unknown_count": compliance_unknown,
"nist_controlled_percent": overall_control_percent,
"security_program_domain_count": len(security_program_domains),
"security_program_controlled_domain_count": sum(
1
for domain in security_program_domains
if domain["status"] == "controlled"
),
"security_program_controlled_percent": security_program_percent,
"siem_stage_count": len(_SIEM_STAGES),
"siem_observed_stage_count": siem_observed_stages,
"siem_stage_coverage_percent": _percent(
@@ -781,6 +994,7 @@ def build_iwooos_security_asset_control_plane(
"coverage_dimensions": coverage,
"compliance_dimensions": compliance,
"nist_csf_functions": control_functions,
"security_program_domains": security_program_domains,
"siem": {**siem, "pipeline": siem_pipeline},
"ai_automation": {
"window_hours": _WINDOW_HOURS,
@@ -836,6 +1050,9 @@ def build_unavailable_iwooos_security_asset_control_plane(
"compliance_violation_count": 0,
"compliance_unknown_count": 0,
"nist_controlled_percent": 0,
"security_program_domain_count": 16,
"security_program_controlled_domain_count": 0,
"security_program_controlled_percent": 0,
"siem_stage_count": len(_SIEM_STAGES),
"siem_observed_stage_count": 0,
"siem_stage_coverage_percent": 0,
@@ -890,6 +1107,34 @@ def build_unavailable_iwooos_security_asset_control_plane(
("recover", "復原"),
)
],
"security_program_domains": [
{
"domain_id": domain_id,
"label": label,
"controlled_percent": 0,
"status": "not_evidenced",
"evidence_count": 0,
"gap_code": "live_database_unavailable",
}
for domain_id, label in (
("governance_risk", "治理、風險與責任"),
("asset_attack_surface", "資產與攻擊面"),
("identity_zero_trust", "IAM 與 Zero Trust"),
("data_secrets_privacy", "資料、Secret 與隱私"),
("vulnerability_exposure", "漏洞與暴露面"),
("endpoint_xdr_wazuh", "端點、XDR 與 Wazuh"),
("network_dns_tls", "網路、DNS 與 TLS"),
("cloud_container_k8s", "容器、K8s 與執行環境"),
("appsec_api", "AppSec、API 與 DAST"),
("software_supply_chain", "軟體供應鏈與 SBOM"),
("telemetry_detection", "遙測、偵測與可觀測性"),
("siem_soc_threat_intel", "SIEM、SOC 與威脅情報"),
("incident_response_soar", "事故應變、SOAR 與鑑識"),
("backup_dr_resilience", "備份、DR 與韌性"),
("ai_security_automation", "AI 安全與 Agent 自動化"),
("compliance_audit", "合規、稽核與證據保存"),
)
],
"siem": {
"pipeline": [
{

View File

@@ -132,6 +132,13 @@ def test_builds_live_asset_siem_audit_and_ai_control_plane_without_false_closure
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(

View File

@@ -34,6 +34,7 @@ type Copy = {
aiLoop: string;
verified: string;
functions: string;
framework: string;
siemFlow: string;
aiFlow: string;
scope: string;
@@ -57,6 +58,7 @@ const COPY: Record<"zh" | "en", Copy> = {
aiLoop: "AI 閉環",
verified: "24h 已驗證",
functions: "治理六功能",
framework: "完整資安框架",
siemFlow: "SIEM 八段",
aiFlow: "AI Agent 七段",
scope: "全資產範圍",
@@ -78,6 +80,7 @@ const COPY: Record<"zh" | "en", Copy> = {
aiLoop: "AI closure",
verified: "Verified 24h",
functions: "Six functions",
framework: "Security framework",
siemFlow: "SIEM pipeline",
aiFlow: "AI Agent loop",
scope: "Asset scope",
@@ -309,6 +312,44 @@ export function SecurityAssetControlPlaneCockpit({
</div>
</div>
<div>
<div className="mb-2 flex items-center justify-between gap-3 text-[11px] font-semibold text-[#4f4d47]">
<span>{copy.framework}</span>
<span className="font-mono text-[#77736a]">
{payload.summary.security_program_controlled_domain_count}/
{payload.summary.security_program_domain_count}
</span>
</div>
<div className="grid grid-cols-2 gap-1 sm:grid-cols-4">
{payload.security_program_domains.map((domain) => (
<div
key={domain.domain_id}
className="min-w-0 border border-[#d8d3c7] bg-white px-2 py-1.5"
title={`${domain.label}: ${domain.controlled_percent}%${domain.gap_code ? ` · ${domain.gap_code}` : ""}`}
>
<div className="flex items-center gap-1.5">
<span
className={cn(
"h-2 w-2 shrink-0",
domain.status === "controlled"
? "bg-[#2f8a50]"
: domain.status === "partial"
? "bg-[#c58a2e]"
: "bg-[#c9584d]"
)}
/>
<span className="min-w-0 flex-1 truncate text-[9px] text-[#4f4d47]">
{domain.label}
</span>
<span className="font-mono text-[9px] font-semibold text-[#141413]">
{domain.controlled_percent}
</span>
</div>
</div>
))}
</div>
</div>
<div>
<div className="mb-2 flex items-center justify-between gap-3 text-[11px] font-semibold text-[#4f4d47]">
<span>{copy.scope}</span>

View File

@@ -29,6 +29,9 @@ function payload(): SecurityAssetControlPlanePayload {
compliance_violation_count: 0,
compliance_unknown_count: 0,
nist_controlled_percent: 82,
security_program_domain_count: 16,
security_program_controlled_domain_count: 9,
security_program_controlled_percent: 68,
siem_stage_count: 8,
siem_observed_stage_count: 8,
siem_stage_coverage_percent: 100,
@@ -47,6 +50,7 @@ function payload(): SecurityAssetControlPlanePayload {
},
asset_scopes: [],
nist_csf_functions: [],
security_program_domains: [],
siem: { pipeline: [] },
ai_automation: {
stages: [],

View File

@@ -16,6 +16,9 @@ export type SecurityControlPlaneSummary = {
compliance_violation_count: number;
compliance_unknown_count: number;
nist_controlled_percent: number;
security_program_domain_count: number;
security_program_controlled_domain_count: number;
security_program_controlled_percent: number;
siem_stage_count: number;
siem_observed_stage_count: number;
siem_stage_coverage_percent: number;
@@ -78,6 +81,14 @@ export type SecurityAssetControlPlanePayload = {
};
asset_scopes: SecurityControlPlaneScope[];
nist_csf_functions: SecurityControlPlaneFunction[];
security_program_domains: Array<{
domain_id: string;
label: string;
controlled_percent: number;
status: string;
evidence_count: number;
gap_code: string | null;
}>;
siem: {
pipeline: SecurityControlPlaneStage[];
incident_total_24h?: number;
@@ -130,7 +141,11 @@ export function isSecurityAssetControlPlanePayload(
if (!isRecord(value)) return false;
if (value.schema_version !== "iwooos_security_asset_control_plane_v1") return false;
if (!isRecord(value.summary) || !isRecord(value.boundaries)) return false;
if (!Array.isArray(value.asset_scopes) || !Array.isArray(value.nist_csf_functions)) {
if (
!Array.isArray(value.asset_scopes) ||
!Array.isArray(value.nist_csf_functions) ||
!Array.isArray(value.security_program_domains)
) {
return false;
}
if (!isRecord(value.siem) || !Array.isArray(value.siem.pipeline)) return false;