Repository navigation
Move Fastly names out of core - #1399
Open
jwrosewell wants to merge 50 commits into
Open
jwrosewell wants to merge 50 commits into
jwrosewell wants to merge 50 commits into
Conversation
A Fastly config store entry holds at most 8,000 characters, so a longer settings document is stored as chunks with a pointer at its key. Core followed that pointer itself while loading settings, which put the Fastly entry limit and pointer format in platform-neutral core. The Fastly adapter's config store now follows a chunk pointer when it reads a key, checking every length and hash as before, so every reader receives the whole document, and core's settings load reads the entry as the platform's config store returns it. The error messages are unchanged. The reassembly tests move to the adapter, with two more for a chunk whose hash disagrees and for other JSON at the key. Two comments on core's store selector helpers that named the Fastly adapter now describe the behavior without naming the platform.
Core held the name of Fastly's staging variable, FASTLY_IS_STAGING, so that the Fastly adapter and the DataDome module could each read it, and DataDome gated its test bypass on that one platform's variable. Core now has a neutral declaration, declare_platform_staging and platform_is_staging, which the adapter makes once before it serves, as it declares its cache headers. The Fastly adapter declares it from its own variable, whose name it now holds, and uses the same reading for the service's identity and the x-ts-env header. DataDome asks core whether the platform serves from staging, so its test bypass works on any platform that declares it, and its tests declare the flag rather than setting the variable.
Core read and stripped `fastly-ssl` and `fastly-client-ip`, and kept `x-debug-fastly-pop` among its internal headers. Each now comes from the adapter, the way the cache headers do. - `platform/request_headers.rs` holds three lists an adapter declares. TLS headers are read for the scheme and never forwarded to an origin, spoofable headers are stripped at entry, and internal headers are never forwarded to a third party. - `SPOOFABLE_FORWARDED_HEADERS` keeps the three standard names, and `sanitize_forwarded_headers` also strips the declared TLS and spoofable headers. - `detect_request_scheme` checks the declared TLS headers as its fourth signal, and the origin request strips them. - `is_internal_header` joins `INTERNAL_HEADERS` with the declared internal headers. The trusted client IP validation, Permutive and Lockr use it. - The trusted client IP header may be an `x-` header or a platform's own header ending `-client-ip`, so `fastly-client-ip` stays valid without core naming it. The guide states the new rule. - The Fastly adapter declares its three headers in `declare_platform`, which `run` calls before serving so that settings validation sees them, and which every state build also calls. Its entry strip names its own two headers directly. - The `build_state_with_registrations` doc comment had become attached to the cache header constant and is back on the function.
`[device] module = "fastly"` selected the module the Fastly adapter builds, so core's device selection and the registry both named Fastly. The value is now `platform`, as it already is for `[geo] module`, and `build_device_module` takes a `build_platform` factory. The Fastly module keeps its own id, `fastly`. A document that still writes `fastly` names a device module no running module supplies, which the registry refuses with a configuration error, so documents move to `platform` with this change. The guide, the example settings and the device crates' docs say `platform`.
`platform_response_to_fastly` returns a buffered response and `platform_response_to_fastly_asset` an asset response that keeps a stream, and neither touches Fastly. They are now `platform_response_to_buffered` and `platform_response_to_asset`, and the error and doc text that called the result a Fastly response says what it is.
The review found two blocking issues. A client-sent x-debug-fastly-pop now reaches Permutive and Lockr on the Axum, Cloudflare and Spin adapters, and the declared spoofable header list is read only by a function whose one production caller declares nothing. The spec now states both as the code has them today and leaves the code fixes as open questions. It also adds the effects on the other adapters, the scheme change on Axum and Cloudflare, where each refusal happens, the order for changing the package and the device selector together, the Fastly name that stays, the untested paths and the corrected counts and test descriptions. The changelog entry gains the x-debug-fastly-pop change and the DataDome guide names the staging condition as the platform's declaration.
The second review found no blocking issues. The changelog now gives the strip of declared spoofable headers its precondition, that the adapter calls sanitize_forwarded_headers, and adds the scheme change on the Axum and Cloudflare adapters and the move of the x-debug-fastly-pop refusal from ts config validate to the service load on Fastly. The spec names that move in its Fastly sentence, corrects when the Axum, Cloudflare and Spin adapters strip fastly-client-ip, which each does where trusted_client_ip names it as ip_header, and lists the module comment in request_headers.rs among the comments left for a later change.
From this branch core reads a config store entry as the platform's store returns it, and the Fastly adapter follows a chunk pointer itself in config_chunks::whole_entry. The config push test that read a chunked document back through core's reader therefore moves its round trip to config_chunks.rs, as the selector design says. Test: a_written_document_is_read_back_whole reads a fixture of the entries `ts config push --local --key a.publisher.example` wrote for a document too long for one entry, chunks first and the pointer last, and checks whole_entry gives back the envelope with the pushed publisher domain. The CLI test keeps its checks of the layout, that every chunk is written before the pointer and that the pointer names the chunks in the order they were written.
The configuration rules guide's table of old names to new had no row for `[device] module = "fastly"`, which this branch replaces with `[device] module = "platform"` and refuses as naming a device module no running module supplies. The table now has that row, after the Edge Cookie one.
This was referenced Oct 17, 2026
12 of 14 tasks
# Conflicts: # AGENTS.md # scripts/README.md
The handler tests of the header rewrite merged in main (#1238) build their request with fastly-ssl: 1 to mark it HTTPS. This change takes that header out of core, so core reads the request as plain HTTP and three of those tests receive http:// where they expect https://. The core platform name check also fails on the header's name. The helper now sends x-forwarded-proto: https, which core reads on every platform and which the origin redirect tests already use. python scripts/lint-core-platform-names.py passes, and the three tests, transformed_page_headers_map_origin_urls_to_serving_host, bodiless_redirect_location_maps_origin_url_to_serving_host and same_scheme_redirect_to_current_url_stays_on_serving_host, pass.
jwrosewell
marked this pull request as ready for review
October 19, 2026 20:24
12 of 15 tasks
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-adapter-fastly/srcscripts/lint-core-platform-names.pydocs/superpowerscrates/trusted-server-adapter-fastly/build.rscrates/bot-protection/datadomedocs/guidecrates/trusted-server-cli/tests.github/workflowscrates/trusted-server-core/README.mdCHANGELOG.mdcrates/trusted-server-core/Cargo.tomltrusted-server.example.tomlcrates/audience/permutivecrates/device/README.mdcrates/device/fastlycrates/identity/lockrAGENTS.mdCargo.lockcrates/trusted-server-adapter-fastly/Cargo.tomlscripts/README.mdcrates/trusted-server-core/build.rsCloses
Part of #777, being its Fastly row under "What is still named in core".
Spec
Spec: fastly-names-in-core
Test plan
CI on this pull request at d1aa512 passed all 27 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!)On top of the AWS signing series (#1391). Issue: #777, the Fastly row of "What is still named in core".
What this adds
What changes.
Core names no hosting platform. The places core still named Fastly move to the Fastly adapter, and core keeps a neutral declaration or interface in the place of each. They are the configuration chunk format, the staging variable, the
fastly-ssl,fastly-client-ipandx-debug-fastly-popheaders, thefastlydevice module selector, and the names of the asset proxy's two response conversions. Counted the way #777 counts, the shipped lines of core that name Fastly go from 43 to none.How it works.
PlatformConfigStore::getreturns an entry whole. The Fastly adapter's store (config_chunks.rs) follows a chunk pointer, reads each chunk and checks every length and hash, so core's settings load reads what any platform's store returns. A long document reads as before, and one whose chunks disagree with the pointer is refused as before.platform::declare_platform_staging, and a module asksplatform::platform_is_staging. The Fastly adapter declares it fromFASTLY_IS_STAGING, and the DataDome module's test bypass follows the declaration.forwarded,x-forwarded-hostandx-forwarded-proto. Its internal headers are never copied to a third party and are refused as trusted client IP headers.constants::is_internal_headeranswers for core's list and the declared one together.app::declare_platform(), whichrun()calls before it serves and every state build also calls. Settings are validated as they load, so a declaration made only in the state build would come after the first validation.ip_headermust start withx-or end with-client-ip, which is the shape of a platform's own client address header, becausets config validatechecks a document where no adapter has declared anything.fastly-client-ipstays valid.[device] module = "platform"selects the platform's own device module, as[geo] module = "platform"selects the platform's geo lookup, andbuild_device_moduletakes abuild_platformfactory. The Fastly module keeps its id.platform_response_to_fastlyandplatform_response_to_fastly_assetareplatform_response_to_bufferedandplatform_response_to_asset, because neither touches Fastly.Why
Core is the interfaces, the routing, the origin fetch, the caches and their tests, and a hosting platform is a vendor to core. Each of these names was a place where a change by Fastly meant a change in core. Each name moves with the code that reads it, as the platforms' cache headers did in the last names series.
What breaks
[device] module = "fastly"writesmodule = "platform". The old value is refused at startup as a device module no running module supplies.ENV_FASTLY_IS_STAGINGandHEADER_X_DEBUG_FASTLY_POPleave core,SPOOFABLE_FORWARDED_HEADERSholds the three standard forwarding headers,build_device_moduletakes abuild_platformfactory, and aPlatformConfigStorereturns each entry whole.fastly-sslis no longer removed from the request to the publisher's origin, and on Spin a client'sfastly-sslandfastly-client-ipare no longer stripped at entry. Trusted Server reads neither header there. A client'sx-debug-fastly-popis copied to a third party like any otherx-header, and the DataDome test bypass no longer follows aFASTLY_IS_STAGINGvariable.The commits
platform.Each carries its section of the series' design page,
docs/superpowers/specs/2026-10-15-fastly-names-in-core-design.md, and each of the first four its changelog entry. The design page takes its round 1 review and round 2 corrections in commits of its own (b319bf0 and 67d34c2), and merges of the series below carry Tech Lab main at 6ef07ae. 6fee073 marks HTTPS in the handler tests of the header rewrite merged in main (#1238) withx-forwarded-protorather than a platform's header, so they pass and core names no platform.What is not in this pull request
Core still names Fastly in comments in about 25 files, and in the names and assertion messages of some tests, the publisher's surrogate cache tests among them. The Axum, Cloudflare and Spin adapters compare their behavior with the Fastly adapter's in comments, and two of their errors suggest the Fastly adapter for parallel bidder fan-out. The
tsdevelopment proxy stripsfastly-ssl. None of these is a shipped line of core.