Test FastlyPlatformSecretStore read path and write stubs (PR4)#557
Test FastlyPlatformSecretStore read path and write stubs (PR4)#557
Conversation
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.
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.
…o-pr2-platform-traits
- 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()
- 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)
- 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)
aram356
left a comment
There was a problem hiding this comment.
Summary
This PR introduces a full platform abstraction layer (+2553/-530 lines, 25 files) including crates/trusted-server-core/src/platform/, a new storage module, RuntimeServices threading, geo refactor, backend validation, and config store hardening. The code is well-structured with good documentation and proper error handling. Main concerns are the PR description accuracy and code duplication between adapter and core storage.
Blocking
🔧 wrench
-
PR description severely understates scope: The description claims "No implementation code is added — all production code already existed from prior PRs; this PR is tests only" touching one file. The actual diff is +2553/-530 across 25 files with significant production code changes (platform abstraction, storage module, RuntimeServices wiring,
fastly_storage.rsdeletion, geo refactor, backend validation). This makes the PR difficult to review accurately and could mislead approvers. Please rewrite the PR body to accurately describe the full scope. -
Code duplication between adapter and core storage: See inline comment on
config_store.rs:17.
❓ question
- URL-encoding behavioral change: See inline comment on
api_client.rs:22.
Non-blocking
🤔 thinking
UnsupportedvsNotImplementeddistinction (platform/error.rs:27-32): Test doubles returnUnsupported, adapter stubs returnNotImplemented. The distinction is documented but callers may not realistically branch on it.
♻️ refactor
LazyLockfor trivial conversion (request_signing/jwks.rs:17-18):LazyLockforStoreName::from(JWKS_CONFIG_STORE_NAME)is heavyweight for aStringfrom&str. Could be simplified ifStoreNamesupportedconst fnor ifget()accepted&str.
🌱 seedling
PlatformHttpClient: Send + Syncwith?Sendfutures (platform/http.rs:203-204): Correct for wasm32 and well-documented. May need revisiting if a multi-threaded adapter (e.g., Axum) is added.
👍 praise
- Newtype
StoreName/StoreId(platform/types.rs): Prevents accidental swaps between runtime edge names and management API identifiers. Clean implementation. - Graceful KV store degradation (
adapter-fastly/src/main.rs:66-79): Fallback toUnavailableKvStorekeeps non-synthetic routes working when KV is unavailable. - Control character validation in
BackendConfig(backend.rs:107-116): Prevents log/header injection attacks. Good security hardening. - Geo deduplication via
geo_from_fastly(geo.rs): Eliminates duplication between legacy and new paths. - Comprehensive test coverage: Platform stubs are well-tested including edge cases (empty host, custom timeout, nocert suffix, store failures).
⛏ nitpick
- PR checklist says "Uses
tracingmacros": Project convention in CLAUDE.md specifieslogmacros (withlog-fastlybackend), nottracing.
📝 note
- CLAUDE.md removes
attach_with()guidance:attach_with()is a validerror-stackAPI for lazy attachment via closure. Fine to remove if unused in this project. test_supportmodule ispub(crate)+#[cfg(test)]: Adapter crate can't reuse it, which is fine since it has its own stubs.
CI Status
- All checks: PASS
…zero-pr3-config-store
…o-pr4-secret-store
ChristianPavilonis
left a comment
There was a problem hiding this comment.
Clean, minimal test-only PR. All three tests are correct, follow project conventions, and provide meaningful coverage of the targeted code paths. LGTM.
aram356
left a comment
There was a problem hiding this comment.
Summary
Clean, small, test-only PR that correctly verifies the secret store open-failure path and both write-stub behaviors. Code follows project conventions consistently.
Non-blocking
👍 praise
- Consistent style and convention adherence: Tests follow all CLAUDE.md conventions —
expect_err("should ...")messages, Arrange-Act-Assert pattern, descriptive assertions, section comment separators matching existing patterns, and consistent naming. Good mirroring of the existing config store and HTTP client test patterns. (platform.rs:537-575)
🌱 seedling
- Missing config store write-stub test symmetry: PR3 added
FastlyPlatformConfigStorewithput()anddelete()stubs returningNotImplemented, but no tests for those. Consider addingfastly_platform_config_store_put_returns_not_implementedandfastly_platform_config_store_delete_returns_not_implementedin a follow-up. - Happy-path test for
get_secret_bytes: Two failure modes are tested (open failure, decrypt failure), but no success path. TheStubSecretStorealready supportsOk(Some(bytes)), so a happy-path test would be straightforward. The "key not found" path (Ok(None)) is also untested. StubSecretStoremissingLookuperror variant:StubSecretReadErroronly has aDecryptvariant. Adding aLookupvariant would allow testing the lookup-failure path through the stub.
CI Status
- fmt: PASS
- clippy: PASS
- rust tests: PASS
Summary
FastlyPlatformSecretStorein the Fastly adapter to prove the read path and write stubs satisfy issue Secret store trait (read-only) #485's "Done when" criteriaPlatformError::SecretStore),create()stub (PlatformError::NotImplemented), anddelete()stub (PlatformError::NotImplemented)Changes
crates/trusted-server-adapter-fastly/src/platform.rs#[cfg(test)]blockCloses
Closes #485
Test plan
cargo test --workspacecargo clippy --workspace --all-targets --all-features -- -D warningscargo fmt --all -- --checkcd crates/js/lib && npx vitest run— N/A (no JS changes)cd crates/js/lib && npm run format— N/A (no JS changes)cd docs && npm run format— N/A (no docs changes)cargo build --package trusted-server-adapter-fastly --release --target wasm32-wasip1— N/A (#[cfg(test)]code is excluded from WASM binary)fastly compute serve— N/A (tests only)Checklist
unwrap()in production code — useexpect("should ...")tracingmacros (notprintln!)