Compare commits

...

1 Commits

Author SHA1 Message Date
Matti Nannt
b81235ac71 refactor: simplify Docker build by removing dummy secret requirements
- Add build-time defaults for DATABASE_URL, ENCRYPTION_KEY, and REDIS_URL in env.ts
- Remove secret mounting for dummy values from Dockerfile
- Delete read-secrets.sh script (no longer needed)
- Update all GitHub Actions and workflows to remove DUMMY_* secrets
- Only SENTRY_AUTH_TOKEN remains as optional secret for sourcemap uploads

This simplifies local Docker builds - users can now build with just:
  docker build -f apps/web/Dockerfile -t formbricks-web .

Build-time validation uses defaults, runtime validation remains strict.
2025-11-27 09:49:26 +01:00
8 changed files with 27 additions and 89 deletions

View File

@@ -281,15 +281,9 @@ runs:
tags: ${{ inputs.registry_type == 'ecr' && steps.ecr-tags.outputs.tags || (inputs.registry_type == 'ghcr' && inputs.experimental_mode == 'true' && steps.ghcr-meta-experimental.outputs.tags) || (inputs.registry_type == 'ghcr' && inputs.experimental_mode == 'false' && steps.ghcr-extra-tags.outputs.tags) || (inputs.registry_type == 'ghcr' && format('ghcr.io/{0}:{1}', inputs.ghcr_image_name, steps.version.outputs.version)) || (inputs.registry_type == 'ecr' && format('{0}/{1}:{2}', inputs.ecr_registry, inputs.ecr_repository, steps.version.outputs.version)) }}
labels: ${{ inputs.registry_type == 'ghcr' && inputs.experimental_mode == 'true' && steps.ghcr-meta-experimental.outputs.labels || '' }}
secrets: |
database_url=${{ env.DUMMY_DATABASE_URL }}
encryption_key=${{ env.DUMMY_ENCRYPTION_KEY }}
redis_url=${{ env.DUMMY_REDIS_URL }}
sentry_auth_token=${{ env.SENTRY_AUTH_TOKEN }}
env:
DEPOT_PROJECT_TOKEN: ${{ env.DEPOT_PROJECT_TOKEN }}
DUMMY_DATABASE_URL: ${{ env.DUMMY_DATABASE_URL }}
DUMMY_ENCRYPTION_KEY: ${{ env.DUMMY_ENCRYPTION_KEY }}
DUMMY_REDIS_URL: ${{ env.DUMMY_REDIS_URL }}
SENTRY_AUTH_TOKEN: ${{ env.SENTRY_AUTH_TOKEN }}
- name: Sign GHCR image (GHCR only)

View File

@@ -88,7 +88,4 @@ jobs:
make_latest: ${{ inputs.MAKE_LATEST }}
env:
DEPOT_PROJECT_TOKEN: ${{ secrets.DEPOT_PROJECT_TOKEN }}
DUMMY_DATABASE_URL: ${{ secrets.DUMMY_DATABASE_URL }}
DUMMY_ENCRYPTION_KEY: ${{ secrets.DUMMY_ENCRYPTION_KEY }}
DUMMY_REDIS_URL: ${{ secrets.DUMMY_REDIS_URL }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}

View File

@@ -70,9 +70,7 @@ jobs:
cache-from: type=gha
cache-to: type=gha,mode=max
secrets: |
database_url=${{ secrets.DUMMY_DATABASE_URL }}
encryption_key=${{ secrets.DUMMY_ENCRYPTION_KEY }}
redis_url=redis://localhost:6379
sentry_auth_token=
- name: Verify and Initialize PostgreSQL
run: |
@@ -129,7 +127,6 @@ jobs:
shell: bash
env:
GITHUB_SHA: ${{ github.sha }}
DUMMY_ENCRYPTION_KEY: ${{ secrets.DUMMY_ENCRYPTION_KEY }}
run: |
echo "🧪 Testing if the Docker image starts correctly..."
@@ -141,7 +138,7 @@ jobs:
$DOCKER_RUN_ARGS \
-p 3000:3000 \
-e DATABASE_URL="postgresql://test:test@host.docker.internal:5432/formbricks" \
-e ENCRYPTION_KEY="$DUMMY_ENCRYPTION_KEY" \
-e ENCRYPTION_KEY="test-key-00000000000000000000000000000000000000000000000000" \
-e REDIS_URL="redis://host.docker.internal:6379" \
-d "formbricks-test:$GITHUB_SHA"

