Add Secrets Manager resolution to probod-bootstrap

Introduce a Resolver that owns env lookup and typed parsing for
probod-bootstrap. Env values prefixed with aws://<secret-id> are
fetched from AWS Secrets Manager (plaintext SecretString); each
secret ID is cached per run. Builder now takes a Resolver only.

Prefix every probod-bootstrap input with PROBOD_ so bootstrap config
does not collide with unrelated process environment (for example
AWS_* used by other tooling). Secrets Manager authentication uses
the standard AWS SDK default chain (AWS_REGION, IAM role, profile);
PROBOD_AWS_* vars configure S3 in the generated config only.

Update Helm deployment env names, GNUmakefile dev-config, Lima
provision, e2e testutil, compose.prod.yaml, and docs.

Deployments must rename bootstrap env vars to PROBOD_* (e.g.
AUTH_COOKIE_SECRET → PROBOD_AUTH_COOKIE_SECRET).

BREAKING CHANGE: all env vars are now prefixed by `PROBOD_`.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
This commit is contained in:
Ludovic Vielle
2026-06-24 11:06:49 +02:00
parent 612e9cbc22
commit 2b8f6f5b3b
18 changed files with 1152 additions and 732 deletions

View File

@@ -11,127 +11,136 @@
# - `#` starts a comment, `export KEY=value` is accepted.
# - Malformed assignments (e.g. unquoted spaces) abort `make dev-config`.
#
# See pkg/bootstrap/builder.go for the full env-var surface; the values
# All probod-bootstrap inputs are prefixed with PROBOD_. See pkg/bootstrap/builder.go; the values
# set below in the Makefile's `cfg/dev.yaml` recipe are the dev defaults
# that this file can override.
# ── Base URL & ports ──────────────────────────────────────────────────
# PROBOD_BASE_URL=http://localhost:8080
# API_ADDR=:8080
# API_CORS_ALLOWED_ORIGINS=http://localhost:8080,http://localhost:5173,http://localhost:5174
# TRUST_CENTER_HTTP_ADDR=:80
# TRUST_CENTER_HTTPS_ADDR=:443
# PROBOD_API_ADDR=:8080
# PROBOD_API_CORS_ALLOWED_ORIGINS=http://localhost:8080,http://localhost:5173,http://localhost:5174
# PROBOD_TRUST_CENTER_HTTP_ADDR=:80
# PROBOD_TRUST_CENTER_HTTPS_ADDR=:443
# ── Observability ─────────────────────────────────────────────────────
# METRICS_ADDR=localhost:8081
# TRACING_ADDR=localhost:4317
# PROBOD_METRICS_ADDR=localhost:8081
# PROBOD_TRACING_ADDR=localhost:4317
# ── Secrets (rotate before prod) ──────────────────────────────────────
# PROBOD_ENCRYPTION_KEY=thisisnotasecretAAAAAAAAAAAAAAAAAAAAAAAAAAA=
# AUTH_COOKIE_SECRET=this-is-a-secure-secret-for-cookie-signing-at-least-32-bytes
# AUTH_PASSWORD_PEPPER=this-is-a-secure-pepper-for-password-hashing-at-least-32-bytes
# PROBOD_AUTH_COOKIE_SECRET=this-is-a-secure-secret-for-cookie-signing-at-least-32-bytes
# PROBOD_AUTH_PASSWORD_PEPPER=this-is-a-secure-pepper-for-password-hashing-at-least-32-bytes
#
# Optional: load secrets from AWS Secrets Manager by setting env vars to
# aws://<secret-id> (e.g. PROBOD_ENCRYPTION_KEY=aws://probo/sandbox/probod/encryption_key).
# The path after aws:// is the Secrets Manager secret name or ARN; the
# plaintext SecretString is used directly. Plain env values are also supported.
# Requires AWS credentials for Secrets Manager resolution (IAM role, AWS_ACCESS_KEY_ID,
# or AWS_PROFILE) and AWS_REGION. These use the standard AWS SDK default chain, not
# PROBOD_AWS_*.
# PROBOD_ENCRYPTION_KEY=aws://probo/sandbox/probod/encryption_key
# ── Cookie ────────────────────────────────────────────────────────────
# AUTH_COOKIE_DOMAIN=localhost
# AUTH_COOKIE_SECURE=false
# AUTH_COOKIE_DURATION=24
# PROBOD_AUTH_COOKIE_DOMAIN=localhost
# PROBOD_AUTH_COOKIE_SECURE=false
# PROBOD_AUTH_COOKIE_DURATION=24
# ── Postgres ──────────────────────────────────────────────────────────
# PG_ADDR=localhost:5432
# PG_USERNAME=postgres
# PG_PASSWORD=postgres
# PG_DATABASE=probod
# PG_POOL_SIZE=100
# PG_MIN_POOL_SIZE=10
# PG_MAX_CONN_IDLE_TIME_SECONDS=1800
# PG_MAX_CONN_LIFETIME_SECONDS=3600
# PG_DEBUG=false
# PROBOD_PG_ADDR=localhost:5432
# PROBOD_PG_USERNAME=postgres
# PROBOD_PG_PASSWORD=postgres
# PROBOD_PG_DATABASE=probod
# PROBOD_PG_POOL_SIZE=100
# PROBOD_PG_MIN_POOL_SIZE=10
# PROBOD_PG_MAX_CONN_IDLE_TIME_SECONDS=1800
# PROBOD_PG_MAX_CONN_LIFETIME_SECONDS=3600
# PROBOD_PG_DEBUG=false
# ── Object storage (SeaweedFS via compose) ────────────────────────────
# AWS_REGION=us-east-1
# AWS_BUCKET=probod
# AWS_ACCESS_KEY_ID=probod
# AWS_SECRET_ACCESS_KEY=thisisnotasecret
# AWS_ENDPOINT=http://127.0.0.1:8333
# PROBOD_AWS_REGION=us-east-1
# PROBOD_AWS_BUCKET=probod
# PROBOD_AWS_ACCESS_KEY_ID=probod
# PROBOD_AWS_SECRET_ACCESS_KEY=thisisnotasecret
# PROBOD_AWS_ENDPOINT=http://127.0.0.1:8333
# ── Mailer (Mailpit via compose) ──────────────────────────────────────
# SMTP_ADDR=localhost:1025
# SMTP_USER=
# SMTP_PASSWORD=
# SMTP_TLS_REQUIRED=false
# MAILER_SENDER_EMAIL=no-reply@notification.getprobo.com
# MAILER_SENDER_NAME=Probo
# PROBOD_SMTP_ADDR=localhost:1025
# PROBOD_SMTP_USER=
# PROBOD_SMTP_PASSWORD=
# PROBOD_SMTP_TLS_REQUIRED=false
# PROBOD_MAILER_SENDER_EMAIL=no-reply@notification.getprobo.com
# PROBOD_MAILER_SENDER_NAME=Probo
# ── LLM providers ─────────────────────────────────────────────────────
# OPENAI_API_KEY=sk-...
# ANTHROPIC_API_KEY=sk-ant-...
# LLM_DEFAULT_PROVIDER=openai
# LLM_DEFAULT_MODEL_NAME=gpt-4o
# PROBOD_OPENAI_API_KEY=sk-...
# PROBOD_ANTHROPIC_API_KEY=sk-ant-...
# PROBOD_LLM_DEFAULT_PROVIDER=openai
# PROBOD_LLM_DEFAULT_MODEL_NAME=gpt-4o
# ── LLM-backed workers (inherit from LLM defaults when unset) ─────────
# PROBO_AGENT_PROVIDER=anthropic
# PROBO_AGENT_MODEL_NAME=claude-sonnet-4-6
# EVIDENCE_DESCRIBER_PROVIDER=openai
# EVIDENCE_DESCRIBER_MODEL_NAME=gpt-4o-mini
# AGENT_THIRD_PARTY_VETTER_PROVIDER=openai # inherits AGENT_DEFAULT_PROVIDER when unset
# AGENT_THIRD_PARTY_VETTER_MODEL_NAME=gpt-4o # inherits AGENT_DEFAULT_MODEL_NAME when unset
# THIRD_PARTY_VETTING_INTERVAL=10
# THIRD_PARTY_VETTING_STALE_AFTER=1500
# THIRD_PARTY_VETTING_MAX_CONCURRENCY=1
# PROBOD_PROBO_AGENT_PROVIDER=anthropic
# PROBOD_PROBO_AGENT_MODEL_NAME=claude-sonnet-4-6
# PROBOD_EVIDENCE_DESCRIBER_PROVIDER=openai
# PROBOD_EVIDENCE_DESCRIBER_MODEL_NAME=gpt-4o-mini
# PROBOD_AGENT_THIRD_PARTY_VETTER_PROVIDER=openai # inherits AGENT_DEFAULT_PROVIDER when unset
# PROBOD_AGENT_THIRD_PARTY_VETTER_MODEL_NAME=gpt-4o # inherits AGENT_DEFAULT_MODEL_NAME when unset
# PROBOD_THIRD_PARTY_VETTING_INTERVAL=10
# PROBOD_THIRD_PARTY_VETTING_STALE_AFTER=1500
# PROBOD_THIRD_PARTY_VETTING_MAX_CONCURRENCY=1
# ── Document signature/approval notifications (seconds) ───────────────
# DOCUMENT_NOTIFICATION_INTERVAL=300
# DOCUMENT_NOTIFICATION_DEBOUNCE_DELAY=900
# DOCUMENT_NOTIFICATION_REMINDER_INTERVAL=86400
# PROBOD_DOCUMENT_NOTIFICATION_INTERVAL=300
# PROBOD_DOCUMENT_NOTIFICATION_DEBOUNCE_DELAY=900
# PROBOD_DOCUMENT_NOTIFICATION_REMINDER_INTERVAL=86400
# ── OIDC sign-in providers ────────────────────────────────────────────
# AUTH_GOOGLE_CLIENT_ID=
# AUTH_GOOGLE_CLIENT_SECRET=
# AUTH_MICROSOFT_CLIENT_ID=
# AUTH_MICROSOFT_CLIENT_SECRET=
# PROBOD_AUTH_GOOGLE_CLIENT_ID=
# PROBOD_AUTH_GOOGLE_CLIENT_SECRET=
# PROBOD_AUTH_MICROSOFT_CLIENT_ID=
# PROBOD_AUTH_MICROSOFT_CLIENT_SECRET=
# ── Connectors (set _CLIENT_ID to enable; _CLIENT_SECRET is required) ─
# CONNECTOR_SLACK_CLIENT_ID=
# CONNECTOR_SLACK_CLIENT_SECRET=
# CONNECTOR_SLACK_SIGNING_SECRET=
# CONNECTOR_HUBSPOT_CLIENT_ID=
# CONNECTOR_HUBSPOT_CLIENT_SECRET=
# CONNECTOR_GITHUB_CLIENT_ID=
# CONNECTOR_GITHUB_CLIENT_SECRET=
# CONNECTOR_NOTION_CLIENT_ID=
# CONNECTOR_NOTION_CLIENT_SECRET=
# CONNECTOR_SENTRY_CLIENT_ID=
# CONNECTOR_SENTRY_CLIENT_SECRET=
# CONNECTOR_INTERCOM_CLIENT_ID=
# CONNECTOR_INTERCOM_CLIENT_SECRET=
# CONNECTOR_DOCUSIGN_CLIENT_ID=
# CONNECTOR_DOCUSIGN_CLIENT_SECRET=
# CONNECTOR_BREX_CLIENT_ID=
# CONNECTOR_BREX_CLIENT_SECRET=
# CONNECTOR_GITLAB_CLIENT_ID=
# CONNECTOR_GITLAB_CLIENT_SECRET=
# CONNECTOR_BITBUCKET_CLIENT_ID=
# CONNECTOR_BITBUCKET_CLIENT_SECRET=
# CONNECTOR_HEROKU_CLIENT_ID=
# CONNECTOR_HEROKU_CLIENT_SECRET=
# CONNECTOR_PAGERDUTY_CLIENT_ID=
# CONNECTOR_PAGERDUTY_CLIENT_SECRET=
# CONNECTOR_ASANA_CLIENT_ID=
# CONNECTOR_ASANA_CLIENT_SECRET=
# CONNECTOR_NETLIFY_CLIENT_ID=
# CONNECTOR_NETLIFY_CLIENT_SECRET=
# CONNECTOR_CLICKUP_CLIENT_ID=
# CONNECTOR_CLICKUP_CLIENT_SECRET=
# CONNECTOR_VERCEL_CLIENT_ID=
# CONNECTOR_VERCEL_CLIENT_SECRET=
# CONNECTOR_VERCEL_INTEGRATION_SLUG=
# CONNECTOR_MONDAY_CLIENT_ID=
# CONNECTOR_MONDAY_CLIENT_SECRET=
# CONNECTOR_DATADOG_CLIENT_ID=
# CONNECTOR_DATADOG_CLIENT_SECRET=
# PROBOD_CONNECTOR_SLACK_CLIENT_ID=
# PROBOD_CONNECTOR_SLACK_CLIENT_SECRET=
# PROBOD_CONNECTOR_SLACK_SIGNING_SECRET=
# PROBOD_CONNECTOR_HUBSPOT_CLIENT_ID=
# PROBOD_CONNECTOR_HUBSPOT_CLIENT_SECRET=
# PROBOD_CONNECTOR_GITHUB_CLIENT_ID=
# PROBOD_CONNECTOR_GITHUB_CLIENT_SECRET=
# PROBOD_CONNECTOR_NOTION_CLIENT_ID=
# PROBOD_CONNECTOR_NOTION_CLIENT_SECRET=
# PROBOD_CONNECTOR_SENTRY_CLIENT_ID=
# PROBOD_CONNECTOR_SENTRY_CLIENT_SECRET=
# PROBOD_CONNECTOR_INTERCOM_CLIENT_ID=
# PROBOD_CONNECTOR_INTERCOM_CLIENT_SECRET=
# PROBOD_CONNECTOR_DOCUSIGN_CLIENT_ID=
# PROBOD_CONNECTOR_DOCUSIGN_CLIENT_SECRET=
# PROBOD_CONNECTOR_BREX_CLIENT_ID=
# PROBOD_CONNECTOR_BREX_CLIENT_SECRET=
# PROBOD_CONNECTOR_GITLAB_CLIENT_ID=
# PROBOD_CONNECTOR_GITLAB_CLIENT_SECRET=
# PROBOD_CONNECTOR_BITBUCKET_CLIENT_ID=
# PROBOD_CONNECTOR_BITBUCKET_CLIENT_SECRET=
# PROBOD_CONNECTOR_HEROKU_CLIENT_ID=
# PROBOD_CONNECTOR_HEROKU_CLIENT_SECRET=
# PROBOD_CONNECTOR_PAGERDUTY_CLIENT_ID=
# PROBOD_CONNECTOR_PAGERDUTY_CLIENT_SECRET=
# PROBOD_CONNECTOR_ASANA_CLIENT_ID=
# PROBOD_CONNECTOR_ASANA_CLIENT_SECRET=
# PROBOD_CONNECTOR_NETLIFY_CLIENT_ID=
# PROBOD_CONNECTOR_NETLIFY_CLIENT_SECRET=
# PROBOD_CONNECTOR_CLICKUP_CLIENT_ID=
# PROBOD_CONNECTOR_CLICKUP_CLIENT_SECRET=
# PROBOD_CONNECTOR_VERCEL_CLIENT_ID=
# PROBOD_CONNECTOR_VERCEL_CLIENT_SECRET=
# PROBOD_CONNECTOR_VERCEL_INTEGRATION_SLUG=
# PROBOD_CONNECTOR_MONDAY_CLIENT_ID=
# PROBOD_CONNECTOR_MONDAY_CLIENT_SECRET=
# PROBOD_CONNECTOR_DATADOG_CLIENT_ID=
# PROBOD_CONNECTOR_DATADOG_CLIENT_SECRET=
# Zendesk OAuth requires a Zendesk-approved global OAuth client (Marketplace).
# CONNECTOR_ZENDESK_CLIENT_ID=
# CONNECTOR_ZENDESK_CLIENT_SECRET=
# PROBOD_CONNECTOR_ZENDESK_CLIENT_ID=
# PROBOD_CONNECTOR_ZENDESK_CLIENT_SECRET=
# PostHog Cloud (US + EU) OAuth needs NO config: it uses the CIMD public-client
# flow (no app registration, no client_secret), auto-enabled when this
# deployment is publicly reachable at PROBOD_BASE_URL. Self-hosted PostHog uses
@@ -140,9 +149,9 @@
# ── OAuth2 authorization server ───────────────────────────────────────
# Comma-separated HTTPS client metadata document URLs allowed for CIMD
# OAuth clients (e.g. MCP connectors). Leave unset to disable CIMD.
# OAUTH2_SERVER_CIMD_ALLOWED_CLIENT_IDS=https://chatgpt.com/oauth/client.json,https://claude.ai/oauth/client.json
# PROBOD_OAUTH2_SERVER_CIMD_ALLOWED_CLIENT_IDS=https://chatgpt.com/oauth/client.json,https://claude.ai/oauth/client.json
# ── Custom domains (Pebble ACME via compose) ──────────────────────────
# CUSTOM_DOMAINS_CNAME_TARGET=custom.getprobo.com
# ACME_DIRECTORY=https://localhost:14000/dir
# ACME_EMAIL=admin@probo.com
# PROBOD_CUSTOM_DOMAINS_CNAME_TARGET=custom.getprobo.com
# PROBOD_ACME_DIRECTORY=https://localhost:14000/dir
# PROBOD_ACME_EMAIL=admin@probo.com