fix: refuse to analyze an empty rule catalog

The bug

Both entry points printed their extracted rule count and continued whatever the number was. Zero is never a valid run.

stig_ai_analyzer.py would perform zero analyses and still write a checklist, a compliance report, and an evidence map, exiting zero. That is an accreditation artifact asserting nothing about 286 controls while presenting as a completed run, and a reader cannot tell it apart from a clean pass. Same failure class as the STIG_INFO stamping fix in !12 (merged), one step further along: not a half-derived benchmark, but a verdict set with no verdicts.

generate_batch_pipeline.py would emit a child pipeline with no batch jobs. GitLab rejects that, so it does fail, but as a config error that never names the XCCDF as the cause.

Why it is not hypothetical

Rule extraction in both files pins the XCCDF 1.1 namespace. DISA publishes some benchmarks under 1.2. A 1.2 file is well-formed, parses without error, and matches nothing. ckl_parser._find_child already carried a comment saying exactly this, including that a 1.2 file "yields no rules to analyze". The hazard was documented and left live.

This guard does not add 1.2 support, which needs a real fixture and its own tests. It makes the mismatch announce itself.

Tests

Nine in tests/test_rule_catalog_guard.py. Two matter more than the rest:

  • A negative control asserting a populated 1.1 benchmark still generates, so the guard cannot fire on a healthy catalog.
  • The 1.2 case asserted as currently yielding zero rules, so if 1.2 support lands, that assertion fails and forces a deliberate update.

The negative control earned its place immediately: it caught that the first harness checked for the output file after the temporary directory was already cleaned up, making every "wrote no pipeline" assertion pass for the wrong reason.

Suite is 128 tests, all passing.

Follow-up

XCCDF 1.2 support wants its own issue: make extraction namespace-agnostic in both entry points using the local-name matching ckl_parser already has, with a real 1.2 fixture.

Merge request reports

Loading
Loading