View File

@@ -44,7 +44,4 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DEPOT_PROJECT_TOKEN: ${{ secrets.DEPOT_PROJECT_TOKEN }}
DUMMY_DATABASE_URL: ${{ secrets.DUMMY_DATABASE_URL }}
DUMMY_ENCRYPTION_KEY: ${{ secrets.DUMMY_ENCRYPTION_KEY }}
DUMMY_REDIS_URL: ${{ secrets.DUMMY_REDIS_URL }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}

View File

@@ -102,7 +102,4 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DEPOT_PROJECT_TOKEN: ${{ secrets.DEPOT_PROJECT_TOKEN }}
DUMMY_DATABASE_URL: ${{ secrets.DUMMY_DATABASE_URL }}
DUMMY_ENCRYPTION_KEY: ${{ secrets.DUMMY_ENCRYPTION_KEY }}
DUMMY_REDIS_URL: ${{ secrets.DUMMY_REDIS_URL }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}

View File

@@ -25,10 +25,6 @@ RUN corepack prepare pnpm@9.15.9 --activate
# Install necessary build tools and compilers
RUN apk update && apk add --no-cache cmake g++ gcc jq make openssl-dev python3
# Copy the secrets handling script
COPY apps/web/scripts/docker/read-secrets.sh /tmp/read-secrets.sh
RUN chmod +x /tmp/read-secrets.sh
# Increase Node.js memory limit as a regular build argument
ARG NODE_OPTIONS="--max_old_space_size=8192"
ENV NODE_OPTIONS=${NODE_OPTIONS}
@@ -37,6 +33,10 @@ ENV NODE_OPTIONS=${NODE_OPTIONS}
# but needs explicit declaration for some build systems (like Depot)
ARG TARGETARCH
# Base path for the application (optional)
ARG BASE_PATH=""
ENV BASE_PATH=${BASE_PATH}
# Set the working directory
WORKDIR /app
@@ -57,13 +57,11 @@ RUN pnpm install --ignore-scripts
# Build the database package first
RUN pnpm build --filter=@formbricks/database
# Build the project using our secret reader script
# This mounts the secrets only during this build step without storing them in layers
RUN --mount=type=secret,id=database_url \
--mount=type=secret,id=encryption_key \
--mount=type=secret,id=redis_url \
--mount=type=secret,id=sentry_auth_token \
/tmp/read-secrets.sh pnpm build --filter=@formbricks/web...
# Build the project - only mount Sentry token for optional sourcemap uploads
# DATABASE_URL, REDIS_URL, ENCRYPTION_KEY defaults are provided by env.ts during build
RUN --mount=type=secret,id=sentry_auth_token \
SENTRY_AUTH_TOKEN=$(cat /run/secrets/sentry_auth_token 2>/dev/null || echo "") \
pnpm build --filter=@formbricks/web...
# Extract Prisma version
RUN jq -r '.devDependencies.prisma' packages/database/package.json > /prisma_version.txt

View File

