81 lines
3.3 KiB
Bash
81 lines
3.3 KiB
Bash
#!/bin/sh
|
|
# Infisical secret injection entrypoint
|
|
# Fetches secrets from Infisical API and injects them as env vars before starting the app.
|
|
# Required env vars: INFISICAL_CLIENT_ID, INFISICAL_CLIENT_SECRET
|
|
# Optional: INFISICAL_PROJECT_SLUG (default: rspace), INFISICAL_ENV (default: prod),
|
|
# INFISICAL_URL (default: http://infisical:8080)
|
|
# Optional: INFISICAL_AI_CLIENT_ID, INFISICAL_AI_CLIENT_SECRET — fetches AI keys
|
|
# from a second Infisical project (INFISICAL_AI_PROJECT_SLUG, INFISICAL_AI_SECRET_PATH)
|
|
|
|
set -e
|
|
|
|
INFISICAL_URL="${INFISICAL_URL:-http://infisical:8080}"
|
|
INFISICAL_ENV="${INFISICAL_ENV:-prod}"
|
|
INFISICAL_PROJECT_SLUG="${INFISICAL_PROJECT_SLUG:-rspace}"
|
|
|
|
fetch_secrets() {
|
|
# Args: $1=clientId, $2=clientSecret, $3=projectSlug, $4=secretPath, $5=label
|
|
bun -e "
|
|
(async () => {
|
|
try {
|
|
const base = '$INFISICAL_URL';
|
|
const auth = await fetch(base + '/api/v1/auth/universal-auth/login', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ clientId: '$1', clientSecret: '$2' })
|
|
}).then(r => r.json());
|
|
if (!auth.accessToken) { console.error('[infisical:$5] Auth failed'); process.exit(1); }
|
|
|
|
const secrets = await fetch(base + '/api/v3/secrets/raw?workspaceSlug=$3&environment=$INFISICAL_ENV&secretPath=$4&recursive=true', {
|
|
headers: { 'Authorization': 'Bearer ' + auth.accessToken }
|
|
}).then(r => r.json());
|
|
|
|
if (!secrets.secrets) { console.error('[infisical:$5] No secrets returned'); process.exit(1); }
|
|
|
|
for (const s of secrets.secrets) {
|
|
const escaped = s.secretValue.replace(/'/g, \"'\\\\''\" );
|
|
console.log('export ' + s.secretKey + \"='\" + escaped + \"'\");
|
|
}
|
|
} catch (e) { console.error('[infisical:$5] Error:', e.message); process.exit(1); }
|
|
})();
|
|
" 2>&1
|
|
}
|
|
|
|
if [ -z "$INFISICAL_CLIENT_ID" ] || [ -z "$INFISICAL_CLIENT_SECRET" ]; then
|
|
echo "[infisical] No credentials set, starting without secret injection"
|
|
exec "$@"
|
|
fi
|
|
|
|
# ── Primary project secrets (rspace) ──
|
|
echo "[infisical] Fetching secrets from ${INFISICAL_PROJECT_SLUG}/${INFISICAL_ENV}..."
|
|
EXPORTS=$(fetch_secrets "$INFISICAL_CLIENT_ID" "$INFISICAL_CLIENT_SECRET" "$INFISICAL_PROJECT_SLUG" "/" "primary") || {
|
|
echo "[infisical] WARNING: Failed to fetch primary secrets, starting with existing env vars"
|
|
exec "$@"
|
|
}
|
|
|
|
if echo "$EXPORTS" | grep -q "^export "; then
|
|
COUNT=$(echo "$EXPORTS" | grep -c "^export ")
|
|
eval "$EXPORTS"
|
|
echo "[infisical] Injected ${COUNT} secrets from ${INFISICAL_PROJECT_SLUG}"
|
|
else
|
|
echo "[infisical] WARNING: $EXPORTS"
|
|
echo "[infisical] Starting with existing env vars"
|
|
fi
|
|
|
|
# ── AI project secrets (optional second source) ──
|
|
if [ -n "$INFISICAL_AI_CLIENT_ID" ] && [ -n "$INFISICAL_AI_CLIENT_SECRET" ]; then
|
|
AI_SLUG="${INFISICAL_AI_PROJECT_SLUG:-claude-ops}"
|
|
AI_PATH="${INFISICAL_AI_SECRET_PATH:-/ai}"
|
|
echo "[infisical] Fetching AI secrets from ${AI_SLUG}${AI_PATH}..."
|
|
AI_EXPORTS=$(fetch_secrets "$INFISICAL_AI_CLIENT_ID" "$INFISICAL_AI_CLIENT_SECRET" "$AI_SLUG" "$AI_PATH" "ai") || true
|
|
if echo "$AI_EXPORTS" | grep -q "^export "; then
|
|
AI_COUNT=$(echo "$AI_EXPORTS" | grep -c "^export ")
|
|
eval "$AI_EXPORTS"
|
|
echo "[infisical] Injected ${AI_COUNT} AI secrets from ${AI_SLUG}${AI_PATH}"
|
|
else
|
|
echo "[infisical] WARNING: Failed to fetch AI secrets: $AI_EXPORTS"
|
|
fi
|
|
fi
|
|
|
|
exec "$@"
|