Skip to content

fix: finish rstack dev for its first release and read long encrypted BReg values - #2648

Open
jeremi wants to merge 24 commits into
mainfrom
fix/rstack-dev-followups
Open

jeremi wants to merge 24 commits into
mainfrom
fix/rstack-dev-followups

Conversation

@jeremi

@jeremi jeremi commented Nov 11, 2026 •

Copy link
Copy Markdown
Member

Follow-ups to rstack dev (#2635, #2637) before its first release, plus a BReg read fix found on the way.

rstack dev

  • stop RUN_ID --recover waits for the run’s process guards, releases its databases and roles on the original PostgreSQL cluster and maintenance database, and removes the run directory.
  • Refusals and startup failures from start, status, token and stop use the registry.rstack.error.v1 envelope. A failed journey exits 1 with the regular run report and leaves the run available for inspection.
    • domain (exit 1): project, plan or run state refused.
    • usage (exit 2): a malformed run ID, --ttl or test person name, refused from the command line alone.
    • operational (exit 3): unreachable PostgreSQL, failed provisioning, deadlines, a supervisor panic.
  • check validates binding fragments with the products' own readers, so a configuration a product would refuse fails before start provisions anything, at the plan field that produced it:
    • BReg review authority: the reader in registry_breg::runtime_config, now naming the rule each check states, never the value.
    • Casework context providers: caseworkctl check --runtime-config on the configuration the run writes. bregctl does not link a Casework crate, so the dependency-direction gate holds. Casework's offline check gains the rule casework.runtime.invalid-context-provider.
  • Projects with encrypted fields run on a per-run data key. It is kept in the owner-only run directory under BReg's local-file custody, never printed, and removed before the run directory on stop, expiry, failed start and --recover.
  • A how-to page, "Run a project with rstack dev", linked from PROJECT-DEV.md and from the command help.

BReg

  • PostgreSQL's encode(..., 'base64') breaks lines every 76 characters. Row decode now drops the line breaks. Before this, reading an encrypted value whose envelope exceeds 57 bytes failed with source.unavailable, through every read projection and the history journal capture of reviewed migrations. This affects released versions from v0.33.0 through v0.46.0. Tests cover each projection and the field-encryption flip migration with wrapped envelopes.
  • PostGIS provisioning keeps the SQLSTATE of a refused statement (for example 42501), including the bbox role batch.

Not in this PR

Checks run locally (macOS)

Check Result
cargo fmt --all --check clean
clippy on bregctl, casework-breg, casework, rstack, cli-docs clean
clippy on breg two failures, both also present on main and in files this PR does not change (commit_guard.rs, postgres_migration.rs type_complexity)
registry-rstack 129 passed
bregctl lib 738 passed, 4 ignored
bregctl project_dev 33 passed
Casework 153 passed across 13 binaries
cli-docs 28 passed
breg postgres_field_encryption 15 passed
breg postgres_migration 61 passed
PostGIS provisioning SQLSTATE test passed
dependency gates: rstack, Casework, Coordinator, MCP pass
products/platform/scripts/test-rstack-dev.py against PostgreSQL 18 all 11 scenarios passed
docs site npm run check pass

--spatial was not run: the local PostgreSQL has no PostGIS.

Closes #2639
Closes #2640
Closes #2641
Closes #2642

@jeremi jeremi added the ci:full Run the heavy integration tier on this pull request label Nov 11, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 11, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-11T15:20:48.547573Z 9dc0abd New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0cacb9a073

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Stop --recover releases the processes, databases and roles of a run whose
supervisor is lost, signalling a recorded process group only while its
leader's start time matches the one recorded at start. Every rstack dev
refusal or failure now prints registry.rstack.error.v1 with a class
(domain, usage, operational) and, for runs needing attention, the run ID
and recovery facts. Operational failures exit 3.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
`rstack dev check` now renders each binding fragment with the code `start`
uses and validates it with BReg's review-authority reader and Casework's
context-binding checks, so a configuration a product would refuse fails
before `start` provisions anything. Refusals name the plan field that
produced the value. The runner no longer restates the resource and scope
rules the readers own, and `check` compares the Casework status profile with
the context provider's service-status profile instead of leaving it to
Casework start.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
…eaks

PostgreSQL's base64 encode breaks its output every 76 characters. The
record read and history migration projections pass that text through
unchanged, so reading an encrypted value whose envelope exceeds 57 bytes
failed with source.unavailable. Row decode now drops the line breaks,
which covers every projection that feeds it.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
`rstack dev` no longer refuses a BReg project with encrypted fields.
`start` draws a data key for the run with BReg's key generator, owner-only
in the owner-only run directory, and configures BReg's local-file key
custody to read it by reference. The key never reaches output, the plan,
the error envelope or the checkout, and goes with the run directory on
stop, TTL expiry, a failed start and `stop --recover`. A run that needs
recovery names the key file in `recovery.field_encryption_key`.

Environment failures now report the operational class (exit 3): an
unreachable PostgreSQL server or refused administrator session, failed
provisioning, an unreadable CA file, a product process that cannot be
started, and no free loopback port. The worker carries the class to the
supervisor. Project and plan refusals stay domain (exit 1).

The admin connection deadline is tested against a server that accepts
and never answers, for the first connection and the cleanup reconnection,
and the large-plan test starts through the supervisor instead of writing
the worker input by hand.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
…jection

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Add "Run a project with rstack dev" under configure/: install the
components, start a local TLS PostgreSQL server, adapt the licensing
dev.yaml, check, start, call both products with a development token, stop,
and recover a failed run. Register it in the Operations sidebar group, link
it from PROJECT-DEV.md, and link it from the rstack dev command help so the
generated CLI reference carries the link.

The regenerated crates/registry-cli-docs/catalog.json also picks up
`stop --recover` and `--database-url`, which the earlier command change had
not regenerated.

Closes #2641

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
… link

`rstack dev check` linked registry-casework-breg into bregctl to run
Casework's context-binding reader in process, which breaks the rule that
BReg tooling never depends on a Casework crate. The dependency-direction
gate already refuses that closure.

Casework now refuses an invalid `contextProviders` binding in its own
offline check, at the member and naming the rule, through the same
validation provider construction runs (including the HTTPS base URL and
the delegated display exchange). `rstack dev check` renders the Casework
configuration the run writes, runs `caseworkctl check --runtime-config` on
it, and reports a refusal at the plan field that produced the member. A
refusal it cannot attribute to the binding is reported as an operational
failure rather than a pass.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
`rstack dev check` reported a refused review authority binding as
"runtime configuration contains an invalid deployment binding", so a
developer saw the plan field but not the rule. `check_review_authority`
now returns the rule each check states (the endpoint suffixes, the
profile and producer ID grammar, the absolute resource and assertion
audience URIs, and the shared OAuth scope limits), never the value. The
runtime keeps its existing refusal.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
… as usage

A run that misses a readiness or start deadline, or whose supervisor panics,
failed in the environment, so the envelope now says operational (exit 3)
instead of domain. An interrupted start stays domain: the operator asked for it.

A malformed run ID, --ttl value or test person name is refused from the
command line alone, before any project or run state is read, so it is usage
(exit 2). start now checks --ttl before loading the project, so a bad value is
reported as such rather than as a missing dev.yaml. A well-formed run ID that
names no run is unchanged.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
…pts and hosts

remove_run_dir deletes the run's field-encryption key before it renames the
run directory away, so a deletion that is interrupted leaves a .removing
directory without key material for the operator to delete.

ps reports start times in the host's time zone, and recovery compares them
with the times a run recorded. Reading them with TZ=UTC beside LC_ALL=C keeps
that comparison independent of the caller's environment.

The run's key-writing refusal now names the key generator's reason, which
carries no key material, instead of a fixed message.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
…changelogs

The platform changelog names what rstack dev gained before its first
release: stop --recover, the registry.rstack.error.v1 envelope with its three
classes and exit codes, and a per-run key for projects with encrypted fields.

The BReg entry for the long-envelope fix is rewrapped and names the history
journal capture of reviewed migrations, which reads through the same decoder.
The field-encryption flip test now seals values whose envelopes PostgreSQL
wraps, so that path is covered.

The PostGIS provisioning test also checks that the bbox role batch keeps the
SQLSTATE of a refused statement.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
… its cause

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
An interrupt during the Casework inspection in rstack dev start or check
became an unavailable inspection, so it reported the operational class. An
interrupt is the operator's request and reports as domain, as an
interrupted start does. Only other inspection failures become
InspectionUnavailable, with their cause in the reason.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
@jeremi
jeremi force-pushed the fix/rstack-dev-followups branch from 5c89596 to 06e364a Compare November 11, 2026 08:36
@jeremi
jeremi enabled auto-merge November 11, 2026 09:32
cargo deny refuses rustix 1.1.5: its xattr functions mark unwritten bytes as initialized when given a zero-length buffer. Only the rustix entry and its references change.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
…scope

The configuration conventions check refuses an unregistered schema under products/*/schemas. The rstack error report is a command output, not a configuration format.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:full Run the heavy integration tier on this pull request

Projects

None yet

2 participants