Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions .env.dev
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Non-secret development overlays used while generating the Axum config blob.
# Sourcing this file alone does not configure the Axum server: also export the
# blob and referenced secret-store values as shown in docs/guide/getting-started.md.

# [publisher]
TRUSTED_SERVER__PUBLISHER__ORIGIN_URL=http://localhost:9090

Expand Down
14 changes: 9 additions & 5 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
# Trusted Server Environment Variables
# Copy this file to .env.dev, .env.staging, or .env.production and fill in values
# See docs/guide/configuration.md for details
# Trusted Server development environment variables
# Copy this file to .env.dev, .env.staging, or .env.production and fill in
# non-secret values. App-config secrets are key names in the pushed blob and
# their values belong in the platform secret store; see the configuration guide.
# For Axum runtime loading, export the config blob as:
# TRUSTED_SERVER_CONFIG_TRUSTED_SERVER_CONFIG_TRUSTED_SERVER_CONFIG=<blob-envelope-json>
# and export one secret per key name as:
# TRUSTED_SERVER_SECRET_TRUSTED_SERVER_SECRETS_<KEY_NAME>=<secret-value>
# The commented examples below are CLI overlays for ordinary fields only.

# =============================================================================
# Publisher Settings
# =============================================================================
TRUSTED_SERVER__PUBLISHER__DOMAIN=publisher.com
TRUSTED_SERVER__PUBLISHER__COOKIE_DOMAIN=.publisher.com
TRUSTED_SERVER__PUBLISHER__ORIGIN_URL=https://origin.publisher.com
TRUSTED_SERVER__PUBLISHER__PROXY_SECRET=<your-proxy-secret>

# =============================================================================
# Synthetic ID Settings
# =============================================================================
TRUSTED_SERVER__SYNTHETIC__COUNTER_STORE=counter_store
TRUSTED_SERVER__SYNTHETIC__OPID_STORE=opid_store
TRUSTED_SERVER__SYNTHETIC__SECRET_KEY=<your-synthetic-secret>
# Template variables: client_ip, user_agent, first_party_id, auth_user_id, publisher_domain, accept_language
TRUSTED_SERVER__SYNTHETIC__TEMPLATE={{ client_ip }}:{{ user_agent }}:{{ first_party_id }}

