Repository navigation
A source module says where the publisher path and asset routes fetch from - #1380
Draft
jwrosewell wants to merge 5 commits into
Draft
jwrosewell wants to merge 5 commits into
jwrosewell wants to merge 5 commits into
Conversation
…from Where content comes from was written twice, in [publisher] and in every asset route, and fetched by code that knew one kind of source. A source module now answers it. [source] selects the publisher's, and each [[proxy.asset_routes]] entry selects its own in a source table of the same shape. Core supplies origin, an HTTP origin, and a module a build links offers another through with_source_module. For each request a source answers a SourceLocation, being the address and folder, the Host to send, the signing and the index file. The publisher path and the asset routes fetch, cache, rewrite the origin host and follow the redirect rule from that answer, so a source that answers a different origin for each request is kept apart everywhere. The origin fields move into [source.origin] and [proxy.asset_routes.source.origin]. A document writing one where it was is refused naming the new place, and a document with no [source] is refused. A path in an asset route's url names a folder the target path is added under, a target path with a dot segment under a folder is answered 400, and a route applies directory_index as the publisher does. Stored page and asset keys are unchanged for an existing deployment. The configuration page masks the origin's url and host_header by default, and the signing secrets are declared at their new paths. Design: docs/superpowers/specs/2026-10-14-source-modules-design.md
Request addressing takes a prefix off the path and keeps it as a request extension, so a source can say where content comes from. A module was handed the continuing path only, so a module that names things after the tenant a path addressed, such as a prefix module naming cookies after the publisher, could not tell which one it was. ModuleRequest::of now reads the removed prefix and removed_prefix() gives it, with_removed_prefix sets it, and ResolvedRequest keeps it, so a held request still has it. A request addressing nothing carries none.
A route reads its request through its module call, and the call carried the request as resolved, the settings and the request state, but no evidence. A route that asks for the request as evidence, the client address and headers a module reads, was refused with "there is no request evidence where this module runs", so every such route answered 500 in production while its own tests, which build the context by hand, passed. handle_proxy now takes the evidence before the route takes the request, in the form the permission path reads it: the normalized client address, the headers after the caller's EC header is removed, and the address asked for. The test goes through handle_proxy, so it fails if the evidence is dropped again. (cherry picked from commit efad1ece83c3ec214e7d60c3e0754fb1053c5b41)
A document without [source] is refused since the source series, and the test built its registry from default settings.
This branch has not been deployed
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
Changes
crates/trusted-server-core/srcdocs/guidedocs/superpowerscrates/trusted-server-adapter-fastly/srccrates/trusted-server-adapter-cloudflare/srctrusted-server.example.tomlcrates/trusted-server-adapter-axum/testscrates/trusted-server-adapter-cloudflare/testscrates/trusted-server-adapter-spin/srccrates/trusted-server-adapter-axum/srccrates/trusted-server-adapter-spin/testscrates/trusted-server-integration-tests/testscrates/tag/google-tag-managercrates/testing/seam-probeCHANGELOG.mdcrates/trusted-server-integration-tests/srccrates/trusted-server-cli/srccrates/auction/prebid-servercrates/auction/prebidcrates/trusted-server-integration-tests/fixtures.github/actionsscripts/template-cache-local-test.sh.github/workflowscrates/trusted-server-cli/testsscripts/attestation-local-test.shCloses
Closes #1332
Test plan
CI: 16 of 19 checks green, the fork's CI on d17b184 (jwrosewell#34).
cargo test-fastly && cargo test-axumcargo clippy-fastly && cargo clippy-axumcargo fmt --all -- --checkcd crates/trusted-server-js/lib && npx vitest runcd crates/trusted-server-js/lib && npm run formatcd docs && npm run formatcargo build --package trusted-server-adapter-fastly --release --target wasm32-wasip1fastly compute serveChecklist
unwrap()in production code (clippy deniesunwrap_usedin CI)logmacros as AGENTS.md asks (notprintln!)On top of the middleware settings table (#33). Issue: #1332.
What this adds
What changes.
A source module says where the publisher path and the asset routes fetch from.
[source]selects the publisher's source by name, and each[[proxy.asset_routes]]entry selects its own in a source table of the same shape. Core suppliesorigin, an HTTP origin, and a module a build links offers another throughwith_source_module.How it works.
SourceLocationfor each request, being the address and folder, theHostto send, the signing and the index file. The publisher path and the asset routes fetch, cache, rewrite the origin host and follow the redirect rule from that answer, so a source that answers a different origin for each request is kept apart everywhere.[publisher]keeps who the publisher is. The origin fields leave it for[source.origin], wherehost_header,directory_indexandauthare optional. A document writing one where it was is refused naming the new place, and a document with no[source]is refused with the shape to write.[proxy.asset_routes.source]and the source's own table replace a route's own origin address and signing. A path in a route's url names a folder the target path is added under, a target path with a dot segment under a folder is answered 400, and a route appliesdirectory_indexas the publisher does.ModuleRequest::ofnow reads the removed prefix,removed_prefix()gives it, and a held request keeps it.Why
Where content comes from was written twice, in
[publisher]and in every asset route, and fetched by code that knew one kind of source. A deployment that wants a page from assets built into its binary, from a store its platform offers, or from a service of its own had no place for that code but core. One interface core declares, with the origin fetch as the source core supplies, gives each of those a crate of its own and keeps one table for who the publisher is and one for where the content comes from.What breaks
A
[publisher]table carryingorigin_url,origin_host_header_override,origin_auth,directory_indexor the origin query rule is refused at startup, with the[source]shape to write instead, and an asset route carrying its own origin address or signing is refused the same way. Every deployment's settings document changes shape, so the build and the documents go out together. The integration test environment and the attestation script setTRUSTED_SERVER__SOURCE__ORIGIN__URLin place of the previous variable, because the overlay ignores a variable for a key the document lacks and the old name would silently leave a build on the placeholder origin.The commits
The design page is
docs/superpowers/specs/2026-10-14-source-modules-design.md, and the same page goes to the design documents pull request (#1084) so every design page stays in one place.What is not in this pull request
A source other than the HTTP origin. The interface and the selection are here, a source that answers another address is a module of its own, and a source that holds its content itself, with no network origin, is a later extension of the interface.
How it was verified
On the series' head: core (2,968 tests), the Fastly adapter under Viceroy on wasm32 (277), the Axum, Cloudflare and Spin adapters, the Prebid, Prebid Server, Google Tag Manager, seam probe and modules crates (19 suites), a native workspace check with all targets, and clippy for Fastly, Axum, Cloudflare and Spin native with
-D warnings, all clean. Thetscommand's suites ran on the previous base, where the CLI is unchanged. CI on the fork is the verdict.