Generate cfg/dev.yaml via a Make target
Committing a fully-materialised cfg/dev.yaml hid the dev configuration surface and blocked the OAuth2 signing-key inlining change: the new config requires a per-dev private key that must not be committed. Replace the checked-in file with a dev-config Make target that shells out to probod-bootstrap with dev-safe defaults and a stable RSA signing key stashed under cfg/.dev-oauth2-signing-key.pem on first run. The recipe sources cfg/dev.env when present so devs can override any setting without editing the Makefile; cfg/dev.env.example ships the full list of overridable knobs. cfg/dev.yaml, cfg/dev.env, and the signing key are all gitignored. Update README, CONTRIBUTING, and contrib/claude/config.md to describe the new workflow. Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -20,3 +20,5 @@ __generated__/
|
||||
pkg/server/api/*/v1/types/types.go
|
||||
pkg/server/api/*/v1/schema.graphql
|
||||
cfg/dev_local.yaml
|
||||
cfg/dev.yaml
|
||||
cfg/dev.env
|
||||
|
||||
@@ -84,7 +84,18 @@ Signed-off-by: John Doe <john.doe@example.org>
|
||||
make stack-up
|
||||
```
|
||||
|
||||
6. Start the development servers:
|
||||
6. Generate the local dev config (writes `cfg/dev.yaml`):
|
||||
|
||||
```bash
|
||||
# Optional: override any dev default (secrets, OAuth clients, LLM keys).
|
||||
# cp cfg/dev.env.example cfg/dev.env && $EDITOR cfg/dev.env
|
||||
|
||||
make dev-config
|
||||
```
|
||||
|
||||
The target stashes a dev-only RSA signing key under `cfg/.dev-oauth2-signing-key.pem` so tokens survive probod restarts, and sources `cfg/dev.env` if present so you can override defaults without editing the Makefile. `cfg/dev.yaml`, `cfg/dev.env`, and the signing key are all gitignored. Re-run the target to regenerate.
|
||||
|
||||
7. Start the development servers:
|
||||
|
||||
```bash
|
||||
# In one terminal - start the API server
|
||||
|
||||
28
GNUmakefile
28
GNUmakefile
@@ -151,6 +151,34 @@ coverage-combined: coverage-report test-e2e-coverage ## Generate combined covera
|
||||
.PHONY: build
|
||||
build: bin/probod bin/prb bin/probod-bootstrap
|
||||
|
||||
CFG_DEV_OAUTH2_KEY = cfg/.dev-oauth2-signing-key.pem
|
||||
CFG_DEV_ENV = cfg/dev.env
|
||||
|
||||
.PHONY: dev-config
|
||||
dev-config: cfg/dev.yaml ## Generate cfg/dev.yaml via probod-bootstrap (rerun after deleting the file)
|
||||
|
||||
$(CFG_DEV_OAUTH2_KEY):
|
||||
@$(MKDIR) $(@D)
|
||||
$(OPENSSL) genrsa -out $@ 2048
|
||||
|
||||
cfg/dev.yaml: bin/probod-bootstrap $(CFG_DEV_OAUTH2_KEY)
|
||||
@$(MKDIR) $(@D)
|
||||
@set -a; \
|
||||
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"; \
|
||||
AUTH_COOKIE_SECURE=false; \
|
||||
OAUTH2_SERVER_SIGNING_KEY="$$($(CAT) $(CFG_DEV_OAUTH2_KEY))"; \
|
||||
API_CORS_ALLOWED_ORIGINS="http://localhost:8080,http://localhost:5173,http://localhost:5174"; \
|
||||
AWS_ACCESS_KEY_ID=probod; \
|
||||
AWS_SECRET_ACCESS_KEY=thisisnotasecret; \
|
||||
AWS_ENDPOINT=http://127.0.0.1:8333; \
|
||||
OPENAI_API_KEY=thisisnotasecret; \
|
||||
ACME_DIRECTORY=https://localhost:14000/dir; \
|
||||
if [ -f $(CFG_DEV_ENV) ]; then . $(CFG_DEV_ENV); fi; \
|
||||
set +a; \
|
||||
./bin/probod-bootstrap -output $@
|
||||
|
||||
.PHONY: sbom-docker
|
||||
sbom-docker: docker-build
|
||||
$(SYFT) docker:$(DOCKER_IMAGE_NAME):$(DOCKER_TAG_NAME) -o cyclonedx-json \
|
||||
|
||||
@@ -48,6 +48,9 @@ Probo is designed to be accessible, transparent, and community-driven.
|
||||
# Build the project
|
||||
make build
|
||||
|
||||
# Generate the local dev config (writes cfg/dev.yaml)
|
||||
make dev-config
|
||||
|
||||
# Start the application using development settings
|
||||
bin/probod -cfg-file cfg/dev.yaml
|
||||
```
|
||||
@@ -65,7 +68,7 @@ To test the custom domains feature locally, add the CNAME target to your hosts f
|
||||
127.0.0.1 custom.getprobo.com
|
||||
```
|
||||
|
||||
This allows you to test custom trust center domains on your local machine. The CNAME target can be configured in `cfg/dev.yaml` under `custom-domains.cname-target`.
|
||||
This allows you to test custom trust center domains on your local machine. The generated `cfg/dev.yaml` sets the CNAME target via `custom-domains.cname-target`; change `CUSTOM_DOMAINS_CNAME_TARGET` before running `make dev-config` to override it.
|
||||
|
||||
For detailed setup instructions, see our [Contributing Guide](CONTRIBUTING.md).
|
||||
|
||||
|
||||
81
cfg/dev.env.example
Normal file
81
cfg/dev.env.example
Normal file
@@ -0,0 +1,81 @@
|
||||
# Dev overrides for `make dev-config`.
|
||||
#
|
||||
# Copy this file to cfg/dev.env and uncomment any variable you want to
|
||||
# override. The file is sourced as a shell snippet, so quote values that
|
||||
# contain spaces. cfg/dev.env is gitignored; this .example file is the
|
||||
# canonical list of overridable knobs.
|
||||
#
|
||||
# See pkg/bootstrap/builder.go for the full env-var surface; 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
|
||||
|
||||
# ── 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
|
||||
|
||||
# ── Cookie ────────────────────────────────────────────────────────────
|
||||
# AUTH_COOKIE_DOMAIN=localhost
|
||||
# AUTH_COOKIE_SECURE=false
|
||||
|
||||
# ── Postgres ──────────────────────────────────────────────────────────
|
||||
# PG_ADDR=localhost:5432
|
||||
# PG_USERNAME=postgres
|
||||
# PG_PASSWORD=postgres
|
||||
# PG_DATABASE=probod
|
||||
# PG_POOL_SIZE=100
|
||||
|
||||
# ── 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
|
||||
|
||||
# ── Mailer (Mailpit via compose) ──────────────────────────────────────
|
||||
# SMTP_ADDR=localhost:1025
|
||||
# MAILER_SENDER_EMAIL=no-reply@notification.getprobo.com
|
||||
# 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
|
||||
|
||||
# ── OIDC sign-in providers ────────────────────────────────────────────
|
||||
# AUTH_GOOGLE_CLIENT_ID=
|
||||
# AUTH_GOOGLE_CLIENT_SECRET=
|
||||
# AUTH_MICROSOFT_CLIENT_ID=
|
||||
# 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=
|
||||
|
||||
# ── Custom domains (Pebble ACME via compose) ──────────────────────────
|
||||
# CUSTOM_DOMAINS_CNAME_TARGET=custom.getprobo.com
|
||||
# ACME_DIRECTORY=https://localhost:14000/dir
|
||||
# ACME_EMAIL=admin@getprobo.com
|
||||
143
cfg/dev.yaml
143
cfg/dev.yaml
@@ -1,143 +0,0 @@
|
||||
unit:
|
||||
metrics:
|
||||
addr: "localhost:8081"
|
||||
tracing:
|
||||
addr: "localhost:4317"
|
||||
max-batch-size: 512
|
||||
batch-timeout: 1
|
||||
export-timeout: 1
|
||||
max-queue-size: 2048
|
||||
|
||||
probod:
|
||||
base-url: "http://localhost:8080"
|
||||
encryption-key: "thisisnotasecretAAAAAAAAAAAAAAAAAAAAAAAAAAA="
|
||||
chrome-dp-addr: "localhost:9222"
|
||||
|
||||
trust-center:
|
||||
http-addr: ":8085"
|
||||
https-addr: ":8443"
|
||||
|
||||
api:
|
||||
addr: "localhost:8080"
|
||||
cors:
|
||||
allowed-origins:
|
||||
- "http://localhost:8080"
|
||||
- "http://localhost:5173"
|
||||
- "http://localhost:5174"
|
||||
|
||||
pg:
|
||||
addr: "localhost:5432"
|
||||
username: "postgres"
|
||||
password: "postgres"
|
||||
database: "probod"
|
||||
pool-size: 100
|
||||
|
||||
auth:
|
||||
disable-signup: false
|
||||
invitation-confirmation-token-validity: 3600
|
||||
cookie:
|
||||
name: "SSID"
|
||||
domain: "localhost"
|
||||
secret: "this-is-a-secure-secret-for-cookie-signing-at-least-32-bytes"
|
||||
duration: 24
|
||||
secure: false
|
||||
password:
|
||||
pepper: "this-is-a-secure-pepper-for-password-hashing-at-least-32-bytes"
|
||||
iterations: 1000000
|
||||
|
||||
aws:
|
||||
region: "us-east-1"
|
||||
bucket: "probod"
|
||||
access-key-id: "probod"
|
||||
secret-access-key: "thisisnotasecret"
|
||||
endpoint: "http://127.0.0.1:8333"
|
||||
|
||||
notifications:
|
||||
mailer:
|
||||
sender-name: "Probo"
|
||||
sender-email: "no-reply@notification.getprobo.com"
|
||||
smtp:
|
||||
addr: "localhost:1025"
|
||||
tls-required: false
|
||||
mailer-interval: 60
|
||||
slack:
|
||||
sender-interval: 60
|
||||
|
||||
llm:
|
||||
providers:
|
||||
openai:
|
||||
type: openai
|
||||
api-key: "thisisnotasecret"
|
||||
defaults:
|
||||
provider: openai
|
||||
model-name: gpt-4o
|
||||
temperature: 0.1
|
||||
max-tokens: 4096
|
||||
|
||||
evidence-describer:
|
||||
interval: 10
|
||||
stale-after: 300
|
||||
max-concurrency: 10
|
||||
|
||||
custom-domains:
|
||||
renewal-interval: 3600
|
||||
provision-interval: 30
|
||||
cname-target: "custom.getprobo.com"
|
||||
acme:
|
||||
directory: "https://localhost:14000/dir"
|
||||
email: "admin@getprobo.com"
|
||||
key-type: "EC256"
|
||||
|
||||
connectors:
|
||||
- provider: "SLACK"
|
||||
protocol: "oauth2"
|
||||
config:
|
||||
client-id: "your-slack-client-id"
|
||||
client-secret: "your-slack-client-secret"
|
||||
settings:
|
||||
signing-secret: "your-slack-signing-secret"
|
||||
- provider: "GOOGLE_WORKSPACE"
|
||||
protocol: "oauth2"
|
||||
config:
|
||||
client-id: "your-google-client-id.apps.googleusercontent.com"
|
||||
client-secret: "your-google-client-secret"
|
||||
- provider: "LINEAR"
|
||||
protocol: "oauth2"
|
||||
config:
|
||||
client-id: "your-linear-client-id"
|
||||
client-secret: "your-linear-client-secret"
|
||||
- provider: "BREX"
|
||||
protocol: "oauth2"
|
||||
config:
|
||||
client-id: "your-brex-client-id"
|
||||
client-secret: "your-brex-client-secret"
|
||||
- provider: "HUBSPOT"
|
||||
protocol: "oauth2"
|
||||
config:
|
||||
client-id: "your-hubspot-client-id"
|
||||
client-secret: "your-hubspot-client-secret"
|
||||
- provider: "DOCUSIGN"
|
||||
protocol: "oauth2"
|
||||
config:
|
||||
client-id: "your-docusign-client-id"
|
||||
client-secret: "your-docusign-client-secret"
|
||||
- provider: "NOTION"
|
||||
protocol: "oauth2"
|
||||
config:
|
||||
client-id: "your-notion-client-id"
|
||||
client-secret: "your-notion-client-secret"
|
||||
- provider: "GITHUB"
|
||||
protocol: "oauth2"
|
||||
config:
|
||||
client-id: "your-github-client-id"
|
||||
client-secret: "your-github-client-secret"
|
||||
- provider: "SENTRY"
|
||||
protocol: "oauth2"
|
||||
config:
|
||||
client-id: "your-sentry-client-id"
|
||||
client-secret: "your-sentry-client-secret"
|
||||
- provider: "INTERCOM"
|
||||
protocol: "oauth2"
|
||||
config:
|
||||
client-id: "your-intercom-client-id"
|
||||
client-secret: "your-intercom-client-secret"
|
||||
@@ -10,7 +10,7 @@ When a configuration field is added, renamed, or removed in the Go config struct
|
||||
| 2 | `pkg/probod/probod.go` `New()` | Default values for new fields |
|
||||
| 3 | `pkg/bootstrap/builder.go` | Env-var → struct mapping (`Build()` method) |
|
||||
| 4 | `pkg/bootstrap/builder.go` | Required-env validation (`validateRequired()`) |
|
||||
| 5 | `cfg/dev.yaml` | Local development config |
|
||||
| 5 | `GNUmakefile` (`dev-config` target) | Env vars fed to `probod-bootstrap` to regenerate `cfg/dev.yaml` (file itself is gitignored) |
|
||||
| 6 | `e2e/internal/testutil/testutil.go` | E2E env-var map fed to `bootstrap.NewBuilder` |
|
||||
| 7 | `contrib/lima/provision.sh` | Sandbox env vars passed to `probod-bootstrap` |
|
||||
| 8 | `contrib/helm/charts/probo/values.yaml` | Helm default values |
|
||||
@@ -27,7 +27,7 @@ Go struct (pkg/probod/)
|
||||
│
|
||||
├─► bootstrap builder.go (env var → struct)
|
||||
│ │
|
||||
│ ├─► cfg/dev.yaml (static YAML, local dev)
|
||||
│ ├─► GNUmakefile dev-config (env vars → probod-bootstrap → cfg/dev.yaml)
|
||||
│ ├─► e2e/internal/testutil/ (env map → bootstrap.Build, tests)
|
||||
│ ├─► contrib/lima/provision.sh (env vars → probod-bootstrap)
|
||||
│ └─► Helm chart
|
||||
@@ -44,7 +44,7 @@ Go struct (pkg/probod/)
|
||||
1. **Never add a Go config field without updating every file in the checklist.**
|
||||
2. **Env var naming** — follow the existing convention in `builder.go`: `SECTION_FIELD_NAME` (e.g. `AUTH_COOKIE_DOMAIN`, `CUSTOM_DOMAINS_RENEWAL_INTERVAL`).
|
||||
3. **Secrets** go through `secret.yaml` and are referenced via `secretKeyRef` in `deployment.yaml`. Non-secret values are set inline.
|
||||
4. **`cfg/dev.yaml`** uses safe, non-production defaults (plaintext passwords, `localhost`, `secure: false`).
|
||||
4. **`make dev-config`** writes `cfg/dev.yaml` via `probod-bootstrap` with safe, non-production defaults (plaintext passwords, `localhost`, `secure: false`). The generated file and the per-dev OAuth2 signing key (`cfg/.dev-oauth2-signing-key.pem`) are both gitignored. The recipe sources `cfg/dev.env` if present so devs can override any env var without editing the `GNUmakefile`; keep `cfg/dev.env.example` in sync when you add or rename env vars.
|
||||
5. **`e2e/internal/testutil/testutil.go`** builds the e2e config through `bootstrap.NewBuilder` with a test-only env-var map (different ports, `probod_test` DB, shorter intervals). Any new field whose test value differs from the bootstrap default must be added to that map.
|
||||
6. **`provision.sh`** only sets env vars that differ from `builder.go` defaults (e.g. `PROBOD_BASE_URL`, `AUTH_COOKIE_DOMAIN`, `AUTH_COOKIE_SECURE`). If the new field's default is acceptable in the sandbox, no env var is needed.
|
||||
7. **Helm `values.yaml`** exposes the field under the appropriate `probo.*` key with a sensible default. `values-production.yaml.example` includes it only when the production value differs or the user must set it.
|
||||
|
||||
Reference in New Issue
Block a user