Prüfung / Lint, Typen, Tests (push) Canceled after 0s
Prüfung / Images bauen (pdf) (push) Canceled after 0s
Prüfung / Images bauen (web) (push) Canceled after 0s
Prüfung / Images bauen (worker) (push) Canceled after 0s
Images / bauen (pdf, docker/pdf.Dockerfile) (push) Canceled after 0s
Images / bauen (web, docker/web.Dockerfile) (push) Canceled after 0s
Images / bauen (worker, docker/worker.Dockerfile) (push) Canceled after 0s
Die Adresse zeigte auf /var/run/clamav/clamd.sock in einem geteilten Volume. Das offizielle clamav-Image legt seinen Unix-Socket aber unter /tmp im eigenen Container an - nachgemessen, das Verzeichnis im Volume bleibt leer. Jeder Verbindungsversuch lief damit in ENOENT, und die Statusseite meldete die Virenpruefung dauerhaft als gestoert. Folgenreich war das nicht nur fuer die Anzeige: ohne erreichbaren Scanner bleiben Uploads auf "Pruefung unvollstaendig" liegen und brauchen die Freigabe von Hand. Die Kette hat also gehalten, aber niemand kam durch. Dasselbe Image oeffnet ab Werk TCPSocket 3310. Darueber laeuft die Anbindung jetzt; der Port ist im Stack nicht veroeffentlicht und nur im internen Netz erreichbar. CLAMAV_ADDRESS nimmt weiterhin einen Pfad an, falls irgendwo doch ein Unix-Socket erreichbar ist. Das Socket-Volume faellt weg, es enthielt nie etwas. Der Scanner sieht ausserdem die Dateiablage nicht mehr: uebertragen wird per INSTREAM durch die Verbindung, gelesen hat er dort nie etwas. Geprueft gegen ein laufendes clamd, einschliesslich EICAR. Diese Pruefung bleibt als abschaltbarer Teil der Suite stehen: CLAMAV_LIVE=clamav:3310 pnpm --filter @afis/web test pruefkette Die uebrigen neuen Pruefungen decken das Zerlegen der Adresse ab. Sie haetten den Fehler nicht gefunden - eine Adresse, die auf nichts zeigt, ist syntaktisch tadellos. Nur eine echte Verbindung beantwortet das.
149 lines
5.1 KiB
Bash
Executable File
149 lines
5.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Startet die Anwendung für die lokale Entwicklung: Datenbank, Worker, Web.
|
|
#
|
|
# Das hier ist ausdrücklich **nicht** der Betrieb. Im Betrieb läuft alles als
|
|
# ein Dockge-Stack, siehe docs/11-betrieb.md. Dieses Skript ist für den Fall,
|
|
# dass der Stack gerade nicht läuft und man am Code arbeiten will.
|
|
#
|
|
# ./start.sh Datenbank, Worker und Web starten
|
|
# ./start.sh --ohne-worker nur Datenbank und Web (kein Discord nötig)
|
|
# ./start.sh --nur-db nur die Datenbank hochfahren
|
|
#
|
|
# Beenden mit Strg+C, das nimmt alle Kindprozesse mit.
|
|
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")"
|
|
|
|
DB_CONTAINER="afis-dev-db"
|
|
DB_PORT="${AFIS_DB_PORT:-5434}"
|
|
DB_IMAGE="postgres:16-alpine"
|
|
|
|
MIT_WORKER=1
|
|
NUR_DB=0
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--ohne-worker) MIT_WORKER=0 ;;
|
|
--nur-db) NUR_DB=1 ;;
|
|
-h|--help) awk 'NR>1 && /^#/ { sub(/^# ?/, ""); print; next } NR>1 { exit }' "$0"; exit 0 ;;
|
|
*) echo "Unbekannte Option: $arg" >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
info() { printf '\033[36m▸\033[0m %s\n' "$*"; }
|
|
warn() { printf '\033[33m!\033[0m %s\n' "$*"; }
|
|
fehler() { printf '\033[31m✗\033[0m %s\n' "$*" >&2; exit 1; }
|
|
|
|
# --- Node aus nvm holen, falls es nicht schon im PATH liegt -------------------
|
|
if ! command -v node >/dev/null 2>&1; then
|
|
if [ -s "$HOME/.nvm/nvm.sh" ]; then
|
|
# shellcheck disable=SC1091
|
|
. "$HOME/.nvm/nvm.sh" >/dev/null
|
|
nvm use --lts >/dev/null 2>&1 || nvm use node >/dev/null 2>&1 || true
|
|
fi
|
|
fi
|
|
command -v node >/dev/null 2>&1 || fehler "Node nicht gefunden. Node 22 installieren oder nvm laden."
|
|
|
|
if ! command -v pnpm >/dev/null 2>&1; then
|
|
corepack enable >/dev/null 2>&1 || true
|
|
fi
|
|
command -v pnpm >/dev/null 2>&1 || fehler "pnpm nicht gefunden. 'corepack enable' ausführen."
|
|
|
|
command -v docker >/dev/null 2>&1 || fehler "Docker nicht gefunden, die Datenbank läuft im Container."
|
|
|
|
[ -f .env ] || fehler ".env fehlt. Von .env.example abschreiben und die Discord-Werte eintragen."
|
|
|
|
# --- Datenbank ---------------------------------------------------------------
|
|
if [ -n "$(docker ps -q -f "name=^${DB_CONTAINER}$")" ]; then
|
|
info "Datenbank läuft bereits"
|
|
elif [ -n "$(docker ps -aq -f "name=^${DB_CONTAINER}$")" ]; then
|
|
info "Datenbank starten"
|
|
docker start "$DB_CONTAINER" >/dev/null
|
|
else
|
|
info "Datenbank anlegen (Port ${DB_PORT})"
|
|
docker run -d --name "$DB_CONTAINER" \
|
|
-e POSTGRES_DB=afis -e POSTGRES_USER=afis -e POSTGRES_PASSWORD=afis \
|
|
-p "${DB_PORT}:5432" "$DB_IMAGE" >/dev/null \
|
|
|| fehler "Container nicht gestartet. Läuft schon etwas auf Port ${DB_PORT}?"
|
|
fi
|
|
|
|
printf ' warte auf Postgres'
|
|
for _ in $(seq 1 60); do
|
|
if docker exec "$DB_CONTAINER" pg_isready -U afis -d afis >/dev/null 2>&1; then
|
|
printf ' bereit\n'
|
|
break
|
|
fi
|
|
printf '.'
|
|
sleep 1
|
|
done
|
|
docker exec "$DB_CONTAINER" pg_isready -U afis -d afis >/dev/null 2>&1 \
|
|
|| fehler "Postgres antwortet nicht."
|
|
|
|
# --- Schema und Grundzustand -------------------------------------------------
|
|
info "Prisma-Client erzeugen"
|
|
pnpm --filter @afis/db run build >/dev/null
|
|
|
|
info "Migrationen anwenden"
|
|
pnpm db:deploy >/dev/null
|
|
|
|
info "Grundzustand einspielen"
|
|
pnpm db:seed >/dev/null
|
|
|
|
# --- Dateiablage -------------------------------------------------------------
|
|
# Im Stack ist das ein Volume, hier ein Verzeichnis. Ohne es scheitert der
|
|
# erste Upload mit einem Fehler, der nichts erklärt.
|
|
FILES_DIR_LOKAL="$(grep -E '^FILES_DIR=' .env 2>/dev/null | cut -d= -f2- || true)"
|
|
FILES_DIR_LOKAL="${FILES_DIR_LOKAL:-/tmp/afis-files}"
|
|
mkdir -p "${FILES_DIR_LOKAL}/quarantine" "${FILES_DIR_LOKAL}/store"
|
|
info "Dateiablage unter ${FILES_DIR_LOKAL}"
|
|
|
|
# Die Prüfkette braucht beides. Fehlt eines, bleiben die betroffenen Uploads in
|
|
# der Quarantäne - sie gehen nicht ungeprüft durch. Siehe docs/07.
|
|
CLAMAV_ADRESSE="$(grep -E '^CLAMAV_ADDRESS=' .env 2>/dev/null | cut -d= -f2- || true)"
|
|
CLAMAV_ADRESSE="${CLAMAV_ADRESSE:-clamav:3310}"
|
|
clamd_erreichbar() {
|
|
case "$CLAMAV_ADRESSE" in
|
|
/*) [ -S "$CLAMAV_ADRESSE" ] ;;
|
|
*) (exec 3<>"/dev/tcp/${CLAMAV_ADRESSE%:*}/${CLAMAV_ADRESSE##*:}") 2>/dev/null ;;
|
|
esac
|
|
}
|
|
clamd_erreichbar \
|
|
|| warn "Kein clamd unter ${CLAMAV_ADRESSE}: Uploads landen auf 'Prüfung unvollständig' und brauchen die Freigabe von Hand"
|
|
command -v qpdf >/dev/null \
|
|
|| warn "qpdf fehlt: PDF-Uploads landen auf 'Prüfung unvollständig' (im Container ist es enthalten)"
|
|
|
|
if [ "$NUR_DB" = "1" ]; then
|
|
info "Datenbank läuft auf localhost:${DB_PORT}. Beenden mit: docker stop ${DB_CONTAINER}"
|
|
exit 0
|
|
fi
|
|
|
|
# --- Kindprozesse ------------------------------------------------------------
|
|
PIDS=()
|
|
aufraeumen() {
|
|
echo
|
|
info "Beenden"
|
|
for pid in "${PIDS[@]:-}"; do
|
|
kill "$pid" 2>/dev/null || true
|
|
done
|
|
wait 2>/dev/null || true
|
|
info "Die Datenbank läuft weiter. Anhalten mit: docker stop ${DB_CONTAINER}"
|
|
}
|
|
trap aufraeumen INT TERM EXIT
|
|
|
|
if [ "$MIT_WORKER" = "1" ]; then
|
|
info "Worker starten (Discord-Rollenabgleich)"
|
|
pnpm worker:dev 2>&1 | sed 's/^/[worker] /' &
|
|
PIDS+=($!)
|
|
fi
|
|
|
|
info "Web starten"
|
|
pnpm dev 2>&1 | sed 's/^/[web] /' &
|
|
PIDS+=($!)
|
|
|
|
echo
|
|
info "Anwendung unter http://localhost:3000"
|
|
[ "$MIT_WORKER" = "1" ] || warn "Ohne Worker: Rollen werden nicht abgeglichen, /api/health meldet das Gateway als gestört"
|
|
echo
|
|
|
|
wait
|