Repository navigation
Let a module name the browser's cookies and the shared store keys - #1368
Open
jwrosewell wants to merge 50 commits into
Open
jwrosewell wants to merge 50 commits into
jwrosewell wants to merge 50 commits into
Conversation
Core gains a prefix module, `PrefixModule`, which gives two things for the publisher a request resolved to: a public prefix that starts every name the browser holds, being cookies and first-party storage keys, and a server key prefix that starts every key in a store publishers share. Core's own module gives `ts` and `ts.<publisher.domain>` and runs when `[prefix] module` selects nothing, so a stock build's names are what they were. The registry resolves the selection as it does geo and device, refuses a name nothing this deployment runs supplies, and asks the module once when the registry is built, so a module naming a value its call never carries is refused at startup. Every adapter puts the resolved prefixes on the request's services, and the Fastly entry point keeps what its request resolved to for the finishing steps that run after the request has been handed to the router. The robots.txt holding and the loading cache take the prefix from the request's services rather than from the settings.
The cookie constants lose their fixed `ts-` head and name the entry alone, `ec`, `ecr`, `ec-pull-complete`, `eids` and `tester`, and every read and write names the cookie through the request's public prefix, so a deployment whose module gives `_ex` reads and writes `_ex-ec`. The Edge Cookie state carries the prefix it was read under, and a module's response header naming a cookie under that prefix is refused as a cookie under `ts-` was. The page's bundle tag tells the client script the prefix, as `data-ts-public-prefix`, so the script names its own cookies after it and holds no copy. The template fingerprint includes the prefix, so a page stored under one is never served under another, and a key cookie naming one of the request's own identity cookies shares no template.
A prefix's first part starts with a letter or a single `_`, so no cookie name starts with `__`, where browsers give names such as `__Host-` rules of their own and drop a cookie that breaks them. The Edge Cookie test reads and writes under a prefix carrying a publisher's name as well, and a test holds the client script to the attribute the server writes.
The probe declares a prefix module on its registration, giving `_probe` and `probe.<publisher.domain>`, and its report route answers the prefixes the request's services carry, so the Axum adapter proves from outside core that `[prefix] module` resolves the module and that a request's services carry what it gives.
The configuration guide lists `[prefix]` among the sections and describes the selection and the names it changes. The integration guide's registration table gains `.with_prefix_module(name, ...)` and a section on giving the deployment its prefixes. The example configuration notes the section, and the changelog records the addition and the renamed cookie constants.
# Conflicts: # CHANGELOG.md # crates/trusted-server-adapter-fastly/src/app.rs # crates/trusted-server-adapter-fastly/src/middleware.rs # crates/trusted-server-core/src/integrations/registry.rs # crates/trusted-server-core/src/robots_txt/holding.rs # trusted-server.example.toml
The page handler and the HTML processor read the prefix the request's services carry instead of resolving the module again. Writing [prefix] module = "ts" selects core's own module, the per-request fallback to core's prefixes is gone, and the unused prefix forms are removed. The client refuses a leading __ as the server does, and the template cache keys keeping ts are named as the exception.
The Fastly test of the data page's sandbox called handle_data with the three arguments it took before the prefix module, so the adapter's tests did not compile. It now passes the default public prefix. The [prefix] table in the configuration guide is formatted as Prettier writes it.
# Conflicts: # crates/trusted-server-core/src/publisher.rs
This was referenced Oct 15, 2026
EntryRequest::of, which keeps the request's method, host, scheme, path and query for the module calls that run after the request is handed to the router, read Host with get_header_str, which panics on a value whose bytes are not valid UTF-8. A client chooses those bytes, and a request addressed by a hook can reach this read with such a Host. It now reads Host through request_host, as entry_request and the selection by host do, so such a Host is kept as no host. Test: a_kept_entry_request_reads_a_host_that_is_not_utf8_as_no_host builds the kept request from a Host of the bytes b"\xffa.example" and checks the kept host and the module request it makes are both empty.
This branch's prefix module gives the start of every name the browser holds, so COOKIE_TS_EC_RESOLVED became COOKIE_EC_RESOLVED, the name's end. The three tests that the demo Edge Cookie module fix brought up from split/4-client-resolve named the marker by the old constant, so core's tests stopped compiling here. They now name the marker `ts-ecr`, its name under the default public prefix, as this branch's own resolve tests do.
14 of 15 tasks
# Conflicts: # CHANGELOG.md
The default selection was built by SelectedPrefixModule::trusted_server, which the registry called when nothing or ts is selected and which Default called too. The code scanning rule for cleartext logging takes a function whose name holds "trusted" to return a secret, so it followed that module into the registry and the auction and reported a count of planned providers and a skipped module's name as logged secrets. The registry now asks for SelectedPrefixModule::default, as its other uses already do, Default builds core's own module itself, and the constructor, which nothing else calls, is gone.
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/srccrates/trusted-server-js/libcrates/trusted-server-adapter-fastly/srcdocs/guidecrates/trusted-server-adapter-spin/srccrates/trusted-server-adapter-axum/testscrates/trusted-server-adapter-axum/srccrates/trusted-server-adapter-cloudflare/srccrates/testing/seam-probetrusted-server.example.tomlCHANGELOG.mdcrates/loading-cache/51degreescrates/trusted-server-core/benchesCloses
Closes #1285
Spec
Spec: prefix-module
Test plan
CI on this pull request at bb54e54 passed all 20 checks.
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!)Stacks on a vendor's shared table (#1367).
What changed after the 51Degrees PR review
Agreed at the review on 23 October, point 1. No configuration or permission policy is compiled into the WASM, and a WASM without a policy does not start. Since #1345 a loaded domain carries its permission policy and every services graph needs one, so the tests below give theirs the sample policy.
template_fingerprint.Kept current
mainat 7aa5c99 and the changes made lower in the stack.What this pull request does
A prefix module,
PrefixModule, which gives two things for the publisher a request resolved to: a public prefix that starts every cookie name the browser holds, and a server key prefix that starts every key in a store publishers share. Core's own module givestsandts.<publisher.domain>and runs when[prefix] moduleselects nothing or namests, so a stock build's names are byte for byte what they were, with a test.A module gives the parts and each use writes its own form, because what is allowed differs by use:
ts-ecfor a cookie,ts.example.comfor a store key. The public prefix carries no domain, because a browser already keeps each site's names apart from every other site's. The server key prefix carries the publisher's domain with a single leadingwww.folded, sowww.example.comandexample.comshare keys andclients.example.comandpublic.example.comdo not, and the domain comes from the publisher the request resolved to, never from the raw request, because aHostheader can say anything and a prefix built from one would let any request start a key space of its own.The template cache is the exception. Its surrogate keys,
ts-templateandts-template-url-<digest>, and its store key,ts-template-cache-v<n>-<digest>, keeptswhatever the module gives, sots cache purgenames one key in every deployment. The store key's digest covers the request's host and the public prefix, so no two publishers share a template.The registry resolves
[prefix] moduleas it does[geo]and[device], refuses a name nothing this deployment runs supplies, and asks the module once when it is built, so a module naming a value its call never carries is refused at startup. Every adapter puts the resolved prefixes on the request's services, and the page handler reads them there. Every cookie core writes or reads is named through the public prefix, the Edge Cookie state carries the prefix it was read under, a module's response header naming a cookie under that prefix is refused as one underts-was, the page's bundle tag tells the client script the prefix asdata-ts-public-prefixso the script holds no copy, and the template fingerprint includes the prefix so a page stored under one is never served under another. A prefix's first part starts with a letter or a single_, so no cookie name starts with__, where browsers give names such as__Host-rules of their own. The client script refuses the same shapes.The seam probe declares a prefix module giving
_probeandprobe.<publisher.domain>, and its report route answers the prefixes the request's services carry. The Axum adapter's tests select it with[prefix] moduleand read back both prefixes through the route.Why
A deployment that is not Trusted Server, or one host serving several publishers, needs its own names in the browser and its own key space in a shared store, and until now both were fixed in core as
ts. The names a reader's browser holds and the keys a store holds are a deployment's identity, so the module that gives them is an extension point rather than a setting, and the default keeps the stock build unchanged.What breaks
ts-ecis ignored under_ex, asthe_edge_cookie_is_read_and_written_under_the_requests_prefixproves.COOKIE_TS_ECtoCOOKIE_ECand so on, because their value is no longer a whole name. A crate outside core that read them writesservices.public_prefix().cookie_name(COOKIE_EC)instead.ServerKeyPrefix::for_settingsis removed. A caller takesservices.server_key_prefix().example.com., now gives the same server key prefix asexample.com, so its loading cache entries are made again under the new key.How it was verified
Not exercised. No module outside the stock build gives a prefix. The probe's module is the one reader, through the Axum adapter.
References #1285.