Skip to content

test(storage): replay the capture over TLS in the parity oracle - #915

Merged
cameri merged 2 commits into
rewrite/mainfrom
factory/911-tls-parity
Oct 20, 2026
Merged

cameri merged 2 commits into
rewrite/mainfrom
factory/911-tls-parity

Conversation

@chappie-daemon

@chappie-daemon chappie-daemon commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

scripts/storage-parity.sh now starts a second Postgres that requires TLS and replays the same capture over it. Fixes #911.

What the leg does

A second postgres:16-alpine starts with ssl=on and a self-signed pair generated per run, publishing on PARITY_PG_TLS_PORT (default 18778). Ports, the per-run password, the org.testcontainers=true label, the single-address bind and the exit trap are unchanged; the only new bind sources are the certificate pair and that server's PGDATA, both inside the worktree under
.test-reports/parity-tls-<pid>-<random>/, translated to the daemon's view the way scripts/rust.sh translates
the source tree (NOSTREAM_HOST_DIR overrides). The directory is per invocation and removed by the exit trap, so
two oracle runs cannot delete each other's live PGDATA.

The test is the_same_replay_over_tls_matches_the_capture_and_the_plaintext_run, and it asserts three things:

  1. the sslmode=require connection works at all;
  2. SELECT ssl FROM pg_stat_ssl WHERE pid = pg_backend_pid() is true — the server reports the session encrypted, so a connection string alone cannot pass the leg. with_database keeps the query string, so sslmode=require survives into the replay connection the assertion is made over;
  3. the full 118-op replay over TLS equals the TypeScript capture and equals the plaintext replay, op by op, with the differing op named if one diverges.

The step fails if the test does not run, and not merely by counting passes: the script sets PARITY_TLS_REQUIRED,
under which the test panics instead of skipping when it has no TLS URL, and it greps for a
TLS_PARITY_COMPLETE line that the test prints only after its assertions. A skip, a rename and an early return
all fail the run — measured: with PARITY_TLS_REQUIRED=1 and no URL the test fails with
PARITY_TLS_REQUIRED is set but PARITY_TLS_ADMIN_URL is not. In CI's existing Storage parity step neither
variable is set, so the test prints that it is skipping and returns; the oracle is where the leg runs.

The uid-70 trap, and how it is handled

The official image's postgres user is uid 70, and PostgreSQL refuses a key with group or world access (private key file ... has permissions ... u=rw (0600) or less), so a host-generated 0600 key is unreadable to it and chmod 644 is not accepted either. The server therefore runs as the invoking uid (--user "$(id -u):$(id -g)") with its own PGDATA on a bind: the key stays 0600, owned by the user the server runs as, and the image is unmodified. No host step is needed; the script does it.

Oracle output

PARITY_BIND=100.106.134.5 PARITY_HOST=100.106.134.5 RUST_CACHE_VISIBLE=/workspace/containers/rust-builder/cache NODE_PATH=/workspace/projects/nostream/node_modules ./scripts/storage-parity.sh on this head, exit 0:

== credential redaction
== containers (bound to 100.106.134.5, per-run credentials)
   postgres (plaintext and TLS) and redis are accepting connections on 100.106.134.5
== migrations and schema parity
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in 1.60s
== behavioural parity
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.39s
== tls parity (the same replay over sslmode=require)
   the replay over sslmode=require matches the plaintext run (finished in 2.22s)
== cucumber on the sqlx-migrated schema
118 scenarios (118 passed)
587 steps (587 passed)
== storage-parity: all four steps passed

Baseline for comparison: the same command on 6ef609a passes the three original steps with 118 scenarios; this run keeps every one of them and adds the fourth.

Controls, at two layers

The build, tls-none. A scratch copy with Cargo.toml back to tls-none fails — but earlier than the TLS leg, in the behavioural step, at the guard #913 merged:

test a_tls_connection_is_attempted_rather_than_refused_by_this_build ... FAILED
sqlx refused to negotiate TLS locally: ... TLS upgrade required by connect options but SQLx was built without TLS support enabled

So the two tests cover different layers rather than repeating each other: the guard pins the build, the leg pins the server handshake and the replay equality. Because the run aborts at the guard, the leg's own control is a server-side change, not the feature flag.

The server, ssl=off. The same TLS leg pointed at a Postgres with TLS off, at sslmode=require:

the TLS administrative database is reachable (is ssl=on?): Tls("server does not support TLS")
test result: FAILED. 0 passed; 1 failed

That is the leg's own negative control: no fallback to plaintext, and the failure names the server rather than the build.

Local checks

cargo fmt --all --check clean; cargo clippy --workspace --all-targets --all-features -- -D warnings clean; cargo test --workspace --all-features 594 passed, 0 failed.

The oracle started Postgres without TLS, so nothing exercised a server that insists on
it. It now starts a second server with ssl=on and a per-run self-signed pair, and the
same replay runs over sslmode=require, compared op by op against the TypeScript capture
and against the plaintext run; pg_stat_ssl confirms the session the server sees.

The postgres image runs as uid 70 and PostgreSQL refuses a 0600 key it cannot read, so
that server runs as the invoking uid with its own PGDATA on a bind, keeping the key 0600.
With tls-none restored the leg fails to connect instead of falling back. Fixes #911.
@changeset-bot

changeset-bot Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 0ad608e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@greptile-apps

greptile-apps Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[Low impact] The PR appears safe to merge; both previous findings are addressed.

Summary

Adds a TLS replay to the storage parity oracle and addresses both previous findings.

  • The storage parity script checks the same database replay over TLS and plaintext.

No new actionable issues were found. The checks in this review were static; tests were not run.

Reviews (2) · Last reviewed commit: "fix(tooling): isolate the oracle's TLS r..." · Reviewed by Greptile

Comment thread scripts/storage-parity.sh Outdated
Comment thread scripts/storage-parity.sh Outdated
Two runs of the oracle shared .test-reports/parity-tls, so a second run deleted the
first one's live PGDATA. The directory now carries the pid and a random token and the
exit trap removes it, so concurrent runs (on different ports) cannot touch each other.

The TLS test returned early without a TLS URL, which also printed '1 passed', so the
script's pass-count check could not tell a skip from a run. PARITY_TLS_REQUIRED makes
the test panic instead of skipping, and a completion marker printed after the
assertions is what the script checks.
@cameri
cameri merged commit 471d439 into rewrite/main Oct 20, 2026
15 checks passed
@cameri
cameri deleted the factory/911-tls-parity branch October 20, 2026 03:12
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.

2 participants