Skip to content

Latest commit

 

History

History
80 lines (64 loc) · 4.04 KB

File metadata and controls

80 lines (64 loc) · 4.04 KB

breadbox doctor

A pre-flight + readiness command that validates configuration and connectivity without booting the server. Use it as the first diagnostic when something "feels off", and let install scripts gate on its exit code.

breadbox doctor [--json] [--skip-external]
  • Exit code 0 — all checks pass (or were skipped).
  • Exit code 1 — one or more checks failed. Remediation hints are printed next to each failure.

Flags

Flag Description
--json Emit a structured {"checks": [...], "ok": bool} document instead of a pretty table. Useful in CI and install scripts.
--skip-external Skip DNS and outbound HTTP checks (DNS lookup + GET /health/ready against PUBLIC_URL/DOMAIN). Use this on air-gapped installs or when the box is still behind a firewall.

Checks

Name What it validates
config load .local.env / .docker.env parse cleanly and required env vars decode.
database DATABASE_URL is set, Postgres accepts a connection, and Ping succeeds.
migrations The goose_db_version in the DB matches the highest numeric prefix among embedded migrations. Reports "behind" (needs breadbox migrate) or "ahead" (binary downgrade).
encryption key ENCRYPTION_KEY is set (required if Plaid or Teller is configured), hex-decodes to exactly 32 bytes, and is accepted by AES.
plaid When PLAID_CLIENT_ID is set: PLAID_SECRET is present and PLAID_ENV is one of sandbox/development/production.
teller When TELLER_APP_ID is set: TELLER_ENV is valid, cert/key paths (if any) exist and are readable, or PEM bytes are available via app_config.
provider credentials Walks every non-disconnected bank_connections row and verifies encrypted_credentials decrypts with the current key. Catches silent ENCRYPTION_KEY rotations.
admin account auth_accounts contains at least one row — otherwise the setup wizard hasn't run.
scheduler sync_interval_minutes is positive; any BACKUP_CRON / SYNC_CRON env value parses as a 5-field cron expression.
public url When PUBLIC_URL or DOMAIN is set (and --skip-external isn't): DNS resolves and GET /health/ready returns < 400.

Encryption-key fingerprint vs stored hash: deferred to issue #688. Once the fingerprint is persisted at setup, doctor will compare it against the key in the environment to catch rotations even before any bank connection exists. Until then, the credential-decrypt walk is the proxy.

Example output

     Check                 Status
  -  --------------------  ----------------------------------------
  ✓  config load           environment=local
  ✓  database              connected and reachable
  ✓  migrations            up-to-date (version 20260417032707)
  ✓  encryption key        set and 32 bytes
  ✓  plaid                 client/secret set, env=sandbox
  ✓  teller                cert/key present, env=sandbox
  ✓  provider credentials  3 connection(s) decrypt cleanly
  ✓  admin account         1 account(s) present
  ✓  scheduler             sync every 720m; cron expressions valid
  ⊘  public url            neither PUBLIC_URL nor DOMAIN set

OK — all checks passed.

CI / install-script use

breadbox doctor --json --skip-external > doctor.json
jq -e '.ok == true' doctor.json

A future one-liner installer (issue #686) is expected to run breadbox doctor after launching the process to surface configuration problems before handing the operator a URL. This PR does not yet wire doctor into install.sh.

What doctor intentionally does not do

  • Does not mutate state. Read-only across the board. Running it repeatedly is safe.
  • Does not boot the HTTP server. Use breadbox serve for that — doctor is designed to diagnose startup failures without needing startup to succeed.
  • Does not probe provider APIs. A healthy Plaid env var doesn't guarantee the credentials are valid with Plaid itself; the credential-decrypt walk is strictly a local AES check.