Skip to content

Commit d32f149

Browse files
Harden Cloudflare runtime config loading
1 parent 37718b7 commit d32f149

4 files changed

Lines changed: 82 additions & 23 deletions

File tree

crates/trusted-server-adapter-cloudflare/src/app.rs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,20 +58,28 @@ pub struct AppState {
5858
/// Returns an error when settings, the auction orchestrator, or the integration
5959
/// registry fail to initialise.
6060
fn build_state() -> Result<Arc<AppState>, Report<TrustedServerError>> {
61-
#[cfg(target_arch = "wasm32")]
62-
if let Some(settings) = settings_from_cloudflare_config_json()? {
63-
return build_state_with_settings(settings);
64-
}
65-
66-
let settings = Settings::from_toml(include_str!("../../../trusted-server.example.toml"))?;
61+
let settings = load_startup_settings()?;
6762
build_state_with_settings(settings)
6863
}
6964

7065
#[cfg(target_arch = "wasm32")]
71-
fn settings_from_cloudflare_config_json() -> Result<Option<Settings>, Report<TrustedServerError>> {
72-
let Some(raw_config) = CLOUDFLARE_CONFIG_JSON.get() else {
73-
return Ok(None);
74-
};
66+
fn load_startup_settings() -> Result<Settings, Report<TrustedServerError>> {
67+
settings_from_cloudflare_config_json()
68+
}
69+
70+
#[cfg(not(target_arch = "wasm32"))]
71+
fn load_startup_settings() -> Result<Settings, Report<TrustedServerError>> {
72+
Settings::from_toml(include_str!("../../../trusted-server.example.toml"))
73+
}
74+
75+
#[cfg(target_arch = "wasm32")]
76+
fn settings_from_cloudflare_config_json() -> Result<Settings, Report<TrustedServerError>> {
77+
let raw_config = CLOUDFLARE_CONFIG_JSON.get().ok_or_else(|| {
78+
Report::new(TrustedServerError::Configuration {
79+
message: "Cloudflare TRUSTED_SERVER_CONFIG is required".to_string(),
80+
})
81+
.attach("set TRUSTED_SERVER_CONFIG to JSON containing the app_config blob envelope")
82+
})?;
7583
let value: serde_json::Value = serde_json::from_str(raw_config).map_err(|error| {
7684
Report::new(TrustedServerError::Configuration {
7785
message: "invalid Cloudflare TRUSTED_SERVER_CONFIG JSON".to_string(),
@@ -86,7 +94,7 @@ fn settings_from_cloudflare_config_json() -> Result<Option<Settings>, Report<Tru
8694
message: "Cloudflare TRUSTED_SERVER_CONFIG missing app_config".to_string(),
8795
})
8896
})?;
89-
settings_from_config_blob(envelope).map(Some)
97+
settings_from_config_blob(envelope)
9098
}
9199

92100
/// Build the application state from explicit settings.

crates/trusted-server-adapter-cloudflare/wrangler.ci.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ binding = "TRUSTED_SERVER_KV"
99
id = "ci-local-kv"
1010

1111
[vars]
12-
# Settings are baked into the WASM binary at build time; this JSON only needs
13-
# to satisfy any runtime config-store lookups (e.g. request-signing keys).
12+
# Placeholder replaced by the integration test harness with a JSON object that
13+
# contains the runtime Trusted Server app-config blob envelope.
1414
TRUSTED_SERVER_CONFIG = "{}"

crates/trusted-server-adapter-cloudflare/wrangler.toml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ binding = "TRUSTED_SERVER_KV"
1717
id = "REPLACE_WITH_YOUR_KV_NAMESPACE_ID"
1818

1919
[vars]
20-
# TRUSTED_SERVER_CONFIG is consumed by the edgezero layer as a JSON-encoded env
21-
# var binding. At runtime it is bridged to PlatformConfigStore via
22-
# ConfigStoreHandleAdapter — replace the placeholder values with your publisher
23-
# settings before deploying.
24-
TRUSTED_SERVER_CONFIG = '{"publisher.domain":"your-publisher.com"}'
20+
# TRUSTED_SERVER_CONFIG is required at startup. Replace this intentionally
21+
# invalid placeholder with JSON containing an `app_config` blob envelope before
22+
# deploying or running `wrangler dev` against real traffic.
23+
TRUSTED_SERVER_CONFIG = '{"app_config":""}'

crates/trusted-server-integration-tests/tests/environments/cloudflare.rs

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::common::config::cloudflare_config_json;
22
use crate::common::runtime::{
33
RuntimeEnvironment, RuntimeProcess, RuntimeProcessHandle, TestError, TestResult, origin_port,
44
};
5-
use error_stack::ResultExt as _;
5+
use error_stack::{Report, ResultExt as _};
66
use std::io::{BufRead as _, BufReader};
77
use std::path::{Path, PathBuf};
88
use std::process::{Child, Command, Stdio};
@@ -25,6 +25,7 @@ pub struct CloudflareWorkers;
2525
const CLOUDFLARE_DEFAULT_PORT: u16 = 8787;
2626
const CI_CONFIG_TEMPLATE: &str = "wrangler.ci.toml";
2727
const GENERATED_CI_CONFIG: &str = "wrangler.integration.generated.toml";
28+
const TRUSTED_SERVER_CONFIG_PLACEHOLDER: &str = "TRUSTED_SERVER_CONFIG = \"{}\"";
2829

2930
fn write_generated_ci_config(wrangler_dir: &Path) -> TestResult<String> {
3031
let template_path = wrangler_dir.join(CI_CONFIG_TEMPLATE);
@@ -35,10 +36,7 @@ fn write_generated_ci_config(wrangler_dir: &Path) -> TestResult<String> {
3536
template_path.display()
3637
))?;
3738
let config_json = cloudflare_config_json(origin_port())?;
38-
let generated = template.replace(
39-
"TRUSTED_SERVER_CONFIG = \"{}\"",
40-
&format!("TRUSTED_SERVER_CONFIG = '''{config_json}'''"),
41-
);
39+
let generated = inject_cloudflare_config(&template, &config_json)?;
4240
let output_path = wrangler_dir.join(GENERATED_CI_CONFIG);
4341
std::fs::write(&output_path, generated)
4442
.change_context(TestError::RuntimeSpawn)
@@ -49,6 +47,20 @@ fn write_generated_ci_config(wrangler_dir: &Path) -> TestResult<String> {
4947
Ok(GENERATED_CI_CONFIG.to_string())
5048
}
5149

50+
fn inject_cloudflare_config(template: &str, config_json: &str) -> TestResult<String> {
51+
let placeholder_count = template.matches(TRUSTED_SERVER_CONFIG_PLACEHOLDER).count();
52+
if placeholder_count != 1 {
53+
return Err(Report::new(TestError::RuntimeSpawn).attach(format!(
54+
"Cloudflare CI wrangler config must contain exactly one `{TRUSTED_SERVER_CONFIG_PLACEHOLDER}` placeholder, found {placeholder_count}"
55+
)));
56+
}
57+
58+
Ok(template.replace(
59+
TRUSTED_SERVER_CONFIG_PLACEHOLDER,
60+
&format!("TRUSTED_SERVER_CONFIG = '''{config_json}'''"),
61+
))
62+
}
63+
5264
impl RuntimeEnvironment for CloudflareWorkers {
5365
fn id(&self) -> &'static str {
5466
"cloudflare"
@@ -182,3 +194,43 @@ impl Drop for CloudflareHandle {
182194
let _ = self.child.wait();
183195
}
184196
}
197+
198+
#[cfg(test)]
199+
mod tests {
200+
use super::*;
201+
202+
#[test]
203+
fn inject_cloudflare_config_replaces_single_placeholder() {
204+
let template = format!("[vars]\n{TRUSTED_SERVER_CONFIG_PLACEHOLDER}\n");
205+
206+
let generated = inject_cloudflare_config(&template, r#"{"app_config":"blob"}"#)
207+
.expect("should inject Cloudflare config");
208+
209+
assert!(
210+
generated.contains("TRUSTED_SERVER_CONFIG = '''{\"app_config\":\"blob\"}'''"),
211+
"should inject generated config JSON"
212+
);
213+
assert!(
214+
!generated.contains(TRUSTED_SERVER_CONFIG_PLACEHOLDER),
215+
"should remove placeholder"
216+
);
217+
}
218+
219+
#[test]
220+
fn inject_cloudflare_config_rejects_missing_placeholder() {
221+
let result = inject_cloudflare_config("[vars]\n", r#"{"app_config":"blob"}"#);
222+
223+
assert!(result.is_err(), "should reject missing placeholder");
224+
}
225+
226+
#[test]
227+
fn inject_cloudflare_config_rejects_duplicate_placeholders() {
228+
let template = format!(
229+
"[vars]\n{TRUSTED_SERVER_CONFIG_PLACEHOLDER}\n{TRUSTED_SERVER_CONFIG_PLACEHOLDER}\n"
230+
);
231+
232+
let result = inject_cloudflare_config(&template, r#"{"app_config":"blob"}"#);
233+
234+
assert!(result.is_err(), "should reject duplicate placeholders");
235+
}
236+
}

0 commit comments

Comments
 (0)