CYBER-0 initial concept ready

This commit is contained in:
Ole Valente
2026-09-22 00:00:45 +02:00
parent 29eecd4f70
commit edb6cde069
70 changed files with 1976 additions and 3140 deletions
+103
View File
@@ -0,0 +1,103 @@
#!/usr/bin/env python3
"""Convert the existing Ansible compliance report to the common report schema."""
import argparse
import json
import os
from pathlib import Path
from typing import Any
from jsonschema import Draft202012Validator, FormatChecker
STATUS_MAP = {True: "passed", False: "failed", "review": "review", "skipped": "skipped"}
def environment(name: str, fallback: str = "") -> str:
return os.environ.get(name, fallback)
def normalize(source: dict[str, Any], raw_path: Path) -> dict[str, Any]:
source_meta = source["meta"]
results = []
for result in source.get("results", []):
requirement = str(result.get("requirement", ""))
standards = []
if requirement:
standards.append(
{
"framework": source_meta.get("standard", "IEC 62443-3-3"),
"version": source_meta.get("security_level", ""),
"control": requirement,
}
)
results.append(
{
"id": str(result["test_id"]),
"title": str(result.get("description", result["test_id"])),
"description": requirement,
"status": STATUS_MAP.get(result.get("passed"), "error"),
"severity": str(result.get("severity", "info")).lower(),
"category": str(result.get("category", "")),
"expected": str(result.get("expected", "")),
"observed": str(result.get("actual", "")),
"remediation": str(result.get("remediation", "")),
"standards": standards,
"evidence": [{"type": "text", "name": "Ansible observation", "value": str(result.get("actual", ""))}],
}
)
counts = dict.fromkeys(("passed", "failed", "errors", "skipped", "review"), 0)
for result in results:
counter = "errors" if result["status"] == "error" else result["status"]
counts[counter] += 1
scored = counts["passed"] + counts["failed"]
return {
"schema_version": "1.0.0",
"run": {
"id": environment("CI_PIPELINE_ID", source_meta.get("timestamp", "local")),
"started_at": source_meta["timestamp"],
"source": "gitlab" if environment("CI") else "local",
"pipeline_url": environment("CI_PIPELINE_URL"),
"commit_sha": environment("CI_COMMIT_SHA"),
},
"project": {
"id": environment("TEST_PROJECT_ID", "local"),
"name": environment("TEST_PROJECT_NAME", "Local test project"),
"environment": environment("TEST_ENVIRONMENT", "test"),
"customer": environment("TEST_CUSTOMER"),
"location": environment("TEST_LOCATION"),
},
"tool": {"id": "ansible", "name": "Ansible", "adapter_version": "1.0.0"},
"target": {"id": source_meta["target"], "type": "managed_host", "groups": []},
"summary": {
"total": len(results),
**counts,
"score": round(counts["passed"] / scored * 100, 2) if scored else 0,
},
"results": results,
"raw_artifacts": [str(raw_path)],
}
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("input", type=Path)
parser.add_argument("output", type=Path)
parser.add_argument("--schema", type=Path, default=Path("schemas/test-report.schema.json"))
args = parser.parse_args()
source = json.loads(args.input.read_text(encoding="utf-8"))
report = normalize(source, args.input)
schema = json.loads(args.schema.read_text(encoding="utf-8"))
Draft202012Validator(schema, format_checker=FormatChecker()).validate(report)
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(json.dumps(report, indent=2) + "\n", encoding="utf-8")
print(f"Normalized {len(report['results'])} Ansible results to {args.output}")
return 0
if __name__ == "__main__":
raise SystemExit(main())