Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
7b08d94
A consent prompt runs in the phase the publisher chooses
jwrosewell Oct 10, 2026
9cb281d
The guides say a consent prompt's phase is the publisher's choice
jwrosewell Oct 10, 2026
0883a7d
Merge branch 'review/20-ads-txt' into review/21-cmp-phases
Jamesr51d Oct 12, 2026
4ce40e2
The InMobi guide says where a prompt in the serve phase lands
Jamesr51d Oct 12, 2026
d09b282
Format the merged InMobi placement check
Jamesr51d Oct 12, 2026
ffa635f
Merge branch 'review/20-ads-txt' into review/21-cmp-phases
Jamesr51d Oct 12, 2026
77e4f13
Merge 20-ads-txt into 21-cmp-phases
Jamesr51d Oct 12, 2026
d8f020c
Merge 20-ads-txt into 21-cmp-phases
jwrosewell Oct 13, 2026
0287372
Merge split/20-ads-txt into split/21-cmp-phases
Jamesr51d Oct 13, 2026
9945df2
Merge split/20-ads-txt into split/21-cmp-phases
Jamesr51d Oct 13, 2026
938be5d
Merge 20-ads-txt into 21-cmp-phases
jwrosewell Oct 13, 2026
ffea14a
A serve entry may not place the consent prompt after fetch middleware
jwrosewell Oct 16, 2026
5e621b1
The consent prompt is refused when both phases name it for one page
jwrosewell Oct 16, 2026
07058b8
A consent module placed in serve is run through the registry and a page
jwrosewell Oct 16, 2026
67504f9
Merge split/20-ads-txt into split/21-cmp-phases
jwrosewell Oct 16, 2026
2fef75d
Merge split/20-ads-txt into split/21-cmp-phases
jwrosewell Oct 16, 2026
1a7d794
Merge the review fixes into split/21-cmp-phases
jwrosewell Oct 16, 2026
2272dd0
Merge split/20-ads-txt into split/21-cmp-phases
jwrosewell Oct 16, 2026
954cb1d
Merge split/20-ads-txt into split/21-cmp-phases
jwrosewell Oct 16, 2026
9f79e87
The Sourcepoint phase test builds its page change with new
jwrosewell Oct 16, 2026
7e1756e
Merge split/20-ads-txt into split/21-cmp-phases
jwrosewell Oct 16, 2026
61d2261
Merge split/20-ads-txt into split/21-cmp-phases
jwrosewell Oct 18, 2026
23098b7
Merge split/20-ads-txt into split/21-cmp-phases
jwrosewell Oct 18, 2026
fc9f730
Merge split/20-ads-txt into split/21-cmp-phases
jwrosewell Oct 18, 2026
f55f2ab
Merge split/20-ads-txt into split/21-cmp-phases
jwrosewell Oct 18, 2026
6ecda42
Merge split/20-ads-txt into split/21-cmp-phases
jwrosewell Oct 19, 2026
fbf6858
Merge split/20-ads-txt into split/21-cmp-phases
jwrosewell Oct 19, 2026
1f861da
Merge split/20-ads-txt into split/21-cmp-phases
jwrosewell Oct 19, 2026
45df894
Merge split/20-ads-txt into split/21-cmp-phases
jwrosewell Oct 19, 2026
734c07c
Merge split/20-ads-txt into split/21-cmp-phases
jwrosewell Oct 28, 2026
8dfb1ae
Merge split/20-ads-txt into split/21-cmp-phases
jwrosewell Oct 28, 2026
075351a
Merge split/20-ads-txt into split/21-cmp-phases
jwrosewell Oct 28, 2026
ce47b9c
Merge split/20-ads-txt into split/21-cmp-phases
jwrosewell Oct 28, 2026
ee3a009
Merge split/20-ads-txt into split/21-cmp-phases
jwrosewell Oct 28, 2026
be57a3c
Merge split/20-ads-txt into split/21-cmp-phases
jwrosewell Oct 28, 2026
35d8bd9
Merge split/20-ads-txt into split/21-cmp-phases
jwrosewell Oct 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- A consent management platform's middleware runs in the phase the publisher chooses. `cmp.inmobi`, `cmp.didomi` and `cmp.sourcepoint` may be named in a `[[fetch]]` or a `[[serve]]` entry, where each ran in the fetch phase alone. A generated configuration still places them in `[[fetch]]`. A `[[serve]]` entry naming `cmp.inmobi` for a page whose `[[fetch]]` entry names another middleware is refused, because the serve phase writes its head markup after what the fetch phase writes ahead of the script bundle, so a vendor's tag there would come ahead of the prompt. Naming `cmp.inmobi` for one page in both phases is refused, because the prompt would be written twice.
- **Breaking:** auction telemetry is selected the way every other module is. `[tinybird]` is now `[analytics.tinybird]`, and `[analytics] module = "tinybird"` selects it, which replaces the `enabled` line. A configuration that still carries `[tinybird]` is refused with directions. A stored configuration written by an earlier version carries the table even where telemetry was off, so push the configuration again with this version. The secret reference is `analytics.tinybird.auction_token_secret`, the table refuses a key it does not know, and a section that selects nothing, or a module this build does not have, is refused. A row is sent only for a reader whose permissions include `analytics.ad_reporting.measure_ad_performance`, so none is sent for a reader the consent gate refuses unless they permit it. The Axum, Cloudflare and Spin adapters send no telemetry, and log a warning at startup when the section selects a module.
- The DataDome module asks its Protection API about a publisher's pages beneath `/admin/` like any other page. It skipped every path beneath `/admin/` and `/_ts/admin/`, which left a publisher's own `/admin/` pages out of bot protection.
- **Breaking:** `ts cache purge` asks the hosting platform to purge instead of calling the service. It takes `--service-id <id>` where it took `--service <url>`, reads a Fastly API token from `FASTLY_API_TOKEN` where it read `TRUSTED_SERVER_ADMIN_PASSWORD`, and no longer takes `--username`. It runs `fastly service purge --key`, which needs Fastly CLI 14.0.0 or later, with the surrogate key it derives by the function the service tags its cached objects with, so `--all` and `--page <url>` purge exactly what they purged before.
Expand Down
44 changes: 42 additions & 2 deletions crates/cmp/didomi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,8 @@ impl DidomiIntegration {
}

