feat(#40): standalone drop-in PostgREST-compatible CLI#48
Merged
Conversation
…le CLI Re-scopes #40 from "turn all 26 config CLI cases green" to: standalone-runnable Bier (docker run bier) + drop-in PostgREST-compatible config (PGRST_* env, kebab keys, config file, PostgREST-format --dump-config) for the keys Bier actually implements, with an honest conformance disposition for the rest (:cli_parity / :unmodeled_key / :db_config). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Nine TDD tasks: shared validators, config-file parser, mapping table + coercion, load/3 precedence, dump/1, run/2 dispatch, escript + to_start_opts, conformance CLI harness path, and full verification. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds Config.to_start_opts/1 to translate a resolved CLI config map into Bier.start_link/1 keyword options (parsing db-uri, collapsing allow-override tx-end variants). Adds Bier.CLI.main/1 as the escript entry point with a blocking boot path, and wires mix.exs escript config with app: nil so --dump-config/--version run without a live DB. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…led to CLI config Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…d-clause warnings Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 tasks
Resolves the conformance_test.exs moduledoc conflict: keeps the CLI-case wording from this branch and drops the :openapi_doc exclusion that main removed when #39 (OpenAPI document generation) landed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KMemDkesmnvCYJ2ovZGKu5
main now gates CI on mix credo --strict; the multi-alias in Bier.CLI was the only one in lib/ and trips Consistency.MultiAliasImportRequireUse. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KMemDkesmnvCYJ2ovZGKu5
- Resolve alias-derived env vars (PGRST_DB_SCHEMA, PGRST_MAX_ROWS, ...): each key spelling is now a full source consulting its own env var then its file key, matching PostgREST's optWithAlias semantics. - Config-file parser: support end-of-line '#' comments after values, keep '#' literal inside quoted strings, and reject trailing garbage or an unterminated quote instead of silently mangling the value. - Print --version/--help before loading config, as PostgREST does, so a broken PGRST_* var or missing config file cannot mask them. - db-uri: accept libpq keyword/value conninfo strings and honor sslmode (require/verify-* map to a new ssl start option wired through Bier.Config and the Postgrex pool). - Count jwt-secret length in bytes (PostgREST's BS.length), not graphemes. - Add openapi-security-active to the CLI spec table and to_start_opts. - Share the admin-server-port/server-port rule as Bier.Config.validate_admin_server_port/2 instead of duplicating it. - COVERAGE.md: stop claiming 1707 exercises the db-pool aliases; it is deferred as :unmodeled_key. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KMemDkesmnvCYJ2ovZGKu5
Advisories published against locked deps (mint/req/plug/bandit today) were failing the job before compile/credo/docs/test ever ran, hiding all signal for the change under review. Every gate still runs and the job still fails on advisories until the deps are updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KMemDkesmnvCYJ2ovZGKu5
…o claude/merge-conflicts-pr-review-5g7g49
Resolves the conformance_test.exs moduledoc conflict again: keeps the CLI-case wording and drops the :jwt exclusion that main removed now that the harness signs JWTs per-case (#41). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KMemDkesmnvCYJ2ovZGKu5
milmazz
pushed a commit
that referenced
this pull request
Jul 3, 2026
PR #48 (the CLI branch this was stacked on) was squash-merged to main, so main and this branch both carried the CLI files. Conflicts resolved by taking main's versions (which include the review-finding fixes) for everything this branch does not touch; mix.exs keeps the releases() config on top of main's state. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KMemDkesmnvCYJ2ovZGKu5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a standalone, drop-in PostgREST-compatible CLI for Bier (closes #40), re-scoped from "turn all 26 config CLI cases green" to standalone-runnable Bier + drop-in config compat for the keys Bier actually implements, with an honest conformance disposition for the rest. Design:
docs/superpowers/specs/2026-06-07-cli-implementation-design.md; plan:docs/superpowers/plans/2026-06-07-cli-implementation.md.Bier.CLI— a pure, testablerun/2core (%{stdout, stderr, exit}or{:boot, resolved}, no IO/halt) plus a thin escriptmain/1+ single-instance boot path.Bier.CLI.Config— the PostgREST-dialect ↔ Bier boundary: a single-source-of-truth mapping table (PGRST_*env, kebab keys, aliases, defaults),coerce/2,load/3(precedenceflags > env > file > default, alias resolution, wrong-type→default, shared validation),dump/1(PostgREST-format, reparse-stable), andto_start_opts/1(incl.db-uriparsing → discrete connection fields).Bier.CLI.ConfigFile—key = valueconfig-file parser.Bier.Config(jwt-secret length, jwt-aud URI) soBier.start_link/1and the CLI reject identically; exact PostgREST messages.Bier.CliCasedriveskind: clicases through the core in-process; newexit_code/dump_contains/stderr_contains/dump_reparse_stableassertions.Conformance impact
15 of the 26 config CLI cases now pass (1706, 1708–1710, 1712, 1713, 1717, 1719–1723, 1726, 1728, 1730). The remaining 11 keep an explicit
pending_reasoninstead of a parity façade::cli_parity(full default-table dump 1705,--example1727),:unmodeled_key(1707, 1711, 1714–1716, 1718, 1729 — keys Bier doesn't implement),:db_config(1724/1725 — DB role-settings source). Recorded inspec/COVERAGE.md.Standalone packaging (
mix release+ Dockerfile) and--readyare deferred to #45.Test plan
mix test— 587 tests; the only 4 failures (GeoJSON 1616–1618, RS256 1467) are pre-existing onmain(verified against the base commit), not regressions.mix format --check-formatted,mix compile --warnings-as-errors,mix docs --warnings-as-errors,mix hex.audit,mix deps.unlock --check-unused— all clean.mix escript.build && ./bier --dump-config | --version | --help.🤖 Generated with Claude Code