mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-14 06:37:25 +00:00
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>
73 lines
2.4 KiB
Python
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()
|