Add store support for Spin adapter (KV, config, secret)#253
Conversation
- dispatch() in request.rs now injects ConfigStoreHandle, KvHandle, and SecretHandle into request extensions on every request - SpinSecretStore normalises the lookup key to lowercase so conventional uppercase names (e.g. SMOKE_SECRET) resolve to the correct Spin variable - contract.rs gains store injection smoke tests (config, kv, secret) and wasm32 compile-time trait checks for SpinKvStore and SpinSecretStore
- spin.toml gains key_value_stores = ["default"] binding and variables declarations for greeting and smoke_secret - edgezero.toml adds "spin" to adapters for config, kv, and secrets routes - smoke_test_kv/config/secrets.sh each gain a spin case that builds the WASM binary and starts spin up --listen 127.0.0.1:3000; the config script skips dotted-key checks (Spin variable names cannot contain dots); the secrets script passes SPIN_VARIABLE_SMOKE_SECRET at startup
spin up creates .spin/ (SQLite KV database and component logs) in the adapter directory during local development, mirroring .wrangler/ for CF.
instead of silently truncating; callers now get an explicit signal rather than incomplete pagination results - Correct DEFAULT_MAX_LIST_KEYS, with_max_list_keys, and module-level docs to accurately describe error-return behaviour (not truncation, not "unbounded allocation" guarding) - Add log::debug in SpinSecretStore::get_bytes when store_name is non-empty so callers learn the flat-namespace constraint at runtime - Add comment in config_store contract tests explaining the InMemory backend accepts dotted/uppercase keys that the real Spin backend would reject via InvalidName - Add comment in lib.rs explaining why SpinConfigStore has different feature gating than SpinKvStore and SpinSecretStore
ChristianPavilonis
left a comment
There was a problem hiding this comment.
Summary
Thanks for adding Spin store support and the smoke/CI coverage. CI is green. I found two configuration-semantics issues worth addressing before relying on non-default store names: Spin KV dispatch is hard-coded to default, and accepting a Spin config-store adapter override is misleading because the runtime does not consume that name.
Resolve conflict in test.yml: keep matrix-based wasm test job (cloudflare/fastly/spin) from this branch; drop main's per-adapter split jobs which pre-date Spin support.
ChristianPavilonis
left a comment
There was a problem hiding this comment.
Summary
Reviewed the Spin store support changes. The implementation adds useful store coverage and CI/smoke-test expansion, but a few issues need attention before merge: one wasm no-default feature build currently fails, Spin store dispatch bypasses manifest resolution, and KV TTL/listing behavior does not match the core contract.
Cross-cutting finding
- 📝 Document Spin-specific store behavior: The user docs and secret-store rustdoc still describe KV TTL, config store behavior, and named secret stores as if Spin behaves like the other adapters. After the implementation behavior is finalized, please update
docs/guide/kv.md,docs/guide/configuration.md, andcrates/edgezero-core/src/secret_store.rsto cover Spin's KV limitations, component variables/flat namespace, lowercase variable names, and whetherrun_apphonors manifest gating.
😃 Praise
- 😃 The Spin wasm CI matrix entry plus the new smoke-test coverage are a strong addition and should catch real integration regressions across the adapter.
CI Status
cargo fmt --all -- --check: PASScargo clippy --workspace --all-targets --all-features -- -D warnings: PASScargo test --workspace --all-targets: PASScargo check --workspace --all-targets --features "fastly cloudflare spin": PASScargo check -p edgezero-adapter-spin --target wasm32-wasip1 --features spin: PASS- Additional check:
cargo check -p edgezero-adapter-spin --target wasm32-wasip1 --no-default-features: FAIL (see inline comment onSpinConfigStore)
aram356
left a comment
There was a problem hiding this comment.
PR Review
Summary
Adds SpinKvStore / SpinConfigStore / SpinSecretStore plus dispatch wiring, a CI matrix entry, and smoke-test coverage. The CI matrix refactor and smoke-test integration are solid, but several correctness and convention issues need addressing before merge — a wasm32 build that breaks without the spin feature, manifest-unaware dispatch, a TTL contract violation, and the most complex new code path (KV pagination) having no test coverage.
Findings
Blocking
- 🔧 SpinConfigStore not gated on the
spinfeature —cargo check -p edgezero-adapter-spin --target wasm32-wasip1without--features spinfails; CI masks it (config_store.rs:47). - 🔧 Dispatch ignores the manifest — hardcoded
"default"KV label, unconditional config/secret injection (request.rs:116). - 🔧
put_bytes_with_ttlreports success while silently dropping the TTL (key_value_store.rs:99). - 🔧
max_list_keyscap is checked after the full fetch — does not bound allocation (key_value_store.rs:129). - 🔧 manifest doc lists
spinas a supported config adapter, contradicting validation (manifest.rs:411). - 🔧
list_keys_pagepagination logic has zero test coverage (key_value_store.rs:123).
Non-blocking
- 🤔
KvError::Validationfor the cap-exceeded case → HTTP 400 misclassifies a server-state condition as a client error (key_value_store.rs:135). - ♻️
run_appcannot reach the non-default KV label (lib.rs:97). - 🤔
SpinConfigStoreis exported but unconstructable on native non-test builds (lib.rs:26). - ⛏ CI wasmtime conditional-install guard never hits (test.yml:141).
- 📝 Docs not updated —
docs/guide/kv.mdanddocs/guide/configuration.mdhave no Spin content;secret_store.rsrustdoc still describes named stores generically. Add Spin's KV limitations (no TTL, O(n) listing), the flat config/secrets variable namespace, and lowercase key normalization. - 📝 PR description inaccuracy — the "Changes" table says
Added "spin" to SUPPORTED_CONFIG_STORE_ADAPTERS, but the change does the opposite (keepsspinout and adds an explanatory comment). Please correct the description.
CI Status
cargo fmt --all -- --check: PASScargo clippy --workspace --all-targets --all-features -- -D warnings: PASScargo test --workspace --all-targets: PASScargo check -p edgezero-adapter-spin --target wasm32-wasip1(nospinfeature): FAIL — see config_store.rs:47
Summary
SpinKvStore,SpinConfigStore, andSpinSecretStoreso Spin handlers can access key-value, configuration, and secret data through the samectx.kv_handle(),ctx.config_store(), andctx.secret_handle()API as every other adapter.run_appmanifest-aware: it resolves the KV label, config-store presence, and secret-store enablement from the embeddededgezero.tomlbefore injecting request handles.Changes
crates/edgezero-adapter-spin/src/config_store.rsSpinConfigStorebacked byspin_sdk::variables; production backend is gated onall(feature = "spin", target_arch = "wasm32"); in-memory test backend runs config-store contract tests on the hostcrates/edgezero-adapter-spin/src/key_value_store.rsSpinKvStorebacked byspin_sdk::key_value; regular get/put/delete/exists operations are supported; TTL writes returnKvError::Validation; key listing is rejected because SpinStore::get_keys()is unboundedcrates/edgezero-adapter-spin/src/secret_store.rsSpinSecretStorebacked byspin_sdk::variables; uses Spin's flat component-variable namespace and normalizes keys to lowercase to match Spin variable naming rulescrates/edgezero-adapter-spin/src/request.rscrates/edgezero-adapter-spin/src/lib.rsrun_appto accept embeddededgezero.toml, resolves Spin store settings from the manifest, and re-exports manifest-aware dispatch helperscrates/edgezero-adapter-spin/tests/contract.rsSpinKvStoreandSpinSecretStorecrates/edgezero-core/src/manifest.rsspinout ofSUPPORTED_CONFIG_STORE_ADAPTERSand documents why[stores.config.adapters.spin]is rejectedcrates/edgezero-core/src/secret_store.rsdocs/guide/kv.mdrun_app, unsupported TTL, and unsupported key listingdocs/guide/configuration.mdrun_apphonors manifest gating.github/workflows/test.ymlexamples/app-demo/edgezero.toml"spin"to the config/KV/secrets routes and sets[stores.kv.adapters.spin] name = "default"for Spin local runtimeexamples/app-demo/crates/app-demo-adapter-spin/spin.tomlkey_value_stores = ["default"]and declares variables forgreetingandsmoke_secretexamples/app-demo/crates/app-demo-adapter-spin/src/lib.rsedgezero.tomlmanifest toedgezero_adapter_spin::run_appscripts/smoke_test_kv.shspincasescripts/smoke_test_config.shspincase; skips dotted-key checks because Spin variable names cannot contain dotsscripts/smoke_test_secrets.shspincase; passes secret value viaSPIN_VARIABLE_SMOKE_SECRETat startup.gitignore.spin/for runtime SQLite KV database and component logsCloses
Closes #73
Closes #74
Test plan
cargo fmt --all -- --checkcargo clippy --workspace --all-targets --all-features -- -D warningscargo test --workspace --all-targetscargo check --workspace --all-targets --features "fastly cloudflare spin"cargo check -p edgezero-adapter-spin --target wasm32-wasip1 --no-default-featurescargo check -p edgezero-adapter-spin --target wasm32-wasip1 --features spincargo check --manifest-path examples/app-demo/Cargo.toml -p app-demo-adapter-spin --target wasm32-wasip1./scripts/smoke_test_kv.sh spin./scripts/smoke_test_config.sh spin./scripts/smoke_test_secrets.sh spinChecklist
{id}syntax (not:id)edgezero_core(nothttpcrate)