Files
adminandClaude Opus 5.5 86261387aa Abwaehlen aendert keine Voreinstellungen des Images mehr (Audit 13.10.2026)
- security-updates/auto-update: Das Ubuntu-Image bringt 20auto-upgrades und
  10periodic selbst mit. Abwaehlen loeschte sie und schaltete damit die
  automatischen Sicherheitsupdates der Distro ab. Jetzt wird dort der
  Auslieferungszustand wiederhergestellt; auf Mint/Debian wie bisher entfernt.
- zeitserver: Abwaehlen trug auf jedem Geraet pool.ntp.org ein, jetzt zurueck
  auf den auskommentierten Standard.
- guest-session: Konto gast nur entfernen, wenn es von der Rolle stammt.
- scripts/pruefe_absent.py: prueft die Abwaehl-Zweige gegen die Paketlisten
  der Golden Images (nach jedem neuen Image laufen lassen).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 16:28:14 +02:00

62 lines
2.3 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Prüft die Abwähl-Zweige aller Rollen gegen die Paketlisten der Golden Images
(roles/grundsystem/files/*.txt): Ein Paket, das ein Image selbst mitbringt,
darf beim Abwählen nur über den Grundsystem-Schutz
(| difference(tuxflotte_grundsystem_pakete …)) entfernt werden.
Aufruf im Repo-Wurzelverzeichnis: python3 scripts/pruefe_absent.py
Nach jedem neuen Golden Image (neue Paketliste) laufen lassen. Rückgabewert 1
bei Fund. Hintergrund: Firmware-Vorfall 09.10.2026, Audit 13.10.2026.
"""
import glob
import re
import sys
import yaml
IMAGES = {
pfad.split("/")[-1][:-4]: set(open(pfad, encoding="utf-8").read().split())
for pfad in glob.glob("roles/grundsystem/files/*.txt")
}
# Entfernt im Zustand "present" absichtlich Pakete (Sperre), kein Abwähl-Zweig.
AUSNAHMEN = {"netzwerkscanner-sperre"}
def aufgaben(liste):
for aufgabe in liste or []:
if not isinstance(aufgabe, dict):
continue
yield aufgabe
for block in ("block", "rescue", "always"):
yield from aufgaben(aufgabe.get(block))
funde = []
geprueft = 0
for datei in sorted(glob.glob("roles/*/tasks/*.yml")):
rolle = datei.split("/")[1]
if rolle in AUSNAHMEN:
continue
for aufgabe in aufgaben(yaml.safe_load(open(datei, encoding="utf-8"))):
for modul, argumente in aufgabe.items():
if not modul.endswith("apt") or not isinstance(argumente, dict) or argumente.get("state") != "absent":
continue
name = argumente.get("name")
text = str(name)
if "difference(tuxflotte_grundsystem_pakete" in text:
continue
pakete = name if isinstance(name, list) else (
re.findall(r"'([a-z0-9][a-z0-9.+-]+)'", text) if "{{" in text else [text]
)
for paket in pakete:
geprueft += 1
images = sorted(image for image, inhalt in IMAGES.items() if paket in inhalt)
if images:
funde.append(f"{rolle}: entfernt '{paket}' ungeschützt, enthalten in {', '.join(images)}")
for fund in funde:
print("FUND:", fund)
print(f"{geprueft} ungeschützt entfernte Pakete gegen {len(IMAGES)} Image-Listen geprüft, {len(funde)} Funde.")
sys.exit(1 if funde else 0)