feat(ops): script to rotate PostgreSQL password safely
Add rotate-postgres-password.sh with optional app role, document the procedure, and stop defaulting production POSTGRES_PASSWORD to postgres. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,182 +0,0 @@
|
|||||||
---
|
|
||||||
name: merge
|
|
||||||
description: >-
|
|
||||||
Merge Git branches safely — fetch latest, merge or rebase onto master, resolve
|
|
||||||
conflicts intelligently, and verify the result. Use when the user asks to merge
|
|
||||||
branches, sync with master, resolve merge conflicts, or bring a feature branch
|
|
||||||
up to date.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Git Merge
|
|
||||||
|
|
||||||
Führe Branch-Merges sicher und nachvollziehbar aus. Für PR-Review, CI und
|
|
||||||
Comment-Triage siehe den **babysit**-Skill — dieser Skill deckt die Git-Merge-
|
|
||||||
Operation selbst ab.
|
|
||||||
|
|
||||||
## Projekt-Kontext
|
|
||||||
|
|
||||||
- **Basis-Branch:** `master` (nicht `main`)
|
|
||||||
- **Monorepo:** `client/` (React PWA) und `server/` (Express API) — Konflikte
|
|
||||||
können in beiden liegen
|
|
||||||
|
|
||||||
## Sicherheitsregeln (immer einhalten)
|
|
||||||
|
|
||||||
- **Niemals** `git config` ändern
|
|
||||||
- **Niemals** `--no-verify`, `--no-gpg-sign` o.ä. ohne explizite Anfrage
|
|
||||||
- **Niemals** `push --force` auf `master` — bei Bedarf warnen und abbrechen
|
|
||||||
- **Niemals** destruktive Befehle (`reset --hard`, `clean -fd`) ohne explizite Anfrage
|
|
||||||
- **Niemals** interaktive Git-Befehle (`-i`-Flags) — nicht unterstützt
|
|
||||||
- **Kein Commit** ohne explizite Anfrage des Users
|
|
||||||
- **Kein Push** ohne explizite Anfrage des Users
|
|
||||||
|
|
||||||
## Workflow
|
|
||||||
|
|
||||||
### 1. Ausgangslage klären
|
|
||||||
|
|
||||||
Parallel ausführen:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git status
|
|
||||||
git branch -vv
|
|
||||||
git log --oneline -5
|
|
||||||
```
|
|
||||||
|
|
||||||
Ermittle:
|
|
||||||
|
|
||||||
- Aktueller Branch
|
|
||||||
- Ziel-Branch (Standard: `master`)
|
|
||||||
- Ob uncommittete Änderungen vorliegen
|
|
||||||
- Ob der Branch einen Remote-Tracking-Branch hat
|
|
||||||
|
|
||||||
**Bei uncommitteten Änderungen:** Stashen (`git stash push -m "pre-merge"`) nur
|
|
||||||
mit Zustimmung oder wenn der User es verlangt hat. Sonst stoppen und melden.
|
|
||||||
|
|
||||||
### 2. Merge-Strategie wählen
|
|
||||||
|
|
||||||
| Situation | Empfehlung |
|
|
||||||
|-----------|------------|
|
|
||||||
| Feature-Branch aktuell halten | `git merge origin/master` (Merge-Commit) |
|
|
||||||
| Linearer Verlauf gewünscht | `git rebase origin/master` (nur wenn User Rebase verlangt) |
|
|
||||||
| Zwei Feature-Branches zusammenführen | `git merge <branch>` auf Ziel-Branch |
|
|
||||||
|
|
||||||
**Standard:** Merge (nicht Rebase), es sei denn der User verlangt Rebase.
|
|
||||||
|
|
||||||
### 3. Remote aktualisieren
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git fetch origin
|
|
||||||
```
|
|
||||||
|
|
||||||
Vor dem Merge prüfen, wie weit der Branch hinter `origin/master` liegt:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git log --oneline HEAD..origin/master
|
|
||||||
git log --oneline origin/master..HEAD
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. Merge ausführen
|
|
||||||
|
|
||||||
**Feature-Branch mit master synchronisieren** (häuigster Fall):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git checkout <feature-branch>
|
|
||||||
git merge origin/master
|
|
||||||
```
|
|
||||||
|
|
||||||
**Branch in master mergen** (nur wenn User das ausdrücklich will — normalerweise
|
|
||||||
passiert das via PR):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git checkout master
|
|
||||||
git pull origin master
|
|
||||||
git merge <feature-branch>
|
|
||||||
```
|
|
||||||
|
|
||||||
Merge-Commit-Nachricht kurz und sachlich halten, z.B.:
|
|
||||||
`Merge branch 'master' into feature/push-notifications-owner`
|
|
||||||
|
|
||||||
### 5. Konflikte lösen
|
|
||||||
|
|
||||||
Konfliktdateien finden:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git diff --name-only --diff-filter=U
|
|
||||||
```
|
|
||||||
|
|
||||||
**Pro Konfliktdatei:**
|
|
||||||
|
|
||||||
1. Datei lesen und beide Seiten verstehen (HEAD = eigener Branch, incoming = gemergter Branch)
|
|
||||||
2. Intent beider Änderungen erhalten — nicht blind eine Seite wählen
|
|
||||||
3. Konfliktmarker entfernen (`<<<<<<<`, `=======`, `>>>>>>>`)
|
|
||||||
4. Bei widersprüchlicher Intent: Merge abbrechen und User fragen
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git merge --abort # oder: git rebase --abort
|
|
||||||
```
|
|
||||||
|
|
||||||
**Typische Konflikt-Muster in diesem Projekt:**
|
|
||||||
|
|
||||||
| Bereich | Hinweis |
|
|
||||||
|---------|---------|
|
|
||||||
| `package-lock.json` | Nach manueller Lösung `npm install` im betroffenen Paket (`client/` oder `server/`) ausführen |
|
|
||||||
| i18n (`client/src/i18n/`) | Beide Sprachkeys (DE + EN) behalten, keine Keys verlieren |
|
|
||||||
| Prisma/Schema | Migrationen beider Seiten zusammenführen, nicht überschreiben |
|
|
||||||
| Verschlüsselung/Auth | Vorsichtig — keine Sicherheitslogik stillschweigend vereinfachen |
|
|
||||||
|
|
||||||
Nach jeder gelösten Datei:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add <file>
|
|
||||||
```
|
|
||||||
|
|
||||||
Merge abschließen (nur wenn User Commit verlangt hat):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git commit -m "$(cat <<'EOF'
|
|
||||||
Merge branch 'master' into <feature-branch>
|
|
||||||
|
|
||||||
EOF
|
|
||||||
)"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 6. Verifizieren
|
|
||||||
|
|
||||||
Nach erfolgreichem Merge:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git status
|
|
||||||
git log --oneline -5
|
|
||||||
```
|
|
||||||
|
|
||||||
Relevante Checks je nach betroffenen Bereichen:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Client
|
|
||||||
cd client && npm run build
|
|
||||||
|
|
||||||
# Server
|
|
||||||
cd server && npm run build
|
|
||||||
```
|
|
||||||
|
|
||||||
Bei Lockfile-Konflikten oder Dependency-Änderungen: Build in beiden Paketen prüfen.
|
|
||||||
|
|
||||||
### 7. Abschluss
|
|
||||||
|
|
||||||
- Ergebnis dem User mitteilen: welche Branches, wie viele Konflikte, was gelöst wurde
|
|
||||||
- Bei `git stash`: erinnern, Stash wieder anzuwenden (`git stash pop`)
|
|
||||||
- Push nur auf explizite Anfrage: `git push origin <branch>`
|
|
||||||
|
|
||||||
## Wann abbrechen und fragen
|
|
||||||
|
|
||||||
- Widersprüchliche fachliche Intent (z.B. beide Seiten ändern dieselbe Logik unterschiedlich)
|
|
||||||
- Konflikte in Krypto-, Auth- oder Sync-Kernlogik ohne klares „richtig“
|
|
||||||
- Merge würde `.env`, Credentials oder Secrets einschließen
|
|
||||||
- User wollte nur Status prüfen, nicht tatsächlich mergen
|
|
||||||
|
|
||||||
## Abgrenzung zu anderen Skills
|
|
||||||
|
|
||||||
| Skill | Wann |
|
|
||||||
|-------|------|
|
|
||||||
| **merge** (dieser) | Git merge/rebase, Konflikte, Branch sync |
|
|
||||||
| **babysit** | PR merge-ready: Comments, CI, PR-Konflikte im PR-Kontext |
|
|
||||||
| **creating-pull-requests** | PR erstellen und pushen |
|
|
||||||
@@ -18,6 +18,8 @@ ORIGIN=http://localhost:5173
|
|||||||
# TRUST_PROXY=1
|
# TRUST_PROXY=1
|
||||||
|
|
||||||
# Docker Compose database (required for production deploy)
|
# Docker Compose database (required for production deploy)
|
||||||
|
# Generate: openssl rand -hex 24
|
||||||
|
# Rotate on running server: ./scripts/rotate-postgres-password.sh (see docs/deployment/postgres-password.md)
|
||||||
# POSTGRES_USER=postgres
|
# POSTGRES_USER=postgres
|
||||||
# POSTGRES_PASSWORD=
|
# POSTGRES_PASSWORD=
|
||||||
# POSTGRES_DB=daagbox
|
# POSTGRES_DB=daagbox
|
||||||
|
|||||||
@@ -258,6 +258,7 @@ Hinter **Nginx Proxy Manager**: [docs/deployment/npm-security.md](docs/deploymen
|
|||||||
| Dokument | Inhalt |
|
| Dokument | Inhalt |
|
||||||
|----------|--------|
|
|----------|--------|
|
||||||
| [docs/deployment/npm-security.md](docs/deployment/npm-security.md) | NPM, TLS, `trust proxy`, Security-Header |
|
| [docs/deployment/npm-security.md](docs/deployment/npm-security.md) | NPM, TLS, `trust proxy`, Security-Header |
|
||||||
|
| [docs/deployment/postgres-password.md](docs/deployment/postgres-password.md) | PostgreSQL-Passwort rotieren / App-Rolle |
|
||||||
| [docs/plausible-events.md](docs/plausible-events.md) | Custom Events für Plausible Analytics |
|
| [docs/plausible-events.md](docs/plausible-events.md) | Custom Events für Plausible Analytics |
|
||||||
| [docs/push-notifications-plan.md](docs/push-notifications-plan.md) | Web Push: Architektur, API, Testplan |
|
| [docs/push-notifications-plan.md](docs/push-notifications-plan.md) | Web Push: Architektur, API, Testplan |
|
||||||
| [docs/plan-compass-course-dial.md](docs/plan-compass-course-dial.md) | Kompass-Dial: UX- und Implementierungsplan |
|
| [docs/plan-compass-course-dial.md](docs/plan-compass-course-dial.md) | Kompass-Dial: UX- und Implementierungsplan |
|
||||||
|
|||||||
+2
-1
@@ -10,7 +10,8 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- pgdata:/var/lib/postgresql/data
|
- pgdata:/var/lib/postgresql/data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -U postgres -d daagbox"]
|
test: ["CMD-SHELL", "pg_isready -U \"$$POSTGRES_USER\" -d \"$$POSTGRES_DB\""]
|
||||||
|
# Not published to the host — reachable only on the Compose network (do not add ports: here)
|
||||||
interval: 5s
|
interval: 5s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 5
|
retries: 5
|
||||||
|
|||||||
@@ -57,4 +57,4 @@ Optional später: `analytics.kapteins-daagbok.eu` als Alias auf dieselbe Plausib
|
|||||||
|
|
||||||
## Docker Compose
|
## Docker Compose
|
||||||
|
|
||||||
Keine Default-Passwörter in Produktion: `POSTGRES_PASSWORD` und `SESSION_SECRET` in `.env` setzen (siehe [`.env.example`](../../.env.example)).
|
Keine Default-Passwörter in Produktion: starkes `POSTGRES_PASSWORD` (siehe [postgres-password.md](postgres-password.md)) und `SESSION_SECRET` in `.env` setzen (siehe [`.env.example`](../../.env.example)).
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# PostgreSQL absichern (Produktion)
|
||||||
|
|
||||||
|
## Ist-Zustand
|
||||||
|
|
||||||
|
- Die Datenbank läuft im Container `daagbox-prod-db` **ohne** Host-Port (nur Docker-Netz `db:5432`) — gut.
|
||||||
|
- Das Passwort wird beim **ersten** Start des Volumes gesetzt; ein späteres Ändern nur von `POSTGRES_PASSWORD` in `.env` **ändert nicht** das laufende Passwort.
|
||||||
|
- Nach Sprint 1 war auf dem Server noch das Legacy-Passwort `postgres` möglich → per Skript rotieren.
|
||||||
|
|
||||||
|
## Empfohlene Schritte
|
||||||
|
|
||||||
|
1. **Backup/Snapshot** (hast du laut Vorgabe).
|
||||||
|
2. Auf dem Server im Repo:
|
||||||
|
```bash
|
||||||
|
cd /opt/kapteins-daagbok
|
||||||
|
git pull
|
||||||
|
chmod +x scripts/rotate-postgres-password.sh
|
||||||
|
./scripts/rotate-postgres-password.sh
|
||||||
|
```
|
||||||
|
3. Inhalt von `.postgres-credentials.<timestamp>` in den Passwort-Manager übernehmen, Datei auf dem Server löschen:
|
||||||
|
```bash
|
||||||
|
shred -u .postgres-credentials.* # oder rm nach manuellem Notieren
|
||||||
|
```
|
||||||
|
|
||||||
|
### Optional: eigener App-Benutzer (statt `postgres` für Prisma)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/rotate-postgres-password.sh --app-user daagbok
|
||||||
|
```
|
||||||
|
|
||||||
|
- **`daagbok`**: Login für Backend/Prisma (kein Superuser)
|
||||||
|
- **`postgres`**: nur noch Admin (Passwort in `POSTGRES_ADMIN_PASSWORD` in `.env`)
|
||||||
|
|
||||||
|
## Lokale Entwicklung
|
||||||
|
|
||||||
|
`scripts/start-dev.sh` nutzt weiterhin `postgres/postgres` auf localhost — nur für Dev. Produktion nie dieses Passwort wiederverwenden.
|
||||||
|
|
||||||
|
## Verifikation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec daagbox-prod-backend wget -qO- http://127.0.0.1:5000/api/health
|
||||||
|
curl -sf https://kapteins-daagbok.eu/api/health
|
||||||
|
```
|
||||||
Executable
+183
@@ -0,0 +1,183 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Rotate PostgreSQL password on a running Docker Compose stack (existing volume safe).
|
||||||
|
#
|
||||||
|
# The Postgres image only applies POSTGRES_PASSWORD on first init; for existing data
|
||||||
|
# you must ALTER USER inside the running database, then update .env and restart backend.
|
||||||
|
#
|
||||||
|
# Usage (on server in repo root, with backup/snapshot taken):
|
||||||
|
# ./scripts/rotate-postgres-password.sh
|
||||||
|
# ./scripts/rotate-postgres-password.sh --app-user daagbok # optional: dedicated app role
|
||||||
|
#
|
||||||
|
# Writes the new credentials once to .postgres-credentials.<timestamp> (mode 600).
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ENV_FILE="${ENV_FILE:-.env}"
|
||||||
|
COMPOSE_FILE="${COMPOSE_FILE:-docker-compose.yml}"
|
||||||
|
DB_CONTAINER="${DB_CONTAINER:-daagbox-prod-db}"
|
||||||
|
BACKEND_CONTAINER="${BACKEND_CONTAINER:-daagbox-prod-backend}"
|
||||||
|
CREATE_APP_USER=""
|
||||||
|
APP_USER_NAME="daagbok"
|
||||||
|
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
--app-user)
|
||||||
|
CREATE_APP_USER=1
|
||||||
|
APP_USER_NAME="${2:-daagbok}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
sed -n '2,12p' "$0"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option: $1" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ! -f "$ENV_FILE" ]; then
|
||||||
|
echo "Error: $ENV_FILE not found" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
set -a
|
||||||
|
source "$ENV_FILE"
|
||||||
|
set +a
|
||||||
|
|
||||||
|
POSTGRES_USER="${POSTGRES_USER:-postgres}"
|
||||||
|
POSTGRES_DB="${POSTGRES_DB:-daagbox}"
|
||||||
|
OLD_PASSWORD="${POSTGRES_PASSWORD:-}"
|
||||||
|
|
||||||
|
if [ -z "$OLD_PASSWORD" ]; then
|
||||||
|
echo "Error: POSTGRES_PASSWORD not set in $ENV_FILE" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
NEW_PASSWORD="$(openssl rand -hex 24)"
|
||||||
|
NEW_APP_PASSWORD=""
|
||||||
|
if [ -n "$CREATE_APP_USER" ]; then
|
||||||
|
NEW_APP_PASSWORD="$(openssl rand -hex 24)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
BACKUP_ENV="${ENV_FILE}.bak.pg-rotate.$(date +%Y%m%d-%H%M%S)"
|
||||||
|
cp "$ENV_FILE" "$BACKUP_ENV"
|
||||||
|
echo "Backed up $ENV_FILE → $BACKUP_ENV"
|
||||||
|
|
||||||
|
echo "Rotating password for PostgreSQL role: $POSTGRES_USER (database: $POSTGRES_DB)"
|
||||||
|
|
||||||
|
# Escape single quotes for SQL string literals
|
||||||
|
sql_escape() {
|
||||||
|
printf "%s" "$1" | sed "s/'/''/g"
|
||||||
|
}
|
||||||
|
NEW_PW_SQL="$(sql_escape "$NEW_PASSWORD")"
|
||||||
|
|
||||||
|
export PGPASSWORD="$OLD_PASSWORD"
|
||||||
|
if ! docker exec -e PGPASSWORD="$OLD_PASSWORD" "$DB_CONTAINER" \
|
||||||
|
psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -v ON_ERROR_STOP=1 \
|
||||||
|
-c "ALTER USER \"${POSTGRES_USER}\" WITH PASSWORD '${NEW_PW_SQL}';" >/dev/null; then
|
||||||
|
echo "Error: ALTER USER failed. Is POSTGRES_PASSWORD in .env still correct?" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
unset PGPASSWORD
|
||||||
|
|
||||||
|
TARGET_USER="$POSTGRES_USER"
|
||||||
|
TARGET_PASSWORD="$NEW_PASSWORD"
|
||||||
|
|
||||||
|
if [ -n "$CREATE_APP_USER" ]; then
|
||||||
|
APP_PW_SQL="$(sql_escape "$NEW_APP_PASSWORD")"
|
||||||
|
export PGPASSWORD="$NEW_PASSWORD"
|
||||||
|
docker exec -e PGPASSWORD="$NEW_PASSWORD" "$DB_CONTAINER" psql -U postgres -d "$POSTGRES_DB" -v ON_ERROR_STOP=1 <<SQL
|
||||||
|
DO \$\$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '${APP_USER_NAME}') THEN
|
||||||
|
CREATE ROLE ${APP_USER_NAME} LOGIN PASSWORD '${APP_PW_SQL}';
|
||||||
|
ELSE
|
||||||
|
ALTER ROLE ${APP_USER_NAME} WITH LOGIN PASSWORD '${APP_PW_SQL}';
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
\$\$;
|
||||||
|
GRANT CONNECT ON DATABASE ${POSTGRES_DB} TO ${APP_USER_NAME};
|
||||||
|
GRANT USAGE, CREATE ON SCHEMA public TO ${APP_USER_NAME};
|
||||||
|
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO ${APP_USER_NAME};
|
||||||
|
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO ${APP_USER_NAME};
|
||||||
|
ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO ${APP_USER_NAME};
|
||||||
|
ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO ${APP_USER_NAME};
|
||||||
|
SQL
|
||||||
|
unset PGPASSWORD
|
||||||
|
TARGET_USER="$APP_USER_NAME"
|
||||||
|
TARGET_PASSWORD="$NEW_APP_PASSWORD"
|
||||||
|
echo "Created/updated application role: $APP_USER_NAME (postgres superuser password also rotated)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Update .env without exposing values in process list longer than necessary
|
||||||
|
python3 - "$ENV_FILE" "$TARGET_USER" "$TARGET_PASSWORD" "$NEW_PASSWORD" "$CREATE_APP_USER" <<'PY'
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
path = Path(sys.argv[1])
|
||||||
|
target_user = sys.argv[2]
|
||||||
|
target_password = sys.argv[3]
|
||||||
|
postgres_password = sys.argv[4]
|
||||||
|
use_app_user = sys.argv[5] == "1"
|
||||||
|
|
||||||
|
text = path.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
def set_var(name: str, value: str, content: str) -> str:
|
||||||
|
pattern = rf"^{re.escape(name)}=.*$"
|
||||||
|
line = f"{name}={value}"
|
||||||
|
if re.search(pattern, content, flags=re.M):
|
||||||
|
return re.sub(pattern, line, content, count=1, flags=re.M)
|
||||||
|
return content.rstrip() + "\n" + line + "\n"
|
||||||
|
|
||||||
|
text = set_var("POSTGRES_USER", target_user, text)
|
||||||
|
text = set_var("POSTGRES_PASSWORD", target_password, text)
|
||||||
|
text = set_var("POSTGRES_DB", "daagbox", text) if "POSTGRES_DB=" not in text else text
|
||||||
|
if use_app_user:
|
||||||
|
text = set_var("POSTGRES_ADMIN_PASSWORD", postgres_password, text)
|
||||||
|
|
||||||
|
path.write_text(text, encoding="utf-8")
|
||||||
|
PY
|
||||||
|
|
||||||
|
CREDS_FILE=".postgres-credentials.$(date +%Y%m%d-%H%M%S)"
|
||||||
|
umask 077
|
||||||
|
{
|
||||||
|
echo "# Generated $(date -Iseconds) — store in password manager, then delete this file."
|
||||||
|
echo "POSTGRES_USER=$TARGET_USER"
|
||||||
|
echo "POSTGRES_PASSWORD=$TARGET_PASSWORD"
|
||||||
|
echo "POSTGRES_DB=$POSTGRES_DB"
|
||||||
|
if [ -n "$CREATE_APP_USER" ]; then
|
||||||
|
echo "POSTGRES_ADMIN_USER=postgres"
|
||||||
|
echo "POSTGRES_ADMIN_PASSWORD=$NEW_PASSWORD"
|
||||||
|
fi
|
||||||
|
} > "$CREDS_FILE"
|
||||||
|
chmod 600 "$CREDS_FILE"
|
||||||
|
echo "Credentials written to $CREDS_FILE (chmod 600)"
|
||||||
|
|
||||||
|
echo "Restarting backend to pick up DATABASE_URL..."
|
||||||
|
docker compose -f "$COMPOSE_FILE" up -d backend
|
||||||
|
|
||||||
|
echo "Waiting for backend health..."
|
||||||
|
for _ in $(seq 1 45); do
|
||||||
|
status="$(docker inspect --format='{{.State.Health.Status}}' "$BACKEND_CONTAINER" 2>/dev/null || echo missing)"
|
||||||
|
if [ "$status" = healthy ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
export PGPASSWORD="$TARGET_PASSWORD"
|
||||||
|
docker exec -e PGPASSWORD="$TARGET_PASSWORD" "$DB_CONTAINER" \
|
||||||
|
psql -U "$TARGET_USER" -d "$POSTGRES_DB" -tAc 'SELECT count(*) FROM "User";' >/dev/null
|
||||||
|
unset PGPASSWORD
|
||||||
|
|
||||||
|
if curl -sf http://127.0.0.1/api/health | grep -q '"status":"ok"'; then
|
||||||
|
echo "OK: /api/health and DB connection verified."
|
||||||
|
else
|
||||||
|
echo "Warning: health check failed — see: docker compose logs backend" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Done. Remove $CREDS_FILE after saving credentials securely."
|
||||||
@@ -29,8 +29,11 @@ echo "Patching $ENV_FILE for Sprint 1..."
|
|||||||
# Match running container (docker exec daagbox-prod-db: USER=postgres DB=daagbox)
|
# Match running container (docker exec daagbox-prod-db: USER=postgres DB=daagbox)
|
||||||
ensure_var POSTGRES_USER "postgres"
|
ensure_var POSTGRES_USER "postgres"
|
||||||
ensure_var POSTGRES_DB "daagbox"
|
ensure_var POSTGRES_DB "daagbox"
|
||||||
# Default from legacy docker-compose.yml; change only if you use a different DB password
|
if ! grep -q "^POSTGRES_PASSWORD=" "$ENV_FILE" || grep -q "^POSTGRES_PASSWORD=$" "$ENV_FILE"; then
|
||||||
ensure_var POSTGRES_PASSWORD "postgres"
|
echo " skip POSTGRES_PASSWORD (set manually or run scripts/rotate-postgres-password.sh)"
|
||||||
|
else
|
||||||
|
echo " keep POSTGRES_PASSWORD (already set)"
|
||||||
|
fi
|
||||||
# NPM on 172.16.10.10 → app on this host
|
# NPM on 172.16.10.10 → app on this host
|
||||||
ensure_var TRUST_PROXY "172.16.10.10"
|
ensure_var TRUST_PROXY "172.16.10.10"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user