@@ -1,6 +1,10 @@
import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";
// During build time, we only need valid-format URLs for Prisma to generate the client.
// Actual connectivity and secrets are validated at runtime by the startup script.
const isBuildTime = process.env.NEXT_PHASE === "phase-production-build";
export const env = createEnv({
/*
* Serverside Environment variables, not available on the client.
@@ -14,14 +18,21 @@ export const env = createEnv({
CRON_SECRET: z.string().optional(),
BREVO_API_KEY: z.string().optional(),
BREVO_LIST_ID: z.string().optional(),
DATABASE_URL: z.string().url(),
DATABASE_URL: isBuildTime
? z
.string()
.optional()
.default("postgresql://formbricks:formbricks@localhost:5432/formbricks?schema=public")
: z.string().url(),
DEBUG: z.enum(["1", "0"]).optional(),
AUTH_DEFAULT_TEAM_ID: z.string().optional(),
AUTH_SKIP_INVITE_FOR_SSO: z.enum(["1", "0"]).optional(),
E2E_TESTING: z.enum(["1", "0"]).optional(),
EMAIL_AUTH_DISABLED: z.enum(["1", "0"]).optional(),
EMAIL_VERIFICATION_DISABLED: z.enum(["1", "0"]).optional(),
ENCRYPTION_KEY: z.string(),
ENCRYPTION_KEY: isBuildTime
? z.string().optional().default("0000000000000000000000000000000000000000000000000000000000000000")
: z.string(),
ENTERPRISE_LICENSE_KEY: z.string().optional(),
GITHUB_ID: z.string().optional(),
GITHUB_SECRET: z.string().optional(),
@@ -54,8 +65,9 @@ export const env = createEnv({
OIDC_ISSUER: z.string().optional(),
OIDC_SIGNING_ALGORITHM: z.string().optional(),
OPENTELEMETRY_LISTENER_URL: z.string().optional(),
REDIS_URL:
process.env.NODE_ENV === "test"
REDIS_URL: isBuildTime
? z.string().optional().default("redis://localhost:6379")
: process.env.NODE_ENV === "test"
? z.string().optional()
: z.string().url("REDIS_URL is required for caching, rate limiting, and audit logging"),
PASSWORD_RESET_DISABLED: z.enum(["1", "0"]).optional(),

View File

@@ -1,54 +0,0 @@
#!/bin/sh
set -eu
if [ -f "/run/secrets/database_url" ]; then
IFS= read -r DATABASE_URL < /run/secrets/database_url || true
DATABASE_URL=${DATABASE_URL%$'\n'}
export DATABASE_URL
else
echo "DATABASE_URL secret not found. Build will fail because it is required by the application."
fi
if [ -f "/run/secrets/encryption_key" ]; then
IFS= read -r ENCRYPTION_KEY < /run/secrets/encryption_key || true
ENCRYPTION_KEY=${ENCRYPTION_KEY%$'\n'}
export ENCRYPTION_KEY
else
echo "ENCRYPTION_KEY secret not found. Build will fail because it is required by the application."
fi
if [ -f "/run/secrets/redis_url" ]; then
IFS= read -r REDIS_URL < /run/secrets/redis_url || true
REDIS_URL=${REDIS_URL%$'\n'}
export REDIS_URL
else
echo "REDIS_URL secret not found. Build will fail because it is required by the application."
fi
if [ -f "/run/secrets/sentry_auth_token" ]; then
# Only upload sourcemaps on amd64 platform to avoid duplicate uploads
# Sourcemaps are platform-agnostic, so we only need to upload once
# TARGETARCH is automatically set by Docker during multi-platform builds
if [ "${TARGETARCH:-}" = "amd64" ]; then
IFS= read -r SENTRY_AUTH_TOKEN < /run/secrets/sentry_auth_token || true
SENTRY_AUTH_TOKEN=${SENTRY_AUTH_TOKEN%$'\n'}
export SENTRY_AUTH_TOKEN
echo "✅ Sentry auth token found. Sourcemaps will be uploaded during build (${TARGETARCH} platform)."
echo "🔧 SENTRY_AUTH_TOKEN environment variable exported for build process."
else
echo "✅ Sentry auth token found but skipping upload on ${TARGETARCH:-unknown} platform."
echo " Sourcemaps will only be uploaded on amd64 platform to avoid duplicates."
echo "🔧 Debug IDs will still be injected for proper error correlation."
fi
else
echo "⚠️ SENTRY_AUTH_TOKEN secret not found. Sourcemaps will not be uploaded but Debug IDs will still be injected."
fi
# Verify environment variables are set before starting build
echo " DATABASE_URL: $([ -n "${DATABASE_URL:-}" ] && printf '[SET]' || printf '[NOT SET]')"
echo " ENCRYPTION_KEY: $([ -n "${ENCRYPTION_KEY:-}" ] && printf '[SET]' || printf '[NOT SET]')"
echo " REDIS_URL: $([ -n "${REDIS_URL:-}" ] && printf '[SET]' || printf '[NOT SET]')"
echo " SENTRY_AUTH_TOKEN: $([ -n "${SENTRY_AUTH_TOKEN:-}" ] && printf '[SET]' || printf '[NOT SET]')"
echo " TARGETARCH: $([ -n "${TARGETARCH:-}" ] && printf '%s' "${TARGETARCH}" || printf '[NOT SET]')"
exec "$@"