Extract client IP and TLS info once at adapter boundary (PR7)#599
Conversation
Documents the call site migration plan: five Fastly SDK extraction points in trusted-server-core replaced by RuntimeServices::client_info reads, following Phase 1 injection pattern from the EdgeZero migration design.
- Correct erroneous claim about generate_synthetic_id being called twice via DeviceInfo; it is called once (line 91 for fresh_id), DeviceInfo.ip is a separate req.get_client_ip_addr() call fixed independently - Add before/after snippet for handle_publisher_request call site in main.rs - Add noop_services import instruction for http_util.rs test module - Clarify _services rename (drop underscore, not add new param) in didomi.rs - Clarify nextjs #[allow(deprecated)] annotations are out of scope (different function)
- Change RequestInfo::from_request signature to &ClientInfo (not &RuntimeServices) so prebid can call it with context.client_info - Scope SDK-call acceptance criteria to active non-deprecated code only - List all six AuctionContext construction sites including two production sites in orchestrator.rs and three test helpers in orchestrator/prebid - Add explicit warn-and-continue pattern for publisher.rs geo lookup - Correct testing table: formats.rs and endpoints.rs have no test modules; add orchestrator.rs and prebid.rs test helper update rows
Plan covers 6 tasks in compilation-safe order: AuctionContext struct change first, then from_request signature, then synthetic.rs cascade, then publisher geo, then didomi. Includes two new copy_headers unit tests (Some/None). Spec fixes: clarify injection pattern exceptions for &ClientInfo and Option<IpAddr>; reword acceptance criterion to reflect that provider-layer reads flow through AuctionContext.client_info.
- Finding 1 (High): Add missing publisher.rs test call site at line ~695 for get_or_generate_synthetic_id — was omitted from Task 3 Step 6 - Finding 2 (Medium): Remove crate::geo::GeoInfo import from endpoints.rs rather than replacing it — type is not used by name after the change, keeping any import fails clippy -D warnings - Finding 3 (Low): Replace interactive git add -p in Task 6 with explicit file staging instruction - Open Q1: Add Task 2 step to update stale handle_publisher_request signature in auction/README.md - Open Q2: Add Task 2 step to update from_request doc comment to reflect ClientInfo-based TLS detection instead of Fastly SDK calls
- Step 7: cover all four stale Fastly-SDK-specific locations in http_util.rs (SPOOFABLE_FORWARDED_HEADERS doc, RequestInfo struct doc, from_request doc, detect_request_scheme doc) - Step 8: replace the whole routing snippet in auction/README.md, not just the one handle_publisher_request line — handle_auction and integration_registry.handle_proxy are also stale in that snippet
- Add missing Location 2 (RequestInfo.scheme field doc, line ~67) to Step 7; renumber subsequent locations 3-5 - Replace &runtime_services with runtime_services in Step 5 and README snippet — runtime_services is already &RuntimeServices in route_request
… into handle_publisher_request
…ls in formats and endpoints
Fix multi-line function call style in didomi.rs, line-break wrapping in publisher.rs test, and import ordering in synthetic.rs test module.
Adds noop_services_with_client_ip helper to test_support and a new test that verifies the client_ip path through generate_synthetic_id by asserting the HMAC differs when the IP changes.
…edgezero-pr7-geo-client-info
…edgezero-pr7-geo-client-info # Conflicts: # crates/trusted-server-core/src/auction/endpoints.rs # crates/trusted-server-core/src/auction/formats.rs # crates/trusted-server-core/src/integrations/registry.rs # crates/trusted-server-core/src/publisher.rs # crates/trusted-server-core/src/synthetic.rs
aram356
left a comment
There was a problem hiding this comment.
Summary
Clean, well-scoped PR that achieves exactly what it claims: removing all active Fastly SDK calls for client IP and TLS info from trusted-server-core by threading ClientInfo through RuntimeServices. The changes are mechanical but correct — no logic errors, no missing call sites, proper warn-and-continue for geo lookups, and good test coverage for the new paths.
Non-blocking
👍 praise
- Clean extraction pattern — each function that previously called Fastly SDK methods now reads from
services.client_infoorcontext.client_info. No unnecessary abstractions introduced. - Warn-and-continue for geo lookups — all three geo lookup sites use
unwrap_or_else(|e| { log::warn!(...); None }). Correct — geo is best-effort enrichment and should never hard-fail the request. - Good test coverage — new
test_generate_ec_id_uses_client_ip, two TLS detection tests, twocopy_headerstests. Validates that client IP actually influences output throughRuntimeServices. noop_services_with_client_iphelper — clean addition for tests that need IP-dependent paths.
🤔 thinking
- Remaining deprecated
GeoInfo::from_requeststill has Fastly SDK call in core — the#[deprecated]method still exists with a livereq.get_client_ip_addr()inside core. No active code calls it, but worth tracking for removal in a follow-up. AuctionContextcarries bothclient_infoand can access it viaRuntimeServices— the field is redundant with what's available throughRuntimeServices(both get passed together). Works fine since values are identical, but could confuse future contributors about which source to use.
♻️ refactor
- Repeated
ClientInfoconstruction in Prebid tests — ~19 test call sites each inlineClientInfo { client_ip: None, tls_protocol: None, tls_cipher: None }. Consider implementingDefaultforClientInfo(all fields areOption) or extracting anempty_client_info()test helper to reduce noise.
📌 out of scope
RequestSigner::from_config()still uses FastlyConfigStoredirectly in core — separate concern from IP/TLS extraction but worth noting for EdgeZero migration tracking.
CI Status
- fmt: PASS
- clippy: PASS
- rust tests: PASS
- js tests: PASS
ChristianPavilonis
left a comment
There was a problem hiding this comment.
Please fix conflicts
…edgezero-pr7-geo-client-info
aram356
left a comment
There was a problem hiding this comment.
Summary
Clean, well-executed migration. The extract-once pattern threads ClientInfo from the adapter boundary through RuntimeServices and AuctionContext, eliminating all active Fastly IP/TLS SDK calls from trusted-server-core. Test coverage is solid — both positive and negative paths for new code.
Non-blocking
♻️ refactor
- Repeated
ClientInfoliteral in tests: ~20 prebid/orchestrator test sites construct identicalClientInfo { client_ip: None, ... }inline. A shared constant or helper would reduce boilerplate. (prebid.rs, orchestrator.rs)
🤔 thinking
convert_tsjs_to_auction_requestat 7-param limit: Now at exactly the CLAUDE.md convention limit. Next addition will need a struct. (formats.rs:83)
🌱 seedling
- Deprecated
GeoInfo::from_requestcleanup: The deprecated method in geo.rs still callsreq.get_client_ip_addr()directly. Now that all active call sites go throughservices.geo().lookup(), this could be removed in a follow-up.
👍 praise
- Extract-once pattern: Well-designed
ClientInfoinjection — single adapter-boundary extraction, clean threading through the call chain. - Warn-and-continue geo pattern: Consistent across endpoints.rs and publisher.rs.
generate_ec_id_uses_client_iptest: Smart HMAC prefix comparison proves IP input flows through.- Didomi copy_headers tests: Both
Some(ip)andNonepaths covered.
CI Status
- integration tests: PASS
- browser integration tests: PASS
- prepare integration artifacts: PASS
| &settings, | ||
| &request, | ||
| &crate::platform::ClientInfo { | ||
| client_ip: None, |
There was a problem hiding this comment.
♻️ refactor — The identical ClientInfo { client_ip: None, tls_protocol: None, tls_cipher: None } literal is repeated ~20 times across prebid and orchestrator tests. A shared constant or helper would reduce boilerplate and make future field additions less painful.
| @@ -83,14 +83,17 @@ pub struct BannerUnit { | |||
| pub fn convert_tsjs_to_auction_request( | |||
There was a problem hiding this comment.
🤔 thinking — This function now takes exactly 7 parameters, which is the project convention limit. It passes today, but one more addition will require restructuring.
aram356
left a comment
There was a problem hiding this comment.
LGTM — extract-once at adapter boundary is cleanly executed. All Fastly SDK calls removed from trusted-server-core, warn-and-continue applied consistently to geo lookups, and call-site propagation is exhaustive. CI green, 801 tests pass.
* Document content rewriting as platform-agnostic in platform module * Document html_processor as platform-agnostic * Document streaming_processor as platform-agnostic * Fix unresolved doc link: replace EdgeRequest with edgezero_core::http::Request - Fix intra-doc link syntax and restore missing blank line in `html_processor` - Replace opaque PR number references with descriptive context labels - Move HTTP-type coupling caveat from `platform` module down to `publisher.rs` - Convert `StreamingPipeline::process` plain-text generics to an intra-doc link
db579cf
into
feature/edgezero-pr6-backend-http-client
* Rename crates to trusted-server-core and trusted-server-adapter-fastly Rename crates/common → crates/trusted-server-core and crates/fastly → crates/trusted-server-adapter-fastly following the EdgeZero naming convention. Add EdgeZero workspace dependencies pinned to rev 170b74b. Update all references across docs, CI workflows, scripts, agent files, and configuration. * Add platform abstraction layer with traits and RuntimeServices Introduces trusted-server-core::platform with PlatformConfigStore, PlatformSecretStore, PlatformKvStore, PlatformBackend, PlatformHttpClient, and PlatformGeo traits alongside ClientInfo, PlatformError, and RuntimeServices. Wires the Fastly adapter implementations and threads RuntimeServices into route_request. Moves GeoInfo to platform/types as platform-neutral data and adds geo_from_fastly for field mapping. * Address platform layer review feedback - Defer KV store opening: replace early error return with a local UnavailableKvStore fallback so routes that do not need synthetic ID access succeed when the KV store is missing or temporarily unavailable - Use ConfigStore::try_open + try_get and SecretStore::try_get throughout FastlyPlatformConfigStore and FastlyPlatformSecretStore to honour the Result contract instead of panicking on open/lookup failure - Encapsulate RuntimeServices service fields as pub(crate) with public getter methods (config_store, secret_store, backend, http_client, geo) and a pub new() constructor; adapter updated to use new() - Reference #487 in FastlyPlatformHttpClient stub (PR 6 implements it) - Remove unused KvPage re-export from platform/mod.rs - Use super::KvHandle shorthand in RuntimeServices::kv_handle() * Reject host strings containing control characters in BackendConfig * Fix clippy error * Validate scheme and host for control characters in BackendConfig * Address review findings on platform abstraction layer * Address review findings on platform abstraction layer * Add config store read path and storage module split - Split fastly_storage.rs into storage/{config_store,secret_store,api_client,mod}.rs - Add PlatformConfigStore read path via FastlyPlatformConfigStore::get using ConfigStore::try_open/try_get - Add PlatformError::NotImplemented variant; stub write methods on FastlyPlatformConfigStore and FastlyPlatformSecretStore - Add StoreName/StoreId newtypes with From<String>, From<&str>, AsRef<str> - Add UnavailableKvStore to core platform module - Add RuntimeServicesBuilder replacing 7-arg constructor - Migrate get_active_jwks and handle_trusted_server_discovery to use &RuntimeServices - Update call sites in signing.rs, rotation.rs, main.rs - Add success-path test for handle_trusted_server_discovery using StubJwksConfigStore - Fix test_parse_cookies_to_jar_empty typo (was emtpy) * Harden legacy config-store reads and align Fastly adapter stubs * Address storage review feedback * Resolved github-advanced-security bot problems * Address PR review feedback on platform abstraction layer - Make StoreName and StoreId inner fields private; From/AsRef provide all needed construction and access - Add #[deprecated] to GeoInfo::from_request with #[allow(deprecated)] at the three legacy call sites to track migration progress - Enumerate the six platform traits in the platform module doc comment - Extract backend_config_from_spec helper to remove duplicate BackendConfig construction in predict_name and ensure - Replace .into_iter().collect() with .to_vec() on secret plaintext bytes - Remove unused bytes dependency from trusted-server-adapter-fastly - Add comment on SecretStore::open clarifying it already returns Result (unlike ConfigStore::open which panics) * Add PR 4 design spec for secret store trait (read-only) * Clarify test scope and deferred branches in PR 4 spec * Add implementation plan for PR 4 secret store trait * Add test for get_secret_bytes open-failure path * Add NotImplemented tests for FastlyPlatformSecretStore write stubs * Inline StoreId binding and add section comment in write-stub tests * Remove plan * Add PR 6 design spec for backend and HTTP client traits * Address spec review findings on PR 6 design * Implement PlatformHttpClient and thread RuntimeServices through proxy layer - Add PlatformHttpClient trait with send(), send_async(), and select() methods - Add PlatformBackend trait with predict_name() and ensure() methods - Add PlatformResponse wrapper around EdgeZero HTTP responses - Add PlatformPendingRequest and PlatformSelectResult for auction fan-out - Thread RuntimeServices through IntegrationProxy::handle(), IntegrationRegistry::handle_proxy(), and all first-party proxy endpoints so handlers can reach the HTTP client - Add StubHttpClient and StubBackend test stubs with build_services_with_http_client helper - Add proxy_request_calls_platform_http_client_send integration test - Fix proxy_with_redirects to stay within 7-arg clippy limit via ProxyRequestHeaders struct - Document Body::Stream limitation in edge_request_to_fastly with warning log - Document intentional duplication of platform_response_to_fastly across proxy and orchestrator - Remove spec file (promoted to plan + implementation) * Address pr review findings * Resolve pr review findings * Fix ci test and format failure * Address review findings * Address PR review findings * Address review findings * Extract client IP and TLS info once at adapter boundary (PR7) (#599) * Add PR7 design spec for geo lookup + client info extract-once Documents the call site migration plan: five Fastly SDK extraction points in trusted-server-core replaced by RuntimeServices::client_info reads, following Phase 1 injection pattern from the EdgeZero migration design. * Fix spec review issues in PR7 design doc - Correct erroneous claim about generate_synthetic_id being called twice via DeviceInfo; it is called once (line 91 for fresh_id), DeviceInfo.ip is a separate req.get_client_ip_addr() call fixed independently - Add before/after snippet for handle_publisher_request call site in main.rs - Add noop_services import instruction for http_util.rs test module - Clarify _services rename (drop underscore, not add new param) in didomi.rs - Clarify nextjs #[allow(deprecated)] annotations are out of scope (different function) * Update PR7 spec to address all five agent review findings - Change RequestInfo::from_request signature to &ClientInfo (not &RuntimeServices) so prebid can call it with context.client_info - Scope SDK-call acceptance criteria to active non-deprecated code only - List all six AuctionContext construction sites including two production sites in orchestrator.rs and three test helpers in orchestrator/prebid - Add explicit warn-and-continue pattern for publisher.rs geo lookup - Correct testing table: formats.rs and endpoints.rs have no test modules; add orchestrator.rs and prebid.rs test helper update rows * Add PR7 implementation plan and address plan review findings Plan covers 6 tasks in compilation-safe order: AuctionContext struct change first, then from_request signature, then synthetic.rs cascade, then publisher geo, then didomi. Includes two new copy_headers unit tests (Some/None). Spec fixes: clarify injection pattern exceptions for &ClientInfo and Option<IpAddr>; reword acceptance criterion to reflect that provider-layer reads flow through AuctionContext.client_info. * Fix three plan review findings and two open questions - Finding 1 (High): Add missing publisher.rs test call site at line ~695 for get_or_generate_synthetic_id — was omitted from Task 3 Step 6 - Finding 2 (Medium): Remove crate::geo::GeoInfo import from endpoints.rs rather than replacing it — type is not used by name after the change, keeping any import fails clippy -D warnings - Finding 3 (Low): Replace interactive git add -p in Task 6 with explicit file staging instruction - Open Q1: Add Task 2 step to update stale handle_publisher_request signature in auction/README.md - Open Q2: Add Task 2 step to update from_request doc comment to reflect ClientInfo-based TLS detection instead of Fastly SDK calls * Broaden two low-severity doc cleanup steps in PR7 plan - Step 7: cover all four stale Fastly-SDK-specific locations in http_util.rs (SPOOFABLE_FORWARDED_HEADERS doc, RequestInfo struct doc, from_request doc, detect_request_scheme doc) - Step 8: replace the whole routing snippet in auction/README.md, not just the one handle_publisher_request line — handle_auction and integration_registry.handle_proxy are also stale in that snippet * Fix two remaining low findings in PR7 plan - Add missing Location 2 (RequestInfo.scheme field doc, line ~67) to Step 7; renumber subsequent locations 3-5 - Replace &runtime_services with runtime_services in Step 5 and README snippet — runtime_services is already &RuntimeServices in route_request * Fix count drift in Step 7: four → five locations * Add client_info field to AuctionContext and fix all construction sites * Change RequestInfo::from_request to take &ClientInfo, thread services into handle_publisher_request * Add Task 2 follow-up coverage and README route fixes * Add services param to generate_synthetic_id, remove Fastly IP/geo calls in formats and endpoints * Revert premature publisher geo change from Task 3 * Replace deprecated GeoInfo::from_request in publisher.rs with services.geo().lookup() * Remove Fastly IP extraction from Didomi copy_headers, use ClientInfo instead * Move IpAddr import to test module level in didomi.rs * Apply rustfmt formatting to didomi.rs, publisher.rs, and synthetic.rs Fix multi-line function call style in didomi.rs, line-break wrapping in publisher.rs test, and import ordering in synthetic.rs test module. * Add test coverage for generate_synthetic_id with concrete client IP Adds noop_services_with_client_ip helper to test_support and a new test that verifies the client_ip path through generate_synthetic_id by asserting the HMAC differs when the IP changes. * Align geo lookup warn log format with codebase convention ({e} not {e:?}) * Apply Prettier formatting to PR7 plan and spec docs * Verify content rewriting pipeline is platform-agnostic (PR 8) (#600) * Document content rewriting as platform-agnostic in platform module * Document html_processor as platform-agnostic * Document streaming_processor as platform-agnostic * Fix unresolved doc link: replace EdgeRequest with edgezero_core::http::Request - Fix intra-doc link syntax and restore missing blank line in `html_processor` - Replace opaque PR number references with descriptive context labels - Move HTTP-type coupling caveat from `platform` module down to `publisher.rs` - Convert `StreamingPipeline::process` plain-text generics to an intra-doc link
Summary
req.get_client_ip_addr(),req.get_tls_protocol(), andreq.get_tls_cipher_openssl_name()calls from active code intrusted-server-core; the adapter extracts these once intoClientInfoand threads it throughRuntimeServices, keeping core fully platform-agnosticclient_info: &'a ClientInfotoAuctionContext, changesRequestInfo::from_requestandgenerate_synthetic_idto take&ClientInfo/&RuntimeServicesinstead of calling the Fastly SDK directly, and applies a warn-and-continue pattern for all geo lookupstrusted-server-corecontains zero direct calls to Fastly request introspection APIsChanges
src/auction/types.rsclient_info: &'a ClientInfofield toAuctionContextsrc/auction/endpoints.rsclient_infointoAuctionContext; replace deprecated geo call with warn-and-continuesrc/auction/formats.rsservices: &RuntimeServicesandgeo: Option<GeoInfo>params; useservices.client_info.client_ipsrc/auction/orchestrator.rsclient_infothrough mediator and provider context construction sitessrc/http_util.rsRequestInfo::from_requesttakes&ClientInfo;detect_request_schemetakes TLS params directlysrc/integrations/didomi.rscopy_headerstakesclient_ip: Option<IpAddr>; removes internal SDK callsrc/integrations/prebid.rsclient_infointo allRequestInfo::from_requestcall sites andAuctionContextconstructionsrc/integrations/registry.rsservicestoget_or_generate_synthetic_idsrc/publisher.rsservicesthrough; replace deprecated geo and synthetic ID callssrc/synthetic.rsgenerate_synthetic_idtakes&RuntimeServices; useservices.client_info.client_ipsrc/platform/test_support.rsnoop_services_with_client_iptest helperadapter-fastly/src/main.rsruntime_servicesintohandle_publisher_requestsrc/auction/README.mdmain.rsCloses
Closes #488
Test plan
cargo test --workspacecargo clippy --workspace --all-targets --all-features -- -D warningscargo fmt --all -- --checkcd crates/js/lib && npx vitest runcd crates/js/lib && npm run formatcd docs && npm run formatcargo build --package trusted-server-adapter-fastly --release --target wasm32-wasip1Checklist
unwrap()in production code — useexpect("should ...")logmacros (notprintln!)