feat(callback): retrieve the artifact, and refuse to start without one - #9
Merged
SupremaLex merged 9 commits intoSep 14, 2026
Merged
Conversation
SupremaLex
force-pushed
the
feat/callback-artifact-retrieval
branch
from
September 9, 2026 16:14
c04789f to
6d472d3
Compare
SupremaLex
requested review from
Wondertan and
xgreenx
and removed request for
Wondertan
September 9, 2026 16:50
SupremaLex
force-pushed
the
feat/callback-artifact-retrieval
branch
from
September 9, 2026 18:52
447d61d to
972326a
Compare
This was referenced Sep 10, 2026
SupremaLex
force-pushed
the
feat/callback-artifact-retrieval
branch
from
September 11, 2026 11:34
ebbf109 to
31f3b70
Compare
Wondertan
approved these changes
Sep 11, 2026
The callback artifact is retrieved from `{ccdpOrigin}/ccdp/callback.html`
before the listener binds and revalidated every five minutes against the
`ETag` it came with; a failed refresh leaves the served document as it is,
and a valid replacement replaces the document and its policy together.
Redirects are refused; the request carries no cookie, credential or query.
A deployment that cannot retrieve its artifact exits non-zero.
There is no file override: the artifact is always the Distribution's, and a
development stack serves its own over HTTP on `localhost` or `127.0.0.1`.
`src/artifact/callback.html` is test data, now under `tests/fixtures/`, and
the tests retrieve it from one Distribution on loopback per test binary,
served on a runtime that outlives the tests.
Assisted-by: Claude Opus 5
Assisted-by: Claude Fable 5.1
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
`callback_source` answers a `304` to its unconditional request as `ArtifactUnavailable`, like every other answer that is not the artifact. Assisted-by: Claude Fable 5.1 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
`libid_server_rs::fixtures` holds the shared Distribution, the dead wire port and the deployment builder, compiled for the crate's tests and, under the `fixtures` feature, for the integration tests; `tests/http.rs` and the artifact tests build from it. `tests/startup.rs` runs the binary on a configuration file: it serves, stops on SIGINT, and refuses a configuration naming no platform. Assisted-by: Claude Fable 5.1 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
| Before | After | |---|---| | `callback_source(origin, allowed)` | `Published::retrieved(&upstream, allowed)` | | `artifact(response)` | `Fetched::of(response)` | | `fixtures::config(args)` | `Config::fixture(args)` | | `fixtures::deployment(args)` | `AppState::fixture(args)` | | `fixtures::distribution()` | `Distribution::shared()` | `assemble` stays a free function: it returns `TokenResponse`, which is libid-ceremony's to construct. No behaviour changes. Assisted-by: Claude Fable 5.1 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
Production: - `ON_EVERY_RESPONSE`: the `no-store` and `nosniff` pair, declared once in `routes` and carried by the health, callback, configuration and token responses. - `Published::log`: the one log line naming a document's URL, validator and policy, at retrieval and at replacement. Tests: - `tests/http.rs`: one request builder (`token_request`), one body builder (`token_body_with` / `token_body_without`), one permit-holding poster; `post_token` takes the origins as a list. - `session.rs`: one assembly helper over a duplex socket, with the notary's behaviour as an enum; one bearer opening. - `request.rs`: one layout helper. `upstream.rs`: one deployed-Distribution helper. jscpd: 12 clones, 66 lines → 1 clone, 5 lines; the one left is `redirect_uri` beside `notary_host` (#10's function, kept verbatim). Assisted-by: Claude Fable 5.1 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
The duplex writer of that case is dropped before the assembly reads, so the reader sees end of file; the two record failures are asserted by their own words, end of file and the budget. Assisted-by: Claude Fable 5.1 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
Use released libid-rs v0.3.0 and the matching TLSN/MPZ pins, including the MPZ active-context lifetime fix. Assisted-by: GPT-6 Signed-off-by: Wondertan <hlibwondertan@gmail.com>
Pin the shared Rust transcript reader and classify the actual error field using the same reader. Assisted-by: GPT-6 Signed-off-by: Wondertan <hlibwondertan@gmail.com>
Replace the closed whitespace PR dependency with its released successor while retaining the matched RC3 TLSN and MPZ runtime patches. Assisted-by: GPT-6 Signed-off-by: Wondertan <hlibwondertan@gmail.com>
SupremaLex
force-pushed
the
feat/callback-artifact-retrieval
branch
from
September 14, 2026 12:04
daebcf3 to
14bbdb2
Compare
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.
Stacked on #8 (base
feat/ceremony-github-token). Review #8 first.#8 configures and serves the callback document but does not fetch it: a deployment named a file, or got a compiled-in floor that completes no ceremony. This adds the retrieval
specs/oauth-bridge.md§ Callback document asks for, and nothing else.What it does
{ccdp_origin}/ccdp/callback.html, validates and composes it, and publishes document and headers as one value. A deployment that cannot retrieve its artifact does not start:build_statereturnsErr, the process exits non-zero, the port is never bound. Taken from @Wondertan's review of feat!: the OAuth Bridge — configuration and the callback document #8.If-None-Match.304keeps the document; a200that composes replaces it and advances the ETag; anything else keeps the last valid one. Connect 15 s, request 20 s, the body bounded while it is read. Any3xxis refused, never followed. No cookie, credential, query or incoming header goes upstream.CALLBACK_ARTIFACT_PATHand the compiled-incallback.htmlare gone; the fixture artifact lives undertests/fixtures/.build_stateisasync.Also here
src/fixtures.rs(featurefixtures, reached by the integration tests through a self dev-dependency): one set of fixtures for the crate's own tests andtests/:Distribution::shared(),Config::fixture,AppState::fixture, the request builders.tests/startup.rsruns the real binary on a TOML file over TCP: every route, SIGINT, a configuration it refuses.libid-org/tlsn@94aaaf33and mpz1dd2349matching notary RC3, JSON whitespace accepted in token responses, libid-rs at tagv0.4.0.For review
tokio-rustlsisdefault-features = falseon purpose: rustls resolves withringalone, its defaults would addaws-lc-rs, and two providers panic at runtime.cargo tree -i aws-lc-rsstays empty.hyperis driven directly, no client crate: one connection every five minutes, and refusing a3xxis amatcharm rather than a setting.Verification
127 tests: 88 unit, 37 over the router, 2 over the socket.
upstream.rsat 97% line coverage. The retrieval tests run against an axum fixture on loopback. Measured against a running Distribution: retrieve,304, replace on a new validator,304against the new one, serving throughout; exit 1 naming the URL when it is unreachable.