feat(vuln): vuln-scanner platform manifests, Flux tier, alerts, L0/L2/L3 tests
Hand-authored platform/vuln-scanner (non-gating Flux tier, digest-pinned Trivy 0.76.1 and python 3.14.9-alpine, read-only RBAC, per-pod oauth2-proxy, internal-only cve.<domain>), five alerts with promtool tests, R-VULN-01..09 registry entries, and vuln-* L0 checks with mutation self-tests. src/ and the bot workflow are integrated separately. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
4c3a284cad
commit
b85d1e3ed7
47 files changed
+2572
-6
No files matched your search
@@ -0,0 +1,28 @@
|
||||
# =============================================================================
|
||||
# L0 STATIC — accepted CVE risk has a reason and a bounded expiry (R-VULN-08, docs/17 "Risk acceptance").
|
||||
# Offline, no cluster.
|
||||
# =============================================================================
|
||||
apiVersion: chainsaw.kyverno.io/v1alpha1
|
||||
kind: Test
|
||||
metadata:
|
||||
name: vuln-acceptances-schema
|
||||
labels:
|
||||
conformance.home.k3s/R-VULN-08: "true"
|
||||
annotations:
|
||||
conformance.home.k3s/requirements: "R-VULN-08"
|
||||
conformance.home.k3s/layer: "L0"
|
||||
conformance.home.k3s/scope: "whole-repo"
|
||||
conformance.home.k3s/safety-critical: "false"
|
||||
conformance.home.k3s/executable: "true"
|
||||
conformance.home.k3s/intent: >-
|
||||
platform/vuln-scanner/acceptances.yaml rejects any entry without a reason or expiry, with a
|
||||
malformed expiry, or expiring more than 180 days out. Proven with mutated negative fixtures.
|
||||
spec:
|
||||
steps:
|
||||
- name: assert-acceptance-schema
|
||||
description: >-
|
||||
Validate acceptances.yaml against the docs/17 shape, then run the validator on mutated
|
||||
negative fixtures to prove it can fail.
|
||||
try:
|
||||
- script:
|
||||
content: bash ./check.sh
|
||||
@@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# L0 static check (offline, no cluster) — vuln-acceptances-schema
|
||||
# Serves: R-VULN-08 (docs/17 "Risk acceptance": "An entry with no reason or expiry is rejected by the gate").
|
||||
#
|
||||
# GIVEN platform/vuln-scanner/acceptances.yaml,
|
||||
# THEN (1) it is a YAML list;
|
||||
# (2) every entry has a non-empty id, a non-empty reason, an expires of the form YYYY-MM-DD
|
||||
# at most 180 days from today, and only the permitted keys (image is optional);
|
||||
# AND (3) the validator rejects mutated negative fixtures for each rule and accepts a good entry.
|
||||
# =============================================================================
|
||||
set -euo pipefail
|
||||
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT="$(cd "${DIR}/../../../.." && pwd)"
|
||||
exec python3 - "$ROOT" <<'PY'
|
||||
import datetime as dt, re, sys
|
||||
from pathlib import Path
|
||||
import yaml
|
||||
|
||||
ROOT = Path(sys.argv[1])
|
||||
NAME = "vuln-acceptances-schema"
|
||||
FAILURES, CHECKS = [], 0
|
||||
TODAY = dt.datetime.now(dt.timezone.utc).date()
|
||||
MAX_DAYS = 180
|
||||
ALLOWED_KEYS = {"id", "image", "reason", "expires"}
|
||||
DATE_RE = re.compile(r"^\d{4}-\d{2}-\d{2}$")
|
||||
|
||||
|
||||
def check(cond, desc):
|
||||
global CHECKS
|
||||
CHECKS += 1
|
||||
if not cond:
|
||||
FAILURES.append(desc)
|
||||
|
||||
|
||||
def validate(entries):
|
||||
errs = []
|
||||
if not isinstance(entries, list):
|
||||
return ["acceptances must be a YAML list"]
|
||||
for i, e in enumerate(entries):
|
||||
if not isinstance(e, dict):
|
||||
errs.append(f"entry {i} is not a mapping")
|
||||
continue
|
||||
if set(e) - ALLOWED_KEYS:
|
||||
errs.append(f"entry {i} has unknown keys {sorted(set(e) - ALLOWED_KEYS)}")
|
||||
for field in ("id", "reason"):
|
||||
if not isinstance(e.get(field), str) or not e[field].strip():
|
||||
errs.append(f"entry {i} has no non-empty {field}")
|
||||
if "image" in e and (not isinstance(e["image"], str) or not e["image"].strip()):
|
||||
errs.append(f"entry {i} has an empty image")
|
||||
exp = e.get("expires")
|
||||
if isinstance(exp, dt.date) and not isinstance(exp, dt.datetime):
|
||||
exp_s = exp.isoformat()
|
||||
elif isinstance(exp, str):
|
||||
exp_s = exp
|
||||
else:
|
||||
errs.append(f"entry {i} has no expires")
|
||||
continue
|
||||
if not DATE_RE.match(exp_s):
|
||||
errs.append(f"entry {i} expires is malformed: {exp_s!r}")
|
||||
continue
|
||||
try:
|
||||
d = dt.date.fromisoformat(exp_s)
|
||||
except ValueError:
|
||||
errs.append(f"entry {i} expires is not a real date: {exp_s!r}")
|
||||
continue
|
||||
if (d - TODAY).days > MAX_DAYS:
|
||||
errs.append(f"entry {i} expires {exp_s}, more than {MAX_DAYS} days out")
|
||||
return errs
|
||||
|
||||
|
||||
path = ROOT / "platform" / "vuln-scanner" / "acceptances.yaml"
|
||||
if not path.is_file():
|
||||
print(f"CHECK FAIL ({NAME}): platform/vuln-scanner/acceptances.yaml is absent", file=sys.stderr)
|
||||
raise SystemExit(1)
|
||||
entries = yaml.safe_load(path.read_text())
|
||||
check(entries == [] or (isinstance(entries, list) and entries), "(1) acceptances.yaml parsed to a list")
|
||||
errs = validate(entries)
|
||||
check(not errs, f"(2) acceptances.yaml is valid: {errs}")
|
||||
|
||||
soon = (TODAY + dt.timedelta(days=30)).isoformat()
|
||||
far = (TODAY + dt.timedelta(days=200)).isoformat()
|
||||
good = {"id": "CVE-2026-00000", "image": "docker.io/library/x", "reason": "not reachable", "expires": soon}
|
||||
check(validate([good]) == [], "(3) a well-formed entry is accepted")
|
||||
check(validate([{k: v for k, v in good.items() if k != "image"}]) == [], "(3) image is optional (platform-wide)")
|
||||
for name, entry in {
|
||||
"no reason": {k: v for k, v in good.items() if k != "reason"},
|
||||
"empty reason": dict(good, reason=""),
|
||||
"no expires": {k: v for k, v in good.items() if k != "expires"},
|
||||
"no id": {k: v for k, v in good.items() if k != "id"},
|
||||
"malformed expiry": dict(good, expires="next-tuesday"),
|
||||
"impossible date": dict(good, expires="2027-13-45"),
|
||||
"past 180 days": dict(good, expires=far),
|
||||
"unknown key": dict(good, owner="me"),
|
||||
}.items():
|
||||
check(bool(validate([entry])), f"(3) the validator accepted a bad entry: {name}")
|
||||
check(bool(validate({"not": "a list"})), "(3) the validator accepted a non-list")
|
||||
|
||||
if FAILURES:
|
||||
print(f"CHECK FAIL ({NAME}): {len(FAILURES)} of {CHECKS} assertions failed", file=sys.stderr)
|
||||
for f in FAILURES:
|
||||
print(f" - {f}", file=sys.stderr)
|
||||
raise SystemExit(1)
|
||||
print(f"PASS ({NAME}): {CHECKS} assertions")
|
||||
PY
|
||||
Reference in new issue
Block a user