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>
36 lines
1.1 KiB
Python
36 lines
1.1 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
import re
|
|
from unittest import TestCase, main
|
|
|
|
from utils.security import pipeline
|
|
|
|
|
|
class TestPipeline(TestCase):
|
|
def test_the_role_script_loads_once(self):
|
|
self.assertIs(pipeline.pipeline(), pipeline.pipeline())
|
|
|
|
def test_every_engine_has_a_semver_pin(self):
|
|
for engine in pipeline.pipeline().ENGINES:
|
|
with self.subTest(engine=engine):
|
|
self.assertRegex(
|
|
pipeline.engine_image(engine),
|
|
re.compile(r"^ghcr\.io/.+:v?\d+\.\d+\.\d+$"),
|
|
)
|
|
|
|
def test_the_engines_run_as_the_calling_user(self):
|
|
self.assertEqual(pipeline.user_runtime()[-1], f"{os.getuid()}:{os.getgid()}")
|
|
|
|
def test_the_role_default_is_a_valid_scan_config(self):
|
|
runtime = pipeline.role_services()["runtime"]
|
|
keys = ("targets", "engines", "severity", "fixed_only", "workers", "db_update")
|
|
config = pipeline.pipeline().scan_config({key: runtime[key] for key in keys})
|
|
self.assertLessEqual(
|
|
set(config.severity.values()), set(pipeline.pipeline().ACTIONS)
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|