New unified helm chart at helm/marktvogt/ that combines backend (Go API, Postgres, Dragonfly, migrate hook, discovery cron) and web (SvelteKit SSR) into a single release. Replaces the per-service charts at backend/deploy/helm and web/deploy/helm — kept in place until the live migration is verified (see helm/marktvogt/MIGRATION.md). Selector labels and resource names match the existing per-service charts exactly so migration is by re-annotation rather than recreate; CNPG cluster and Dragonfly survive the cutover with no data loss. Adds scripts/k8s-secrets-sync.sh + .env.helm.example for reproducible out-of-band secret creation. .env.helm itself is gitignored.
93 lines
2.8 KiB
Bash
Executable File
93 lines
2.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Sync Kubernetes secrets to tenant-2 from a local .env.helm file.
|
|
# Idempotent — safe to run repeatedly. Uses dry-run | apply pattern so existing
|
|
# secrets get updated in place rather than recreated.
|
|
#
|
|
# Usage: ./scripts/k8s-secrets-sync.sh [path/to/.env.helm]
|
|
# Default env file is .env.helm at repo root. Override namespace via NAMESPACE env.
|
|
|
|
set -euo pipefail
|
|
|
|
ENV_FILE="${1:-.env.helm}"
|
|
NS="${NAMESPACE:-tenant-2}"
|
|
|
|
if [[ ! -f "$ENV_FILE" ]]; then
|
|
echo "Missing $ENV_FILE"
|
|
echo "Copy .env.helm.example to .env.helm and fill in values."
|
|
exit 1
|
|
fi
|
|
|
|
# Parse line by line — no shell interpretation of values. Avoids `source`
|
|
# choking on unquoted spaces, $, %, etc. that are legitimate in secrets.
|
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
|
# Skip blanks + comments
|
|
[[ -z "${line//[[:space:]]/}" ]] && continue
|
|
[[ "${line#"${line%%[![:space:]]*}"}" =~ ^# ]] && continue
|
|
# Split on first =
|
|
key="${line%%=*}"
|
|
value="${line#*=}"
|
|
# Trim whitespace from key
|
|
key="${key//[[:space:]]/}"
|
|
[[ -z "$key" ]] && continue
|
|
export "$key=$value"
|
|
done < "$ENV_FILE"
|
|
|
|
apply_secret() {
|
|
local name=$1
|
|
shift
|
|
local args=()
|
|
local missing=()
|
|
for kv in "$@"; do
|
|
local key="${kv%%=*}"
|
|
local var="${kv#*=}"
|
|
local val="${!var:-}"
|
|
if [[ -z "$val" ]]; then
|
|
missing+=("$var")
|
|
continue
|
|
fi
|
|
args+=(--from-literal="$key=$val")
|
|
done
|
|
if [[ ${#args[@]} -eq 0 ]]; then
|
|
echo "skip $name — no values set in $ENV_FILE"
|
|
return
|
|
fi
|
|
if [[ ${#missing[@]} -gt 0 ]]; then
|
|
echo "apply secret/$name in $NS (omitting unset: ${missing[*]})"
|
|
else
|
|
echo "apply secret/$name in $NS"
|
|
fi
|
|
kubectl create secret generic "$name" \
|
|
--namespace="$NS" \
|
|
"${args[@]}" \
|
|
--dry-run=client -o yaml | kubectl apply -f -
|
|
}
|
|
|
|
# App-level secrets the backend reads via envFrom: secretRef
|
|
apply_secret marktvogt-backend-secrets \
|
|
"APP_SECRET=APP_SECRET" \
|
|
"SENTRY_DSN=SENTRY_DSN" \
|
|
"OAUTH_GOOGLE_CLIENT_ID=OAUTH_GOOGLE_CLIENT_ID" \
|
|
"OAUTH_GOOGLE_CLIENT_SECRET=OAUTH_GOOGLE_CLIENT_SECRET" \
|
|
"OAUTH_APPLE_CLIENT_ID=OAUTH_APPLE_CLIENT_ID" \
|
|
"OAUTH_APPLE_CLIENT_SECRET=OAUTH_APPLE_CLIENT_SECRET" \
|
|
"OAUTH_FACEBOOK_CLIENT_ID=OAUTH_FACEBOOK_CLIENT_ID" \
|
|
"OAUTH_FACEBOOK_CLIENT_SECRET=OAUTH_FACEBOOK_CLIENT_SECRET" \
|
|
"OAUTH_GITHUB_CLIENT_ID=OAUTH_GITHUB_CLIENT_ID" \
|
|
"OAUTH_GITHUB_CLIENT_SECRET=OAUTH_GITHUB_CLIENT_SECRET"
|
|
|
|
# SMTP credentials
|
|
apply_secret marktvogt-backend-smtp \
|
|
"SMTP_HOST=SMTP_HOST" \
|
|
"SMTP_USER=SMTP_USER" \
|
|
"SMTP_PASSWORD=SMTP_PASSWORD"
|
|
|
|
# Turnstile + discovery + AI bootstrap
|
|
apply_secret marktvogt-backend-ci-secrets \
|
|
"TURNSTILE_SECRET_KEY=TURNSTILE_SECRET_KEY" \
|
|
"DISCOVERY_TOKEN=DISCOVERY_TOKEN" \
|
|
"AI_API_KEY=AI_API_KEY" \
|
|
"AI_AGENT_SIMPLE=AI_AGENT_SIMPLE" \
|
|
"AI_AGENT_DISCOVERY=AI_AGENT_DISCOVERY"
|
|
|
|
echo "done"
|