Skip to content

Add trusted-server-adapter-cloudflare crate (PR 17)#644

Draft
prk-Jr wants to merge 8 commits intofeature/edgezero-pr16-axum-dev-serverfrom
feature/edgezero-pr17-cloudflare-adapter
Draft

Add trusted-server-adapter-cloudflare crate (PR 17)#644
prk-Jr wants to merge 8 commits intofeature/edgezero-pr16-axum-dev-serverfrom
feature/edgezero-pr17-cloudflare-adapter

Conversation

@prk-Jr
Copy link
Copy Markdown
Collaborator

@prk-Jr prk-Jr commented Apr 18, 2026

Summary

  • Add `trusted-server-adapter-cloudflare` crate — a Cloudflare Workers entry point using `#[event(fetch)]` and `edgezero_adapter_cloudflare::run_app`. Implements `Hooks` with full route parity to the Fastly and Axum adapters including admin key routes, auction, first-party proxy, and publisher fallback.
  • Add `CloudflareHttpClient` (wasm32 only) backed by `worker::Fetch` so outbound proxy requests actually reach the origin on the Workers runtime. Strips `content-encoding`/`transfer-encoding` headers since the Workers runtime auto-decompresses responses, preventing a double-decompress error in the proxy layer.
  • Wire real Cloudflare store implementations in `platform.rs` via edgezero handles injected by `run_app` — reducing `#[cfg(target_arch = "wasm32")]` blocks from 5 to 2:
    • Config: `ConfigStoreHandleAdapter` bridges `ctx.config_store()` to `PlatformConfigStore` — reuses the already-parsed `TRUSTED_SERVER_CONFIG` JSON handle.
    • KV: `KvHandleAdapter` bridges `ctx.kv_handle()` to `PlatformKvStore` — reuses the `env.kv()` handle opened by `run_app`.
    • Secrets: `CloudflareSecretStoreAdapter` calls `env.secret()` synchronously (still `#[cfg]` — `SecretHandle::get_bytes` is async while `PlatformSecretStore::get_bytes` is sync).
    • Geo: `CloudflareGeo` reads `cf-ipcountry`, `cf-ipcity`, `cf-ipcontinent`, `cf-iplatitude`, `cf-iplongitude` — no `#[cfg]` needed, degrades gracefully on native.
  • Replace `std::time::Instant` with `web_time::Instant` in the auction orchestrator and audit remaining `std::time::SystemTime` usages in `proxy.rs` and `signing.rs` — `std::time` panics on `wasm32-unknown-unknown` (Cloudflare), while `web_time` works on all three targets.

Changes

File Change
`crates/trusted-server-adapter-cloudflare/src/lib.rs` New — `#[event(fetch)]` entry point, cfg-gated for wasm32
`crates/trusted-server-adapter-cloudflare/src/app.rs` New — `TrustedServerApp` implementing `Hooks`, full route table
`crates/trusted-server-adapter-cloudflare/src/platform.rs` New — real store adapters (`ConfigStoreHandleAdapter`, `KvHandleAdapter`, `CloudflareSecretStoreAdapter`, `CloudflareGeo`), `CloudflareHttpClient` (wasm32), `extract_client_ip` + 7 unit tests
`crates/trusted-server-adapter-cloudflare/build.sh` New — NVM + `.env` sourcing, `cd SCRIPT_DIR` guard, worker-build 0.7
`crates/trusted-server-adapter-cloudflare/Cargo.toml` New — crate manifest with wasm32 target deps
`crates/trusted-server-adapter-cloudflare/wrangler.toml` New — wrangler config; uses `--cwd` DX so `wrangler dev` runs from workspace root
`crates/trusted-server-adapter-cloudflare/cloudflare.toml` New — edgezero manifest declaring `TRUSTED_SERVER_CONFIG`, `TRUSTED_SERVER_KV`, secrets bindings
`crates/trusted-server-adapter-cloudflare/.gitignore` Add `build/` and `.dev.vars` (wrangler convention for local secrets)
`crates/trusted-server-adapter-cloudflare/tests/routes.rs` New — host-target smoke test: `routes()` builds without panic
`crates/trusted-server-core/src/auction/orchestrator.rs` `std::time::Instant` → `web_time::Instant`
`crates/trusted-server-core/src/proxy.rs` `std::time::SystemTime` → `web_time::SystemTime` (import + test)
`crates/trusted-server-core/src/request_signing/signing.rs` `std::time::SystemTime` → `web_time::SystemTime` (production + test)
`crates/trusted-server-core/src/consent/mod.rs` `std::time::SystemTime` → `web_time::SystemTime`
`crates/trusted-server-core/src/platform/http.rs` Add `UnavailableHttpClient` (shared stub for platforms without outbound HTTP)
`Cargo.toml` Add `web-time`, `js-sys`, `bytes` to workspace deps
`.github/workflows/test.yml` Add CI jobs: native check + wasm32-unknown-unknown check for Cloudflare adapter
`crates/integration-tests/tests/environments/cloudflare.rs` New — `CloudflareWorkers` integration test environment
`crates/integration-tests/tests/environments/mod.rs` Export `cloudflare` environment module
`crates/integration-tests/tests/integration.rs` Add Cloudflare integration test cases (ignored pending wrangler dev)
`.vscode/tasks.json` Add "cloudflare dev server" task using `wrangler dev --cwd` from workspace root
`CLAUDE.md` Document Cloudflare adapter build/check/test commands

