CYBER-0 initial concept ready
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Combine normalized tool reports into one schema-valid project report."""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from jsonschema import Draft202012Validator, FormatChecker
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("inputs", nargs="+", type=Path)
|
||||
parser.add_argument("--output", type=Path, required=True)
|
||||
parser.add_argument("--schema", type=Path, default=Path("schemas/test-report.schema.json"))
|
||||
args = parser.parse_args()
|
||||
|
||||
reports = [json.loads(path.read_text(encoding="utf-8")) for path in args.inputs]
|
||||
if not reports:
|
||||
parser.error("at least one normalized report is required")
|
||||
|
||||
project = reports[0]["project"]
|
||||
run = reports[0]["run"]
|
||||
results = []
|
||||
raw_artifacts = []
|
||||
for report in reports:
|
||||
if report["project"]["id"] != project["id"]:
|
||||
parser.error("all reports must belong to the same project")
|
||||
tool = report["tool"]
|
||||
for result in report["results"]:
|
||||
combined = dict(result)
|
||||
combined["id"] = f"{tool['id']}:{result['id']}"
|
||||
combined["category"] = f"{tool['name']} | {result.get('category', '')}".rstrip(" |")
|
||||
results.append(combined)
|
||||
raw_artifacts.extend(report.get("raw_artifacts", []))
|
||||
|
||||
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"]
|
||||
aggregate = {
|
||||
"schema_version": "1.0.0",
|
||||
"run": run,
|
||||
"project": project,
|
||||
"tool": {"id": "combined", "name": "Combined test methodologies", "adapter_version": "1.0.0"},
|
||||
"target": {"id": "project-scope", "type": "test_environment", "groups": []},
|
||||
"summary": {
|
||||
"total": len(results),
|
||||
**counts,
|
||||
"score": round(counts["passed"] / scored * 100, 2) if scored else 0,
|
||||
},
|
||||
"results": results,
|
||||
"raw_artifacts": sorted(set(raw_artifacts)),
|
||||
}
|
||||
|
||||
schema = json.loads(args.schema.read_text(encoding="utf-8"))
|
||||
Draft202012Validator(schema, format_checker=FormatChecker()).validate(aggregate)
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.output.write_text(json.dumps(aggregate, indent=2) + "\n", encoding="utf-8")
|
||||
print(f"Aggregated {len(reports)} reports with {len(results)} results")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user