import json from scripts.manifest import ( Manifest, PlanUnit, PlanResult, InitResult, CatalogEntry, ModuleGraphEntry, TrivyFinding, ) def test_roundtrip_minimal(): m = Manifest( base_ref="main", head_ref="feat/x", mode="local", default_branch="main", changed_source_dirs=[], plan_units=[], catalog=[], trivy_findings=[], module_graph={}, errors=[], ) payload = json.loads(m.to_json()) assert payload["base_ref"] == "main" assert payload["mode"] == "local" assert payload["plan_units"] == [] def test_catalog_entry_required_fields(): from scripts.manifest import CatalogInstance entry = CatalogEntry( source_dir="live/prod/audit", local_address="aws_s3_bucket.audit_logs", type="aws_s3_bucket", source="both", instances=[CatalogInstance( plan_dir="live/prod/audit", address_at_plan="aws_s3_bucket.audit_logs", action="create", )], block_header='resource "aws_s3_bucket" "audit_logs" {', evidence_line='acl = "private"', key_attributes={"acl": "private"}, review_context={"variables": {}, "locals": {}, "related_blocks": []}, block_file="main.tf", block_start=1, block_end=3, ) d = entry.to_dict() assert d["source"] == "both" assert d["type"] == "aws_s3_bucket" assert d["instances"][0]["plan_dir"] == "live/prod/audit" assert d["block_header"].startswith('resource') assert d["evidence_line"] == 'acl = "private"' assert d["key_attributes"] == {"acl": "private"} assert d["review_context"] == {"variables": {}, "locals": {}, "related_blocks": []} def test_plan_unit_serializes_triggered_by(): pu = PlanUnit( plan_dir="live/prod/app", tool="terragrunt", init=InitResult(ok=True, stdout_tail="ok", stderr_tail=""), plan=PlanResult(ok=True, stdout_path="/tmp/x", exit_code=0, summary="1 to add, 0 to change, 0 to destroy"), triggered_by=["modules/app-role"], terragrunt_changed=True, changed_files=["live/prod/app/terragrunt.hcl"], ) d = pu.to_dict() assert d["tool"] == "terragrunt" assert d["triggered_by"] == ["modules/app-role"] assert d["init"]["ok"] is True assert d["plan"]["exit_code"] == 0 assert d["terragrunt_changed"] is True assert d["changed_files"] == ["live/prod/app/terragrunt.hcl"] def test_trivy_findings_serialize(): finding = TrivyFinding( check_id="AVD-AWS-0089", title="S3 bucket allows public ACL", severity="high", message="Bucket ACL allows public access.", file="main.tf", start_line=21, end_line=30, resource_type="aws_s3_bucket", ) assert finding.to_dict() == { "check_id": "AVD-AWS-0089", "title": "S3 bucket allows public ACL", "severity": "high", "message": "Bucket ACL allows public access.", "file": "main.tf", "start_line": 21, "end_line": 30, "resource_type": "aws_s3_bucket", "source": "trivy", } def test_module_graph_serializes(): g = { "modules/app-role": ModuleGraphEntry( callsites=["live/prod/app", "live/staging/app"], sibling_modules_at_callsites=["modules/iam-policy-doc"], ) } findings = [ TrivyFinding( check_id="AVD-AWS-0089", title="S3 bucket allows public ACL", severity="high", message="Bucket ACL allows public access.", file="main.tf", resource_type="aws_s3_bucket", ) ] m = Manifest( base_ref="main", head_ref="x", mode="local", default_branch="main", changed_source_dirs=[], plan_units=[], catalog=[], trivy_findings=findings, module_graph=g, errors=[], ) payload = json.loads(m.to_json()) assert payload["module_graph"]["modules/app-role"]["callsites"] == [ "live/prod/app", "live/staging/app", ] assert payload["trivy_findings"][0]["check_id"] == "AVD-AWS-0089"