Closes

Closes #498

Test plan

  • `cargo test --workspace` (excluding Fastly adapter — Fastly WASM ABI not linkable on native host, pre-existing)
  • `cargo clippy --workspace --all-targets --all-features -- -D warnings`
  • `cargo fmt --all -- --check`
  • JS tests: `cd crates/js/lib && npx vitest run`
  • JS format: `cd crates/js/lib && npm run format`
  • Docs format: `cd docs && npm run format`
  • WASM build: `cargo check -p trusted-server-adapter-cloudflare --target wasm32-unknown-unknown`
  • Manual testing via `wrangler dev` — proxy reaches origin, JS static routes serve correctly, no double-decompress errors
  • Native host-target tests: `cargo test -p trusted-server-adapter-cloudflare` (7 unit + 1 smoke test pass)

Checklist

  • Changes follow CLAUDE.md conventions
  • No `unwrap()` in production code — use `expect("should ...")`
  • Uses `log` macros (not `println!`)
  • New code has tests
  • No secrets or credentials committed

Known deferred items

  • Secret store writes (`create`/`delete`) are not supported on Cloudflare Workers — `/admin/keys/rotate` and `/admin/keys/deactivate` read and write keys via `PlatformConfigStore`/`PlatformSecretStore`. Reads work via `CloudflareSecretStoreAdapter`; write-back would require a Cloudflare management API call outside the Workers runtime.

prk-Jr added 5 commits April 17, 2026 13:58
…ator

wasm32-unknown-unknown (Cloudflare Workers) does not support
std::time::Instant — it panics at runtime. web_time::Instant is a
zero-cost drop-in on native and JS-backed on WASM.
Implements the Cloudflare Workers adapter following the same pattern as
trusted-server-adapter-axum: TrustedServerApp implements the Hooks trait,
platform services use noop stubs on native (CI-compilable), and the
#[event(fetch)] entry point delegates to edgezero_adapter_cloudflare::run_app.

Also adds UnavailableHttpClient to trusted-server-core platform module,
parallel to the existing UnavailableKvStore.
CI: test-cloudflare job checks native host compile, wasm32-unknown-unknown
compile (with cloudflare feature), and runs host-target unit tests.
CLAUDE.md: add cloudflare crate to workspace layout and build commands.
…un_app

The rev (38198f9) of edgezero used in this workspace requires worker 0.7
(not 0.6) and run_app() takes a manifest_src: &str as first argument.
Updated Cargo.toml and lib.rs accordingly.
- Implement CloudflareHttpClient (wasm32 only) using worker::Fetch for real
  outbound proxy requests; strip content-encoding/transfer-encoding headers
  since the Workers runtime auto-decompresses responses
- Add build.sh with cd-to-SCRIPT_DIR guard so worker-build always runs from
  the correct crate root regardless of invocation directory
- Switch wrangler dev task to use --cwd from workspace root (same DX as Fastly)
- Add js-sys to workspace dependencies; reference it via { workspace = true }
- Fix #[ignore] messages on Cloudflare integration tests
- Replace std::time::{SystemTime,UNIX_EPOCH} with web_time in test code for
  signing.rs and proxy.rs (consistency with production paths)
- Add NoopConfigStore/NoopSecretStore TODO comment tracking the gap
- Add extract_client_ip unit tests (parses cf-connecting-ip, absent, invalid)
- Remove empty crate_compiles_on_host_target test
- Add CloudflareHttpClient timeout doc noting Workers CPU-budget tradeoff
@prk-Jr prk-Jr self-assigned this Apr 18, 2026
@prk-Jr prk-Jr marked this pull request as draft April 18, 2026 13:08
prk-Jr added 3 commits April 18, 2026 19:25
Replace direct worker::Env store construction with edgezero handles
already injected by run_app, reducing #[cfg(target_arch = "wasm32")]
blocks from 5 to 2.

- ConfigStoreHandleAdapter: bridges ctx.config_store() to
  PlatformConfigStore — reuses the already-parsed TRUSTED_SERVER_CONFIG
  JSON handle rather than re-parsing it on every request
- KvHandleAdapter: bridges ctx.kv_handle() to PlatformKvStore — reuses
  the env.kv() handle opened by run_app rather than opening a new one
- CloudflareGeo: moved outside #[cfg]; reads cf-ipcountry and related
  headers via ctx.request().headers() which needs no platform import
- CloudflareSecretStoreAdapter: kept under #[cfg] — env.secret() is
  synchronous at the JS level but PlatformSecretStore::get_bytes is sync
  while SecretHandle::get_bytes is async; direct env access is required
- Add .dev.vars to .gitignore (wrangler convention for local secrets)
- Add bytes workspace dep for KvStore impl
- Implement CloudflareWorkers::spawn() to start wrangler dev; in CI uses
  wrangler.ci.toml (no build step, uses pre-built bundle); locally uses
  wrangler.toml (triggers build.sh rebuild)
- Add wrangler.ci.toml: no [build] section so wrangler dev skips the
  worker-build step when the bundle is pre-built as a CI artifact
- Add build-cloudflare input to setup-integration-test-env: adds
  wasm32-unknown-unknown target and runs build.sh with integration test env vars
- In prepare-artifacts: enable build-cloudflare and upload build/ dir as artifact
- In integration-tests: restore CF build dir, install wrangler, set
  CLOUDFLARE_WRANGLER_DIR, and remove --skip flags for cloudflare tests
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.

1 participant