Skip to content

fix(#45): graceful config validation on the standalone boot path#59

Merged
milmazz merged 1 commit into
mainfrom
cli-config-graceful-errors
Jul 8, 2026
Merged

fix(#45): graceful config validation on the standalone boot path#59
milmazz merged 1 commit into
mainfrom
cli-config-graceful-errors

Conversation

@milmazz

@milmazz milmazz commented Jul 7, 2026

Copy link
Copy Markdown
Owner

What

Values the CLI's parse layer accepts for PostgREST --dump-config parity — e.g. db-max-rows=0, server-port=0 or negative (Bier's schema uses :pos_integer, i.e. >= 1) — passed --dump-config but crashed boot with a raw MatchError/ArgumentError from inside Bier.start_link/1. docker run first-contact users hit exactly this. This is the open hardening tail from the #40 review noted on #45.

How

  • Bier.Config.new/2: non-raising variant of new!/2 (which now delegates to it), returning {:ok, config} | {:error, message} for both NimbleOptions schema failures and the semantic validators (jwt-secret / jwt-aud / db-channel / admin-port). Validator failures still raise ArgumentError from new!/2 as before; schema failures now raise ArgumentError too (previously NimbleOptions.ValidationError — nothing depended on that type).
  • Bier.CLI.Config.validated_start_opts/1: to_start_opts/1 plus a full Bier.Config.new/2 pass, collapsing multi-line NimbleOptions union-type messages into the CLI's one-line fatal format.
  • Both boot paths route through it: the escript boot in Bier.CLI.main/1 prints the message to stderr and exits 1 (same shape as the existing jwt-secret/admin-port fatals), and Bier.Application.standalone_spec/1 (the BIER_STANDALONE release/Docker path) returns the fatal message that standalone_children/1 already reports on stderr before halting.
  • --dump-config parity preserved: validation runs at BOOT, not at parse/dump — the dump still prints whatever was parsed (e.g. db-max-rows = 0, server-port = -1) and exits 0, exactly as the conformance cases pin it.

Out of scope (still open on #45): --ready subcommand, db-config source, Docker smoke CI job.

Part of #45.

Verification

  • mix format --check-formatted, mix compile --warnings-as-errors, MIX_ENV=test mix compile --warnings-as-errors, mix credo --strict, mix docs --warnings-as-errors, mix deps.unlock --check-unused — all clean locally.
  • Exercised the new paths in-process (mix run --no-start): db-max-rows=0 / server-port=0 / server-port=-1 now yield single-line {:error, message}; valid config yields the same opts as to_start_opts/1; --dump-config with those values still exits 0.
  • New unit tests in test/bier/cli/boot_validation_test.exs cover the error paths, the standalone spec, Bier.Config.new/2, and the dump parity; CI runs them (conformance suite is the judge, per repo policy).

🤖 Generated with Claude Code

Values the CLI's parse layer tolerates for PostgREST --dump-config parity
(e.g. db-max-rows=0, server-port=0 or negative) crashed boot with a raw
MatchError/ArgumentError because they only hit Bier's NimbleOptions schema
inside Bier.start_link/1.

- Add Bier.Config.new/2, the non-raising variant of new!/2 (which now
  delegates to it), returning {:ok, config} | {:error, message} for both
  schema and semantic validator failures.
- Add Bier.CLI.Config.validated_start_opts/1: to_start_opts/1 plus a full
  Bier.Config.new/2 pass, with multi-line NimbleOptions messages collapsed
  to the CLI's one-line fatal format.
- Route both boot paths through it: the escript boot in Bier.CLI.main/1
  emits the message on stderr and exits 1 (like the jwt-secret/admin-port
  fatals); Bier.Application.standalone_spec/1 returns the fatal message.
- --dump-config is untouched: validation runs at boot, not at parse/dump,
  so the conformance-pinned dump behavior is preserved (pinned by new
  tests in test/bier/cli/boot_validation_test.exs).

Part of #45.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@milmazz
milmazz merged commit 021b98d into main Jul 8, 2026
3 checks passed
@milmazz
milmazz deleted the cli-config-graceful-errors branch July 8, 2026 06:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant