diff --git a/.env.example b/.env.example index 5b8b6d3e..8cea9a21 100644 --- a/.env.example +++ b/.env.example @@ -11,14 +11,35 @@ # --------------------------------------------------------------------- # Required: secrets resolver # --------------------------------------------------------------------- -# SECRET_PROVIDER selects which cloud secret store the resolver fetches -# from. Default `aws` matches the email factory's default backend -# (internal/email/factory.go) — using a value the email factory does -# not understand (e.g. `env`) makes app startup fail because email -# init runs unconditionally. For local dev that doesn't actually call -# email or secret-store paths, `aws` is a safe placeholder. -# aws | gcp | azure -SECRET_PROVIDER=aws +# SECRET_PROVIDER selects which secret store the resolver fetches from. +# aws | gcp | azure — production: real Secrets Manager / Key Vault +# env — local dev: resolve secret names to env vars +# In `env` mode, every secret-ref var (ADMIN_PASSWORD_SECRET, +# API_KEY_SECRET_ARN, etc.) holds the NAME of another env var whose +# value is the actual secret. See `internal/secrets/env_resolver.go`. +# Pairs with EMAIL_ENABLED=false so the email factory's no-op sender +# kicks in (see PR #333) — otherwise `env` is not a recognised email +# backend and the factory would fail dispatch. +SECRET_PROVIDER=env + +# --------------------------------------------------------------------- +# Required: scheduled-task auth mode (no default — must be explicit) +# --------------------------------------------------------------------- +# Selects how the internal /api/scheduled/* endpoints authenticate. +# oidc — production: verify Google-issued OIDC ID tokens +# bearer — shared-secret token in Authorization header +# disabled — local dev: no auth check +# Required by `internal/server/scheduledauth/config.go`; app refuses +# to start when unset. +SCHEDULED_TASK_AUTH_MODE=disabled + +# --------------------------------------------------------------------- +# Required: email gate (factory short-circuit, see PR #333) +# --------------------------------------------------------------------- +# When `false`, internal/email/factory.go returns a no-op sender that +# logs each invocation at debug level instead of dispatching to a +# cloud-specific backend. Pair with SECRET_PROVIDER=env for local dev. +EMAIL_ENABLED=false # --------------------------------------------------------------------- # Required: credential encryption key @@ -35,9 +56,20 @@ CREDENTIAL_ENCRYPTION_ALLOW_DEV_KEY=1 # CREDENTIAL_ENCRYPTION_KEY=<64-hex-chars> # --------------------------------------------------------------------- -# Required for production: admin auth + API -# --------------------------------------------------------------------- -ADMIN_EMAIL=admin@example.com +# Required: admin auth + API +# --------------------------------------------------------------------- +# With SECRET_PROVIDER=env, the *_SECRET / *_SECRET_ARN vars hold the +# NAME of another env var whose value is the actual secret. The matched +# env var must then be defined below. Two reasons for the indirection: +# (1) production uses the same var name pointing at a real ARN/name; +# (2) the dev value is co-located with its lookup key so future readers +# can trace the chain in one file. +ADMIN_EMAIL=admin@cudly.local +ADMIN_PASSWORD_SECRET=ADMIN_PASSWORD_DEV +ADMIN_PASSWORD_DEV=LocalDev!Pass123 +API_KEY_SECRET_ARN=ADMIN_API_KEY_DEV +ADMIN_API_KEY_DEV=cudly-local-dev-api-key-not-for-prod +# Production examples (override SECRET_PROVIDER and these): # ADMIN_PASSWORD_SECRET=arn:aws:secretsmanager:us-east-1:000000000000:secret:cudly-admin-password-PLACEHOLDER # API_KEY_SECRET_ARN=arn:aws:secretsmanager:us-east-1:000000000000:secret:cudly-api-key-PLACEHOLDER diff --git a/docker-compose.yml b/docker-compose.yml index fa8d5d04..b006d78e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -42,10 +42,29 @@ services: DB_AUTO_MIGRATE: "true" DB_MIGRATIONS_PATH: /app/internal/database/postgres/migrations - # Secret provider (use aws with empty credentials for local dev) - SECRET_PROVIDER: aws - # Email disabled for local development (no SNS topic) + # Secret provider — "env" reads secrets from env vars (local-dev only). + # Production uses "aws" / "azure" / "gcp" with real Secrets Manager. + SECRET_PROVIDER: env + + # Admin password secret: the EnvResolver looks up the env var whose + # NAME equals ADMIN_PASSWORD_SECRET. Here it points at ADMIN_PASSWORD_DEV. + ADMIN_PASSWORD_SECRET: ADMIN_PASSWORD_DEV + ADMIN_PASSWORD_DEV: "LocalDev!Pass123" + ADMIN_EMAIL: admin@cudly.local + + # API-key secret: same pattern — name → env var that holds the value. + # Frontend asks for this in the admin-setup modal. + API_KEY_SECRET_ARN: ADMIN_API_KEY_DEV + ADMIN_API_KEY_DEV: "cudly-local-dev-api-key-not-for-prod" + + # Credential encryption: dev key (all-zero) is gated behind this flag. + CREDENTIAL_ENCRYPTION_ALLOW_DEV_KEY: "1" + + # Email disabled for local development (no SNS topic / SES creds) EMAIL_ENABLED: "false" + # Scheduled-task auth: OIDC for prod, disabled for local dev so the + # internal /api/scheduled/* endpoints don't require Google ID tokens. + SCHEDULED_TASK_AUTH_MODE: disabled # Application settings ENVIRONMENT: development