/// Writes the browser module's settings into the head, on the pages a
/// `[[fetch]]` entry names [`MODULE`] for.
/// `[[fetch]]` or `[[serve]]` entry names [`MODULE`] for, in the phase the
/// publisher chooses.
struct ClientConfig {
/// The script, made once when the module registers.
script: String,
Expand All @@ -614,7 +615,7 @@ impl Middleware for ClientConfig {
}

fn phases(&self) -> &[MiddlewarePhase] {
&[MiddlewarePhase::Fetch]
&MiddlewarePhase::ALL
}

fn create(&self, _context: &MiddlewareContext<'_>) -> MiddlewareAction {
Expand Down Expand Up @@ -1388,6 +1389,16 @@ mod tests {
assert!(validate_proxy_path("/leading-slash-ok").is_ok());
}

#[test]
fn the_page_change_may_run_in_either_phase() {
let integration = DidomiIntegration::new(Arc::new(config()));
assert_eq!(
ClientConfig::new(&integration).phases(),
MiddlewarePhase::ALL,
"the publisher chooses the phase by the entry"
);
}

#[test]
fn head_markup_emits_proxy_path() {
let custom_config = DidomiIntegrationConfig {
Expand Down Expand Up @@ -1555,4 +1566,33 @@ mod tests {
),
);
}

/// Named in `[[serve]]` in place of `[[fetch]]`, the page change passes
/// the registry's check and gives a reader the recorded page, because a
/// page with no other middleware gets it in the same place from either
/// phase.
#[test]
fn placed_in_serve_the_page_change_gives_a_reader_the_recorded_page() {
use trusted_server_core::html_processor::test_support::{
page_settings, place_on_every_page, processed_page,
};
let mut settings = page_settings(include_str!("fixtures/page-change.settings.toml"));
settings.fetch = trusted_server_core::middleware::PhaseEntries::default();
place_on_every_page(&mut settings, MiddlewarePhase::Serve, &[MODULE]);
let registry = IntegrationRegistry::with_registrations(&settings, &[super::builder()])
.expect("the registry should accept the page change in a serve entry");

let page = processed_page(
&settings,
&registry,
include_str!("fixtures/page-change.input.html"),
8192,
);

assert_eq!(
page,
include_str!("fixtures/page-change.recorded.html"),
"a serve entry should give the reader the page a fetch entry does"
);
}
}
Loading
Loading