Files
kleiderboerse/scripts/image-pruefen.py
T
StefanandClaude Opus 5 31f59fd3c8 Phase 5: Gitea Actions, Betriebs-Compose und README
Ein Versions-Tag (v*) löst den Bau aus, ein Push auf main nicht - so bleibt
das Zusammenführen von Branches folgenlos und ein Release ist ein bewusster
Schritt. Die CI baut, testet das FERTIGE Image und veröffentlicht erst
danach; "latest" nur bei echten Tags.

Beim Durchspielen des Prüfschritts zwei Fehler gefunden, die beide erst in
der CI aufgefallen wären - und einer davon gar nicht:

1. "docker exec" ohne -i hängt kein stdin an. Das Here-Dokument lief damit
   ins Leere, python bekam ein leeres Programm, tat nichts und meldete
   Erfolg. Ein Test, der nie hätte fehlschlagen können. Lokal nachgestellt
   und mit -i behoben.
2. Die YAML war ungültig: eingebettete Python-Blöcke standen links vom
   Einzug und brachen den run-Block auf. Das Prüfskript liegt jetzt als
   scripts/image-pruefen.py vor - dadurch lässt es sich auch lokal gegen
   ein gebautes Image laufen lassen - und die Warteschleife ist einzeilig.

Aus der Kantone-App übernommen: github.ref_name geht über env in die
Shell statt direkt als Ausdruck (Tag-Namen dürfen " und $ enthalten, und
der Job hält ein Registry-Token), Anmeldung per --password-stdin, docker
logout mit if: always(), Rechte auf contents:read und packages:write.

docker-compose.betrieb.yml liefert bewusst KEIN Passwort mit: ohne eigenes
bleibt der Erfassungsbereich gesperrt. Genau das war die schwerste Lücke
der Kantone-App.

Ausserdem fehlte eine .dockerignore - der ganze Kontext samt .git und .env
ging an den Docker-Daemon, obwohl das Dockerfile nur gezielt kopiert.

81 Tests grün, der CI-Prüfschritt lokal gegen das gebaute Image
durchgespielt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GR4bNaj9GtRu57J4Niii8o
2026-08-30 08:40:57 +02:00

58 lines
1.9 KiB
Python

"""Prüft das fertige Image, bevor es veröffentlicht wird.
Wird von der CI in den Container gepipt:
docker exec -i "$CID" python - < scripts/image-pruefen.py
Bewusst eine eigene Datei statt eines Here-Dokuments im Workflow: ein
unindentierter Block bricht den YAML-Block auf, und als Datei lässt sich
das Ganze auch lokal gegen ein gebautes Image laufen lassen.
Die Untergrenzen liegen bewusst unter dem Ist-Stand, damit der Test nicht
bei jeder zusätzlichen Kategorie anschlägt.
"""
import json
import sys
import urllib.error
import urllib.request
BASIS = "http://localhost:8000"
def hole(pfad: str):
with urllib.request.urlopen(BASIS + pfad) as antwort:
return json.load(antwort)
def main() -> None:
kategorien = hole("/api/v1/categories")
groessen = hole("/api/v1/sizes")
print(f"Kategorien: {len(kategorien)}, Grössen: {len(groessen)}")
assert len(kategorien) >= 5, "zu wenige Kategorien - Stammdaten fehlen?"
assert len(groessen) >= 20, "zu wenige Grössen - Stammdaten fehlen?"
with urllib.request.urlopen(BASIS + "/") as antwort:
seite = antwort.read().decode()
assert "Kleider-Börse" in seite, "Galerie wird nicht ausgeliefert"
# Das CSS entsteht in einer eigenen Build-Stufe und würde bei einem
# Fehler dort still fehlen - die Seite käme dann ohne Gestaltung.
assert "/static/style.css" in seite, "kein CSS eingebunden"
print("Galerie und CSS: ok")
# Ohne Anmeldung darf nichts geschrieben werden.
try:
urllib.request.urlopen(urllib.request.Request(
BASIS + "/api/v1/items", method="POST",
data=b'{"size":"80"}',
headers={"Content-Type": "application/json"},
))
except urllib.error.HTTPError as fehler:
assert fehler.code == 401, f"ergab {fehler.code}, erwartet 401"
else:
sys.exit("Schreiben war ohne Anmeldung möglich!")
print("Schreibschutz greift.")
if __name__ == "__main__":
main()