Skip to content

Read middleware settings from [middleware.<name>] - #1379

Open
jwrosewell wants to merge 38 commits into
feature/37-origin-redirectfrom
feature/38-middleware-settings
Open

jwrosewell wants to merge 38 commits into
feature/37-origin-redirectfrom
feature/38-middleware-settings

Conversation

@jwrosewell

@jwrosewell jwrosewell commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Changes

Area Change
crates/trusted-server-core/src 2 files, 350 lines added, 4 removed
docs/superpowers 1 file, 180 lines added, 0 removed
docs/guide 1 file, 27 lines added, 2 removed
CHANGELOG.md 1 file, 1 line added, 0 removed

Closes

Closes #1331

Spec

Spec: middleware-settings

Test plan

CI on this pull request at bf80fec passed all 20 checks.

  • cargo test-fastly && cargo test-axum
  • cargo clippy-fastly && cargo clippy-axum
  • cargo fmt --all -- --check
  • JS tests: cd crates/trusted-server-js/lib && npx vitest run
  • JS format: cd crates/trusted-server-js/lib && npm run format
  • Docs format: cd docs && npm run format
  • WASM build: cargo build --package trusted-server-adapter-fastly --release --target wasm32-wasip1
  • Manual testing via fastly compute serve
  • Other: the full workflow set of this repository, run on this pull request at bf80fec

Checklist

  • Feature PRs: spec linked above, ending in a review log of two or more review rounds
  • Changes follow AGENTS.md conventions
  • No unwrap() in production code (clippy denies unwrap_used in CI)
  • Uses log macros as AGENTS.md asks (not println!)
  • New code has tests
  • No secrets or credentials committed

