diff --git a/.github/actions/build-and-push-docker/action.yml b/.github/actions/build-and-push-docker/action.yml index 3e52c8f108..a3f563006c 100644 --- a/.github/actions/build-and-push-docker/action.yml +++ b/.github/actions/build-and-push-docker/action.yml @@ -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) diff --git a/.github/workflows/build-and-push-ecr.yml b/.github/workflows/build-and-push-ecr.yml index c8c96eb00c..e0021c8c31 100644 --- a/.github/workflows/build-and-push-ecr.yml +++ b/.github/workflows/build-and-push-ecr.yml @@ -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 }} diff --git a/.github/workflows/docker-build-validation.yml b/.github/workflows/docker-build-validation.yml index 8fc29e3a49..9dd8e2c36e 100644 --- a/.github/workflows/docker-build-validation.yml +++ b/.github/workflows/docker-build-validation.yml @@ -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" diff --git a/.github/workflows/release-docker-github-experimental.yml b/.github/workflows/release-docker-github-experimental.yml index ac32a4e9c3..c262546320 100644 --- a/.github/workflows/release-docker-github-experimental.yml +++ b/.github/workflows/release-docker-github-experimental.yml @@ -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 }} diff --git a/.github/workflows/release-docker-github.yml b/.github/workflows/release-docker-github.yml index 9745635d3c..647128cc5c 100644 --- a/.github/workflows/release-docker-github.yml +++ b/.github/workflows/release-docker-github.yml @@ -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 }} diff --git a/apps/web/Dockerfile b/apps/web/Dockerfile index 1a3848b400..bd5a1368b4 100644 --- a/apps/web/Dockerfile +++ b/apps/web/Dockerfile @@ -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 diff --git a/apps/web/lib/env.ts b/apps/web/lib/env.ts index 03226736ac..b7bcb56254 100644 --- a/apps/web/lib/env.ts +++ b/apps/web/lib/env.ts @@ -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(), diff --git a/apps/web/scripts/docker/read-secrets.sh b/apps/web/scripts/docker/read-secrets.sh deleted file mode 100644 index 6a994a4fc8..0000000000 --- a/apps/web/scripts/docker/read-secrets.sh +++ /dev/null @@ -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 "$@" \ No newline at end of file