Repository navigation
Add the module documentation set and finish the decomposition - #1347
Open
jwrosewell wants to merge 46 commits into
Open
jwrosewell wants to merge 46 commits into
jwrosewell wants to merge 46 commits into
Conversation
Fifth and final slice of the PR 838 decomposition: - Documentation for the provider model: configuration reference for the [ec], [device], and [geo] sections (including the required default_country, the assume_single_jurisdiction acknowledgment, and the requires-signal floor on a failed lookup), the Edge Cookie guide rewritten around providers and the permission model (including the narrow withdrawal semantics, the hardened resolve endpoint, and the resolved-marker cookie), setup and error-reference updates, and the permission-model guide joins the docs navigation. - The example configuration documents every provider selector in one place, with the [geo] baseline explained and acknowledged. - The HostSignals trait moves to the top of the evidence module with its service framing documented. - The Fastly EC lifecycle integration-test job joins the test workflow. The earlier draft of this slice carried an IntegrationResponseMutator response-header hook. It shipped with no consumer, so it is not included: the hook returns together with the first integration that needs it. Two specs land with this slice: the migration and rollout spec (docs/superpowers/specs/2026-07-30-provider-migration-rollout-design.md), its sign-off ledger kept intact with each row the series implements marked with its PR, and the response-header hook spec (docs/superpowers/specs/2026-07-30-integration-response-header-hook-design.md), retained as the design bar for the hook when its first consumer arrives.
The rollout spec cited commit SHAs from a rebuilt branch, credited the series with a passphrase tightening that pre-dates it, said graph rows were keyed verbatim when the pre-series normalization already lowercased them, attributed the Fastly-only identity endpoints to PR 1046, and claimed a CLI regression test for the provider overrides that does not exist. The hook spec said the fastly device provider is startup-rejected (it ships opt-in), that integrations cannot touch response headers (request filters can name them) and that the wasm target builds with panic = abort (it has no unwinding at all). The configuration guide now lists every Edge Cookie and geo provider value, the API reference documents each resolve response and the coded identifier form, and the setup guide shows the hmac~ prefix a minted cookie carries.
The no-client-IP test now derives identity from the request query and cookies through `EvidenceCapturingProvider`, which left `NoClientIpProvider` with no remaining caller. It is deleted rather than left looking like a live fixture, and the branch builds without the dead-code warning that denied clippy. That test's comment claimed the provider receives the documented unavailable value, the empty string, but the rewrite no longer observes what the provider was handed, so nothing proved it. The comment now says only what the test asserts, which is that a provider reading other evidence still mints when the host can determine no client IP. Restoring the stronger assertion would mean recording the client IP the provider saw, which is a change to the fixture rather than to this cleanup. The `http::HeaderMap` import in the device tests was unused, because the one place needing the type names it in full. Addresses: crates/trusted-server-core/src/ec/mod.rs and crates/trusted-server-core/src/ec/device.rs, which carried a dead test provider, a comment asserting more than the test proved, and an unused import.
The rewrite that replaced the old no-client-IP fixture left its comment claiming the provider receives the documented unavailable value while nothing asserted it, so the contract went unchecked and the comment said more than the test knew. The shared evidence-capturing provider now records the client IP it was given alongside the query parameter and cookie it already recorded, and the test asserts the empty string reaches it. A provider cannot decide how to behave on a host that cannot determine a client IP without knowing what absence looks like, so that value is part of the contract rather than an implementation detail. Verified by falsifying the expectation and watching the assertion report the real value it observed rather than passing regardless. Addresses: crates/trusted-server-core/src/ec/mod.rs, a comment claiming more than its test proved
The core library is exercised only through the WebAssembly adapter targets, which build with panic=abort. Their harness stops at the first failing test and reports every later one as never run, so a red build shows one failure when there may be several, and the ones it hides are invisible until the first is fixed and the suite is run again. This adds a host-target run of the same crate to the job that already runs the CLI and codegen tests natively, so every failure is reported at once. It costs one more compilation of a crate the job has already built for other targets. Addresses: .github/workflows/test.yml, core failures hidden behind panic=abort
The permission baseline and consent handling for a request the geo provider leaves unmatched come from the top of the permissions.yaml rules tree, so the [geo] reference no longer documents a default_country field. The deployer states the policy in that file, and the software encodes no jurisdiction's law.
The paragraph still placed the permissions file at the repository root and referenced the retired default_country. It now points at the config/permissions sample and the top-of-tree fallback.
Brings the permission signal work up to the documentation branch. The merge has no conflicts.
Brings the documentation and assertion message fixes up from split/4-client-resolve. The merge has no conflicts.
Brings upd/split/4-client-resolve at 69e7d57, which carries main at 066ea3c through split/1 to split/4, into split/5-response-hook-docs. Five files conflicted, all in the documentation set and the example configuration, and all for one reason. This branch documents split/1's move of the Edge Cookie passphrase under [ec.providers.hmac] behind provider = "hmac", still as a plaintext value, while main's #1036 made the passphrase the name of a secret-store key. Every resolution keeps this branch's layout with main's key-name model. In configuration.md, ec-setup-guide.md, error-reference.md and fastly.md, the TOML examples select provider = "hmac" with passphrase = "ec_passphrase" under [ec.providers.hmac], and the environment overrides use TRUSTED_SERVER__EC__PROVIDERS__HMAC__PASSPHRASE with the key name. Three examples merged cleanly with the plaintext placeholder still under [ec.providers.hmac] and take the key name too. The [ec.providers.hmac] reference table gains main's note that the passphrase is a key name, and its passphrase row says so. The security, staging and placeholder bullets are main's, because this branch's bullets described plaintext values in environment variables. The validation bullets keep this branch's provider bullet and take main's three, naming providers.hmac.passphrase. trusted-server.example.toml keeps this branch's host-signal provider block with a key-name placeholder, because that passphrase is also resolved from the secret store (a75571d on split/2), and takes main's partner comment.
The example configuration said the host-signal provider creates the identifier from the host's TLS JA4 and HTTP/2 signals instead of the client IP. HostSignalProvider::generate hashes the JA4 and HTTP/2 signals together with the client IP, as the provider's own documentation says, so the comment now says so.
The configuration guide said a failed geo lookup at request time does not fall back to default_country, a setting that no longer exists. The sentence now says what a failed lookup does without naming it.
Brings upd/split/4-client-resolve at 2c34be4 into split/5-response-hook-docs. That carries the split/1 review follow-ups (0980b73, 0e7f7eb, fb1bc28, cb6f717 and 1b88e42) through split/2, split/3 and split/4, and split/3's be0ed2d fix for the Cloudflare and Spin startup tests, whose four settings blocks this branch carries too. One block conflicted, the admin lookup sentence in docs/guide/api-reference.md. This branch added the hmac~ prefix to main's {64 lowercase hex}.{6 alphanumeric} sentence, and split/1's 1b88e42 rewrote the same sentence to list every form the route accepts, being an identifier from the selected provider such as the hmac~ form, the bare legacy form the HMAC provider still reads, and both HMAC forms when no provider is selected. That sentence covers what this branch added, so it is kept. Tests. The merged tree passes a native all-targets check, 2,885 core tests, the Axum, Cloudflare and Spin adapter tests, the permission signal crate tests, and the Fastly, Cloudflare and Spin wasm checks, and Prettier accepts the resolved API reference.
Brings upd/split/4-client-resolve at b7dd13f into split/5-response-hook-docs. That carries split/3's 88a7482, which makes `tools/permissions-inspector/wasm` pass the request evidence and the signal providers to `assemble_permissions`, and which formats the crate. This branch carries the same inspector and the same `Permissions Inspector` workflow, so it failed the same way. The merge had no conflicts and touches only the four files under `tools/permissions-inspector/wasm`. Tests. `./scripts/build-inspector-wasm.sh` builds clean for wasm32-unknown-unknown on this tree, and `cargo fmt --check` on the crate is clean.
configuration guide Brings upd/split/4-client-resolve at e17090b into split/5-response-hook-docs, which carries split/3's a2a1dfc renaming `config/permissions/vanilla.yaml` to `config/permissions/sample.yaml`. This branch adds the permissions paragraph in `docs/guide/configuration.md`, which split/3 does not have, so the merge could not correct it. That sentence now names the new path and says the sample is for testing and evaluation only and is neither a production policy nor legal advice, matching the file header and the permission model guide. The merge had no conflicts. `trusted-server.example.toml` auto-merged. Tests. `cargo fmt --all --check` is clean and the core suite passes 2,885 tests. The docs Prettier configuration sets `proseWrap: preserve`, so the edited sentence cannot change the formatting of the file.
…guides Brings up the Edge Cookie provider block layout from split/1, the host_signals rename from split/2, the permission signal provider key from split/3 and the client_fixed rename from split/4. All four are the same decision, which is that every provider name an operator types is snake_case, a provider type is a top-level table, and a provider key inside it selects what runs. Nothing conflicted. The response hook and the documentation set this branch carries sit beside the sections those renames touched. The documentation needed the work the clean merge did not do. These guides were written against the old layout, so they still told operators to write a table that is now refused and to select providers by spellings that now stop startup. The configuration guide, the Edge Cookie setup guide, the error reference, the Fastly guide and the key rotation guide all move from [ec.providers.hmac] to [ec.hmac], and the environment override for that passphrase becomes TRUSTED_SERVER__EC__HMAC__PASSPHRASE, which is the path the settings now hold it at. The configuration guide's [ec] reference needed more than a rename. Its rule that every selection must have a matching block is no longer what the code does, because a provider has a block only when it has settings, so it now says which providers need one and which do not, and it explains the implementation key that lets a block carry a label of the operator's choosing. Its provider list and its validation notes follow the snake_case names, and the resolve_allowed_origins key this stack added to the [ec] section is documented alongside the rest. The Edge Cookie guide named the host-signal and demonstration providers by their old spellings throughout, including in a diagram label, and now names them host_signals and client_fixed. The cargo feature that compiles the demonstration provider in keeps the name client-fixed-demo, because a cargo feature name is not a configuration value. The example configuration's commented-out host-signal block carried both the old table and the old name, and is now [ec.host_signals] selected by provider = "host_signals". Tests. cargo fmt --all -- --check is clean and cargo clippy -p trusted-server-core --all-targets --all-features -- -D warnings passes. The core suite passes 2,909 tests and 8 doc-tests with 4 ignored. The Axum adapter passes 64 tests across its five binaries, cargo clippy-axum is clean, and cargo check -p trusted-server-adapter-fastly --target wasm32-wasip1 builds.
Four sentences in the guides joined their clauses with a semicolon, and one table row grew past its column. They now read as one sentence each, and the table is realigned, so the pages follow the house style the rest of the guide follows.
Carries up the resolutions from split/4. Main's documentation refresh rewrote the section table in the configuration guide, so its version is taken with this branch's sections added in alphabetical order. That is device and geo, which the old table listed, and permission_signal, which it never did.
Brings main at 7a0ecb4 and the refreshed lower branches into the documentation set. Nine of the eleven conflict blocks differed only by the module rename and are settled as this branch's text with the rename applied. By hand: the evidence module keeps the HostSignals trait where this branch moved it, the setup guide keeps this branch's description of the ec_id value ahead of main's text on grouped mappings, and the Edge Cookie guide keeps the client_fixed paragraph and takes main's completion-marker text for the ec_identity_store paragraph where this branch moved it.
What an operator selects to supply a capability is a module, and provider keeps the one meaning it has on main, an auction provider instance. This renames the words this branch adds on top of the client resolve path, which already says module, and only those words: every provider word was compared with upstream main, and a word that exists there is untouched, as is the icu_provider crate the permissions inspector's lock file names. - The environment overrides the configuration guide and the error reference show read TRUSTED_SERVER__EC__MODULE, TRUSTED_SERVER__DEVICE__MODULE and TRUSTED_SERVER__GEO__MODULE, and the selectors in every example read module. - The configuration, Edge Cookie, setup, error reference and Fastly guides, the example settings, the evidence module's documentation and the no-client-IP test's message say module wherever they meant an Edge Cookie, device or geo module.
Brings the fix that threads the selected module into the resolve conflict test's context.
Brings the inspector lockfile fix, which names the icu_provider crate again.
Brings the naming module, the permission signal modules named by their crate folders and [permission-signal] modules, with their guides.
A name written in `[ec] module`, an `[ec.<name>]` block or an `implementation` line is parts joined by `.`, each of lower case letters, digits, `_` or `-`, in place of snake_case, and a module from a crate may be written in full, as `edgecookie.<name>`, or with that type folder left off. The sections table names `[permission-signal]`.
The Edge Cookie guide still said that an unknown country falls back to a configured default country, and that only the storage permission is resolved from a TCF signal. Neither is how the permission model works. - When no country is identified, or neither the region nor the country has a rule, the baseline on the top node of the rules tree applies. - Every permission is resolved from that baseline and the signals, each signal read by its own permission signal module in the configured order, with the Model Terms for Marketing preference among them. - A location lookup that fails resolves at the requires-signal floor. The setup guide describes the bare identifier form by what it is, a value with no module prefix, rather than by when it was issued.
Core's build script compiles the git version in by emitting TRUSTED_SERVER__GIT_VERSION as a rustc-env variable, and cargo also sets that variable on the test process. The test-only from_toml_and_env read it as a git_version setting, which Settings refuses as an unknown field, so twelve settings tests failed in the host-target core library tests this branch runs in CI. The loader now builds its environment source from the process variables without that one, and a new test loads settings with the variable set.
This was referenced Oct 17, 2026
No response carries the EC ID in a header of its own. Core reads x-ts-ec from requests, removes it from the requests it forwards and clears it from responses, and a module may not set an x-ts- response header, so the identifier reaches the browser only in the ts-ec cookie, as the API reference says. The sentence now says so, and points to the API reference for the routes that use the cookie.
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
docs/guidecrates/trusted-server-core/src.github/workflowstrusted-server.example.toml.gitignorecrates/geo/README.mdcrates/trusted-server-js/libCloses
Part of #782, which stays open until the hook itself is built.
Spec
Spec: integration-response-header-hook
Test plan
CI on this pull request at 643de85 passed all 32 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 the client-set Edge Cookie value path (#1346), and depends on #1343
to #1346 together, because this pull request documents what they build. It is the fifth and last of the pull requests (#1343 to #1347) that
decompose the module work of the combined change (#838), as the review of
the earlier design specs (#986) asked.
The design specs for the series are carried by the spec pull request (#1342),
including the two this pull request used to carry:
2026-07-30-provider-migration-rollout-design.md,the migration and rollout draft revised against the implemented series. Its
sign-off ledger is kept intact, with each row the series implements marked
with its pull request, so the task force can ratify rows rather than argue
them again.
2026-07-30-integration-response-header-hook-design.md,kept as the design bar for the response-header hook. The hook itself is not
in this series.
What this pull request does
IntegrationResponseMutatorresponse-header hook that an earlier versionof this pull request added is not in the series. The hook had no consumer,
and the spec set's own rule is against speculative surface. The hook returns
with the first integration that needs one, and its spec is the starting bar
for that design.
docs/guide/configuration.mdgains the
[ec] moduleselector with its[ec.hmac]and[ec.host_signals]tables, the[device]and[geo]selectors, theimplementationline, theassume_single_jurisdictionacknowledgment, therequires-signal floor on a failed geo lookup, the bare-origin rule for
resolve_allowed_origins, and a section on the country and region rules inpermissions.yaml. It also says what stops a deployment, being a table theselector does not name, a name this build does not have, a name that is
not a module name, and a setting the module does not know.
(
docs/guide/ec-setup-guide.md)is rewritten around modules and the permission model, including the narrow
withdrawal rules, the hardened resolve endpoint and the resolved-marker
cookie. The setup guide, API reference, error reference, Fastly guide and
key-rotation guide are updated to match.
trusted-server.example.tomladds a commented
[ec.host_signals]block and rewrites the[device]and[geo]comments to say what each default does and how to override it..github/workflows/test.ymlon
windows-latestas well asubuntu-latest, and the Axum job also runsthe core library's unit tests natively, because on the WebAssembly targets
the test harness stops at the first failing test and reports the rest as
never run.
crates/trusted-server-core/src/ec/mod.rschecks that a module receives the empty string as the client IP when the
host cannot determine one, and
crates/trusted-server-core/src/evidence.rscorrects its module documentation and moves the
HostSignalstrait to thetop of the file.
What happens to #838
Once the five pull requests that decompose #838 merge, #838 is closed. It stays
open as a draft reference for the review period only.
References #777 and #778. Decomposes #838. Spec baseline from #986.