Expand Down
37 changes: 25 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ criterion = { version = "0.5", default-features = false, features = ["cargo_benc
derive_more = { version = "2.0", features = ["display", "error"] }
directories = "5"
ed25519-dalek = { version = "2.2", features = ["rand_core"] }
edgezero-adapter-axum = { git = "https://github.com/stackpop/edgezero", tag = "v0.0.4", default-features = false }
edgezero-adapter-cloudflare = { git = "https://github.com/stackpop/edgezero", tag = "v0.0.4", default-features = false }
edgezero-adapter-fastly = { git = "https://github.com/stackpop/edgezero", tag = "v0.0.4", default-features = false }
edgezero-adapter-spin = { git = "https://github.com/stackpop/edgezero", tag = "v0.0.4", default-features = false }
edgezero-cli = { git = "https://github.com/stackpop/edgezero", tag = "v0.0.4" }
edgezero-core = { git = "https://github.com/stackpop/edgezero", tag = "v0.0.4", default-features = false }
edgezero-adapter-axum = { git = "https://github.com/stackpop/edgezero", rev = "bb4411625856472b1279a3db49aeeac5e8b1507e", default-features = false }
edgezero-adapter-cloudflare = { git = "https://github.com/stackpop/edgezero", rev = "bb4411625856472b1279a3db49aeeac5e8b1507e", default-features = false }
edgezero-adapter-fastly = { git = "https://github.com/stackpop/edgezero", rev = "bb4411625856472b1279a3db49aeeac5e8b1507e", default-features = false }
edgezero-adapter-spin = { git = "https://github.com/stackpop/edgezero", rev = "bb4411625856472b1279a3db49aeeac5e8b1507e", default-features = false }
edgezero-cli = { git = "https://github.com/stackpop/edgezero", rev = "bb4411625856472b1279a3db49aeeac5e8b1507e" }
edgezero-core = { git = "https://github.com/stackpop/edgezero", rev = "bb4411625856472b1279a3db49aeeac5e8b1507e", default-features = false }
env_logger = "0.11"
error-stack = "0.6"
fastly = "0.12"
Expand Down
11 changes: 8 additions & 3 deletions crates/trusted-server-adapter-axum/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use trusted_server_core::settings_data::{
use trusted_server_core::platform::RuntimeServices;

use crate::middleware::{AuthMiddleware, FinalizeResponseMiddleware};
use crate::platform::{AxumPlatformConfigStore, build_runtime_services};
use crate::platform::{AxumPlatformConfigStore, AxumPlatformSecretStore, build_runtime_services};

// ---------------------------------------------------------------------------
// AppState
Expand All @@ -55,8 +55,13 @@ pub struct AppState {
fn build_state() -> Result<Arc<AppState>, Report<TrustedServerError>> {
let store_name = default_config_store_name();
let config_key = default_config_key();
let settings =
get_settings_from_config_store(&AxumPlatformConfigStore, &store_name, &config_key)?;
let settings = get_settings_from_config_store(
&AxumPlatformConfigStore,
&AxumPlatformSecretStore,
&store_name,
&config_key,
&trusted_server_core::settings_data::default_secret_store_name(),
)?;
build_state_with_settings(settings)
}

Expand Down
41 changes: 34 additions & 7 deletions crates/trusted-server-adapter-cloudflare/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ use error_stack::Report;
use trusted_server_core::auction::endpoints::handle_auction;
use trusted_server_core::auction::{AuctionOrchestrator, build_orchestrator};
#[cfg(target_arch = "wasm32")]
use trusted_server_core::config_payload::settings_from_config_blob;
use trusted_server_core::config_payload::{DEFAULT_SECRET_STORE_ID, settings_from_config_blob};
use trusted_server_core::ec::EcContext;
use trusted_server_core::error::{IntoHttpResponse as _, TrustedServerError};
use trusted_server_core::integrations::{IntegrationRegistry, ProxyDispatchInput};
use trusted_server_core::platform::RuntimeServices;
#[cfg(target_arch = "wasm32")]
use trusted_server_core::platform::StoreName;
use trusted_server_core::proxy::{
handle_first_party_click, handle_first_party_proxy, handle_first_party_proxy_rebuild,
handle_first_party_proxy_sign,
Expand All @@ -38,11 +40,23 @@ use crate::platform::build_runtime_services;
// ---------------------------------------------------------------------------

#[cfg(target_arch = "wasm32")]
static CLOUDFLARE_CONFIG_JSON: std::sync::OnceLock<String> = std::sync::OnceLock::new();
thread_local! {
static CLOUDFLARE_CONFIG_JSON: std::cell::OnceCell<String> = const { std::cell::OnceCell::new() };
static CLOUDFLARE_ENV: std::cell::OnceCell<worker::Env> = const { std::cell::OnceCell::new() };
}

#[cfg(target_arch = "wasm32")]
pub fn set_cloudflare_config_json(value: String) {
let _ = CLOUDFLARE_CONFIG_JSON.set(value);
CLOUDFLARE_CONFIG_JSON.with(|slot| {
let _ = slot.set(value);
});
}

#[cfg(target_arch = "wasm32")]
pub fn set_cloudflare_env(env: worker::Env) {
CLOUDFLARE_ENV.with(|slot| {
let _ = slot.set(env);
});
}

/// Application state built once at startup and shared across all requests.
Expand Down Expand Up @@ -70,18 +84,22 @@ fn load_startup_settings() -> Result<Settings, Report<TrustedServerError>> {

#[cfg(not(target_arch = "wasm32"))]
fn load_startup_settings() -> Result<Settings, Report<TrustedServerError>> {
Settings::from_toml(include_str!("../../../trusted-server.example.toml"))
Err(Report::new(TrustedServerError::Configuration {
message: "Cloudflare startup settings require a Worker config binding".to_string(),
})
.attach("use TrustedServerApp::routes_with_settings for host tests"))
}

#[cfg(target_arch = "wasm32")]
fn settings_from_cloudflare_config_json() -> Result<Settings, Report<TrustedServerError>> {
let raw_config = CLOUDFLARE_CONFIG_JSON.get().ok_or_else(|| {
let raw_config = CLOUDFLARE_CONFIG_JSON.with(|slot| slot.get().cloned());
let raw_config = raw_config.ok_or_else(|| {
Report::new(TrustedServerError::Configuration {
message: "Cloudflare TRUSTED_SERVER_CONFIG is required".to_string(),
})
.attach("set TRUSTED_SERVER_CONFIG to JSON containing the app_config blob envelope")
})?;
let value: serde_json::Value = serde_json::from_str(raw_config).map_err(|error| {
let value: serde_json::Value = serde_json::from_str(&raw_config).map_err(|error| {
Report::new(TrustedServerError::Configuration {
message: "invalid Cloudflare TRUSTED_SERVER_CONFIG JSON".to_string(),
})
Expand All @@ -95,7 +113,16 @@ fn settings_from_cloudflare_config_json() -> Result<Settings, Report<TrustedServ
message: "Cloudflare TRUSTED_SERVER_CONFIG missing app_config".to_string(),
})
})?;
settings_from_config_blob(envelope)
let env = CLOUDFLARE_ENV
.with(|slot| slot.get().cloned())
.ok_or_else(|| {
Report::new(TrustedServerError::Configuration {
message: "Cloudflare Worker environment is unavailable during startup".to_string(),
})
})?;
let secret_store = crate::platform::CloudflareSecretStoreAdapter { env };
let default_secret_store = StoreName::from(DEFAULT_SECRET_STORE_ID);
settings_from_config_blob(envelope, &secret_store, &default_secret_store)
}

/// Build the application state from explicit settings.
Expand Down
1 change: 1 addition & 0 deletions crates/trusted-server-adapter-cloudflare/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub async fn main(req: Request, env: Env, ctx: Context) -> Result<Response> {
if let Ok(config) = env.var("TRUSTED_SERVER_CONFIG") {
app::set_cloudflare_config_json(config.to_string());
}
app::set_cloudflare_env(env.clone());

match edgezero_adapter_cloudflare::run_app::<app::TrustedServerApp>(req, env, ctx).await {
Ok(resp) => Ok(resp),
Expand Down
4 changes: 2 additions & 2 deletions crates/trusted-server-adapter-cloudflare/src/platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -547,8 +547,8 @@ impl PlatformHttpClient for CloudflareHttpClient {
/// Bridges [`worker::Env`] secrets to [`PlatformSecretStore`] by calling
/// `env.secret(key)` synchronously. Writes and deletes return errors.
#[cfg(target_arch = "wasm32")]
struct CloudflareSecretStoreAdapter {
env: worker::Env,
pub(crate) struct CloudflareSecretStoreAdapter {
pub(crate) env: worker::Env,
}

#[cfg(target_arch = "wasm32")]
Expand Down
9 changes: 9 additions & 0 deletions crates/trusted-server-adapter-cloudflare/wrangler.ci.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,12 @@ id = "ci-local-kv"
# Placeholder replaced by the integration test harness with a JSON object that
# contains the runtime Trusted Server app-config blob envelope.
TRUSTED_SERVER_CONFIG = "{}"

# Fictitious integration-only secret values. `worker::Env::secret` reads these
# string bindings in local Wrangler runs; production values are provisioned with
# `wrangler secret put` instead of being committed to a manifest.
integration_admin_password = "integration-admin-password-32-bytes-ok"
integration_proxy_secret = "integration-test-proxy-secret-32-bytes-ok"
integration_ec_passphrase = "integration-test-ec-secret-padded-32"
integration_partner_token_alpha = "integration-test-token-alpha-32-bytes-ok"
integration_partner_token_bravo = "integration-test-token-bravo-32-bytes-ok"
4 changes: 4 additions & 0 deletions crates/trusted-server-adapter-cloudflare/wrangler.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ id = "REPLACE_WITH_YOUR_KV_NAMESPACE_ID"
# invalid placeholder with JSON containing an `app_config` blob envelope before
# deploying or running `wrangler dev` against real traffic.
TRUSTED_SERVER_CONFIG = '{"app_config":""}'

# App-config secret values are provisioned as Worker secrets with
# `wrangler secret put <key-name>`. The pushed blob contains only those key
# names; never add secret values to this file.
8 changes: 7 additions & 1 deletion crates/trusted-server-adapter-fastly/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,13 @@ pub(crate) fn build_state() -> Result<Arc<AppState>, Report<TrustedServerError>>
pub(crate) fn load_settings_from_config_store() -> Result<Settings, Report<TrustedServerError>> {
let store_name = default_config_store_name();
let config_key = default_config_key();
get_settings_from_config_store(&FastlyPlatformConfigStore, &store_name, &config_key)
get_settings_from_config_store(
&FastlyPlatformConfigStore,
&FastlyPlatformSecretStore,
&store_name,
&config_key,
&trusted_server_core::settings_data::default_secret_store_name(),
)
}

pub(crate) fn build_state_from_settings(
Expand Down
12 changes: 12 additions & 0 deletions crates/trusted-server-adapter-spin/spin.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ version = "0.1.0"
[variables]
v_current_x2dkid = { default = "" }
v_active_x2dkids = { default = "" }
# Trusted Server app-config secret references. Replace the empty defaults with
# values supplied by the deployment's secret provider; never commit values here.
v_trusted_x5fserver_x5fsecrets_v_publisher_x5fproxy_x5fsecret = { default = "", secret = true }
v_trusted_x5fserver_x5fsecrets_v_ec_x5fpassphrase = { default = "", secret = true }
v_trusted_x5fserver_x5fsecrets_v_partner_x5fapi_x5ftoken = { default = "", secret = true }
v_trusted_x5fserver_x5fsecrets_v_partner_x5fts_x5fpull_x5ftoken = { default = "", secret = true }
v_trusted_x5fserver_x5fsecrets_v_handler_x5fpassword = { default = "", secret = true }

[[trigger.http]]
route = "/..."
Expand All @@ -43,6 +50,11 @@ key_value_stores = ["default"]
[component.trusted-server.variables]
v_current_x2dkid = "{{ v_current_x2dkid }}"
v_active_x2dkids = "{{ v_active_x2dkids }}"
v_trusted_x5fserver_x5fsecrets_v_publisher_x5fproxy_x5fsecret = "{{ v_trusted_x5fserver_x5fsecrets_v_publisher_x5fproxy_x5fsecret }}"
v_trusted_x5fserver_x5fsecrets_v_ec_x5fpassphrase = "{{ v_trusted_x5fserver_x5fsecrets_v_ec_x5fpassphrase }}"
v_trusted_x5fserver_x5fsecrets_v_partner_x5fapi_x5ftoken = "{{ v_trusted_x5fserver_x5fsecrets_v_partner_x5fapi_x5ftoken }}"
v_trusted_x5fserver_x5fsecrets_v_partner_x5fts_x5fpull_x5ftoken = "{{ v_trusted_x5fserver_x5fsecrets_v_partner_x5fts_x5fpull_x5ftoken }}"
v_trusted_x5fserver_x5fsecrets_v_handler_x5fpassword = "{{ v_trusted_x5fserver_x5fsecrets_v_handler_x5fpassword }}"

[component.trusted-server.build]
command = "cargo build --target wasm32-wasip1 --release -p trusted-server-adapter-spin --features spin"
Expand Down
Loading
Loading