Files
computer-playbook/tests/unit/python/utils/security/test_engine.py
T
kevinveenbirkenbachandClaude Opus 5.5 1e1d37d679 feat(sys-ctl-hlth-runtime): map severities to fail or warn and publish every run for Prometheus, Loki and Wazuh
The scan threshold becomes a severity-to-verdict mapping in
roles/sys-ctl-hlth-runtime/meta/services.yml, CRITICAL: fail and HIGH: warn,
for production and CI alike. A finding mapped to fail fails the service and
the deploy, a warn prints a warning line and passes, a suppressed one prints
an info line. Engine errors, missing databases and PHP hardening violations
still fail. The old list form is rejected with a config error. The daily
mirror scan stays strict: every unsuppressed fail or warn finding is a row,
so it fails while an image is red.

Every run publishes one list of judged findings four ways:
- report.json of the latest run (summary + records) under
  DIR_HEALTH_RUNTIME_REPORT, written atomically;
- findings.jsonl under DIR_HEALTH_RUNTIME_LOG, one record per finding,
  appended per run and rotated weekly by a logrotate drop-in;
- one JSON line per target plus a summary line on stdout for the journal;
- infinito_hlth_runtime.prom in DIR_METRICS_TEXTFILE when web-app-prometheus
  is deployed: findings per target, kind, image, severity, scanner and
  verdict (no CVE label), last run time and success, scanner errors.

Each record carries run_id, timestamp, host, environment, target, kind,
image, scanner, id, severity, package, installed_version, fixed_version,
suppressed, suppressed_until and verdict. The paths are SPOT variables in
group_vars/all/05_paths.yml, the script takes them as arguments.

Requirement 070 and the role README describe the mapping, the outputs and
the per-image vulnerability issue of the previous commit.

Part of #1324

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 17:48:09 +01:00

73 lines
2.4 KiB
Python

from __future__ import annotations
import random
from unittest import TestCase, main
from utils.security import engine
from utils.security.pipeline import pipeline
class TestEnginesFor(TestCase):
def test_every_pin_runs_behind_syft(self):
for name in engine.SCANNERS:
with self.subTest(engine=name):
self.assertEqual(engine.engines_for(name), ["syft", name])
def test_an_unknown_engine_is_rejected(self):
with self.assertRaises(ValueError):
engine.engines_for("clair")
def test_every_pin_reads_the_grype_database(self):
self.assertEqual(engine.databases_for("trivy"), ["trivy", "grype"])
self.assertEqual(engine.databases_for("grype"), ["grype"])
def test_the_ci_pool_matches_the_role_pipeline(self):
self.assertEqual(engine.SCANNERS, pipeline().SCANNERS)
def test_every_pin_is_a_valid_role_config(self):
p = pipeline()
for name in engine.SCANNERS:
with self.subTest(engine=name):
config = p.scan_config(
{
"targets": ["host", "container"],
"engines": engine.engines_for(name),
"severity": {"CRITICAL": "fail", "HIGH": "warn"},
"fixed_only": True,
"workers": 2,
"db_update": False,
}
)
self.assertEqual(list(config.databases()), engine.databases_for(name))
class TestDrawEngine(TestCase):
def test_a_draw_is_one_scanner(self):
rng = random.Random(1) # noqa: S311 - seeded draw, not crypto
self.assertIn(engine.draw_engine(rng), engine.SCANNERS)
def test_draws_cover_every_scanner(self):
rng = random.Random(7) # noqa: S311 - seeded draw, not crypto
self.assertEqual(
{engine.draw_engine(rng) for _ in range(60)}, set(engine.SCANNERS)
)
class TestDeployOverrides(TestCase):
def test_a_deploy_reads_provided_databases(self):
runtime = engine.deploy_overrides("osv", "/opt/vulnerability-db")[engine.ROLE][
"services"
]["runtime"]
self.assertEqual(
runtime,
{
"engines": ["syft", "osv"],
"database_dir": "/opt/vulnerability-db",
"db_update": False,
},
)
if __name__ == "__main__":
main()