safe-redeploy-service.sh152 lines · main
1#!/usr/bin/env bash
2# Safe service-scoped redeploy for Briven France (compose project briven-brivenfrance-uilsk6).
3#
4# Why: bare `docker compose up --build` without the Dokploy-managed env blanks
5# secrets and can take down api.briven.tech. This script always loads durable env
6# first, then rebuilds only the services you name.
7#
8# On France:
9# /etc/dokploy/compose/briven-brivenfrance-uilsk6/code/scripts/safe-redeploy-service.sh api
10# /etc/dokploy/compose/briven-brivenfrance-uilsk6/code/scripts/safe-redeploy-service.sh api web docs
11#
12# Env sources (first that exists wins, then layered):
13# 1) /etc/dokploy/compose/briven-brivenfrance-uilsk6/.env.prod (durable secrets)
14# 2) /opt/briven_deploy/infra/dokploy/.env (bootstrap secrets)
15# Live Doltgres password always overrides from the running doltgres container.
16
17set -euo pipefail
18
19COMPOSE_DIR="${BRIVEN_COMPOSE_DIR:-/etc/dokploy/compose/briven-brivenfrance-uilsk6/code}"
20PROJECT="${BRIVEN_COMPOSE_PROJECT:-briven-brivenfrance-uilsk6}"
21FILE="${BRIVEN_COMPOSE_FILE:-infra/dokploy/compose.dokploy.yml}"
22DURABLE_ENV="${BRIVEN_DURABLE_ENV:-/etc/dokploy/compose/briven-brivenfrance-uilsk6/.env.prod}"
23BOOTSTRAP_ENV="${BRIVEN_BOOTSTRAP_ENV:-/opt/briven_deploy/infra/dokploy/.env}"
24
25if [[ $# -lt 1 ]]; then
26 echo "usage: $0 <service> [service...]"
27 echo "examples: $0 api | $0 api web | $0 docs"
28 exit 1
29fi
30
31if [[ ! -d "$COMPOSE_DIR" ]]; then
32 echo "error: compose dir not found: $COMPOSE_DIR (run on France)"
33 exit 1
34fi
35
36cd "$COMPOSE_DIR"
37
38load_env_file() {
39 local f="$1"
40 [[ -f "$f" ]] || return 0
41 set -a
42 # shellcheck disable=SC1090
43 . "$f"
44 set +a
45 echo "loaded env: $f"
46}
47
48load_env_file "$BOOTSTRAP_ENV"
49load_env_file "$DURABLE_ENV"
50
51# Live Doltgres password (container is source of truth)
52if docker ps --format '{{.Names}}' | grep -qx 'briven-brivenfrance-uilsk6-doltgres-1'; then
53 LIVE_PW="$(
54 docker inspect briven-brivenfrance-uilsk6-doltgres-1 \
55 --format '{{range .Config.Env}}{{println .}}{{end}}' \
56 | sed -n 's/^DOLTGRES_PASSWORD=//p'
57 )"
58 if [[ -n "${LIVE_PW:-}" ]]; then
59 export BRIVEN_DOLTGRES_PASSWORD="$LIVE_PW"
60 echo "loaded live DOLTGRES password from container"
61 fi
62fi
63
64# Live MinIO root password is source of truth for S3 access.
65# Compose wires BOTH minio.MINIO_ROOT_PASSWORD and api.BRIVEN_MINIO_SECRET_KEY
66# from ${BRIVEN_MINIO_ROOT_PASSWORD}. If durable/bootstrap has a different
67# value than the already-running MinIO volume, logo uploads fail with
68# SignatureDoesNotMatch (and older UI surfaces a confusing 410 on fallback).
69if docker ps --format '{{.Names}}' | grep -qx 'briven-brivenfrance-uilsk6-minio-1'; then
70 LIVE_MINIO_PW="$(
71 docker inspect briven-brivenfrance-uilsk6-minio-1 \
72 --format '{{range .Config.Env}}{{println .}}{{end}}' \
73 | sed -n 's/^MINIO_ROOT_PASSWORD=//p'
74 )"
75 if [[ -n "${LIVE_MINIO_PW:-}" ]]; then
76 export BRIVEN_MINIO_ROOT_PASSWORD="$LIVE_MINIO_PW"
77 export BRIVEN_MINIO_SECRET_KEY="$LIVE_MINIO_PW"
78 # Keep durable env in lockstep so the next redeploy does not drift again.
79 if [[ -f "$DURABLE_ENV" ]]; then
80 if grep -q '^BRIVEN_MINIO_ROOT_PASSWORD=' "$DURABLE_ENV"; then
81 tmp=$(mktemp)
82 while IFS= read -r line || [[ -n "$line" ]]; do
83 case "$line" in
84 BRIVEN_MINIO_ROOT_PASSWORD=*) echo "BRIVEN_MINIO_ROOT_PASSWORD=$LIVE_MINIO_PW" ;;
85 BRIVEN_MINIO_SECRET_KEY=*) echo "BRIVEN_MINIO_SECRET_KEY=$LIVE_MINIO_PW" ;;
86 *) printf '%s\n' "$line" ;;
87 esac
88 done < "$DURABLE_ENV" > "$tmp"
89 mv "$tmp" "$DURABLE_ENV"
90 else
91 printf '\nBRIVEN_MINIO_ROOT_PASSWORD=%s\nBRIVEN_MINIO_SECRET_KEY=%s\n' \
92 "$LIVE_MINIO_PW" "$LIVE_MINIO_PW" >> "$DURABLE_ENV"
93 fi
94 chmod 600 "$DURABLE_ENV"
95 fi
96 echo "loaded live MINIO root password from container (len=${#LIVE_MINIO_PW})"
97 fi
98fi
99
100export BRIVEN_DOMAIN="${BRIVEN_DOMAIN:-briven.tech}"
101export BRIVEN_DOMAIN="${BRIVEN_DOMAIN#https://}"
102export BRIVEN_DOMAIN="${BRIVEN_DOMAIN#http://}"
103export BRIVEN_DOMAIN="${BRIVEN_DOMAIN%%/*}"
104
105if [[ -z "${BRIVEN_DOLTGRES_PASSWORD:-}" ]]; then
106 echo "error: BRIVEN_DOLTGRES_PASSWORD empty — fix $DURABLE_ENV or doltgres container"
107 exit 1
108fi
109if [[ -z "${BRIVEN_ENCRYPTION_KEY:-}" || -z "${BRIVEN_BETTER_AUTH_SECRET:-}" ]]; then
110 echo "error: missing core secrets — copy a full env into $DURABLE_ENV"
111 exit 1
112fi
113
114# Branding + OAuth secrets live in the encrypted tenant-secret store and need
115# BRIVEN_AUTH_MASTER_KEY (64 hex chars). Without it, dashboard Auth → branding
116# save returns "master key not configured for service: auth" and nothing sticks.
117if [[ -z "${BRIVEN_AUTH_MASTER_KEY:-}" || ! "${BRIVEN_AUTH_MASTER_KEY}" =~ ^[0-9a-fA-F]{64}$ ]]; then
118 if [[ -f "$DURABLE_ENV" ]]; then
119 GEN=$(openssl rand -hex 32)
120 if grep -q '^BRIVEN_AUTH_MASTER_KEY=' "$DURABLE_ENV"; then
121 tmp=$(mktemp)
122 while IFS= read -r line || [[ -n "$line" ]]; do
123 case "$line" in
124 BRIVEN_AUTH_MASTER_KEY=*) echo "BRIVEN_AUTH_MASTER_KEY=$GEN" ;;
125 *) printf '%s\n' "$line" ;;
126 esac
127 done < "$DURABLE_ENV" > "$tmp"
128 mv "$tmp" "$DURABLE_ENV"
129 else
130 printf '\nBRIVEN_AUTH_MASTER_KEY=%s\n' "$GEN" >> "$DURABLE_ENV"
131 fi
132 chmod 600 "$DURABLE_ENV"
133 export BRIVEN_AUTH_MASTER_KEY="$GEN"
134 echo "generated BRIVEN_AUTH_MASTER_KEY into $DURABLE_ENV (was missing/invalid)"
135 else
136 echo "error: BRIVEN_AUTH_MASTER_KEY missing and no durable env at $DURABLE_ENV"
137 exit 1
138 fi
139fi
140export BRIVEN_AUTH_MASTER_KEY
141echo "BRIVEN_AUTH_MASTER_KEY loaded (len=${#BRIVEN_AUTH_MASTER_KEY})"
142
143echo "redeploying: $* (project=$PROJECT domain=$BRIVEN_DOMAIN)"
144docker compose -p "$PROJECT" -f "$FILE" build "$@"
145docker compose -p "$PROJECT" -f "$FILE" up -d --force-recreate --no-deps "$@"
146
147echo "done. verify:"
148echo " curl -sS https://api.briven.tech/info | head -c 200"
149echo " curl -sS -o /dev/null -w '%{http_code}\\n' https://docs.briven.tech/auth/parity"
150if [[ " $* " == *" api "* ]] || [[ "$*" == "api" ]]; then
151 echo " docker exec briven-brivenfrance-uilsk6-api-1 sh -c 'echo AUTH_MASTER=\${BRIVEN_AUTH_MASTER_KEY:+SET}'"
152fi