On top of the origin's redirect to itself kept on the reader's address (#1378). Issue: #1331.

Kept current. This update only merges the pull request below (#1378), which brings Tech Lab's main at 7aa5c99, the changes made lower in the stack and fiftyone-caching 4.5.13 (#1372).

What this adds

What changes.

A middleware with settings of its own reads them from [middleware.<name>], one table for each middleware, written with the middleware's full name.

[middleware.example.cleanup]
selectors = [".promo", "#newsletter"]

How it works.

  • One table per middleware, by its full name. [middleware.example.cleanup] is the example.cleanup middleware's table. A table holds values and arrays. A table within one is the table of the longer name it spells and never a setting, so [middleware.example.cleanup] beneath [middleware.example] belongs to example.cleanup and the example middleware never sees it.
  • Core reads none of a table. A middleware reads its own through Settings::middleware_config, which refuses a key the middleware does not know and a value that fails its validation, naming the table.
  • Refused at startup. A value under [middleware] where only tables stand, a table at a name no middleware could have, and a table at a name that no module the deployment runs supplies, with the names that could be written, as an entry naming such a middleware is refused today.
  • Nothing changes for a middleware without a table. A module's one middleware keeps reading the module's own table, as the stock modules do.

Why

A module's one middleware could read the module's table, and nothing else had a place. A vendor whose module supplies several middleware had to put their settings under the vendor's shared table, where the options of one page change sat beside the vendor's endpoint and license key, which is where nothing about one middleware belongs. A table of each middleware's own keeps a vendor's shared table to what every module of the vendor shares, and keeps every table refusing what it does not know.

What breaks

Nothing. A document without [middleware] reads as before, and no stock module reads the section.

The commits

Commit What it does
cd8bd06 A middleware reads its own settings from [middleware.<name>]
f18d248 The middleware table's examples name the example middleware
0da31d3 The middleware settings design
b63866e The middleware settings design takes its round 1 review
3dc0d8c The middleware settings design takes its round 2 corrections
45cfa8e The design header names the pull request that carries it

The other commits merge the branch below into this one, and through it Tech Lab main at 7aa5c99.

What is not in this pull request

  • A stock module's middleware moving to a table of its own. Each keeps reading its module's table.
  • A vendor's middleware that read the vendor's shared table moving to its own, which that vendor's crates do.

A middleware had no table of its own. A module's one middleware read the
module's table, and a vendor whose module supplies several middleware put
their settings under the vendor's shared table, where a page change's
options sat beside the vendor's endpoint and license key, which is where
nothing about one middleware belongs.

Settings gain [middleware], one [middleware.<name>] table for each
middleware that has settings, written with the middleware's full name, so
[middleware.example.cleanup] is the example.cleanup middleware's. A table
holds values and arrays, and a table within one is the table of the longer
name it spells and never a setting, so a middleware never sees another's
settings. Core reads none of a table. A middleware reads its own through
Settings::middleware_config, which refuses a key the middleware does not
know and a value that fails its validation. The section refuses a value
where only tables stand and a name no middleware could have, and the
registry refuses at startup a table at a name that no module it runs
supplies, with the names that could be written, as it refuses an entry
naming such a middleware. A middleware with no table of its own reads its
module's table, as the stock modules do.

The fixture module gains a middleware with a table of its own, and tests
cover a middleware reading its table and not a longer name's, a table at a
name nothing supplies refused on both shapes, a key the middleware does not
know refused with the table and the key named, and the section's own
refusals. The guide documents the section beside the shared tables and says
where a middleware's settings live, and the changelog says what it adds.
# Conflicts:
#	crates/trusted-server-core/src/integrations/registry.rs
Two doc comments used a vendor's middleware as their example of a deeper
table. The examples now use the fixture's example names, as the guide does.
Series 38 had an issue and a pull request but no design document. This one describes the [middleware.<name>] section, how a middleware reads its table, what is checked and when, what each adapter does with a refused table, consent and privacy, rollout, and the joins that have no test. It also lists what the series leaves out.
The review found two behaviors the design did not state. A table under a
quoted key that holds a dot is accepted and never read. The startup check
refuses a first part of a deselected module's name, a table nobody wrote,
before the table that was written, so the sentence saying the module is
not selected is missing. The design now states both as the code has them
and lists the code change each needs under Open questions.

It also corrects what runs a module, how often a table is read on each
adapter, what a refusal does to every route and the crate under
crates/middleware. It adds the rollout order for ts and for builders that
a shared table runs, says that a table change leaves stored pages unread,
and fixes the status date and the issue citation.

One sentence of the configuration guide said a middleware refuses a key it
does not know, which holds only when its settings type denies unknown
fields. The sentence now says so.
@jwrosewell
jwrosewell added this pull request to stack #1401 October 15, 2026 17:56
Round 2 found no blocking issues and four small points.

GET /health is left out of the routes a refusal fails on Fastly, which
answers it before it builds anything, and on Spin, whose error router
answers it with 200. On Axum, which builds the registry once, the 500
lasts until the process restarts. The refusal for a builder that a shared
table runs now names the first part of the name, as Failure handling
explains. The test description says that only the assertion on the
testing.nothing message proves the list of supplied names, because every
refusal message carries the list. Section 3 names the three code comments
left for a later change.
@jwrosewell
jwrosewell removed this pull request from stack #1401 October 15, 2026 20:51
@jwrosewell
jwrosewell removed this pull request from stack #1408 October 18, 2026 20:15
@jwrosewell jwrosewell closed this Oct 18, 2026
@jwrosewell jwrosewell reopened this Oct 18, 2026
@jwrosewell
jwrosewell added this pull request to stack #1418 October 19, 2026 12:18
@jwrosewell
jwrosewell removed this pull request from stack #1418 October 19, 2026 16:30
@jwrosewell jwrosewell closed this Oct 19, 2026
@jwrosewell jwrosewell reopened this Oct 19, 2026
@jwrosewell
jwrosewell added this pull request to stack #1421 October 19, 2026 17:38
@jwrosewell jwrosewell changed the title A middleware reads its own settings from [middleware.<name>] Read middleware settings from [middleware.<name>] Oct 19, 2026
@jwrosewell
jwrosewell removed this pull request from stack #1421 October 19, 2026 18:29
@jwrosewell
jwrosewell added this pull request to stack #1422 October 19, 2026 19:20
@jwrosewell
jwrosewell marked this pull request as ready for review October 19, 2026 20:23
@jwrosewell
jwrosewell removed this pull request from stack #1422 October 28, 2026 11:47
@jwrosewell
jwrosewell added this pull request to stack #1465 October 28, 2026 18:28

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A middleware has no settings table of its own

1 participant