From 98247d66eccb1991ce7f466de59f4713e40ca887 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Wed, 16 Sep 2026 00:26:58 -0700 Subject: [PATCH 01/28] Document EdgeZero store selector alignment --- ...-edgezero-fastly-store-selectors-design.md | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md diff --git a/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md b/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md new file mode 100644 index 0000000000..2f99ce9c45 --- /dev/null +++ b/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md @@ -0,0 +1,61 @@ +# EdgeZero Fastly Store Selector Alignment + +## Problem + +Trusted Server currently depends on EdgeZero `v0.0.8`, whose Fastly staging +deployment flow persists and reads service-scoped runtime store selectors. +Staging can therefore fall back to the logical secret-store name +`trusted_server_secrets` even when the selected GitHub Environment sets the +canonical selector to the physical store `ts_secrets`. Runtime settings then +fail while resolving required secret references such as +`publisher.proxy_secret`. + +EdgeZero PR 381 restores canonical deploy-time selectors and makes staged +deployments link the selected physical Config, KV, and Secret Stores. Trusted +Server needs to consume that behavior and remove guidance for the superseded +service-scoped selector model. + +## Design + +All EdgeZero workspace dependencies will temporarily use the upstream branch +`fix/fastly-environment-store-selectors`. Keeping the dependencies on one branch +ensures the adapter, CLI, core, and platform-specific crates resolve to the same +revision while PR 381 is under review. A follow-up will replace the branch with +the release tag that contains the merged change. + +Trusted Server's local Fastly runtime configuration will use the canonical +selector: + +```text +EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME=ts_secrets +``` + +The Fastly and CLI guides will describe GitHub Environment or deploy-process +variables as deployment inputs. They will no longer instruct operators to +construct a selector containing a Fastly service ID or to persist that key +manually. EdgeZero remains responsible for applying the selected store mapping +to production or to the staged version during deployment. + +## Failure Handling + +Trusted Server will keep failing startup when a required secret reference +cannot be resolved. This change fixes the deployment mapping and resource links +rather than weakening runtime validation or falling back to another store. + +The pull request will state that its branch dependency is temporary and link to +EdgeZero PR 381. If upstream changes its CLI API before merge, Trusted Server's +compile and CLI tests will expose the mismatch before deployment. + +## Validation + +Validation will cover: + +- lockfile resolution of every EdgeZero crate to one upstream revision; +- Trusted Server CLI parsing and behavior tests on the host target; +- Fastly adapter compilation and tests where supported by the local toolchain; +- Rust formatting and target-matched Clippy for changed Rust surfaces; +- searches confirming service-scoped store-selector instructions are removed + from current operator documentation and local Fastly configuration. + +The issue will record the staging failure, expected canonical selector behavior, +and the dependency on EdgeZero PR 381. The pull request will close that issue. From ca5b4d457dde57b41d26728f4db41af6b5171887 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Wed, 16 Sep 2026 00:40:08 -0700 Subject: [PATCH 02/28] Plan EdgeZero store selector alignment --- ...6-09-16-edgezero-fastly-store-selectors.md | 328 ++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 docs/superpowers/plans/2026-09-16-edgezero-fastly-store-selectors.md diff --git a/docs/superpowers/plans/2026-09-16-edgezero-fastly-store-selectors.md b/docs/superpowers/plans/2026-09-16-edgezero-fastly-store-selectors.md new file mode 100644 index 0000000000..879bf5f39a --- /dev/null +++ b/docs/superpowers/plans/2026-09-16-edgezero-fastly-store-selectors.md @@ -0,0 +1,328 @@ +# EdgeZero Fastly Store Selector Alignment Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Restore Trusted Server staging deployments by consuming EdgeZero PR 381's canonical Fastly store-selector behavior and removing the superseded service-scoped configuration. + +**Architecture:** Pin every EdgeZero workspace dependency to the upstream PR branch so the CLI and adapters share one revision. Keep Trusted Server's strict runtime secret resolution, while changing local Viceroy configuration, its regression test, and operator guidance to use canonical `EDGEZERO__STORES__...` selectors that EdgeZero applies during deployment. + +**Tech Stack:** Rust 1.95, Cargo Git dependencies, Fastly Compute/Viceroy TOML configuration, Markdown documentation, GitHub CLI. + +--- + +## File Map + +- `Cargo.toml`: select the EdgeZero PR 381 branch for all EdgeZero crates. +- `Cargo.lock`: lock all EdgeZero packages to the branch revision. +- `fastly.toml`: use the canonical local Viceroy secret-store selector. +- `crates/trusted-server-integration-tests/fixtures/configs/viceroy-template.toml`: keep generated Viceroy integration configurations aligned with the root Fastly configuration. +- `crates/trusted-server-integration-tests/tests/common/config.rs`: regress the canonical selector in both Viceroy configurations. +- `docs/guide/fastly.md`: explain deploy-time canonical selector handling and physical store linking. +- `docs/guide/cli.md`: explain staging Config Store selection under the restored EdgeZero deployment model. +- `docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md`: approved design, already committed. +- `docs/superpowers/plans/2026-09-16-edgezero-fastly-store-selectors.md`: this execution plan. + +### Task 1: Create the Tracking Issue + +**Files:** +- No repository files. + +- [ ] **Step 1: Draft the issue** + +Use a bug title such as `Align Fastly staging store selectors with EdgeZero PR 381` and include: + +- the observed `publisher.proxy_secret` resolution failure; +- the impact that staging cannot build application state; +- the root cause that EdgeZero `v0.0.8` reads service-scoped selectors while the selected GitHub Environment supplies canonical selectors; +- the expected canonical key `EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME=ts_secrets`; +- the dependency on `https://github.com/stackpop/edgezero/pull/381`; +- acceptance criteria covering the branch dependency, Viceroy fixtures, documentation, and validation. + +- [ ] **Step 2: Create the issue and record its number** + +Run: + +```bash +gh issue create --repo IABTechLab/trusted-server --title "Align Fastly staging store selectors with EdgeZero PR 381" --label bug --body-file +``` + +Expected: GitHub prints the new issue URL. Save its issue number for the pull request body. + +### Task 2: Regress Canonical Viceroy Selectors + +**Files:** +- Modify: `crates/trusted-server-integration-tests/tests/common/config.rs:48` +- Modify: `fastly.toml:74` +- Modify: `crates/trusted-server-integration-tests/fixtures/configs/viceroy-template.toml:86` + +- [ ] **Step 1: Change the regression test first** + +Rename `local_fastly_secret_store_mapping_is_service_scoped` to +`local_fastly_secret_store_mapping_is_canonical`. Replace the service-scoped +constant with: + +```rust +const VICEROY_SECRET_STORE_MAPPING_KEY: &str = + "EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME"; +``` + +Assert that both parsed configurations map that key to `ts_secrets`. Remove the +assertion that rejects the canonical key. Keep assertion messages focused on the +canonical selector contract. + +- [ ] **Step 2: Run the focused test and verify it fails** + +Run from `crates/trusted-server-integration-tests` using the host target: + +```bash +cargo test --test integration local_fastly_secret_store_mapping_is_canonical --target aarch64-apple-darwin +``` + +Expected: FAIL because both TOML files still contain the service-scoped key. + +- [ ] **Step 3: Update the two Viceroy configurations** + +In both TOML files replace: + +```text +EDGEZERO__SERVICES__0000000000000000000000__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME +``` + +with: + +```text +EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME +``` + +Adjust the nearby root `fastly.toml` comment to call this a canonical selector. + +- [ ] **Step 4: Run the focused test and verify it passes** + +Run the same focused `cargo test` command. + +Expected: PASS. + +- [ ] **Step 5: Commit the regression and fixtures** + +```bash +git add fastly.toml crates/trusted-server-integration-tests/fixtures/configs/viceroy-template.toml crates/trusted-server-integration-tests/tests/common/config.rs +git commit -m "Use canonical Fastly secret store selectors" +``` + +### Task 3: Consume the EdgeZero PR Branch + +**Files:** +- Modify: `Cargo.toml:59` +- Modify: `Cargo.lock` + +- [ ] **Step 1: Select the upstream branch consistently** + +Replace `tag = "v0.0.8"` on all six `edgezero-*` workspace dependencies with: + +```toml +branch = "fix/fastly-environment-store-selectors" +``` + +- [ ] **Step 2: Refresh the lockfile through a targeted CLI check** + +Run: + +```bash +cargo check --package trusted-server-cli --target aarch64-apple-darwin +``` + +Expected: Cargo fetches the branch, locks every EdgeZero package to the same Git +revision, and the Trusted Server CLI compiles. If upstream API changes cause a +compiler failure, make only the call-site changes required by that error and add +a focused parsing or behavior test before the production edit. + +- [ ] **Step 3: Verify the lockfile revision is consistent** + +Run: + +```bash +rg -n -A3 'name = "edgezero-' Cargo.lock +``` + +Expected: all Git-sourced EdgeZero packages use the branch URL and the same +commit fragment; no EdgeZero entry remains on `tag=v0.0.8`. + +- [ ] **Step 4: Run the CLI test suite** + +Run: + +```bash +./scripts/test-cli.sh +``` + +Expected: all non-ignored tests pass. + +- [ ] **Step 5: Commit the dependency update** + +```bash +git add Cargo.toml Cargo.lock crates/trusted-server-cli +git commit -m "Consume canonical EdgeZero deployment selectors" +``` + +Only stage `crates/trusted-server-cli` if compiler-driven compatibility changes +were necessary. + +### Task 4: Align Operator Documentation + +**Files:** +- Modify: `docs/guide/fastly.md:264` +- Modify: `docs/guide/cli.md:115` + +- [ ] **Step 1: Update Fastly store-selector guidance** + +Keep the canonical export example. Replace the statements that provisioning +persists a service-scoped key and that unscoped keys are ignored with the PR 381 +contract: + +- provisioning creates/reuses resources and the `edgezero_runtime_env` store; +- deployment copies canonical selectors from its selected environment; +- production reconciles them into its runtime store; +- staging applies its selected physical stores to a per-service staging twin and + links those resources to the staged version; +- canonical environment-variable names contain no service ID; +- the selected physical resources must already exist. + +- [ ] **Step 2: Update staging CLI guidance** + +Clarify that `ts config push --staging` writes the staging key into the physical +Config Store selected by the staging environment, and `ts deploy --staging` +links a staging selector store that points at that key. State that production and +staging may select the same or different physical stores. + +- [ ] **Step 3: Check for stale service-scoped guidance** + +Run: + +```bash +rg -n 'EDGEZERO__SERVICES__|service-scoped mapping|ignored unscoped' fastly.toml docs crates/trusted-server-integration-tests --glob '!docs/superpowers/**' +``` + +Expected: no matches outside archived design material. + +- [ ] **Step 4: Format documentation** + +Run: + +```bash +cd docs && npm run format +``` + +Expected: formatter exits successfully without unrelated changes. + +- [ ] **Step 5: Commit documentation** + +```bash +git add docs/guide/fastly.md docs/guide/cli.md +git commit -m "Document deploy-time Fastly store selection" +``` + +### Task 5: Verify the Complete Change + +**Files:** +- Verify all modified files. + +- [ ] **Step 1: Run formatting checks** + +```bash +cargo fmt --all -- --check +cd docs && npm run format +``` + +Expected: both commands exit successfully. + +- [ ] **Step 2: Run target-matched Rust checks** + +```bash +cargo check-fastly +cargo check-axum +cargo check-cloudflare +cargo check-spin +``` + +Expected: all adapters compile with the selected EdgeZero branch. + +- [ ] **Step 3: Run target-matched tests** + +```bash +cargo test-fastly +cargo test-axum +cargo test-cloudflare +cargo test-spin +./scripts/test-cli.sh +cargo test --manifest-path crates/trusted-server-integration-tests/Cargo.toml --test integration local_fastly_secret_store_mapping_is_canonical +cargo test --manifest-path crates/trusted-server-integration-tests/Cargo.toml --test parity +``` + +Expected: all tests pass. Run socket-binding tests with loopback access if the +sandbox blocks them. + +- [ ] **Step 4: Run target-matched Clippy** + +```bash +cargo clippy-fastly +cargo clippy-axum +cargo clippy-cloudflare +cargo clippy-cloudflare-wasm +cargo clippy-spin-native +cargo clippy-spin-wasm +``` + +Expected: every command exits successfully with warnings denied by the aliases. + +- [ ] **Step 5: Run JavaScript and documentation gates** + +```bash +(cd crates/trusted-server-js/lib && node build-all.mjs && npx vitest run && npm run format) +(cd docs && npm run format) +``` + +Expected: the JavaScript build and tests pass, and both formatters exit +successfully without unrelated changes. + +- [ ] **Step 6: Review the final diff** + +```bash +git diff origin/main...HEAD --check +git diff origin/main...HEAD --stat +git status --short +``` + +Expected: no whitespace errors, only planned files changed, and the worktree is +clean after final commits. + +### Task 6: Publish the Pull Request + +**Files:** +- No additional repository files. + +- [ ] **Step 1: Push the isolated branch** + +```bash +git push -u origin fix/align-edgezero-pr-381 +``` + +- [ ] **Step 2: Draft the PR from the repository template** + +Use a title such as `Align Fastly staging store selectors with EdgeZero PR 381`. +Lead with the staging failure and resulting canonical store resolution. Include: + +- the EdgeZero branch dependency and upstream PR link; +- the canonical Viceroy fixtures and regression test; +- documentation changes; +- exact validation results; +- `Closes #`; +- a note that the branch pin will be replaced by the release tag after upstream + merges. + +- [ ] **Step 3: Create the pull request** + +```bash +gh pr create --repo IABTechLab/trusted-server --base main --head fix/align-edgezero-pr-381 --title "Align Fastly staging store selectors with EdgeZero PR 381" --body-file +``` + +Expected: GitHub prints the new pull request URL. From fbeb1950a06a49bc8a75465235a41acee5b7c875 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Wed, 16 Sep 2026 00:42:10 -0700 Subject: [PATCH 03/28] Use canonical Fastly secret store selectors --- .../fixtures/configs/viceroy-template.toml | 2 +- .../tests/common/config.rs | 12 +++--------- fastly.toml | 4 ++-- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/crates/trusted-server-integration-tests/fixtures/configs/viceroy-template.toml b/crates/trusted-server-integration-tests/fixtures/configs/viceroy-template.toml index 816dcbfcfc..f11a67dff7 100644 --- a/crates/trusted-server-integration-tests/fixtures/configs/viceroy-template.toml +++ b/crates/trusted-server-integration-tests/fixtures/configs/viceroy-template.toml @@ -86,7 +86,7 @@ [local_server.config_stores.edgezero_runtime_env] format = "inline-toml" [local_server.config_stores.edgezero_runtime_env.contents] - EDGEZERO__SERVICES__0000000000000000000000__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME = "ts_secrets" + EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME = "ts_secrets" # Generated integration configs inject the trusted_server_config blob # into the store required by the Fastly entry point. diff --git a/crates/trusted-server-integration-tests/tests/common/config.rs b/crates/trusted-server-integration-tests/tests/common/config.rs index d1fddcb95a..60bb846604 100644 --- a/crates/trusted-server-integration-tests/tests/common/config.rs +++ b/crates/trusted-server-integration-tests/tests/common/config.rs @@ -47,7 +47,7 @@ mod tests { const FASTLY_CONFIG: &str = include_str!("../../../../fastly.toml"); const VICEROY_TEMPLATE: &str = include_str!("../../fixtures/configs/viceroy-template.toml"); const VICEROY_SECRET_STORE_MAPPING_KEY: &str = - "EDGEZERO__SERVICES__0000000000000000000000__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME"; + "EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME"; #[test] fn local_fastly_config_defines_runtime_kv_stores() { @@ -74,7 +74,7 @@ mod tests { } #[test] - fn local_fastly_secret_store_mapping_is_service_scoped() { + fn local_fastly_secret_store_mapping_is_canonical() { for (name, config) in [ ("fastly.toml", FASTLY_CONFIG), ("Viceroy integration template", VICEROY_TEMPLATE), @@ -87,13 +87,7 @@ mod tests { assert_eq!( runtime_env[VICEROY_SECRET_STORE_MAPPING_KEY].as_str(), Some("ts_secrets"), - "{name} should scope the secret-store mapping to Viceroy's service ID" - ); - assert!( - runtime_env - .get("EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME") - .is_none(), - "{name} should not define the ignored unscoped secret-store mapping" + "{name} should define the canonical secret-store mapping" ); } } diff --git a/fastly.toml b/fastly.toml index a3812999be..532ff4926f 100644 --- a/fastly.toml +++ b/fastly.toml @@ -72,13 +72,13 @@ build = """ data = "test-tinybird-auction-append-token" # App-config references use logical `trusted_server_secrets`; the - # edgezero_runtime_env mapping below resolves it to physical `ts_secrets`. + # canonical selector below resolves it to physical `ts_secrets`. [local_server.config_stores] [local_server.config_stores.edgezero_runtime_env] format = "inline-toml" [local_server.config_stores.edgezero_runtime_env.contents] - EDGEZERO__SERVICES__0000000000000000000000__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME = "ts_secrets" + EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME = "ts_secrets" [local_server.config_stores.trusted_server_config] format = "inline-toml" From f2b1b396161c5af0ed6ec4dbf2040198b7844ece Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Wed, 16 Sep 2026 00:43:56 -0700 Subject: [PATCH 04/28] Consume canonical EdgeZero deployment selectors --- Cargo.lock | 16 ++++++++-------- Cargo.toml | 12 ++++++------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 311597aae9..ac1658d40f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1427,7 +1427,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?tag=v0.0.8#567964158e4f8bd0d52321b9801de44966422e1b" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8efad3c80ce3eb10bef9e348dd316ff2c90e0fbf" dependencies = [ "toml", ] @@ -1435,7 +1435,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?tag=v0.0.8#567964158e4f8bd0d52321b9801de44966422e1b" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8efad3c80ce3eb10bef9e348dd316ff2c90e0fbf" dependencies = [ "anyhow", "async-trait", @@ -1463,7 +1463,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?tag=v0.0.8#567964158e4f8bd0d52321b9801de44966422e1b" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8efad3c80ce3eb10bef9e348dd316ff2c90e0fbf" dependencies = [ "anyhow", "async-trait", @@ -1486,7 +1486,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?tag=v0.0.8#567964158e4f8bd0d52321b9801de44966422e1b" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8efad3c80ce3eb10bef9e348dd316ff2c90e0fbf" dependencies = [ "anyhow", "async-stream", @@ -1515,7 +1515,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?tag=v0.0.8#567964158e4f8bd0d52321b9801de44966422e1b" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8efad3c80ce3eb10bef9e348dd316ff2c90e0fbf" dependencies = [ "anyhow", "async-trait", @@ -1542,7 +1542,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?tag=v0.0.8#567964158e4f8bd0d52321b9801de44966422e1b" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8efad3c80ce3eb10bef9e348dd316ff2c90e0fbf" dependencies = [ "chrono", "clap", @@ -1567,7 +1567,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?tag=v0.0.8#567964158e4f8bd0d52321b9801de44966422e1b" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8efad3c80ce3eb10bef9e348dd316ff2c90e0fbf" dependencies = [ "anyhow", "async-compression", @@ -1598,7 +1598,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?tag=v0.0.8#567964158e4f8bd0d52321b9801de44966422e1b" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8efad3c80ce3eb10bef9e348dd316ff2c90e0fbf" dependencies = [ "log", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index dfd94d0c4b..fd3b887b5c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,12 +55,12 @@ cssparser = "0.36" 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.8", default-features = false } -edgezero-adapter-cloudflare = { git = "https://github.com/stackpop/edgezero", tag = "v0.0.8", default-features = false } -edgezero-adapter-fastly = { git = "https://github.com/stackpop/edgezero", tag = "v0.0.8", default-features = false } -edgezero-adapter-spin = { git = "https://github.com/stackpop/edgezero", tag = "v0.0.8", default-features = false } -edgezero-cli = { git = "https://github.com/stackpop/edgezero", tag = "v0.0.8" } -edgezero-core = { git = "https://github.com/stackpop/edgezero", tag = "v0.0.8", default-features = false } +edgezero-adapter-axum = { git = "https://github.com/stackpop/edgezero", branch = "fix/fastly-environment-store-selectors", default-features = false } +edgezero-adapter-cloudflare = { git = "https://github.com/stackpop/edgezero", branch = "fix/fastly-environment-store-selectors", default-features = false } +edgezero-adapter-fastly = { git = "https://github.com/stackpop/edgezero", branch = "fix/fastly-environment-store-selectors", default-features = false } +edgezero-adapter-spin = { git = "https://github.com/stackpop/edgezero", branch = "fix/fastly-environment-store-selectors", default-features = false } +edgezero-cli = { git = "https://github.com/stackpop/edgezero", branch = "fix/fastly-environment-store-selectors" } +edgezero-core = { git = "https://github.com/stackpop/edgezero", branch = "fix/fastly-environment-store-selectors", default-features = false } env_logger = "0.11" error-stack = "0.6" esi = "0.7.2" From 3416b71c4a4aa9e25ee80fa12b531b735fdf3949 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Wed, 16 Sep 2026 00:45:30 -0700 Subject: [PATCH 05/28] Document deploy-time Fastly store selection --- docs/guide/cli.md | 23 +++++++++------- docs/guide/fastly.md | 26 ++++++++++++------- ...6-09-16-edgezero-fastly-store-selectors.md | 6 +++++ 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/docs/guide/cli.md b/docs/guide/cli.md index 775a99146b..b133b95dc8 100644 --- a/docs/guide/cli.md +++ b/docs/guide/cli.md @@ -125,8 +125,9 @@ ts deploy --adapter fastly --service-id --staging ts deploy --adapter fastly -- --comment "release" ``` -A staged deploy only redirects the staged version's config selector at the -`_staging` key — it does not copy the production config blob +A staged deploy selects the physical Config Store from the staging environment +and points the staged version's config selector at the +`_staging` key. It does not copy the production config blob there. Push the staged config before probing the staged version: ```bash @@ -134,15 +135,19 @@ ts config push --adapter fastly --staging ts config diff --adapter fastly --staging ``` -The staged version resolves its app-config key through the version-linked -`edgezero_runtime_env` store. After `ts config push --staging`, the staged -binary reads `_staging` while the active production version -continues to read the production key. +The staged version resolves its app-config key through a staging selector store +linked under the name `edgezero_runtime_env`. Production and staging may select +the same physical Config Store or different stores. After +`ts config push --staging`, the staged binary reads +`_staging` in the store selected by the staging environment, +while the active production version continues to read its production key and +store. `--staging` on `config push` / `config diff` writes and compares the -`_staging` key in the same store. It is mutually exclusive -with `--key`: the staging key is derived from the store's logical id, so an -explicit key would be written where nothing reads it. +`_staging` key in the physical store selected by the staging +environment. It is mutually exclusive with `--key`: the staging key is derived +from the store's logical id, so an explicit key would be written where nothing +reads it. Inspect and verify deployments with the deploy lifecycle commands. All three are Fastly-only — the axum, cloudflare, and spin adapters reject them: diff --git a/docs/guide/fastly.md b/docs/guide/fastly.md index f63b4f627f..316f8c97be 100644 --- a/docs/guide/fastly.md +++ b/docs/guide/fastly.md @@ -267,25 +267,33 @@ Trusted Server keeps static app-config credentials under logical store ID as `ts_secrets`. Request-signing private keys remain in their separate, runtime-managed store. -Set the physical mapping before provisioning: +Set the physical mapping in the selected deployment environment before +provisioning and deploying: ```bash export EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME=ts_secrets ts provision --adapter fastly ``` -Provisioning creates or reuses the physical store and persists this runtime -mapping in Fastly Config Store `edgezero_runtime_env`, scoped to the current -Fastly service: +Provisioning creates or reuses the physical store and the +`edgezero_runtime_env` Config Store, but does not write environment selectors. +Deployment copies the selected environment's declared store selectors into +`edgezero_runtime_env` under their canonical names: ```text -EDGEZERO__SERVICES____STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME=ts_secrets +EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME=ts_secrets ``` -The runtime ignores legacy unscoped entries. The Fastly service must link both -`ts_secrets` and `edgezero_runtime_env` to the active service version. The -custom streaming entry point reads the service-scoped mapping before loading -app config, so every startup and reload resolves static credentials from +There is no Fastly service ID in the environment variable name. Each GitHub +Environment or deploy process uses the same canonical names and may select +different physical resources. A production deploy reconciles its selectors +into `edgezero_runtime_env`. A staged deploy creates a per-service staging twin, +applies the staging environment's selectors, links every selected physical +store to the staged version, and links the twin under the name +`edgezero_runtime_env`. Selected resources must already exist before deployment. + +The custom streaming entry point reads the deployed mapping before loading app +config, so every startup and reload resolves static credentials from `ts_secrets` while the portable manifest continues to declare `trusted_server_secrets`. diff --git a/docs/superpowers/plans/2026-09-16-edgezero-fastly-store-selectors.md b/docs/superpowers/plans/2026-09-16-edgezero-fastly-store-selectors.md index 879bf5f39a..7ccd3be2be 100644 --- a/docs/superpowers/plans/2026-09-16-edgezero-fastly-store-selectors.md +++ b/docs/superpowers/plans/2026-09-16-edgezero-fastly-store-selectors.md @@ -25,6 +25,7 @@ ### Task 1: Create the Tracking Issue **Files:** + - No repository files. - [ ] **Step 1: Draft the issue** @@ -51,6 +52,7 @@ Expected: GitHub prints the new issue URL. Save its issue number for the pull re ### Task 2: Regress Canonical Viceroy Selectors **Files:** + - Modify: `crates/trusted-server-integration-tests/tests/common/config.rs:48` - Modify: `fastly.toml:74` - Modify: `crates/trusted-server-integration-tests/fixtures/configs/viceroy-template.toml:86` @@ -112,6 +114,7 @@ git commit -m "Use canonical Fastly secret store selectors" ### Task 3: Consume the EdgeZero PR Branch **Files:** + - Modify: `Cargo.toml:59` - Modify: `Cargo.lock` @@ -170,6 +173,7 @@ were necessary. ### Task 4: Align Operator Documentation **Files:** + - Modify: `docs/guide/fastly.md:264` - Modify: `docs/guide/cli.md:115` @@ -224,6 +228,7 @@ git commit -m "Document deploy-time Fastly store selection" ### Task 5: Verify the Complete Change **Files:** + - Verify all modified files. - [ ] **Step 1: Run formatting checks** @@ -298,6 +303,7 @@ clean after final commits. ### Task 6: Publish the Pull Request **Files:** + - No additional repository files. - [ ] **Step 1: Push the isolated branch** From 645d641fc08e60629cedaa3b88d1b181d18bfd14 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Thu, 17 Sep 2026 13:05:58 -0700 Subject: [PATCH 06/28] Open Fastly stores by logical ID on the EdgeZero PR 381 branch head Move the EdgeZero pin from 8efad3c8 to 657bfdcb. The branch head replaces the edgezero_runtime_env selector store with logical-ID resource links and removes runtime_env_config, so the Fastly entry point now opens trusted_server_config and trusted_server_secrets by logical ID and derives the config key from Fastly's staging signal through EdgeZero's target key rule. Expose the local Viceroy secret store under trusted_server_secrets, drop the runtime selector store from fastly.toml and the integration template, and regress that shape in the config test. Update the Fastly and CLI guides for deterministic config keys, logical-ID links, and the application release that managed deploys now require. --- Cargo.lock | 16 +-- .../trusted-server-adapter-fastly/src/app.rs | 53 +++++----- .../trusted-server-adapter-fastly/src/main.rs | 6 +- .../fixtures/configs/viceroy-template.toml | 15 +-- .../tests/common/config.rs | 25 ++--- docs/guide/cli.md | 32 +++--- docs/guide/fastly.md | 40 ++++---- ...6-09-16-edgezero-fastly-store-selectors.md | 97 ++++++++++--------- ...-edgezero-fastly-store-selectors-design.md | 32 +++--- fastly.toml | 19 ++-- scripts/template-cache-local-test.sh | 6 +- 11 files changed, 168 insertions(+), 173 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ac1658d40f..f6660115ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1427,7 +1427,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8efad3c80ce3eb10bef9e348dd316ff2c90e0fbf" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#657bfdcb4dfaa1d901a74941812bf0b5fca78555" dependencies = [ "toml", ] @@ -1435,7 +1435,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8efad3c80ce3eb10bef9e348dd316ff2c90e0fbf" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#657bfdcb4dfaa1d901a74941812bf0b5fca78555" dependencies = [ "anyhow", "async-trait", @@ -1463,7 +1463,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8efad3c80ce3eb10bef9e348dd316ff2c90e0fbf" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#657bfdcb4dfaa1d901a74941812bf0b5fca78555" dependencies = [ "anyhow", "async-trait", @@ -1486,7 +1486,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8efad3c80ce3eb10bef9e348dd316ff2c90e0fbf" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#657bfdcb4dfaa1d901a74941812bf0b5fca78555" dependencies = [ "anyhow", "async-stream", @@ -1515,7 +1515,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8efad3c80ce3eb10bef9e348dd316ff2c90e0fbf" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#657bfdcb4dfaa1d901a74941812bf0b5fca78555" dependencies = [ "anyhow", "async-trait", @@ -1542,7 +1542,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8efad3c80ce3eb10bef9e348dd316ff2c90e0fbf" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#657bfdcb4dfaa1d901a74941812bf0b5fca78555" dependencies = [ "chrono", "clap", @@ -1567,7 +1567,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8efad3c80ce3eb10bef9e348dd316ff2c90e0fbf" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#657bfdcb4dfaa1d901a74941812bf0b5fca78555" dependencies = [ "anyhow", "async-compression", @@ -1598,7 +1598,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8efad3c80ce3eb10bef9e348dd316ff2c90e0fbf" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#657bfdcb4dfaa1d901a74941812bf0b5fca78555" dependencies = [ "log", "proc-macro2", diff --git a/crates/trusted-server-adapter-fastly/src/app.rs b/crates/trusted-server-adapter-fastly/src/app.rs index 190be505cb..cbd29c02f8 100644 --- a/crates/trusted-server-adapter-fastly/src/app.rs +++ b/crates/trusted-server-adapter-fastly/src/app.rs @@ -90,7 +90,6 @@ use std::sync::Arc; use crate::rate_limiter::{FastlyRateLimiter, RATE_COUNTER_NAME}; use edgezero_adapter_fastly::context::FastlyRequestContext; -use edgezero_adapter_fastly::runtime_env_config; use edgezero_core::app::{App, Hooks, StoreMetadata, StoresMetadata}; use edgezero_core::context::RequestContext; use edgezero_core::env_config::EnvConfig; @@ -100,6 +99,7 @@ use edgezero_core::http::{ }; use edgezero_core::router::RouterService; use error_stack::Report; +use fastly::compute_runtime; use trusted_server_core::auction::AuctionTelemetrySink; use trusted_server_core::auction::endpoints::handle_auction; use trusted_server_core::auction::{ @@ -162,11 +162,21 @@ pub(crate) struct RuntimeStoreConfig { } impl RuntimeStoreConfig { - pub(crate) fn from_env(env: &EnvConfig) -> Self { + /// Store bindings for the running Fastly publication target. + /// + /// Fastly Compute has no process environment. `EdgeZero` links each selected + /// physical store to the service version under its logical ID, so the + /// runtime opens stores by logical ID and derives the config entry key from + /// the target alone: production reads ``, staging reads `_staging`. + pub(crate) fn for_target(staging: bool) -> Self { Self { - config_store_name: StoreName::from(env.store_name("config", DEFAULT_CONFIG_STORE_ID)), - config_key: env.store_key("config", DEFAULT_CONFIG_STORE_ID), - secret_store_name: StoreName::from(env.store_name("secrets", DEFAULT_SECRET_STORE_ID)), + config_store_name: StoreName::from(DEFAULT_CONFIG_STORE_ID), + config_key: EnvConfig::default().store_key_for_target( + "config", + DEFAULT_CONFIG_STORE_ID, + staging, + ), + secret_store_name: StoreName::from(DEFAULT_SECRET_STORE_ID), } } } @@ -1343,8 +1353,7 @@ impl Hooks for TrustedServerApp { } fn routes() -> RouterService { - let runtime_env = runtime_env_config(Self::stores()); - let stores = RuntimeStoreConfig::from_env(&runtime_env); + let stores = RuntimeStoreConfig::for_target(compute_runtime::is_staging()); Self::router_with_state(&stores).0 } @@ -1385,7 +1394,6 @@ mod tests { use edgezero_core::app::Hooks as _; use edgezero_core::body::Body; use edgezero_core::context::RequestContext; - use edgezero_core::env_config::EnvConfig; use edgezero_core::http::{Method, Response, StatusCode, header, request_builder}; use edgezero_core::key_value_store::NoopKvStore; use edgezero_core::params::PathParams; @@ -1455,32 +1463,17 @@ mod tests { } #[test] - fn runtime_store_config_maps_logical_store_names_and_config_key() { - let env = EnvConfig::from_vars([ - ( - "EDGEZERO__STORES__CONFIG__TRUSTED_SERVER_CONFIG__NAME", - "physical_config", - ), - ( - "EDGEZERO__STORES__CONFIG__TRUSTED_SERVER_CONFIG__KEY", - "active_config", - ), - ( - "EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME", - "ts_secrets", - ), - ]); - - let stores = RuntimeStoreConfig::from_env(&env); + fn runtime_store_config_reads_the_staging_config_key_on_staging() { + let stores = RuntimeStoreConfig::for_target(true); - assert_eq!(stores.config_store_name.as_ref(), "physical_config"); - assert_eq!(stores.config_key, "active_config"); - assert_eq!(stores.secret_store_name.as_ref(), "ts_secrets"); + assert_eq!(stores.config_store_name.as_ref(), "trusted_server_config"); + assert_eq!(stores.config_key, "trusted_server_config_staging"); + assert_eq!(stores.secret_store_name.as_ref(), "trusted_server_secrets"); } #[test] - fn runtime_store_config_uses_logical_defaults_without_overrides() { - let stores = RuntimeStoreConfig::from_env(&EnvConfig::default()); + fn runtime_store_config_opens_logical_store_ids_in_production() { + let stores = RuntimeStoreConfig::for_target(false); assert_eq!(stores.config_store_name.as_ref(), "trusted_server_config"); assert_eq!(stores.config_key, "trusted_server_config"); diff --git a/crates/trusted-server-adapter-fastly/src/main.rs b/crates/trusted-server-adapter-fastly/src/main.rs index 367a3e33f7..0adfa712d5 100644 --- a/crates/trusted-server-adapter-fastly/src/main.rs +++ b/crates/trusted-server-adapter-fastly/src/main.rs @@ -2,14 +2,13 @@ use std::sync::Arc; use edgezero_adapter_fastly::config_store::FastlyConfigStore as EdgeZeroFastlyConfigStore; use edgezero_adapter_fastly::request::into_core_request; -use edgezero_adapter_fastly::runtime_env_config; -use edgezero_core::app::Hooks as _; use edgezero_core::body::Body as EdgeBody; use edgezero_core::config_store::ConfigStoreHandle; use edgezero_core::error::EdgeError; use edgezero_core::http::{Request as HttpRequest, Response as HttpResponse}; use edgezero_core::response::IntoResponse; use error_stack::Report; +use fastly::compute_runtime; use fastly::http::Method as FastlyMethod; use fastly::{Request as FastlyRequest, Response as FastlyResponse}; @@ -90,8 +89,7 @@ fn main() { /// Handles a request through the `EdgeZero` router path. fn edgezero_main(mut req: FastlyRequest) { - let runtime_env = runtime_env_config(TrustedServerApp::stores()); - let runtime_stores = RuntimeStoreConfig::from_env(&runtime_env); + let runtime_stores = RuntimeStoreConfig::for_target(compute_runtime::is_staging()); // Short-circuit the JA4 debug probe before app construction. Must run here // because TLS/JA4 accessors are only available on FastlyRequest before diff --git a/crates/trusted-server-integration-tests/fixtures/configs/viceroy-template.toml b/crates/trusted-server-integration-tests/fixtures/configs/viceroy-template.toml index f11a67dff7..aa025b6c7f 100644 --- a/crates/trusted-server-integration-tests/fixtures/configs/viceroy-template.toml +++ b/crates/trusted-server-integration-tests/fixtures/configs/viceroy-template.toml @@ -66,28 +66,23 @@ key = "api_key" data = "test-api-key" - [[local_server.secret_stores.ts_secrets]] + [[local_server.secret_stores.trusted_server_secrets]] key = "integration_admin_password" data = "integration-admin-password-32-bytes-ok" - [[local_server.secret_stores.ts_secrets]] + [[local_server.secret_stores.trusted_server_secrets]] key = "integration_proxy_secret" data = "integration-test-proxy-secret-32-bytes-ok" - [[local_server.secret_stores.ts_secrets]] + [[local_server.secret_stores.trusted_server_secrets]] key = "integration_ec_passphrase" data = "integration-test-ec-secret-padded-32" - [[local_server.secret_stores.ts_secrets]] + [[local_server.secret_stores.trusted_server_secrets]] key = "integration_partner_token_alpha" data = "integration-test-token-alpha-32-bytes-ok" - [[local_server.secret_stores.ts_secrets]] + [[local_server.secret_stores.trusted_server_secrets]] key = "integration_partner_token_bravo" data = "integration-test-token-bravo-32-bytes-ok" [local_server.config_stores] - [local_server.config_stores.edgezero_runtime_env] - format = "inline-toml" - [local_server.config_stores.edgezero_runtime_env.contents] - EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME = "ts_secrets" - # Generated integration configs inject the trusted_server_config blob # into the store required by the Fastly entry point. # GENERATED_TRUSTED_SERVER_CONFIG_STORES diff --git a/crates/trusted-server-integration-tests/tests/common/config.rs b/crates/trusted-server-integration-tests/tests/common/config.rs index 60bb846604..1e83da3634 100644 --- a/crates/trusted-server-integration-tests/tests/common/config.rs +++ b/crates/trusted-server-integration-tests/tests/common/config.rs @@ -46,8 +46,7 @@ pub fn cloudflare_config_json(origin_port: u16) -> TestResult { mod tests { const FASTLY_CONFIG: &str = include_str!("../../../../fastly.toml"); const VICEROY_TEMPLATE: &str = include_str!("../../fixtures/configs/viceroy-template.toml"); - const VICEROY_SECRET_STORE_MAPPING_KEY: &str = - "EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME"; + const LOGICAL_SECRET_STORE_ID: &str = "trusted_server_secrets"; #[test] fn local_fastly_config_defines_runtime_kv_stores() { @@ -74,20 +73,24 @@ mod tests { } #[test] - fn local_fastly_secret_store_mapping_is_canonical() { + fn local_fastly_secret_store_is_exposed_under_its_logical_id() { for (name, config) in [ ("fastly.toml", FASTLY_CONFIG), ("Viceroy integration template", VICEROY_TEMPLATE), ] { let parsed: toml::Value = toml::from_str(config).expect("should parse Fastly configuration"); - let runtime_env = - &parsed["local_server"]["config_stores"]["edgezero_runtime_env"]["contents"]; + let local_server = &parsed["local_server"]; - assert_eq!( - runtime_env[VICEROY_SECRET_STORE_MAPPING_KEY].as_str(), - Some("ts_secrets"), - "{name} should define the canonical secret-store mapping" + assert!( + local_server["secret_stores"][LOGICAL_SECRET_STORE_ID].is_array(), + "{name} should expose the secret store under its logical ID" + ); + assert!( + local_server["config_stores"] + .get("edgezero_runtime_env") + .is_none(), + "{name} should not define the legacy runtime selector store" ); } } @@ -96,9 +99,9 @@ mod tests { fn local_fastly_config_defines_starter_secret_references() { let parsed: toml::Value = toml::from_str(FASTLY_CONFIG).expect("should parse root fastly.toml"); - let entries = parsed["local_server"]["secret_stores"]["ts_secrets"] + let entries = parsed["local_server"]["secret_stores"][LOGICAL_SECRET_STORE_ID] .as_array() - .expect("fastly.toml should define ts_secrets"); + .expect("fastly.toml should define trusted_server_secrets"); for key in [ "publisher_proxy_secret", diff --git a/docs/guide/cli.md b/docs/guide/cli.md index b133b95dc8..0173661ef0 100644 --- a/docs/guide/cli.md +++ b/docs/guide/cli.md @@ -118,30 +118,36 @@ deploy. Adapter passthrough arguments must now follow a `--` separator; unknown flags before `--` (including the renamed-away `--stage`) are rejected at parse time rather than forwarded. This is a change: passthrough args previously worked without the separator, so existing runbooks and CI jobs that pass -adapter flags directly need the `--` added: +adapter flags directly need the `--` added. Trusted Server declares Config, KV, +and Secret Stores, so EdgeZero treats every Fastly deploy as managed and +requires a verified application release root via `--application-release`; a +bare `ts deploy --adapter fastly` without a release is accepted only for +store-free applications: ```bash -ts deploy --adapter fastly --service-id --staging -ts deploy --adapter fastly -- --comment "release" +ts deploy --adapter fastly --service-id --application-release --staging +ts deploy --adapter fastly --service-id --application-release -- --comment "release" ``` A staged deploy selects the physical Config Store from the staging environment -and points the staged version's config selector at the -`_staging` key. It does not copy the production config blob -there. Push the staged config before probing the staged version: +and links it to the staged version under the logical store ID. The staged +runtime reads the `_staging` key from that store. It does not +copy the production config blob there. Push the staged config before probing +the staged version: ```bash ts config push --adapter fastly --staging ts config diff --adapter fastly --staging ``` -The staged version resolves its app-config key through a staging selector store -linked under the name `edgezero_runtime_env`. Production and staging may select -the same physical Config Store or different stores. After -`ts config push --staging`, the staged binary reads -`_staging` in the store selected by the staging environment, -while the active production version continues to read its production key and -store. +Config keys are deterministic on Fastly: production reads ``, +staging reads `_staging`, and local Viceroy reads the +production key. The binary decides which key to read from Fastly's staging +signal, not from a stored selector. Production and staging may select the same +physical Config Store or different stores. After `ts config push --staging`, +the staged binary reads `_staging` in the store selected by +the staging environment, while the active production version continues to read +its production key and store. `--staging` on `config push` / `config diff` writes and compares the `_staging` key in the physical store selected by the staging diff --git a/docs/guide/fastly.md b/docs/guide/fastly.md index 316f8c97be..d4244ab12c 100644 --- a/docs/guide/fastly.md +++ b/docs/guide/fastly.md @@ -275,27 +275,25 @@ export EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME=ts_secrets ts provision --adapter fastly ``` -Provisioning creates or reuses the physical store and the -`edgezero_runtime_env` Config Store, but does not write environment selectors. -Deployment copies the selected environment's declared store selectors into -`edgezero_runtime_env` under their canonical names: - -```text -EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME=ts_secrets -``` - -There is no Fastly service ID in the environment variable name. Each GitHub -Environment or deploy process uses the same canonical names and may select -different physical resources. A production deploy reconciles its selectors -into `edgezero_runtime_env`. A staged deploy creates a per-service staging twin, -applies the staging environment's selectors, links every selected physical -store to the staged version, and links the twin under the name -`edgezero_runtime_env`. Selected resources must already exist before deployment. - -The custom streaming entry point reads the deployed mapping before loading app -config, so every startup and reload resolves static credentials from -`ts_secrets` while the portable manifest continues to declare -`trusted_server_secrets`. +Provisioning creates or reuses the physical store. A managed deployment reads +the selector from its deployment environment and links the selected physical +store to the target service version under the logical ID +`trusted_server_secrets`. The runtime opens the store by that logical ID; no +selector is stored in a Config Store and no service ID appears in the variable +name. + +Each GitHub Environment or deploy process uses the same canonical names and may +select different physical resources. Production and staging can therefore run +identical package bytes against different stores. A staged deploy links the +staging environment's selected stores into only the staged version. Selected +resources must already exist before deployment. + +The custom streaming entry point opens `trusted_server_secrets` before loading +app config, so every startup and reload resolves static credentials from the +physical store linked under that ID while the portable manifest continues to +declare `trusted_server_secrets`. Local Viceroy configuration exposes the store +under the logical ID directly; see `[local_server.secret_stores]` in +`fastly.toml`. Create the separate request-signing store when that feature is enabled: diff --git a/docs/superpowers/plans/2026-09-16-edgezero-fastly-store-selectors.md b/docs/superpowers/plans/2026-09-16-edgezero-fastly-store-selectors.md index 7ccd3be2be..94145d9602 100644 --- a/docs/superpowers/plans/2026-09-16-edgezero-fastly-store-selectors.md +++ b/docs/superpowers/plans/2026-09-16-edgezero-fastly-store-selectors.md @@ -4,7 +4,7 @@ **Goal:** Restore Trusted Server staging deployments by consuming EdgeZero PR 381's canonical Fastly store-selector behavior and removing the superseded service-scoped configuration. -**Architecture:** Pin every EdgeZero workspace dependency to the upstream PR branch so the CLI and adapters share one revision. Keep Trusted Server's strict runtime secret resolution, while changing local Viceroy configuration, its regression test, and operator guidance to use canonical `EDGEZERO__STORES__...` selectors that EdgeZero applies during deployment. +**Architecture:** Pin every EdgeZero workspace dependency to the upstream PR branch so the CLI and adapters share one revision. Keep Trusted Server's strict runtime secret resolution, while moving the Fastly entry point, local Viceroy configuration, its regression test, and operator guidance to the logical-ID store model: EdgeZero links each physical store selected by a canonical `EDGEZERO__STORES__...` deployment selector under its logical ID, and the runtime opens stores by that ID. **Tech Stack:** Rust 1.95, Cargo Git dependencies, Fastly Compute/Viceroy TOML configuration, Markdown documentation, GitHub CLI. @@ -14,9 +14,10 @@ - `Cargo.toml`: select the EdgeZero PR 381 branch for all EdgeZero crates. - `Cargo.lock`: lock all EdgeZero packages to the branch revision. -- `fastly.toml`: use the canonical local Viceroy secret-store selector. -- `crates/trusted-server-integration-tests/fixtures/configs/viceroy-template.toml`: keep generated Viceroy integration configurations aligned with the root Fastly configuration. -- `crates/trusted-server-integration-tests/tests/common/config.rs`: regress the canonical selector in both Viceroy configurations. +- `crates/trusted-server-adapter-fastly/src/main.rs`, `crates/trusted-server-adapter-fastly/src/app.rs`: open stores by logical ID and derive the config key from Fastly's staging signal instead of reading `edgezero_runtime_env`. +- `fastly.toml`: expose the local Viceroy secret store under its logical ID and drop the runtime selector store. +- `crates/trusted-server-integration-tests/fixtures/configs/viceroy-template.toml`, `scripts/template-cache-local-test.sh`: keep generated Viceroy configurations aligned with the root Fastly configuration. +- `crates/trusted-server-integration-tests/tests/common/config.rs`: regress the logical-ID store exposure in both Viceroy configurations. - `docs/guide/fastly.md`: explain deploy-time canonical selector handling and physical store linking. - `docs/guide/cli.md`: explain staging Config Store selection under the restored EdgeZero deployment model. - `docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md`: approved design, already committed. @@ -49,54 +50,42 @@ gh issue create --repo IABTechLab/trusted-server --title "Align Fastly staging s Expected: GitHub prints the new issue URL. Save its issue number for the pull request body. -### Task 2: Regress Canonical Viceroy Selectors +### Task 2: Expose Viceroy Stores Under Their Logical IDs **Files:** - Modify: `crates/trusted-server-integration-tests/tests/common/config.rs:48` -- Modify: `fastly.toml:74` -- Modify: `crates/trusted-server-integration-tests/fixtures/configs/viceroy-template.toml:86` +- Modify: `fastly.toml:56` +- Modify: `crates/trusted-server-integration-tests/fixtures/configs/viceroy-template.toml:69` +- Modify: `scripts/template-cache-local-test.sh:372` - [ ] **Step 1: Change the regression test first** -Rename `local_fastly_secret_store_mapping_is_service_scoped` to -`local_fastly_secret_store_mapping_is_canonical`. Replace the service-scoped -constant with: - -```rust -const VICEROY_SECRET_STORE_MAPPING_KEY: &str = - "EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME"; -``` - -Assert that both parsed configurations map that key to `ts_secrets`. Remove the -assertion that rejects the canonical key. Keep assertion messages focused on the -canonical selector contract. +Replace `local_fastly_secret_store_mapping_is_service_scoped` with +`local_fastly_secret_store_is_exposed_under_its_logical_id`. Assert that both +parsed configurations define `[[local_server.secret_stores.trusted_server_secrets]]` +and define no `edgezero_runtime_env` Config Store. Point the starter secret +reference test at the logical ID as well. - [ ] **Step 2: Run the focused test and verify it fails** Run from `crates/trusted-server-integration-tests` using the host target: ```bash -cargo test --test integration local_fastly_secret_store_mapping_is_canonical --target aarch64-apple-darwin -``` - -Expected: FAIL because both TOML files still contain the service-scoped key. - -- [ ] **Step 3: Update the two Viceroy configurations** - -In both TOML files replace: - -```text -EDGEZERO__SERVICES__0000000000000000000000__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME +cargo test --test integration local_fastly --target aarch64-apple-darwin ``` -with: +Expected: FAIL because both TOML files still name the store `ts_secrets` and +still define `edgezero_runtime_env`. -```text -EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME -``` +- [ ] **Step 3: Update the Viceroy configurations** -Adjust the nearby root `fastly.toml` comment to call this a canonical selector. +In `fastly.toml`, the Viceroy template, and the template-cache script rename +`[[local_server.secret_stores.ts_secrets]]` to +`[[local_server.secret_stores.trusted_server_secrets]]`. Remove the +`[local_server.config_stores.edgezero_runtime_env]` table and its contents from +`fastly.toml` and the template. Adjust the nearby root `fastly.toml` comment to +say Viceroy exposes the store under its logical ID. - [ ] **Step 4: Run the focused test and verify it passes** @@ -107,8 +96,8 @@ Expected: PASS. - [ ] **Step 5: Commit the regression and fixtures** ```bash -git add fastly.toml crates/trusted-server-integration-tests/fixtures/configs/viceroy-template.toml crates/trusted-server-integration-tests/tests/common/config.rs -git commit -m "Use canonical Fastly secret store selectors" +git add fastly.toml scripts/template-cache-local-test.sh crates/trusted-server-integration-tests/fixtures/configs/viceroy-template.toml crates/trusted-server-integration-tests/tests/common/config.rs +git commit -m "Expose Viceroy stores under their logical IDs" ``` ### Task 3: Consume the EdgeZero PR Branch @@ -117,6 +106,8 @@ git commit -m "Use canonical Fastly secret store selectors" - Modify: `Cargo.toml:59` - Modify: `Cargo.lock` +- Modify: `crates/trusted-server-adapter-fastly/src/main.rs:92` +- Modify: `crates/trusted-server-adapter-fastly/src/app.rs:158` - [ ] **Step 1: Select the upstream branch consistently** @@ -139,6 +130,13 @@ revision, and the Trusted Server CLI compiles. If upstream API changes cause a compiler failure, make only the call-site changes required by that error and add a focused parsing or behavior test before the production edit. +The branch head removes `edgezero_adapter_fastly::runtime_env_config`. Replace +`RuntimeStoreConfig::from_env` with `RuntimeStoreConfig::for_target(staging)`: +open `trusted_server_config` and `trusted_server_secrets` by logical ID and +derive the config key with `EnvConfig::store_key_for_target`. Both entry points +pass `fastly::compute_runtime::is_staging()`. Cover the production and staging +keys with unit tests in `app.rs`. + - [ ] **Step 3: Verify the lockfile revision is consistent** Run: @@ -163,7 +161,7 @@ Expected: all non-ignored tests pass. - [ ] **Step 5: Commit the dependency update** ```bash -git add Cargo.toml Cargo.lock crates/trusted-server-cli +git add Cargo.toml Cargo.lock crates/trusted-server-adapter-fastly crates/trusted-server-cli git commit -m "Consume canonical EdgeZero deployment selectors" ``` @@ -183,27 +181,30 @@ Keep the canonical export example. Replace the statements that provisioning persists a service-scoped key and that unscoped keys are ignored with the PR 381 contract: -- provisioning creates/reuses resources and the `edgezero_runtime_env` store; -- deployment copies canonical selectors from its selected environment; -- production reconciles them into its runtime store; -- staging applies its selected physical stores to a per-service staging twin and - links those resources to the staged version; +- provisioning creates/reuses the physical store; +- a managed deployment reads canonical selectors from its selected environment + and links each selected physical store to the target version under its + logical ID; +- the runtime opens stores by logical ID; nothing is stored in + `edgezero_runtime_env`; +- staging links its selected physical stores into only the staged version; - canonical environment-variable names contain no service ID; - the selected physical resources must already exist. - [ ] **Step 2: Update staging CLI guidance** Clarify that `ts config push --staging` writes the staging key into the physical -Config Store selected by the staging environment, and `ts deploy --staging` -links a staging selector store that points at that key. State that production and -staging may select the same or different physical stores. +Config Store selected by the staging environment, and that the staged binary +reads `_staging` because Fastly reports it as staged, not +because of a stored selector. State that production and staging may select the +same or different physical stores. - [ ] **Step 3: Check for stale service-scoped guidance** Run: ```bash -rg -n 'EDGEZERO__SERVICES__|service-scoped mapping|ignored unscoped' fastly.toml docs crates/trusted-server-integration-tests --glob '!docs/superpowers/**' +rg -n 'EDGEZERO__SERVICES__|service-scoped mapping|ignored unscoped|edgezero_runtime_env' fastly.toml docs crates/trusted-server-integration-tests --glob '!docs/superpowers/**' ``` Expected: no matches outside archived design material. @@ -259,7 +260,7 @@ cargo test-axum cargo test-cloudflare cargo test-spin ./scripts/test-cli.sh -cargo test --manifest-path crates/trusted-server-integration-tests/Cargo.toml --test integration local_fastly_secret_store_mapping_is_canonical +cargo test --manifest-path crates/trusted-server-integration-tests/Cargo.toml --test integration local_fastly cargo test --manifest-path crates/trusted-server-integration-tests/Cargo.toml --test parity ``` diff --git a/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md b/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md index 2f99ce9c45..73788e865f 100644 --- a/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md +++ b/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md @@ -10,10 +10,12 @@ canonical selector to the physical store `ts_secrets`. Runtime settings then fail while resolving required secret references such as `publisher.proxy_secret`. -EdgeZero PR 381 restores canonical deploy-time selectors and makes staged -deployments link the selected physical Config, KV, and Secret Stores. Trusted -Server needs to consume that behavior and remove guidance for the superseded -service-scoped selector model. +EdgeZero PR 381 restores canonical deploy-time selectors and makes managed +deployments link each selected physical Config, KV, and Secret Store to the +target service version under its logical ID. The runtime opens stores by +logical ID and no longer reads selectors from an `edgezero_runtime_env` Config +Store; that store is legacy. Trusted Server needs to consume that behavior and +remove guidance for the superseded service-scoped and runtime-selector models. ## Design @@ -23,18 +25,21 @@ ensures the adapter, CLI, core, and platform-specific crates resolve to the same revision while PR 381 is under review. A follow-up will replace the branch with the release tag that contains the merged change. -Trusted Server's local Fastly runtime configuration will use the canonical -selector: +The Fastly entry point will stop reading `edgezero_runtime_env`. It will open +the config and secret stores by their logical IDs, `trusted_server_config` and +`trusted_server_secrets`, and derive the config entry key from Fastly's staging +signal through EdgeZero's target-key rule: production reads +`trusted_server_config`, staging reads `trusted_server_config_staging`. -```text -EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME=ts_secrets -``` +Local Viceroy configuration will expose the secret store under the logical ID +`trusted_server_secrets` and drop the `edgezero_runtime_env` Config Store, so +local runs exercise the same store-opening path as a deployed version. The Fastly and CLI guides will describe GitHub Environment or deploy-process variables as deployment inputs. They will no longer instruct operators to construct a selector containing a Fastly service ID or to persist that key -manually. EdgeZero remains responsible for applying the selected store mapping -to production or to the staged version during deployment. +manually. EdgeZero remains responsible for linking the selected physical stores +to the production or staged version during deployment. ## Failure Handling @@ -54,8 +59,9 @@ Validation will cover: - Trusted Server CLI parsing and behavior tests on the host target; - Fastly adapter compilation and tests where supported by the local toolchain; - Rust formatting and target-matched Clippy for changed Rust surfaces; -- searches confirming service-scoped store-selector instructions are removed - from current operator documentation and local Fastly configuration. +- searches confirming service-scoped store-selector instructions and + `edgezero_runtime_env` references are removed from current operator + documentation and local Fastly configuration. The issue will record the staging failure, expected canonical selector behavior, and the dependency on EdgeZero PR 381. The pull request will close that issue. diff --git a/fastly.toml b/fastly.toml index 532ff4926f..a2de865212 100644 --- a/fastly.toml +++ b/fastly.toml @@ -55,31 +55,26 @@ build = """ # Local-only values for the three secret references in # trusted-server.example.toml. These are public development fixtures. - [[local_server.secret_stores.ts_secrets]] + # App-config references use logical `trusted_server_secrets`. Viceroy + # exposes the store under that ID, matching the resource link a + # deployment creates for the selected physical store. + [[local_server.secret_stores.trusted_server_secrets]] key = "publisher_proxy_secret" data = "local-only-publisher-proxy-secret" - [[local_server.secret_stores.ts_secrets]] + [[local_server.secret_stores.trusted_server_secrets]] key = "ec_passphrase" data = "local-only-ec-passphrase-32-bytes" - [[local_server.secret_stores.ts_secrets]] + [[local_server.secret_stores.trusted_server_secrets]] key = "handler_password" data = "local-only-handler-password" - [[local_server.secret_stores.ts_secrets]] + [[local_server.secret_stores.trusted_server_secrets]] key = "tinybird_auction_append_token" data = "test-tinybird-auction-append-token" - # App-config references use logical `trusted_server_secrets`; the - # canonical selector below resolves it to physical `ts_secrets`. - [local_server.config_stores] - [local_server.config_stores.edgezero_runtime_env] - format = "inline-toml" - [local_server.config_stores.edgezero_runtime_env.contents] - EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME = "ts_secrets" - [local_server.config_stores.trusted_server_config] format = "inline-toml" [local_server.config_stores.trusted_server_config.contents] diff --git a/scripts/template-cache-local-test.sh b/scripts/template-cache-local-test.sh index 58d714cf82..a8a685a711 100755 --- a/scripts/template-cache-local-test.sh +++ b/scripts/template-cache-local-test.sh @@ -369,15 +369,15 @@ import sys with open(sys.argv[1], "a") as manifest: manifest.write(''' -[[local_server.secret_stores.ts_secrets]] +[[local_server.secret_stores.trusted_server_secrets]] key = "publisher_proxy_secret" data = "fictional-local-publisher-proxy-secret-value" -[[local_server.secret_stores.ts_secrets]] +[[local_server.secret_stores.trusted_server_secrets]] key = "ec_passphrase" data = "fictional-local-ec-passphrase-secret-value" -[[local_server.secret_stores.ts_secrets]] +[[local_server.secret_stores.trusted_server_secrets]] key = "handler_password" data = "fictional-local-handler-password-secret-value" ''') From d3bb29d6fd5edfc35de7e66d4dc116179d01fa33 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Thu, 17 Sep 2026 15:19:44 -0700 Subject: [PATCH 07/28] Read the Fastly config entry under its logical ID on every target Move the EdgeZero pin from 657bfdcb to 74207863. Upstream fixed the Fastly config key to the logical store ID for production, staging, and local Viceroy alike, removing the `_staging` suffix and `store_key_for_target`. Staging isolation now comes only from the physical Config Store the staging environment selects. Replace `RuntimeStoreConfig::for_target(staging)` with `logical()`, drop the staging signal from both entry points, and update the CLI guide, spec, and plan to describe the fixed key. --- Cargo.lock | 16 +++++----- .../trusted-server-adapter-fastly/src/app.rs | 32 ++++++------------- .../trusted-server-adapter-fastly/src/main.rs | 3 +- docs/guide/cli.md | 30 ++++++++--------- ...6-09-16-edgezero-fastly-store-selectors.md | 20 ++++++------ ...-edgezero-fastly-store-selectors-design.md | 6 ++-- 6 files changed, 45 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f6660115ed..6a2d540551 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1427,7 +1427,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#657bfdcb4dfaa1d901a74941812bf0b5fca78555" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7420786328c3069e6ec9655cbe9a97519e8f6b7a" dependencies = [ "toml", ] @@ -1435,7 +1435,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#657bfdcb4dfaa1d901a74941812bf0b5fca78555" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7420786328c3069e6ec9655cbe9a97519e8f6b7a" dependencies = [ "anyhow", "async-trait", @@ -1463,7 +1463,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#657bfdcb4dfaa1d901a74941812bf0b5fca78555" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7420786328c3069e6ec9655cbe9a97519e8f6b7a" dependencies = [ "anyhow", "async-trait", @@ -1486,7 +1486,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#657bfdcb4dfaa1d901a74941812bf0b5fca78555" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7420786328c3069e6ec9655cbe9a97519e8f6b7a" dependencies = [ "anyhow", "async-stream", @@ -1515,7 +1515,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#657bfdcb4dfaa1d901a74941812bf0b5fca78555" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7420786328c3069e6ec9655cbe9a97519e8f6b7a" dependencies = [ "anyhow", "async-trait", @@ -1542,7 +1542,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#657bfdcb4dfaa1d901a74941812bf0b5fca78555" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7420786328c3069e6ec9655cbe9a97519e8f6b7a" dependencies = [ "chrono", "clap", @@ -1567,7 +1567,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#657bfdcb4dfaa1d901a74941812bf0b5fca78555" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7420786328c3069e6ec9655cbe9a97519e8f6b7a" dependencies = [ "anyhow", "async-compression", @@ -1598,7 +1598,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#657bfdcb4dfaa1d901a74941812bf0b5fca78555" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7420786328c3069e6ec9655cbe9a97519e8f6b7a" dependencies = [ "log", "proc-macro2", diff --git a/crates/trusted-server-adapter-fastly/src/app.rs b/crates/trusted-server-adapter-fastly/src/app.rs index cbd29c02f8..9f538ad1cb 100644 --- a/crates/trusted-server-adapter-fastly/src/app.rs +++ b/crates/trusted-server-adapter-fastly/src/app.rs @@ -92,14 +92,12 @@ use crate::rate_limiter::{FastlyRateLimiter, RATE_COUNTER_NAME}; use edgezero_adapter_fastly::context::FastlyRequestContext; use edgezero_core::app::{App, Hooks, StoreMetadata, StoresMetadata}; use edgezero_core::context::RequestContext; -use edgezero_core::env_config::EnvConfig; use edgezero_core::error::EdgeError; use edgezero_core::http::{ HandlerFuture, HeaderValue, Method, Request, Response, StatusCode, header, }; use edgezero_core::router::RouterService; use error_stack::Report; -use fastly::compute_runtime; use trusted_server_core::auction::AuctionTelemetrySink; use trusted_server_core::auction::endpoints::handle_auction; use trusted_server_core::auction::{ @@ -162,20 +160,17 @@ pub(crate) struct RuntimeStoreConfig { } impl RuntimeStoreConfig { - /// Store bindings for the running Fastly publication target. + /// Store bindings for the Fastly runtime. /// /// Fastly Compute has no process environment. `EdgeZero` links each selected /// physical store to the service version under its logical ID, so the - /// runtime opens stores by logical ID and derives the config entry key from - /// the target alone: production reads ``, staging reads `_staging`. - pub(crate) fn for_target(staging: bool) -> Self { + /// runtime opens stores by logical ID and reads the config entry under + /// that same ID for every publication target. Staging isolation comes from + /// linking a different physical store, never from a different key. + pub(crate) fn logical() -> Self { Self { config_store_name: StoreName::from(DEFAULT_CONFIG_STORE_ID), - config_key: EnvConfig::default().store_key_for_target( - "config", - DEFAULT_CONFIG_STORE_ID, - staging, - ), + config_key: DEFAULT_CONFIG_STORE_ID.to_owned(), secret_store_name: StoreName::from(DEFAULT_SECRET_STORE_ID), } } @@ -1353,7 +1348,7 @@ impl Hooks for TrustedServerApp { } fn routes() -> RouterService { - let stores = RuntimeStoreConfig::for_target(compute_runtime::is_staging()); + let stores = RuntimeStoreConfig::logical(); Self::router_with_state(&stores).0 } @@ -1463,17 +1458,8 @@ mod tests { } #[test] - fn runtime_store_config_reads_the_staging_config_key_on_staging() { - let stores = RuntimeStoreConfig::for_target(true); - - assert_eq!(stores.config_store_name.as_ref(), "trusted_server_config"); - assert_eq!(stores.config_key, "trusted_server_config_staging"); - assert_eq!(stores.secret_store_name.as_ref(), "trusted_server_secrets"); - } - - #[test] - fn runtime_store_config_opens_logical_store_ids_in_production() { - let stores = RuntimeStoreConfig::for_target(false); + fn runtime_store_config_opens_logical_store_ids_and_key() { + let stores = RuntimeStoreConfig::logical(); assert_eq!(stores.config_store_name.as_ref(), "trusted_server_config"); assert_eq!(stores.config_key, "trusted_server_config"); diff --git a/crates/trusted-server-adapter-fastly/src/main.rs b/crates/trusted-server-adapter-fastly/src/main.rs index 0adfa712d5..92d915b390 100644 --- a/crates/trusted-server-adapter-fastly/src/main.rs +++ b/crates/trusted-server-adapter-fastly/src/main.rs @@ -8,7 +8,6 @@ use edgezero_core::error::EdgeError; use edgezero_core::http::{Request as HttpRequest, Response as HttpResponse}; use edgezero_core::response::IntoResponse; use error_stack::Report; -use fastly::compute_runtime; use fastly::http::Method as FastlyMethod; use fastly::{Request as FastlyRequest, Response as FastlyResponse}; @@ -89,7 +88,7 @@ fn main() { /// Handles a request through the `EdgeZero` router path. fn edgezero_main(mut req: FastlyRequest) { - let runtime_stores = RuntimeStoreConfig::for_target(compute_runtime::is_staging()); + let runtime_stores = RuntimeStoreConfig::logical(); // Short-circuit the JA4 debug probe before app construction. Must run here // because TLS/JA4 accessors are only available on FastlyRequest before diff --git a/docs/guide/cli.md b/docs/guide/cli.md index 0173661ef0..04f8ef3f00 100644 --- a/docs/guide/cli.md +++ b/docs/guide/cli.md @@ -131,29 +131,29 @@ ts deploy --adapter fastly --service-id --application-release _staging` key from that store. It does not -copy the production config blob there. Push the staged config before probing -the staged version: +runtime reads the `` key from that store. It does not copy +the production config blob there. Push the staged config before probing the +staged version: ```bash ts config push --adapter fastly --staging ts config diff --adapter fastly --staging ``` -Config keys are deterministic on Fastly: production reads ``, -staging reads `_staging`, and local Viceroy reads the -production key. The binary decides which key to read from Fastly's staging -signal, not from a stored selector. Production and staging may select the same -physical Config Store or different stores. After `ts config push --staging`, -the staged binary reads `_staging` in the store selected by -the staging environment, while the active production version continues to read -its production key and store. +The config key is fixed on Fastly: production, staging, and local Viceroy all +read ``. Staging isolation comes from the physical store the +staging environment selects with `EDGEZERO__STORES__CONFIG____NAME`, never +from a different key. Production and staging may select the same physical +Config Store or different stores. After `ts config push --staging`, the staged +binary reads `` in the store selected by the staging +environment, while the active production version continues to read the same +key in its own store. `--staging` on `config push` / `config diff` writes and compares the -`_staging` key in the physical store selected by the staging -environment. It is mutually exclusive with `--key`: the staging key is derived -from the store's logical id, so an explicit key would be written where nothing -reads it. +`` key in the physical store selected by the staging +environment. It is mutually exclusive with `--key`: Fastly accepts only the +logical store ID as the key for every target, so an explicit key would be +written where nothing reads it. Inspect and verify deployments with the deploy lifecycle commands. All three are Fastly-only — the axum, cloudflare, and spin adapters reject them: diff --git a/docs/superpowers/plans/2026-09-16-edgezero-fastly-store-selectors.md b/docs/superpowers/plans/2026-09-16-edgezero-fastly-store-selectors.md index 94145d9602..7eff8e023b 100644 --- a/docs/superpowers/plans/2026-09-16-edgezero-fastly-store-selectors.md +++ b/docs/superpowers/plans/2026-09-16-edgezero-fastly-store-selectors.md @@ -14,7 +14,7 @@ - `Cargo.toml`: select the EdgeZero PR 381 branch for all EdgeZero crates. - `Cargo.lock`: lock all EdgeZero packages to the branch revision. -- `crates/trusted-server-adapter-fastly/src/main.rs`, `crates/trusted-server-adapter-fastly/src/app.rs`: open stores by logical ID and derive the config key from Fastly's staging signal instead of reading `edgezero_runtime_env`. +- `crates/trusted-server-adapter-fastly/src/main.rs`, `crates/trusted-server-adapter-fastly/src/app.rs`: open stores and the config entry by logical ID instead of reading `edgezero_runtime_env`. - `fastly.toml`: expose the local Viceroy secret store under its logical ID and drop the runtime selector store. - `crates/trusted-server-integration-tests/fixtures/configs/viceroy-template.toml`, `scripts/template-cache-local-test.sh`: keep generated Viceroy configurations aligned with the root Fastly configuration. - `crates/trusted-server-integration-tests/tests/common/config.rs`: regress the logical-ID store exposure in both Viceroy configurations. @@ -131,11 +131,10 @@ compiler failure, make only the call-site changes required by that error and add a focused parsing or behavior test before the production edit. The branch head removes `edgezero_adapter_fastly::runtime_env_config`. Replace -`RuntimeStoreConfig::from_env` with `RuntimeStoreConfig::for_target(staging)`: -open `trusted_server_config` and `trusted_server_secrets` by logical ID and -derive the config key with `EnvConfig::store_key_for_target`. Both entry points -pass `fastly::compute_runtime::is_staging()`. Cover the production and staging -keys with unit tests in `app.rs`. +`RuntimeStoreConfig::from_env` with `RuntimeStoreConfig::logical()`: open +`trusted_server_config` and `trusted_server_secrets` by logical ID and read +the config entry under `trusted_server_config` for every target. Cover the +logical IDs and key with a unit test in `app.rs`. - [ ] **Step 3: Verify the lockfile revision is consistent** @@ -193,11 +192,10 @@ contract: - [ ] **Step 2: Update staging CLI guidance** -Clarify that `ts config push --staging` writes the staging key into the physical -Config Store selected by the staging environment, and that the staged binary -reads `_staging` because Fastly reports it as staged, not -because of a stored selector. State that production and staging may select the -same or different physical stores. +Clarify that `ts config push --staging` writes the logical key into the +physical Config Store selected by the staging environment, and that the staged +binary reads the same `` key there. State that production and +staging may select the same or different physical stores. - [ ] **Step 3: Check for stale service-scoped guidance** diff --git a/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md b/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md index 73788e865f..ae4c438e5c 100644 --- a/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md +++ b/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md @@ -27,9 +27,9 @@ the release tag that contains the merged change. The Fastly entry point will stop reading `edgezero_runtime_env`. It will open the config and secret stores by their logical IDs, `trusted_server_config` and -`trusted_server_secrets`, and derive the config entry key from Fastly's staging -signal through EdgeZero's target-key rule: production reads -`trusted_server_config`, staging reads `trusted_server_config_staging`. +`trusted_server_secrets`, and read the config entry under +`trusted_server_config` for every target. Staging isolation comes from the +physical store the staging environment selects, not from a different key. Local Viceroy configuration will expose the secret store under the logical ID `trusted_server_secrets` and drop the `edgezero_runtime_env` Config Store, so From 86a3df81c4ca50222b42b661bd35a68b8ccbcb4b Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Thu, 17 Sep 2026 23:13:08 -0700 Subject: [PATCH 08/28] Move the EdgeZero pin to the PR 381 branch head dbb95018 The only upstream change since 74207863 hardens immutable release publication in the Fastly CLI deploy path. No public API or runtime contract changed, so this is a lockfile-only update. --- Cargo.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6a2d540551..994c78f5ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1427,7 +1427,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7420786328c3069e6ec9655cbe9a97519e8f6b7a" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#dbb9501894f6190f66c13c298022d5bdcf319ac4" dependencies = [ "toml", ] @@ -1435,7 +1435,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7420786328c3069e6ec9655cbe9a97519e8f6b7a" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#dbb9501894f6190f66c13c298022d5bdcf319ac4" dependencies = [ "anyhow", "async-trait", @@ -1463,7 +1463,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7420786328c3069e6ec9655cbe9a97519e8f6b7a" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#dbb9501894f6190f66c13c298022d5bdcf319ac4" dependencies = [ "anyhow", "async-trait", @@ -1486,7 +1486,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7420786328c3069e6ec9655cbe9a97519e8f6b7a" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#dbb9501894f6190f66c13c298022d5bdcf319ac4" dependencies = [ "anyhow", "async-stream", @@ -1515,7 +1515,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7420786328c3069e6ec9655cbe9a97519e8f6b7a" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#dbb9501894f6190f66c13c298022d5bdcf319ac4" dependencies = [ "anyhow", "async-trait", @@ -1542,7 +1542,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7420786328c3069e6ec9655cbe9a97519e8f6b7a" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#dbb9501894f6190f66c13c298022d5bdcf319ac4" dependencies = [ "chrono", "clap", @@ -1567,7 +1567,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7420786328c3069e6ec9655cbe9a97519e8f6b7a" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#dbb9501894f6190f66c13c298022d5bdcf319ac4" dependencies = [ "anyhow", "async-compression", @@ -1598,7 +1598,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7420786328c3069e6ec9655cbe9a97519e8f6b7a" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#dbb9501894f6190f66c13c298022d5bdcf319ac4" dependencies = [ "log", "proc-macro2", From 2c433473beee60a69487bc699f641b305d2b771a Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Fri, 18 Sep 2026 10:57:10 -0700 Subject: [PATCH 09/28] Move the EdgeZero pin to the PR 381 branch head fba2076a The only upstream change since dbb95018 aligns the immutable release verifier with the complete set of adapter-manifest references in edgezero.toml. No public API or runtime contract changed, so this is a lockfile-only update. --- Cargo.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 994c78f5ae..78e5c51833 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1427,7 +1427,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#dbb9501894f6190f66c13c298022d5bdcf319ac4" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fba2076a082eb4f4b20b56006325f2297bbb310c" dependencies = [ "toml", ] @@ -1435,7 +1435,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#dbb9501894f6190f66c13c298022d5bdcf319ac4" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fba2076a082eb4f4b20b56006325f2297bbb310c" dependencies = [ "anyhow", "async-trait", @@ -1463,7 +1463,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#dbb9501894f6190f66c13c298022d5bdcf319ac4" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fba2076a082eb4f4b20b56006325f2297bbb310c" dependencies = [ "anyhow", "async-trait", @@ -1486,7 +1486,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#dbb9501894f6190f66c13c298022d5bdcf319ac4" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fba2076a082eb4f4b20b56006325f2297bbb310c" dependencies = [ "anyhow", "async-stream", @@ -1515,7 +1515,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#dbb9501894f6190f66c13c298022d5bdcf319ac4" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fba2076a082eb4f4b20b56006325f2297bbb310c" dependencies = [ "anyhow", "async-trait", @@ -1542,7 +1542,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#dbb9501894f6190f66c13c298022d5bdcf319ac4" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fba2076a082eb4f4b20b56006325f2297bbb310c" dependencies = [ "chrono", "clap", @@ -1567,7 +1567,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#dbb9501894f6190f66c13c298022d5bdcf319ac4" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fba2076a082eb4f4b20b56006325f2297bbb310c" dependencies = [ "anyhow", "async-compression", @@ -1598,7 +1598,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#dbb9501894f6190f66c13c298022d5bdcf319ac4" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fba2076a082eb4f4b20b56006325f2297bbb310c" dependencies = [ "log", "proc-macro2", From f9d959f2330c2fb70c8bb5fb3b90ef04f1485aba Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Fri, 18 Sep 2026 11:25:00 -0700 Subject: [PATCH 10/28] Move the EdgeZero pin to the PR 381 branch head c40ae8d0 The only upstream change since fba2076a scopes the Fastly release verifier and the config push preflight to the selected adapter. A Fastly config push no longer reads the Spin or Cloudflare manifests. No public API or runtime contract changed, so this is a lockfile-only update. --- Cargo.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 78e5c51833..2851046971 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1427,7 +1427,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fba2076a082eb4f4b20b56006325f2297bbb310c" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#c40ae8d0164e9adabe521bceeebd95ec492095dd" dependencies = [ "toml", ] @@ -1435,7 +1435,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fba2076a082eb4f4b20b56006325f2297bbb310c" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#c40ae8d0164e9adabe521bceeebd95ec492095dd" dependencies = [ "anyhow", "async-trait", @@ -1463,7 +1463,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fba2076a082eb4f4b20b56006325f2297bbb310c" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#c40ae8d0164e9adabe521bceeebd95ec492095dd" dependencies = [ "anyhow", "async-trait", @@ -1486,7 +1486,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fba2076a082eb4f4b20b56006325f2297bbb310c" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#c40ae8d0164e9adabe521bceeebd95ec492095dd" dependencies = [ "anyhow", "async-stream", @@ -1515,7 +1515,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fba2076a082eb4f4b20b56006325f2297bbb310c" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#c40ae8d0164e9adabe521bceeebd95ec492095dd" dependencies = [ "anyhow", "async-trait", @@ -1542,7 +1542,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fba2076a082eb4f4b20b56006325f2297bbb310c" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#c40ae8d0164e9adabe521bceeebd95ec492095dd" dependencies = [ "chrono", "clap", @@ -1567,7 +1567,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fba2076a082eb4f4b20b56006325f2297bbb310c" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#c40ae8d0164e9adabe521bceeebd95ec492095dd" dependencies = [ "anyhow", "async-compression", @@ -1598,7 +1598,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fba2076a082eb4f4b20b56006325f2297bbb310c" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#c40ae8d0164e9adabe521bceeebd95ec492095dd" dependencies = [ "log", "proc-macro2", From 713b27134d13262ee5728dff6ca92634f89d1305 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Fri, 18 Sep 2026 14:02:14 -0700 Subject: [PATCH 11/28] Move the EdgeZero pin to the PR 381 branch head 4531aeec Upstream now parses the live Fastly resource-link types (`config`, `kv-store`, `secret-store`), documents the custom entry point migration, and moves the release verifier into edgezero-adapter, which adds serde, serde_json, sha2, and walkdir edges under its cli feature. No public API used by Trusted Server changed, so this is a lockfile-only update. --- Cargo.lock | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2851046971..e5cb562410 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1427,15 +1427,19 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#c40ae8d0164e9adabe521bceeebd95ec492095dd" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#4531aeecfb5cc7ba57997a6b907f402c90f88eed" dependencies = [ + "serde", + "serde_json", + "sha2 0.10.9", "toml", + "walkdir", ] [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#c40ae8d0164e9adabe521bceeebd95ec492095dd" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#4531aeecfb5cc7ba57997a6b907f402c90f88eed" dependencies = [ "anyhow", "async-trait", @@ -1463,7 +1467,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#c40ae8d0164e9adabe521bceeebd95ec492095dd" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#4531aeecfb5cc7ba57997a6b907f402c90f88eed" dependencies = [ "anyhow", "async-trait", @@ -1486,7 +1490,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#c40ae8d0164e9adabe521bceeebd95ec492095dd" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#4531aeecfb5cc7ba57997a6b907f402c90f88eed" dependencies = [ "anyhow", "async-stream", @@ -1515,7 +1519,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#c40ae8d0164e9adabe521bceeebd95ec492095dd" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#4531aeecfb5cc7ba57997a6b907f402c90f88eed" dependencies = [ "anyhow", "async-trait", @@ -1542,7 +1546,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#c40ae8d0164e9adabe521bceeebd95ec492095dd" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#4531aeecfb5cc7ba57997a6b907f402c90f88eed" dependencies = [ "chrono", "clap", @@ -1567,7 +1571,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#c40ae8d0164e9adabe521bceeebd95ec492095dd" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#4531aeecfb5cc7ba57997a6b907f402c90f88eed" dependencies = [ "anyhow", "async-compression", @@ -1598,7 +1602,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#c40ae8d0164e9adabe521bceeebd95ec492095dd" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#4531aeecfb5cc7ba57997a6b907f402c90f88eed" dependencies = [ "log", "proc-macro2", From 3c9d8c05a30d01ab194f6f76840ce3f76f66d850 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Fri, 18 Sep 2026 14:16:51 -0700 Subject: [PATCH 12/28] Move the EdgeZero pin to the PR 381 branch head 7162b7e2 The two upstream commits since 4531aeec touch only the deploy action script and a demo lockfile. No crate source changed, so this is a lockfile-only update. --- Cargo.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e5cb562410..c9b545ca64 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1427,7 +1427,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#4531aeecfb5cc7ba57997a6b907f402c90f88eed" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7162b7e2b2a7d6e2dba7e02488881e6c873143b7" dependencies = [ "serde", "serde_json", @@ -1439,7 +1439,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#4531aeecfb5cc7ba57997a6b907f402c90f88eed" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7162b7e2b2a7d6e2dba7e02488881e6c873143b7" dependencies = [ "anyhow", "async-trait", @@ -1467,7 +1467,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#4531aeecfb5cc7ba57997a6b907f402c90f88eed" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7162b7e2b2a7d6e2dba7e02488881e6c873143b7" dependencies = [ "anyhow", "async-trait", @@ -1490,7 +1490,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#4531aeecfb5cc7ba57997a6b907f402c90f88eed" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7162b7e2b2a7d6e2dba7e02488881e6c873143b7" dependencies = [ "anyhow", "async-stream", @@ -1519,7 +1519,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#4531aeecfb5cc7ba57997a6b907f402c90f88eed" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7162b7e2b2a7d6e2dba7e02488881e6c873143b7" dependencies = [ "anyhow", "async-trait", @@ -1546,7 +1546,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#4531aeecfb5cc7ba57997a6b907f402c90f88eed" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7162b7e2b2a7d6e2dba7e02488881e6c873143b7" dependencies = [ "chrono", "clap", @@ -1571,7 +1571,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#4531aeecfb5cc7ba57997a6b907f402c90f88eed" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7162b7e2b2a7d6e2dba7e02488881e6c873143b7" dependencies = [ "anyhow", "async-compression", @@ -1602,7 +1602,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#4531aeecfb5cc7ba57997a6b907f402c90f88eed" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7162b7e2b2a7d6e2dba7e02488881e6c873143b7" dependencies = [ "log", "proc-macro2", From 9226cfbba9672d52d0c3d63fe0b754b08511f7d9 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Fri, 18 Sep 2026 14:41:13 -0700 Subject: [PATCH 13/28] Move the EdgeZero pin to the PR 381 branch head 8b506782 The two upstream commits since 7162b7e2 only reorganize the EdgeZero CI test workflows. No crate source changed, so this is a lockfile-only update. --- Cargo.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c9b545ca64..283e99dc04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1427,7 +1427,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7162b7e2b2a7d6e2dba7e02488881e6c873143b7" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8b5067821b0556c5e8df6d06a6bc2a2f07ec6c78" dependencies = [ "serde", "serde_json", @@ -1439,7 +1439,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7162b7e2b2a7d6e2dba7e02488881e6c873143b7" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8b5067821b0556c5e8df6d06a6bc2a2f07ec6c78" dependencies = [ "anyhow", "async-trait", @@ -1467,7 +1467,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7162b7e2b2a7d6e2dba7e02488881e6c873143b7" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8b5067821b0556c5e8df6d06a6bc2a2f07ec6c78" dependencies = [ "anyhow", "async-trait", @@ -1490,7 +1490,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7162b7e2b2a7d6e2dba7e02488881e6c873143b7" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8b5067821b0556c5e8df6d06a6bc2a2f07ec6c78" dependencies = [ "anyhow", "async-stream", @@ -1519,7 +1519,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7162b7e2b2a7d6e2dba7e02488881e6c873143b7" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8b5067821b0556c5e8df6d06a6bc2a2f07ec6c78" dependencies = [ "anyhow", "async-trait", @@ -1546,7 +1546,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7162b7e2b2a7d6e2dba7e02488881e6c873143b7" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8b5067821b0556c5e8df6d06a6bc2a2f07ec6c78" dependencies = [ "chrono", "clap", @@ -1571,7 +1571,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7162b7e2b2a7d6e2dba7e02488881e6c873143b7" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8b5067821b0556c5e8df6d06a6bc2a2f07ec6c78" dependencies = [ "anyhow", "async-compression", @@ -1602,7 +1602,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#7162b7e2b2a7d6e2dba7e02488881e6c873143b7" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8b5067821b0556c5e8df6d06a6bc2a2f07ec6c78" dependencies = [ "log", "proc-macro2", From 7d212b7d3182162e881e7208ac37abf92f945188 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Fri, 18 Sep 2026 15:31:21 -0700 Subject: [PATCH 14/28] Move the EdgeZero pin to the PR 381 branch head fd45db1f Upstream replaces the Compute-unsupported version diff snapshot with per-collection reads and drops the parent service ID comparison from the staged-source guard and staging rollback. No public API used by Trusted Server changed, so this is a lockfile-only update. --- Cargo.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 283e99dc04..7423518421 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1427,7 +1427,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8b5067821b0556c5e8df6d06a6bc2a2f07ec6c78" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fd45db1f8dbac02759333ff2364abd1c546a5722" dependencies = [ "serde", "serde_json", @@ -1439,7 +1439,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8b5067821b0556c5e8df6d06a6bc2a2f07ec6c78" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fd45db1f8dbac02759333ff2364abd1c546a5722" dependencies = [ "anyhow", "async-trait", @@ -1467,7 +1467,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8b5067821b0556c5e8df6d06a6bc2a2f07ec6c78" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fd45db1f8dbac02759333ff2364abd1c546a5722" dependencies = [ "anyhow", "async-trait", @@ -1490,7 +1490,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8b5067821b0556c5e8df6d06a6bc2a2f07ec6c78" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fd45db1f8dbac02759333ff2364abd1c546a5722" dependencies = [ "anyhow", "async-stream", @@ -1519,7 +1519,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8b5067821b0556c5e8df6d06a6bc2a2f07ec6c78" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fd45db1f8dbac02759333ff2364abd1c546a5722" dependencies = [ "anyhow", "async-trait", @@ -1546,7 +1546,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8b5067821b0556c5e8df6d06a6bc2a2f07ec6c78" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fd45db1f8dbac02759333ff2364abd1c546a5722" dependencies = [ "chrono", "clap", @@ -1571,7 +1571,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8b5067821b0556c5e8df6d06a6bc2a2f07ec6c78" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fd45db1f8dbac02759333ff2364abd1c546a5722" dependencies = [ "anyhow", "async-compression", @@ -1602,7 +1602,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#8b5067821b0556c5e8df6d06a6bc2a2f07ec6c78" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fd45db1f8dbac02759333ff2364abd1c546a5722" dependencies = [ "log", "proc-macro2", From c7483aa9245e3dea2bf16d197f40d2ca7b08b8a3 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Fri, 18 Sep 2026 16:21:33 -0700 Subject: [PATCH 15/28] Move the EdgeZero pin to the PR 381 branch head 6258b6b2 The only upstream change since fd45db1f corrects the Google Pub/Sub logging snapshot path to the Fastly API's `logging/pubsub` and adds `logentries` to the swept endpoint kinds. No public API used by Trusted Server changed, so this is a lockfile-only update. --- Cargo.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7423518421..5c1e1a4127 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1427,7 +1427,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fd45db1f8dbac02759333ff2364abd1c546a5722" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#6258b6b2f9b577079eeb78e5d2ecfe629320a262" dependencies = [ "serde", "serde_json", @@ -1439,7 +1439,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fd45db1f8dbac02759333ff2364abd1c546a5722" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#6258b6b2f9b577079eeb78e5d2ecfe629320a262" dependencies = [ "anyhow", "async-trait", @@ -1467,7 +1467,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fd45db1f8dbac02759333ff2364abd1c546a5722" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#6258b6b2f9b577079eeb78e5d2ecfe629320a262" dependencies = [ "anyhow", "async-trait", @@ -1490,7 +1490,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fd45db1f8dbac02759333ff2364abd1c546a5722" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#6258b6b2f9b577079eeb78e5d2ecfe629320a262" dependencies = [ "anyhow", "async-stream", @@ -1519,7 +1519,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fd45db1f8dbac02759333ff2364abd1c546a5722" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#6258b6b2f9b577079eeb78e5d2ecfe629320a262" dependencies = [ "anyhow", "async-trait", @@ -1546,7 +1546,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fd45db1f8dbac02759333ff2364abd1c546a5722" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#6258b6b2f9b577079eeb78e5d2ecfe629320a262" dependencies = [ "chrono", "clap", @@ -1571,7 +1571,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fd45db1f8dbac02759333ff2364abd1c546a5722" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#6258b6b2f9b577079eeb78e5d2ecfe629320a262" dependencies = [ "anyhow", "async-compression", @@ -1602,7 +1602,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#fd45db1f8dbac02759333ff2364abd1c546a5722" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#6258b6b2f9b577079eeb78e5d2ecfe629320a262" dependencies = [ "log", "proc-macro2", From 9380c12aff3b22be401a41d13302506c00f34747 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Fri, 18 Sep 2026 17:03:58 -0700 Subject: [PATCH 16/28] Move the EdgeZero pin to the PR 381 branch head bb4e0040 The only upstream change since 6258b6b2 switches the Fastly deploy to the current `service resource-link` and `service version` command spellings, removing the CLI deprecation notices. No public API used by Trusted Server changed, so this is a lockfile-only update. --- Cargo.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5c1e1a4127..d655fc4ed8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1427,7 +1427,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#6258b6b2f9b577079eeb78e5d2ecfe629320a262" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#bb4e0040e4f2af5a70e061660438099e3e12c691" dependencies = [ "serde", "serde_json", @@ -1439,7 +1439,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#6258b6b2f9b577079eeb78e5d2ecfe629320a262" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#bb4e0040e4f2af5a70e061660438099e3e12c691" dependencies = [ "anyhow", "async-trait", @@ -1467,7 +1467,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#6258b6b2f9b577079eeb78e5d2ecfe629320a262" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#bb4e0040e4f2af5a70e061660438099e3e12c691" dependencies = [ "anyhow", "async-trait", @@ -1490,7 +1490,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#6258b6b2f9b577079eeb78e5d2ecfe629320a262" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#bb4e0040e4f2af5a70e061660438099e3e12c691" dependencies = [ "anyhow", "async-stream", @@ -1519,7 +1519,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#6258b6b2f9b577079eeb78e5d2ecfe629320a262" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#bb4e0040e4f2af5a70e061660438099e3e12c691" dependencies = [ "anyhow", "async-trait", @@ -1546,7 +1546,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#6258b6b2f9b577079eeb78e5d2ecfe629320a262" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#bb4e0040e4f2af5a70e061660438099e3e12c691" dependencies = [ "chrono", "clap", @@ -1571,7 +1571,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#6258b6b2f9b577079eeb78e5d2ecfe629320a262" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#bb4e0040e4f2af5a70e061660438099e3e12c691" dependencies = [ "anyhow", "async-compression", @@ -1602,7 +1602,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#6258b6b2f9b577079eeb78e5d2ecfe629320a262" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#bb4e0040e4f2af5a70e061660438099e3e12c691" dependencies = [ "log", "proc-macro2", From b1d41c541e6e089764ef4b9bce404f56b3fd5e3b Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Fri, 18 Sep 2026 18:01:20 -0700 Subject: [PATCH 17/28] Move the EdgeZero pin to the PR 381 branch head cf9a96a0 The only crate change since bb4e0040 canonicalizes the Fastly configuration snapshot by sorting object keys before ordering rows, so the drift check no longer fails on Fastly's random JSON key order. No public API used by Trusted Server changed, so this is a lockfile-only update. --- Cargo.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d655fc4ed8..229bd71919 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1427,7 +1427,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#bb4e0040e4f2af5a70e061660438099e3e12c691" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#cf9a96a03d9bb3a7e902d2341185e7def6a00b00" dependencies = [ "serde", "serde_json", @@ -1439,7 +1439,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#bb4e0040e4f2af5a70e061660438099e3e12c691" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#cf9a96a03d9bb3a7e902d2341185e7def6a00b00" dependencies = [ "anyhow", "async-trait", @@ -1467,7 +1467,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#bb4e0040e4f2af5a70e061660438099e3e12c691" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#cf9a96a03d9bb3a7e902d2341185e7def6a00b00" dependencies = [ "anyhow", "async-trait", @@ -1490,7 +1490,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#bb4e0040e4f2af5a70e061660438099e3e12c691" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#cf9a96a03d9bb3a7e902d2341185e7def6a00b00" dependencies = [ "anyhow", "async-stream", @@ -1519,7 +1519,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#bb4e0040e4f2af5a70e061660438099e3e12c691" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#cf9a96a03d9bb3a7e902d2341185e7def6a00b00" dependencies = [ "anyhow", "async-trait", @@ -1546,7 +1546,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#bb4e0040e4f2af5a70e061660438099e3e12c691" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#cf9a96a03d9bb3a7e902d2341185e7def6a00b00" dependencies = [ "chrono", "clap", @@ -1571,7 +1571,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#bb4e0040e4f2af5a70e061660438099e3e12c691" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#cf9a96a03d9bb3a7e902d2341185e7def6a00b00" dependencies = [ "anyhow", "async-compression", @@ -1602,7 +1602,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#bb4e0040e4f2af5a70e061660438099e3e12c691" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#cf9a96a03d9bb3a7e902d2341185e7def6a00b00" dependencies = [ "log", "proc-macro2", From 429503979dc81a16e19e1b27b48eae79cf8c6c17 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Fri, 18 Sep 2026 18:41:47 -0700 Subject: [PATCH 18/28] Move the EdgeZero pin to the PR 381 branch head 119fbf80 The only upstream commit since cf9a96a0 adds a Cargo target cache to EdgeZero's CI. No crate source changed, so this is a lockfile-only update. --- Cargo.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 229bd71919..c2d6c9f17b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1427,7 +1427,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#cf9a96a03d9bb3a7e902d2341185e7def6a00b00" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#119fbf803f77e26fe23cbc595f00db408e5460a8" dependencies = [ "serde", "serde_json", @@ -1439,7 +1439,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#cf9a96a03d9bb3a7e902d2341185e7def6a00b00" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#119fbf803f77e26fe23cbc595f00db408e5460a8" dependencies = [ "anyhow", "async-trait", @@ -1467,7 +1467,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#cf9a96a03d9bb3a7e902d2341185e7def6a00b00" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#119fbf803f77e26fe23cbc595f00db408e5460a8" dependencies = [ "anyhow", "async-trait", @@ -1490,7 +1490,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#cf9a96a03d9bb3a7e902d2341185e7def6a00b00" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#119fbf803f77e26fe23cbc595f00db408e5460a8" dependencies = [ "anyhow", "async-stream", @@ -1519,7 +1519,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#cf9a96a03d9bb3a7e902d2341185e7def6a00b00" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#119fbf803f77e26fe23cbc595f00db408e5460a8" dependencies = [ "anyhow", "async-trait", @@ -1546,7 +1546,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#cf9a96a03d9bb3a7e902d2341185e7def6a00b00" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#119fbf803f77e26fe23cbc595f00db408e5460a8" dependencies = [ "chrono", "clap", @@ -1571,7 +1571,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#cf9a96a03d9bb3a7e902d2341185e7def6a00b00" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#119fbf803f77e26fe23cbc595f00db408e5460a8" dependencies = [ "anyhow", "async-compression", @@ -1602,7 +1602,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#cf9a96a03d9bb3a7e902d2341185e7def6a00b00" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#119fbf803f77e26fe23cbc595f00db408e5460a8" dependencies = [ "log", "proc-macro2", From 1e6fc674f27e4110866776469d9d197c9e49550d Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Fri, 18 Sep 2026 18:39:33 -0700 Subject: [PATCH 19/28] Watch only bundle inputs in the trusted-server-js build script The build script asked Cargo to rerun on every file under lib/, including node_modules, which emitted 33,932 rerun-if-changed directives in a 2.8 MB output that Cargo re-checked on every build and invalidated the crate after any npm install. Watch the TypeScript sources, package manifests, and bundler configuration explicitly instead. Measured on an Apple Silicon host with a warm cache: a no-op `cargo check -p trusted-server-js` drops from 1.1s to 0.15s, the script emits 7 directives, touching a node_modules file no longer reruns it, and touching lib/src or package-lock.json still does. --- crates/trusted-server-js/build.rs | 40 ++++++++++++------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/crates/trusted-server-js/build.rs b/crates/trusted-server-js/build.rs index ba6cd88f25..519f0bd71f 100644 --- a/crates/trusted-server-js/build.rs +++ b/crates/trusted-server-js/build.rs @@ -15,9 +15,21 @@ use build_print::{info, warn}; use sha2::{Digest as _, Sha256}; fn main() { - // Rebuild if TS sources change (belt-and-suspenders): enumerate every file under lib/ - println!("cargo:rerun-if-changed=lib"); - watch_dir_recursively(Path::new("lib")); + // Rebuild when the TypeScript sources or anything that shapes the bundle + // output changes. `lib` as a whole is deliberately not watched: it holds + // `node_modules`, and enumerating that tree emitted tens of thousands of + // directives that Cargo re-checked on every build. + for watched in [ + "lib/src", + "lib/package.json", + "lib/package-lock.json", + "lib/build-all.mjs", + "lib/build-prebid-external.mjs", + "lib/tsconfig.json", + "lib/vite.config.ts", + ] { + println!("cargo:rerun-if-changed={watched}"); + } // Allow opt-out or force via env let skip = env::var("TSJS_SKIP_BUILD").is_ok_and(|value| value == "1"); @@ -197,25 +209,3 @@ fn copy_bundle(filename: &str, required: bool, dist_dir: &Path, out_dir: &Path) fs::write(&target, "").expect("should write optional empty bundle placeholder"); } - -fn watch_dir_recursively(root: &Path) { - if !root.exists() { - return; - } - let mut stack = vec![root.to_path_buf()]; - while let Some(dir) = stack.pop() { - let Ok(read) = fs::read_dir(&dir) else { - continue; - }; - for entry in read.flatten() { - let path = entry.path(); - // Always ask Cargo to rerun if this path changes - if let Some(path_str) = path.to_str() { - println!("cargo:rerun-if-changed={path_str}"); - } - if path.is_dir() { - stack.push(path); - } - } - } -} From ae47b4350b0297be935f258c9e9d81d22426bf4c Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Fri, 18 Sep 2026 18:50:52 -0700 Subject: [PATCH 20/28] Move the EdgeZero pin to the PR 381 branch head 5878eb74 The only upstream commit since 119fbf80 fixes a shellcheck finding in EdgeZero's CI cache action. No crate source changed, so this is a lockfile-only update. --- Cargo.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c2d6c9f17b..25197f4e60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1427,7 +1427,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#119fbf803f77e26fe23cbc595f00db408e5460a8" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#5878eb740897749e4cfab7b410fa28791a371602" dependencies = [ "serde", "serde_json", @@ -1439,7 +1439,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#119fbf803f77e26fe23cbc595f00db408e5460a8" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#5878eb740897749e4cfab7b410fa28791a371602" dependencies = [ "anyhow", "async-trait", @@ -1467,7 +1467,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#119fbf803f77e26fe23cbc595f00db408e5460a8" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#5878eb740897749e4cfab7b410fa28791a371602" dependencies = [ "anyhow", "async-trait", @@ -1490,7 +1490,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#119fbf803f77e26fe23cbc595f00db408e5460a8" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#5878eb740897749e4cfab7b410fa28791a371602" dependencies = [ "anyhow", "async-stream", @@ -1519,7 +1519,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#119fbf803f77e26fe23cbc595f00db408e5460a8" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#5878eb740897749e4cfab7b410fa28791a371602" dependencies = [ "anyhow", "async-trait", @@ -1546,7 +1546,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#119fbf803f77e26fe23cbc595f00db408e5460a8" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#5878eb740897749e4cfab7b410fa28791a371602" dependencies = [ "chrono", "clap", @@ -1571,7 +1571,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#119fbf803f77e26fe23cbc595f00db408e5460a8" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#5878eb740897749e4cfab7b410fa28791a371602" dependencies = [ "anyhow", "async-compression", @@ -1602,7 +1602,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#119fbf803f77e26fe23cbc595f00db408e5460a8" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#5878eb740897749e4cfab7b410fa28791a371602" dependencies = [ "log", "proc-macro2", From 6e9c50ca51d8fd3a9295f134d95e92fddc128e7a Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Sun, 20 Sep 2026 00:32:31 -0700 Subject: [PATCH 21/28] Select the release manifest in the CLI deploy examples `ts deploy --application-release` does not choose the release's manifest. The CLI loads `edgezero.toml` from the working directory unless `EDGEZERO_MANIFEST` names another file, and it rejects a manifest outside the release root, so both documented commands failed from the checkout root with "loaded application manifest ... is outside application release root" before reaching Fastly. Set `EDGEZERO_MANIFEST` to the release's manifest in both examples, as the EdgeZero deploy action does, and say where the release root comes from. --- docs/guide/cli.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/docs/guide/cli.md b/docs/guide/cli.md index 04f8ef3f00..7231e3d82e 100644 --- a/docs/guide/cli.md +++ b/docs/guide/cli.md @@ -122,13 +122,24 @@ adapter flags directly need the `--` added. Trusted Server declares Config, KV, and Secret Stores, so EdgeZero treats every Fastly deploy as managed and requires a verified application release root via `--application-release`; a bare `ts deploy --adapter fastly` without a release is accepted only for -store-free applications: +store-free applications. The CLI loads `edgezero.toml` from the working +directory unless `EDGEZERO_MANIFEST` names another file, and it rejects a +manifest outside the release root, so select the release's own manifest: ```bash -ts deploy --adapter fastly --service-id --application-release --staging -ts deploy --adapter fastly --service-id --application-release -- --comment "release" +EDGEZERO_MANIFEST="/edgezero.toml" \ + ts deploy --adapter fastly --service-id --application-release "" --staging +EDGEZERO_MANIFEST="/edgezero.toml" \ + ts deploy --adapter fastly --service-id --application-release "" -- --comment "release" ``` +`` is the extracted immutable application release that EdgeZero's +`package-fastly-application-release` action produces from a `ts build`. The +EdgeZero `deploy-fastly` action performs both steps, selects the manifest, and +supplies the release root; see EdgeZero's GitHub Actions deployment guide +(`docs/guide/deploy-github-actions.md` in the EdgeZero repository) for the +producer and consumer workflow. + A staged deploy selects the physical Config Store from the staging environment and links it to the staged version under the logical store ID. The staged runtime reads the `` key from that store. It does not copy From d6fecdf8a24fba7a5a9b916cd0f3dfc6a6876877 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Sun, 20 Sep 2026 10:56:57 -0700 Subject: [PATCH 22/28] Move the EdgeZero pin to the PR 381 branch head 12c3215c Upstream merged main into the branch, which renames the staged-deploy identifiers to the staging naming. Trusted Server references none of the renamed variants, so this is a lockfile-only update. --- Cargo.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 25197f4e60..62bca56107 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1427,7 +1427,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#5878eb740897749e4cfab7b410fa28791a371602" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#12c3215c2637d961a27eefa12e235033fadb4c4a" dependencies = [ "serde", "serde_json", @@ -1439,7 +1439,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#5878eb740897749e4cfab7b410fa28791a371602" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#12c3215c2637d961a27eefa12e235033fadb4c4a" dependencies = [ "anyhow", "async-trait", @@ -1467,7 +1467,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#5878eb740897749e4cfab7b410fa28791a371602" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#12c3215c2637d961a27eefa12e235033fadb4c4a" dependencies = [ "anyhow", "async-trait", @@ -1490,7 +1490,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#5878eb740897749e4cfab7b410fa28791a371602" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#12c3215c2637d961a27eefa12e235033fadb4c4a" dependencies = [ "anyhow", "async-stream", @@ -1519,7 +1519,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#5878eb740897749e4cfab7b410fa28791a371602" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#12c3215c2637d961a27eefa12e235033fadb4c4a" dependencies = [ "anyhow", "async-trait", @@ -1546,7 +1546,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#5878eb740897749e4cfab7b410fa28791a371602" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#12c3215c2637d961a27eefa12e235033fadb4c4a" dependencies = [ "chrono", "clap", @@ -1571,7 +1571,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#5878eb740897749e4cfab7b410fa28791a371602" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#12c3215c2637d961a27eefa12e235033fadb4c4a" dependencies = [ "anyhow", "async-compression", @@ -1602,7 +1602,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#5878eb740897749e4cfab7b410fa28791a371602" +source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#12c3215c2637d961a27eefa12e235033fadb4c4a" dependencies = [ "log", "proc-macro2", From a1710a059c0401447f4ac7e033799d07cbcf0081 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Wed, 23 Sep 2026 23:04:58 -0700 Subject: [PATCH 23/28] Pin EdgeZero to an immutable rev and close the review findings Replace the mutable `branch =` pin on all six EdgeZero dependencies with `rev = "12c3215c2637d961a27eefa12e235033fadb4c4a"`, the commit the lockfile already resolved, so `main` stays reproducible and no `cargo update` or upstream force-push can move it. Issue #1195 tracks replacing the rev with the release tag once the upstream PR merges. Assert the legacy physical `ts_secrets` store is absent from both Viceroy configurations, so a squash merge that resurrects the block fails instead of writing entries into a store nothing opens. Correct the `RuntimeStoreConfig::logical` doc comment: the crate does read the process environment elsewhere, so state the real invariant, that no store selector reaches the runtime. Document the Config Store selector in the Fastly guide alongside the secrets one, and drop the leftover instruction not to create a `trusted_server_secrets` link, which the deployment now creates itself. --- Cargo.lock | 16 ++++++++-------- Cargo.toml | 12 ++++++------ crates/trusted-server-adapter-fastly/src/app.rs | 11 ++++++----- .../tests/common/config.rs | 4 ++++ docs/guide/fastly.md | 14 ++++++++++++-- 5 files changed, 36 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d5b777858a..0aadf37619 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1427,7 +1427,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#12c3215c2637d961a27eefa12e235033fadb4c4a" +source = "git+https://github.com/stackpop/edgezero?rev=12c3215c2637d961a27eefa12e235033fadb4c4a#12c3215c2637d961a27eefa12e235033fadb4c4a" dependencies = [ "serde", "serde_json", @@ -1439,7 +1439,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#12c3215c2637d961a27eefa12e235033fadb4c4a" +source = "git+https://github.com/stackpop/edgezero?rev=12c3215c2637d961a27eefa12e235033fadb4c4a#12c3215c2637d961a27eefa12e235033fadb4c4a" dependencies = [ "anyhow", "async-trait", @@ -1467,7 +1467,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#12c3215c2637d961a27eefa12e235033fadb4c4a" +source = "git+https://github.com/stackpop/edgezero?rev=12c3215c2637d961a27eefa12e235033fadb4c4a#12c3215c2637d961a27eefa12e235033fadb4c4a" dependencies = [ "anyhow", "async-trait", @@ -1490,7 +1490,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#12c3215c2637d961a27eefa12e235033fadb4c4a" +source = "git+https://github.com/stackpop/edgezero?rev=12c3215c2637d961a27eefa12e235033fadb4c4a#12c3215c2637d961a27eefa12e235033fadb4c4a" dependencies = [ "anyhow", "async-stream", @@ -1519,7 +1519,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#12c3215c2637d961a27eefa12e235033fadb4c4a" +source = "git+https://github.com/stackpop/edgezero?rev=12c3215c2637d961a27eefa12e235033fadb4c4a#12c3215c2637d961a27eefa12e235033fadb4c4a" dependencies = [ "anyhow", "async-trait", @@ -1546,7 +1546,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#12c3215c2637d961a27eefa12e235033fadb4c4a" +source = "git+https://github.com/stackpop/edgezero?rev=12c3215c2637d961a27eefa12e235033fadb4c4a#12c3215c2637d961a27eefa12e235033fadb4c4a" dependencies = [ "chrono", "clap", @@ -1571,7 +1571,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#12c3215c2637d961a27eefa12e235033fadb4c4a" +source = "git+https://github.com/stackpop/edgezero?rev=12c3215c2637d961a27eefa12e235033fadb4c4a#12c3215c2637d961a27eefa12e235033fadb4c4a" dependencies = [ "anyhow", "async-compression", @@ -1602,7 +1602,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=fix%2Ffastly-environment-store-selectors#12c3215c2637d961a27eefa12e235033fadb4c4a" +source = "git+https://github.com/stackpop/edgezero?rev=12c3215c2637d961a27eefa12e235033fadb4c4a#12c3215c2637d961a27eefa12e235033fadb4c4a" dependencies = [ "log", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 5476d07605..75060c4c7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,12 +55,12 @@ cssparser = "0.36" 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", branch = "fix/fastly-environment-store-selectors", default-features = false } -edgezero-adapter-cloudflare = { git = "https://github.com/stackpop/edgezero", branch = "fix/fastly-environment-store-selectors", default-features = false } -edgezero-adapter-fastly = { git = "https://github.com/stackpop/edgezero", branch = "fix/fastly-environment-store-selectors", default-features = false } -edgezero-adapter-spin = { git = "https://github.com/stackpop/edgezero", branch = "fix/fastly-environment-store-selectors", default-features = false } -edgezero-cli = { git = "https://github.com/stackpop/edgezero", branch = "fix/fastly-environment-store-selectors" } -edgezero-core = { git = "https://github.com/stackpop/edgezero", branch = "fix/fastly-environment-store-selectors", default-features = false } +edgezero-adapter-axum = { git = "https://github.com/stackpop/edgezero", rev = "12c3215c2637d961a27eefa12e235033fadb4c4a", default-features = false } +edgezero-adapter-cloudflare = { git = "https://github.com/stackpop/edgezero", rev = "12c3215c2637d961a27eefa12e235033fadb4c4a", default-features = false } +edgezero-adapter-fastly = { git = "https://github.com/stackpop/edgezero", rev = "12c3215c2637d961a27eefa12e235033fadb4c4a", default-features = false } +edgezero-adapter-spin = { git = "https://github.com/stackpop/edgezero", rev = "12c3215c2637d961a27eefa12e235033fadb4c4a", default-features = false } +edgezero-cli = { git = "https://github.com/stackpop/edgezero", rev = "12c3215c2637d961a27eefa12e235033fadb4c4a" } +edgezero-core = { git = "https://github.com/stackpop/edgezero", rev = "12c3215c2637d961a27eefa12e235033fadb4c4a", default-features = false } env_logger = "0.11" error-stack = "0.6" esi = "0.7.2" diff --git a/crates/trusted-server-adapter-fastly/src/app.rs b/crates/trusted-server-adapter-fastly/src/app.rs index 9f538ad1cb..0829045ff6 100644 --- a/crates/trusted-server-adapter-fastly/src/app.rs +++ b/crates/trusted-server-adapter-fastly/src/app.rs @@ -162,11 +162,12 @@ pub(crate) struct RuntimeStoreConfig { impl RuntimeStoreConfig { /// Store bindings for the Fastly runtime. /// - /// Fastly Compute has no process environment. `EdgeZero` links each selected - /// physical store to the service version under its logical ID, so the - /// runtime opens stores by logical ID and reads the config entry under - /// that same ID for every publication target. Staging isolation comes from - /// linking a different physical store, never from a different key. + /// Store selection is a deploy-time input; no store selector reaches the + /// Fastly runtime. `EdgeZero` links each selected physical store to the + /// service version under its logical ID, so the runtime opens stores by + /// logical ID and reads the config entry under that same ID for every + /// publication target. Staging isolation comes from linking a different + /// physical store, never from a different key. pub(crate) fn logical() -> Self { Self { config_store_name: StoreName::from(DEFAULT_CONFIG_STORE_ID), diff --git a/crates/trusted-server-integration-tests/tests/common/config.rs b/crates/trusted-server-integration-tests/tests/common/config.rs index 1e83da3634..b8eeb07836 100644 --- a/crates/trusted-server-integration-tests/tests/common/config.rs +++ b/crates/trusted-server-integration-tests/tests/common/config.rs @@ -86,6 +86,10 @@ mod tests { local_server["secret_stores"][LOGICAL_SECRET_STORE_ID].is_array(), "{name} should expose the secret store under its logical ID" ); + assert!( + local_server["secret_stores"].get("ts_secrets").is_none(), + "{name} should not define the legacy physical secret store" + ); assert!( local_server["config_stores"] .get("edgezero_runtime_env") diff --git a/docs/guide/fastly.md b/docs/guide/fastly.md index cfd3df15ab..4ec64ebefd 100644 --- a/docs/guide/fastly.md +++ b/docs/guide/fastly.md @@ -271,6 +271,16 @@ Used for storing public configuration (e.g., public keys, key metadata): fastly config-store create --name jwks_store ``` +Trusted Server's app config lives under logical store ID +`trusted_server_config`. Select its physical store in each deployment +environment, the same way as the secret store below. Production and staging +isolate their app config by selecting different physical stores, because the +config entry key is the logical ID on every target: + +```bash +export EDGEZERO__STORES__CONFIG__TRUSTED_SERVER_CONFIG__NAME= +``` + ### Secret Stores Trusted Server keeps static app-config credentials under logical store ID @@ -312,8 +322,8 @@ Create the separate request-signing store when that feature is enabled: fastly secret-store create --name signing_keys ``` -Do not copy the same app credential store under a second hardcoded -`trusted_server_secrets` Fastly link. Configure the mapping instead. +The deployment creates the `trusted_server_secrets` link itself from the +selected physical store. Do not create that link by hand. ## Create EC KV Store From 86695c304806e5a512b8f4809027b897e285ed73 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Fri, 2 Oct 2026 12:50:23 -0700 Subject: [PATCH 24/28] Address deployment-documentation review and repin EdgeZero Correct the application-release instructions: the action is `package-application-release-fastly`, and `deploy-fastly` consumes a prebuilt archive rather than building one. Warn that `config push --staging` on Fastly selects neither a different store nor a different key. The physical store is whatever EDGEZERO__STORES__CONFIG____NAME resolves to in the shell running the push, so a staged push into the production store overwrites the live entry. Set the selector explicitly in both examples. Add an upgrade section for services deployed before logical store links. Only a managed deploy creates the `trusted_server_secrets` link, so `fastly compute publish` activates a version whose link is missing and every publisher route returns 500 while /health still answers 200. Replace that command in the getting-started guide and AGENTS.md, and annotate the manifest deploy command that EdgeZero never runs for a store-declaring app. Fix the Fastly smoke script. It appended and stripped `ts_secrets` blocks, which nothing opens now, and the base manifest defines the same three keys under indented headers, so removing an appended block still left a resolvable value and no missing-secret case could fail. Match either indentation and strip the base entries on copy. Repin to upstream c2e862f4, eight commits ahead of 12c3215c, and update the test for the key-selector change it brings: with no --key the CLI now writes to EDGEZERO__STORES__CONFIG____KEY instead of ignoring it. Also correct the contradicting staging-key sentence in the EdgeZero guide, the design spec's branch wording, and two stale test messages. --- AGENTS.md | 5 ++- Cargo.lock | 16 ++++---- Cargo.toml | 12 +++--- crates/trusted-server-cli/src/run.rs | 4 +- .../tests/config_store_defaults.rs | 16 ++++++-- docs/guide/cli.md | 41 ++++++++++--------- docs/guide/edgezero.md | 6 ++- docs/guide/fastly.md | 37 +++++++++++++---- docs/guide/getting-started.md | 14 ++++++- ...-edgezero-fastly-store-selectors-design.md | 7 ++-- edgezero.toml | 5 +++ scripts/smoke-fastly.sh | 30 +++++++++++--- 12 files changed, 135 insertions(+), 58 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index b6e61ecf9e..95cdaa5319 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -56,8 +56,9 @@ cargo build --package trusted-server-adapter-fastly --release --target wasm32-wa # Run locally with Fastly simulator fastly compute serve -# Deploy to Fastly -fastly compute publish +# Deploy to Fastly (managed path; links logical stores to the version) +EDGEZERO_MANIFEST="/edgezero.toml" \ + ts deploy --adapter fastly --service-id --application-release "" # Run Axum dev server (native — no Viceroy) cargo run -p trusted-server-adapter-axum diff --git a/Cargo.lock b/Cargo.lock index 6f18bb3294..f5bc297686 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1428,7 +1428,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?rev=12c3215c2637d961a27eefa12e235033fadb4c4a#12c3215c2637d961a27eefa12e235033fadb4c4a" +source = "git+https://github.com/stackpop/edgezero?rev=c2e862f436421cdcfbac620c06995f262d6788c9#c2e862f436421cdcfbac620c06995f262d6788c9" dependencies = [ "serde", "serde_json", @@ -1440,7 +1440,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?rev=12c3215c2637d961a27eefa12e235033fadb4c4a#12c3215c2637d961a27eefa12e235033fadb4c4a" +source = "git+https://github.com/stackpop/edgezero?rev=c2e862f436421cdcfbac620c06995f262d6788c9#c2e862f436421cdcfbac620c06995f262d6788c9" dependencies = [ "anyhow", "async-trait", @@ -1468,7 +1468,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?rev=12c3215c2637d961a27eefa12e235033fadb4c4a#12c3215c2637d961a27eefa12e235033fadb4c4a" +source = "git+https://github.com/stackpop/edgezero?rev=c2e862f436421cdcfbac620c06995f262d6788c9#c2e862f436421cdcfbac620c06995f262d6788c9" dependencies = [ "anyhow", "async-trait", @@ -1491,7 +1491,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?rev=12c3215c2637d961a27eefa12e235033fadb4c4a#12c3215c2637d961a27eefa12e235033fadb4c4a" +source = "git+https://github.com/stackpop/edgezero?rev=c2e862f436421cdcfbac620c06995f262d6788c9#c2e862f436421cdcfbac620c06995f262d6788c9" dependencies = [ "anyhow", "async-stream", @@ -1520,7 +1520,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?rev=12c3215c2637d961a27eefa12e235033fadb4c4a#12c3215c2637d961a27eefa12e235033fadb4c4a" +source = "git+https://github.com/stackpop/edgezero?rev=c2e862f436421cdcfbac620c06995f262d6788c9#c2e862f436421cdcfbac620c06995f262d6788c9" dependencies = [ "anyhow", "async-trait", @@ -1547,7 +1547,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?rev=12c3215c2637d961a27eefa12e235033fadb4c4a#12c3215c2637d961a27eefa12e235033fadb4c4a" +source = "git+https://github.com/stackpop/edgezero?rev=c2e862f436421cdcfbac620c06995f262d6788c9#c2e862f436421cdcfbac620c06995f262d6788c9" dependencies = [ "chrono", "clap", @@ -1572,7 +1572,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?rev=12c3215c2637d961a27eefa12e235033fadb4c4a#12c3215c2637d961a27eefa12e235033fadb4c4a" +source = "git+https://github.com/stackpop/edgezero?rev=c2e862f436421cdcfbac620c06995f262d6788c9#c2e862f436421cdcfbac620c06995f262d6788c9" dependencies = [ "anyhow", "async-compression", @@ -1603,7 +1603,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?rev=12c3215c2637d961a27eefa12e235033fadb4c4a#12c3215c2637d961a27eefa12e235033fadb4c4a" +source = "git+https://github.com/stackpop/edgezero?rev=c2e862f436421cdcfbac620c06995f262d6788c9#c2e862f436421cdcfbac620c06995f262d6788c9" dependencies = [ "log", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 75060c4c7d..ec7aab77f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,12 +55,12 @@ cssparser = "0.36" 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", rev = "12c3215c2637d961a27eefa12e235033fadb4c4a", default-features = false } -edgezero-adapter-cloudflare = { git = "https://github.com/stackpop/edgezero", rev = "12c3215c2637d961a27eefa12e235033fadb4c4a", default-features = false } -edgezero-adapter-fastly = { git = "https://github.com/stackpop/edgezero", rev = "12c3215c2637d961a27eefa12e235033fadb4c4a", default-features = false } -edgezero-adapter-spin = { git = "https://github.com/stackpop/edgezero", rev = "12c3215c2637d961a27eefa12e235033fadb4c4a", default-features = false } -edgezero-cli = { git = "https://github.com/stackpop/edgezero", rev = "12c3215c2637d961a27eefa12e235033fadb4c4a" } -edgezero-core = { git = "https://github.com/stackpop/edgezero", rev = "12c3215c2637d961a27eefa12e235033fadb4c4a", default-features = false } +edgezero-adapter-axum = { git = "https://github.com/stackpop/edgezero", rev = "c2e862f436421cdcfbac620c06995f262d6788c9", default-features = false } +edgezero-adapter-cloudflare = { git = "https://github.com/stackpop/edgezero", rev = "c2e862f436421cdcfbac620c06995f262d6788c9", default-features = false } +edgezero-adapter-fastly = { git = "https://github.com/stackpop/edgezero", rev = "c2e862f436421cdcfbac620c06995f262d6788c9", default-features = false } +edgezero-adapter-spin = { git = "https://github.com/stackpop/edgezero", rev = "c2e862f436421cdcfbac620c06995f262d6788c9", default-features = false } +edgezero-cli = { git = "https://github.com/stackpop/edgezero", rev = "c2e862f436421cdcfbac620c06995f262d6788c9" } +edgezero-core = { git = "https://github.com/stackpop/edgezero", rev = "c2e862f436421cdcfbac620c06995f262d6788c9", default-features = false } env_logger = "0.11" error-stack = "0.6" esi = "0.7.2" diff --git a/crates/trusted-server-cli/src/run.rs b/crates/trusted-server-cli/src/run.rs index e06bb998c5..eb0099b651 100644 --- a/crates/trusted-server-cli/src/run.rs +++ b/crates/trusted-server-cli/src/run.rs @@ -495,7 +495,7 @@ mod tests { let Command::Config(ConfigCommand::Push(push)) = args.command else { panic!("expected config push command"); }; - assert!(push.staging, "should target the derived staging key"); + assert!(push.staging, "should target the staging publication flow"); Args::try_parse_from([ "ts", @@ -518,7 +518,7 @@ mod tests { }; assert!( diff.staging, - "should compare against the derived staging key" + "should compare against the staging publication flow" ); Args::try_parse_from([ diff --git a/crates/trusted-server-cli/tests/config_store_defaults.rs b/crates/trusted-server-cli/tests/config_store_defaults.rs index 23c5f86e9b..6b7998dec1 100644 --- a/crates/trusted-server-cli/tests/config_store_defaults.rs +++ b/crates/trusted-server-cli/tests/config_store_defaults.rs @@ -133,8 +133,14 @@ fn config_push_resolves_the_physical_name_and_explicit_key() { ); } +// The canonical `__KEY` selector is the push destination when `--key` is absent. +// Under EdgeZero v0.0.8 the CLI ignored it and always wrote the logical id; the +// pinned revision returns the selector verbatim so the pushed entry and the +// runtime that reads it cannot diverge. The Fastly runtime reads the logical id +// for every target, so an operator deploying to Fastly should leave this unset, +// which the Fastly guide now states. #[test] -fn config_push_does_not_use_the_runtime_key_override_without_the_key_flag() { +fn config_push_writes_the_runtime_key_override_without_the_key_flag() { let project = project(); let key_var = format!( "EDGEZERO__STORES__CONFIG__{}__KEY", @@ -145,7 +151,11 @@ fn config_push_does_not_use_the_runtime_key_override_without_the_key_flag() { let entries = stored_entries(&project); assert_eq!(entries.len(), 1); assert!( - entries.contains_key(CONFIG_BLOB_KEY), - "runtime-only key override should not move the CLI's write destination" + entries.contains_key("active_config"), + "the canonical key selector should be the push destination" + ); + assert!( + !entries.contains_key(CONFIG_BLOB_KEY), + "the logical id should not also be written" ); } diff --git a/docs/guide/cli.md b/docs/guide/cli.md index 9fb62380db..2d17a62fa5 100644 --- a/docs/guide/cli.md +++ b/docs/guide/cli.md @@ -224,12 +224,13 @@ EDGEZERO_MANIFEST="/edgezero.toml" \ ts deploy --adapter fastly --service-id --application-release "" -- --comment "release" ``` -`` is the extracted immutable application release that EdgeZero's -`package-fastly-application-release` action produces from a `ts build`. The -EdgeZero `deploy-fastly` action performs both steps, selects the manifest, and -supplies the release root; see EdgeZero's GitHub Actions deployment guide -(`docs/guide/deploy-github-actions.md` in the EdgeZero repository) for the -producer and consumer workflow. +`` is an extracted immutable application release. Build the +application CLI and Fastly package, then use EdgeZero's +`package-application-release-fastly` action to assemble the release archive. +The `deploy-fastly` action consumes that prebuilt archive, verifies and extracts +it, selects the manifest, and supplies the release root. See EdgeZero's GitHub +Actions deployment guide (`docs/guide/deploy-github-actions.md` in the EdgeZero +repository) for the producer and consumer workflow. A staged deploy selects the physical Config Store from the staging environment and links it to the staged version under the logical store ID. The staged @@ -238,24 +239,26 @@ the production config blob there. Push the staged config before probing the staged version: ```bash -ts config push --adapter fastly --staging -ts config diff --adapter fastly --staging +EDGEZERO__STORES__CONFIG__TRUSTED_SERVER_CONFIG__NAME= \ + ts config push --adapter fastly --staging +EDGEZERO__STORES__CONFIG__TRUSTED_SERVER_CONFIG__NAME= \ + ts config diff --adapter fastly --staging ``` The config key is fixed on Fastly: production, staging, and local Viceroy all -read ``. Staging isolation comes from the physical store the -staging environment selects with `EDGEZERO__STORES__CONFIG____NAME`, never -from a different key. Production and staging may select the same physical -Config Store or different stores. After `ts config push --staging`, the staged -binary reads `` in the store selected by the staging -environment, while the active production version continues to read the same -key in its own store. +read ``. `--staging` does not choose a different store or +key: the physical store is whatever `EDGEZERO__STORES__CONFIG____NAME` +resolves to in the shell or deploy job that runs the push, falling back to the +logical ID when it is unset. If production and staging select the same +physical Config Store, a staged push overwrites the production entry and +production instances load it on their next start. Give staging its own +physical Config Store and set its selector explicitly when pushing, as the +commands above do. `--staging` on `config push` / `config diff` writes and compares the -`` key in the physical store selected by the staging -environment. It is mutually exclusive with `--key`: Fastly accepts only the -logical store ID as the key for every target, so an explicit key would be -written where nothing reads it. +`` key in the physical store selected by the current +environment. It is mutually exclusive with `--key`, and on Fastly any `--key` +other than the logical store ID is rejected for every target, staged or not. Inspect and verify deployments with the deploy lifecycle commands. All three are Fastly-only — the axum, cloudflare, and spin adapters reject them: diff --git a/docs/guide/edgezero.md b/docs/guide/edgezero.md index 30d56856bf..a3630763a9 100644 --- a/docs/guide/edgezero.md +++ b/docs/guide/edgezero.md @@ -16,8 +16,10 @@ version operations use the adapter commands declared in `edgezero.toml`. Configuration is startup state, not a live control plane. A successful push does not change a running instance until the target's restart or deployment path loads that value. Use `--staging` only with the corresponding staging -deployment flow: it writes `LOGICAL_ID_staging` in the same physical store, -while production continues to read the ordinary logical key. +deployment flow. On Fastly the entry key is always the logical store ID, so +staging isolation comes from selecting a different physical store with +`EDGEZERO__STORES__CONFIG____NAME`; see +[the CLI guide](/guide/cli#lifecycle-commands). ## Logical and physical stores diff --git a/docs/guide/fastly.md b/docs/guide/fastly.md index 05e2ee9744..fa433655b9 100644 --- a/docs/guide/fastly.md +++ b/docs/guide/fastly.md @@ -319,11 +319,9 @@ declare `trusted_server_secrets`. Local Viceroy configuration exposes the store under the logical ID directly; see `[local_server.secret_stores]` in `fastly.toml`. -The same runtime mapping mechanism applies to app-config stores. See -[Fastly runtime config stores](/guide/configuration#fastly-runtime-config-store) -for the initial provisioning and linking sequence, subsequent CLI pushes, and -precautions when changing a live mapping. A process-environment override alone -does not configure the Fastly runtime. +The app-config store is selected the same way, through +`EDGEZERO__STORES__CONFIG__TRUSTED_SERVER_CONFIG__NAME` in the deployment +environment. No runtime mapping is stored in a Config Store. Create the separate request-signing store when that feature is enabled: @@ -334,6 +332,29 @@ fastly secret-store create --name signing_keys The deployment creates the `trusted_server_secrets` link itself from the selected physical store. Do not create that link by hand. +### Upgrading from EdgeZero v0.0.8 + +Services deployed before this change link the physical store directly, such as +`ts_secrets`, together with an `edgezero_runtime_env` Config Store. This binary +opens `trusted_server_secrets` instead, and only a managed deployment creates +that link. A plain `fastly compute publish` clones the active version's links, +so it activates a version whose link is missing: app config fails to load and +every publisher route returns 500 while `/health` keeps answering 200. + +When upgrading an existing service: + +- Deploy only through the managed path, `ts deploy --adapter fastly +--application-release ` or EdgeZero's `deploy-fastly` action, so + the `trusted_server_secrets` link exists before activation. +- Re-push staging app config under the logical key into the staging Config + Store. Entries previously pushed under `_staging` are + ignored. +- Remove any `EDGEZERO__STORES__CONFIG____KEY` selectors. The CLI now + writes to that selector when `--key` is absent, instead of ignoring it, so a + leftover selector pushes app config to a key the Fastly runtime never reads. +- Optionally delete the stale `edgezero_runtime_env` link and any `*_staging` + config entries once no active version reads them. + ## Create EC KV Store Edge Cookie flows require one KV store: @@ -356,7 +377,8 @@ passphrase = "ec_passphrase" ec_store = "ec_identity_store" ``` -Store the high-entropy passphrase under that key in `ts_secrets`. The resolved +Store the high-entropy passphrase under that key in the physical store +selected for `trusted_server_secrets`. The resolved value, rather than the key name, must contain at least 32 characters. Pipe the value over standard input so it never appears in the process argument list: @@ -394,7 +416,8 @@ Run the repository smoke from a clean shell: The script creates an isolated application config, applies its publisher-origin overrides, and runs strict validation. It then executes `ts config push --adapter fastly --local`, adds all three required entries to -`[local_server.secret_stores.ts_secrets]`, and starts `fastly compute serve` +`[local_server.secret_stores.trusted_server_secrets]`, and starts +`fastly compute serve` through Viceroy. The required keys are `handler_password`, `publisher_proxy_secret`, and `ec_passphrase`. diff --git a/docs/guide/getting-started.md b/docs/guide/getting-started.md index 83b8ef105a..267bdbb1f7 100644 --- a/docs/guide/getting-started.md +++ b/docs/guide/getting-started.md @@ -207,10 +207,22 @@ Restart or redeploy instances after secret rotation. See ## Deploy to Fastly +Trusted Server declares Config, KV, and Secret Stores, so deployment must go +through EdgeZero's managed path. That path links each selected physical store +to the service version under its logical ID; `fastly compute publish` clones +the active version's links instead and activates a version whose logical links +are missing. + ```bash -fastly compute publish +EDGEZERO_MANIFEST="/edgezero.toml" \ + ts deploy --adapter fastly --service-id --application-release "" ``` +See [the Fastly guide](/guide/fastly#upgrading-from-edgezero-v0-0-8) when +upgrading a service that was deployed before logical store links, and +[the CLI guide](/guide/cli#lifecycle-commands) for where `` +comes from. + ## Next Steps - Learn about [Edge Cookies](/guide/edge-cookies) diff --git a/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md b/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md index ae4c438e5c..428a080783 100644 --- a/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md +++ b/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md @@ -19,10 +19,11 @@ remove guidance for the superseded service-scoped and runtime-selector models. ## Design -All EdgeZero workspace dependencies will temporarily use the upstream branch -`fix/fastly-environment-store-selectors`. Keeping the dependencies on one branch +All EdgeZero workspace dependencies are pinned with `rev =` to the immutable +commit `c2e862f436421cdcfbac620c06995f262d6788c9` on the upstream branch +`fix/fastly-environment-store-selectors`. Pinning every crate to one commit ensures the adapter, CLI, core, and platform-specific crates resolve to the same -revision while PR 381 is under review. A follow-up will replace the branch with +revision while PR 381 is under review. Issue #1195 tracks replacing the rev with the release tag that contains the merged change. The Fastly entry point will stop reading `edgezero_runtime_env`. It will open diff --git a/edgezero.toml b/edgezero.toml index b40b20281b..54d3578a79 100644 --- a/edgezero.toml +++ b/edgezero.toml @@ -48,6 +48,11 @@ auth-logout = "fastly profile delete" auth-status = "fastly profile list" build = "cargo build --bin trusted-server-adapter-fastly --release --target wasm32-wasip1 --color always" serve = "fastly compute serve" +# Unused by `ts deploy`: this app declares stores, so EdgeZero always takes the +# managed deployment path, which links each selected physical store to the +# service version under its logical ID. Publishing with the Fastly CLI directly +# clones the active version's links and omits the logical links the runtime +# opens. deploy = "fastly compute publish" # -- Axum (native dev server) ----------------------------------------------- diff --git a/scripts/smoke-fastly.sh b/scripts/smoke-fastly.sh index c2e8b01b99..65635c2d23 100755 --- a/scripts/smoke-fastly.sh +++ b/scripts/smoke-fastly.sh @@ -31,7 +31,27 @@ trap cleanup EXIT INT TERM mkdir -p "$FASTLY_PROJECT" cp "$REPO_ROOT/edgezero.toml" "$EDGEZERO_MANIFEST" -cp "$REPO_ROOT/fastly.toml" "$FASTLY_MANIFEST" +# The base manifest defines the same secret keys this smoke appends. Drop its +# entries on copy, or removing an appended block would still leave a resolvable +# value and the missing-secret cases could not fail. +# The base manifest indents its table headers; the blocks this smoke appends +# are unindented. Match either form. +awk ' + /^[[:space:]]*\[\[local_server\.secret_stores\.trusted_server_secrets\]\][[:space:]]*$/ { + if ((getline key_line) <= 0 || (getline data_line) <= 0) { + exit 2 + } + removed++ + next + } + { print } + END { + if (removed < 1) { + print "expected at least one base secret block to strip; found 0" > "/dev/stderr" + exit 1 + } + } +' "$REPO_ROOT/fastly.toml" >"$FASTLY_MANIFEST" ln -s "$REPO_ROOT/crates" "$FASTLY_PROJECT/crates" smoke_resolve_ts_binary "$REPO_ROOT" @@ -90,7 +110,7 @@ write_without_secret() { local destination="$2" local missing_key="$3" awk -v missing_key="$missing_key" ' - $0 == "[[local_server.secret_stores.ts_secrets]]" { + /^[[:space:]]*\[\[local_server\.secret_stores\.trusted_server_secrets\]\][[:space:]]*$/ { header = $0 if ((getline key_line) <= 0 || (getline data_line) <= 0) { exit 2 @@ -131,15 +151,15 @@ run_case missing-config "$BASE_PORT" 500 \ ) cat >>"$FASTLY_MANIFEST" < Date: Wed, 7 Oct 2026 23:20:17 -0700 Subject: [PATCH 25/28] Address review feedback and move sandbox bounds off the deprecated store MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correct the upgrade checklist: on Fastly the CLI rejects any config key other than the logical store ID, so a leftover `__KEY` selector makes `ts config push` and `ts deploy` fail rather than writing to a key the runtime ignores. My earlier note had this backwards. Add the selector-migration steps the checklist was missing. Service-scoped `EDGEZERO__SERVICES____STORES__…__NAME` entries must move to the unscoped variables in the deploy environment, because an unset selector falls back to the logical ID and links whichever account-level store carries that name, possibly another service's. Also call out `trusted_server_kv`, which the managed deploy links even though the Fastly runtime never opens it. Name `EDGEZERO_MANIFEST` in the managed-deploy step, matching the CLI and getting-started guides. Replace the stale "Fastly Runtime Config Store" section in the configuration guide. It still described the removed `edgezero_runtime_env` selector model, `fastly compute publish`, and `--key` overrides. Its local development paragraph also claimed `--local` writes under the resolved `__NAME`; it writes under the logical ID. Update the matching doc comments in settings_data.rs. Read the sandbox reuse bounds from the application's own config store under its logical ID. They previously came from `edgezero_runtime_env`, which is deprecated and which this branch's pin no longer exposes a constant for. The service-scoped key prefix goes with it, since it only existed to namespace entries inside that shared store. --- .../src/sandbox.rs | 115 ++++++--------- .../trusted-server-core/src/settings_data.rs | 16 +-- docs/guide/configuration.md | 134 +++--------------- docs/guide/fastly.md | 34 +++-- ...-edgezero-fastly-store-selectors-design.md | 2 +- 5 files changed, 104 insertions(+), 197 deletions(-) diff --git a/crates/trusted-server-adapter-fastly/src/sandbox.rs b/crates/trusted-server-adapter-fastly/src/sandbox.rs index 228106047a..5286354595 100644 --- a/crates/trusted-server-adapter-fastly/src/sandbox.rs +++ b/crates/trusted-server-adapter-fastly/src/sandbox.rs @@ -13,6 +13,8 @@ use std::time::Duration; use edgezero_core::app::App; use trusted_server_core::settings::Settings; +#[cfg(feature = "reusable-sandbox")] +use trusted_server_core::settings_data::DEFAULT_CONFIG_STORE_ID; use crate::app::AppState; @@ -258,7 +260,7 @@ pub(crate) fn resolve_mode(raw: RawLimits) -> ServeMode { }) } -/// Suffixes of the service-scoped runtime-environment keys holding the bounds. +/// Keys holding the sandbox bounds in the application's own config store. #[cfg(any(feature = "reusable-sandbox", test))] const KEY_MAX_REQUESTS: &str = "TS__SANDBOX__MAX_REQUESTS"; #[cfg(any(feature = "reusable-sandbox", test))] @@ -268,22 +270,6 @@ const KEY_TIMEOUT_MS: &str = "TS__SANDBOX__TIMEOUT_MS"; #[cfg(any(feature = "reusable-sandbox", test))] const KEY_MAX_MEMORY_MIB: &str = "TS__SANDBOX__MAX_MEMORY_MIB"; -/// Builds the service-scoped runtime-environment key for a bound. -/// -/// `EdgeZero`'s own `service_scoped_runtime_env_key` is private, so the shape is -/// reproduced here. It must stay identical to the one `edgezero provision` -/// writes. -/// -/// Follow-up: a public `EdgeZero` key-construction or lookup helper would let -/// this duplication go. Until such an API exists this implementation stays, so -/// the key shape has exactly one definition on our side. The `TS__SANDBOX__*` -/// suffixes and the limit-validation policy in [`resolve_mode`] are -/// application-owned either way and would not move. -#[cfg(any(feature = "reusable-sandbox", test))] -fn scoped_key(service_id: &str, suffix: &str) -> String { - format!("EDGEZERO__SERVICES__{service_id}__{suffix}") -} - /// Collects raw limits from a fallible key lookup. /// /// Separated from the config-store call so the failure modes are testable @@ -293,16 +279,15 @@ fn scoped_key(service_id: &str, suffix: &str) -> String { /// Diagnostics are returned rather than logged. This runs before the logger /// exists, so anything logged here would be discarded. #[cfg(any(feature = "reusable-sandbox", test))] -fn collect_raw_limits(service_id: &str, mut lookup: F) -> (RawLimits, Vec) +fn collect_raw_limits(mut lookup: F) -> (RawLimits, Vec) where E: core::fmt::Display, F: FnMut(&str) -> Result, E>, { let mut diagnostics = Vec::new(); - let mut read = |suffix: &str| -> Option { - let key = scoped_key(service_id, suffix); - match lookup(&key) { + let mut read = |key: &str| -> Option { + match lookup(key) { Ok(Some(raw)) => match raw.trim().parse::() { Ok(value) => Some(value), Err(e) => { @@ -332,45 +317,38 @@ where (limits, diagnostics) } -/// Reads the sandbox bounds from the runtime-environment config store. +/// Reads the sandbox bounds from the application's own config store. +/// +/// The bounds live beside the app config under the logical store ID that a +/// managed deployment links, so no deprecated selector store is involved. +/// `EdgeZero` removed `edgezero_runtime_env` when store selection moved to +/// deploy-time resource links, and nothing in this repository provisions it. /// -/// These keys deliberately bypass `edgezero_adapter_fastly::runtime_env_config`. -/// That helper resolves a closed allowlist — adapter host and port, logging -/// settings, and per-store `__NAME`/`__KEY` selectors — and silently drops -/// everything else, so a sandbox key routed through it would always read as -/// absent and reuse would never engage. Still true at the pinned revision. +/// These keys are read directly rather than through an `EdgeZero` environment +/// helper. Those resolve a closed allowlist, adapter host and port, logging +/// settings, and per-store `__NAME`/`__KEY` selectors, and silently drop +/// everything else, so a sandbox key routed through one would always read as +/// absent and reuse would never engage. /// /// Uses [`fastly::ConfigStore::try_get`], never `get`: `get` panics on a /// lookup error, and this runs in `main` before the health probe, so a panic /// here would take down liveness rather than merely disabling reuse. /// /// Any failure resolves to [`RawLimits::default`], and hence to -/// [`ServeMode::Single`]: an absent or unopenable store, an empty service id, -/// a failed lookup, or a value that does not parse as a `u64`. +/// [`ServeMode::Single`]: an unopenable store, a failed lookup, or a value +/// that does not parse as a `u64`. #[cfg(feature = "reusable-sandbox")] pub(crate) fn read_raw_limits() -> (RawLimits, Vec) { - use edgezero_adapter_fastly::RUNTIME_ENV_STORE_NAME; - - let Ok(store) = fastly::ConfigStore::try_open(RUNTIME_ENV_STORE_NAME) else { + let Ok(store) = fastly::ConfigStore::try_open(DEFAULT_CONFIG_STORE_ID) else { return ( RawLimits::default(), vec![format!( - "sandbox reuse disabled: config store `{RUNTIME_ENV_STORE_NAME}` unavailable" + "sandbox reuse disabled: config store `{DEFAULT_CONFIG_STORE_ID}` unavailable" )], ); }; - // Viceroy reports a service id of twenty-two zeros, which is a valid - // scope for key construction. Only an empty id is unusable. - let service_id = fastly::compute_runtime::service_id(); - if service_id.is_empty() { - return ( - RawLimits::default(), - vec!["sandbox reuse disabled: no service id available for key scoping".to_owned()], - ); - } - - collect_raw_limits(service_id, |key| store.try_get(key)) + collect_raw_limits(|key| store.try_get(key)) } #[cfg(test)] @@ -380,25 +358,25 @@ mod tests { use super::*; #[test] - fn scoped_key_matches_the_edgezero_shape() { - // Viceroy reports twenty-two zeros locally; it is a valid scope. - let service_id = "0000000000000000000000"; - - assert_eq!( - scoped_key(service_id, KEY_MAX_REQUESTS), - "EDGEZERO__SERVICES__0000000000000000000000__TS__SANDBOX__MAX_REQUESTS", - "should reproduce the service-scoped key edgezero writes" - ); - assert_eq!( - scoped_key(service_id, KEY_MAX_LIFETIME_MS), - "EDGEZERO__SERVICES__0000000000000000000000__TS__SANDBOX__MAX_LIFETIME_MS", - "should scope the lifetime bound the same way" - ); - assert_eq!( - scoped_key(service_id, KEY_TIMEOUT_MS), - "EDGEZERO__SERVICES__0000000000000000000000__TS__SANDBOX__TIMEOUT_MS", - "should scope the wait timeout the same way" - ); + fn limit_keys_are_unscoped_app_config_keys() { + // The bounds live in the application's own config store under the + // logical id a deployment links, so the keys carry no service scope and + // no reference to the removed selector store. + for key in [ + KEY_MAX_REQUESTS, + KEY_MAX_LIFETIME_MS, + KEY_TIMEOUT_MS, + KEY_MAX_MEMORY_MIB, + ] { + assert!( + key.starts_with("TS__SANDBOX__"), + "sandbox limit key `{key}` should be an application-owned key" + ); + assert!( + !key.contains("EDGEZERO__SERVICES__"), + "sandbox limit key `{key}` should carry no service scope" + ); + } } fn full(max_requests: u64) -> RawLimits { @@ -579,8 +557,7 @@ mod tests { fn a_failed_lookup_degrades_to_single_request_instead_of_panicking() { // `ConfigStore::get` panics on a lookup error and runs before the // health probe, so the fallible path must absorb the error. - let (limits, diagnostics) = - collect_raw_limits::("svc", |_key| Err(LookupFailed)); + let (limits, diagnostics) = collect_raw_limits::(|_key| Err(LookupFailed)); assert_eq!( limits, @@ -606,7 +583,7 @@ mod tests { #[test] fn an_unparseable_value_degrades_to_single_request() { - let (limits, diagnostics) = collect_raw_limits::("svc", |key| { + let (limits, diagnostics) = collect_raw_limits::(|key| { Ok(Some(if key.ends_with(KEY_MAX_REQUESTS) { "ten".to_owned() } else { @@ -655,7 +632,7 @@ mod tests { Some("4294967295"), Some("4294967296"), ] { - let (limits, _) = collect_raw_limits::("example-service", |key| { + let (limits, _) = collect_raw_limits::(|key| { Ok(if key.ends_with("TS__SANDBOX__MAX_MEMORY_MIB") { memory.map(str::to_owned) } else { @@ -673,7 +650,7 @@ mod tests { #[test] fn absent_keys_report_nothing_and_stay_single_request() { - let (limits, diagnostics) = collect_raw_limits::("svc", |_key| Ok(None)); + let (limits, diagnostics) = collect_raw_limits::(|_key| Ok(None)); assert_eq!( limits, @@ -688,7 +665,7 @@ mod tests { #[test] fn a_complete_store_enables_reuse_end_to_end() { - let (limits, diagnostics) = collect_raw_limits::("svc", |key| { + let (limits, diagnostics) = collect_raw_limits::(|key| { Ok(Some( if key.ends_with(KEY_MAX_REQUESTS) { "10" diff --git a/crates/trusted-server-core/src/settings_data.rs b/crates/trusted-server-core/src/settings_data.rs index 07108fac64..2999eccf35 100644 --- a/crates/trusted-server-core/src/settings_data.rs +++ b/crates/trusted-server-core/src/settings_data.rs @@ -42,10 +42,10 @@ pub fn config_key(env: &EnvConfig) -> String { /// Resolves the `EdgeZero` app-config store name from the process environment. /// -/// Native adapters such as Axum use this wrapper. Fastly instead supplies an -/// `EnvConfig` populated from service-scoped entries in `edgezero_runtime_env` -/// and resolves the store name from that configuration. Without an override, -/// both paths use the manifest default logical store ID. +/// Native adapters such as Axum use this wrapper. Fastly reads no selector at +/// runtime: it opens the store under the logical ID that a managed deployment +/// links to the selected physical store. Without an override, this wrapper +/// also returns the manifest default logical store ID. #[must_use] pub fn default_config_store_name() -> StoreName { config_store_name(&EnvConfig::from_env()) @@ -53,10 +53,10 @@ pub fn default_config_store_name() -> StoreName { /// Resolves the app-config blob key from the process environment. /// -/// Native adapters such as Axum use this wrapper. Fastly resolves the key from -/// service-scoped entries in `edgezero_runtime_env` instead. A runtime `__KEY` -/// override must match `ts config push --key`; an ordinary push without that -/// flag writes at the logical store ID, regardless of the `__KEY` override. +/// Native adapters such as Axum use this wrapper and honour a `__KEY` +/// override. The Fastly runtime always reads the entry under the logical store +/// ID, and its CLI rejects any other `--key` or `__KEY` value, so no override +/// applies there. #[must_use] pub fn default_config_key() -> String { config_key(&EnvConfig::from_env()) diff --git a/docs/guide/configuration.md b/docs/guide/configuration.md index f7220d58c4..d62e054751 100644 --- a/docs/guide/configuration.md +++ b/docs/guide/configuration.md @@ -2803,125 +2803,37 @@ EdgeZero entry point. The former `edgezero_enabled` and `edgezero_rollout_pct` canary keys are no longer read. `[stores.config].default` in `edgezero.toml` supplies the logical config store -ID and default blob key, currently `trusted_server_config`. Fastly has no -process environment. Its entry point reads service-scoped overrides from the -`edgezero_runtime_env` Config Store before opening the app-config store: - -```mermaid -flowchart TD - A[Manifest default store ID] --> B[Resolve store name and blob key] - C[Service-scoped entries in edgezero_runtime_env] --> B - B --> D[Open the resolved resource-link name] - D --> E[Read the selected blob key from the linked physical store] -``` - -For this logical ID, the runtime selectors are: - -```text -EDGEZERO__SERVICES____STORES__CONFIG__TRUSTED_SERVER_CONFIG__NAME -EDGEZERO__SERVICES____STORES__CONFIG__TRUSTED_SERVER_CONFIG__KEY -``` - -The runtime ignores unscoped entries. Missing or blank selectors fall back to -the logical ID. A resource link must exist under the resolved name, not always -under `trusted_server_config`. - -### Initial setup with a service-specific store - -Fastly store names are account-level. Choose a physical name that is not used -by another service. The default physical name is safe only if the service owns -that store exclusively. - -Create the Fastly service and an editable service version before provisioning -non-default mappings. Select its ID through top-level `service_id` in -`fastly.toml` or `FASTLY_SERVICE_ID`. If both are set, they must agree. Do not -reuse the checked-in service ID for your deployment. Without a service ID, -provisioning rejects non-default mappings before creating resources. - -The following example is for initial setup before the service receives traffic. -Replace the service ID and choose your own physical store name: - -```bash -export FASTLY_SERVICE_ID="" -export EDGEZERO__STORES__CONFIG__TRUSTED_SERVER_CONFIG__NAME=example_config - -ts provision --adapter fastly --dry-run -ts provision --adapter fastly -``` - -Provisioning creates the stores and persists the selected name in the -service-scoped `edgezero_runtime_env` entry. Keep all intended store-name -overrides set when provisioning, including any [secret-store mapping](/guide/fastly#secret-stores). -Provisioning reconciles mappings for all declared stores, so omitting a previous -override can remove it. - -For an existing service, Fastly does not reapply `[setup]` entries. Follow the -provisioner's resource-link instructions. Both the app-config store and the -runtime-env store must be linked to the same editable version. For this example: - -```bash -fastly resource-link create --service-id "$FASTLY_SERVICE_ID" --version latest --autoclone \ - --resource-id --name example_config -fastly resource-link create --service-id "$FASTLY_SERVICE_ID" --version latest --autoclone \ - --resource-id --name edgezero_runtime_env - -ts config push --adapter fastly --dry-run -ts config push --adapter fastly -fastly compute publish --service-id "$FASTLY_SERVICE_ID" --version latest -``` - -Look up each store ID by its name before linking. Confirm the push dry run names -`example_config`, not the account-level default. Publish the application to the -linked version only after seeding its config store; a missing or invalid blob -makes application startup fail closed. Do not activate a new service's empty -version before uploading the application. If your deployment separates upload -from activation, activate the prepared version with -`fastly service-version activate --service-id "$FASTLY_SERVICE_ID" --version ` -only after both the code and config are ready. - -Keep the `__NAME` override in your deployment environment for **every subsequent -push**. The CLI reads its process environment, not the service's persisted -runtime mapping. Omitting the override can write to the wrong physical store. -Reject empty values in deployment scripts rather than relying on the fallback. - -For a live service, changing entries in its active `edgezero_runtime_env` store -changes runtime selection immediately, independently of service-version -activation. Do not use the initial-setup sequence to migrate a live mapping. -Prepare and seed the destination and make its resource link available to the -active version before switching the selector, or use an isolated staged runtime -configuration. - -An existing deployment may instead link a service-specific physical store under -the logical name `trusted_server_config`, with no runtime `__NAME` override. -That alias works, but the CLI still needs the physical-name override on every -push. Do not add a runtime override unless a link under the newly selected name -also exists. - -### Selecting another blob key - -A normal push writes at the logical store ID. A runtime `__KEY` override does -not change that write destination. To select another production key, first push -with `ts config push --adapter fastly --key `, then set the matching -service-scoped `__KEY` entry in `edgezero_runtime_env`. Changing that entry affects -the active service immediately. Do not point the production selector at a -staging key; staged deployments need their own runtime-env store. +ID, currently `trusted_server_config`. The Fastly runtime opens the store by +that logical ID and reads the entry under the same key on every target. Store +selection is a deploy-time input: a managed `ts deploy --adapter fastly` links +the physical store named by +`EDGEZERO__STORES__CONFIG__TRUSTED_SERVER_CONFIG__NAME` to the service version +under the logical ID. No selector is read from a Config Store at runtime, and +on Fastly the CLI rejects any `--key` or `__KEY` selector other than the +logical ID. + +Keep the `__NAME` selector set in the shell or deploy job for every push, so +`ts config push` writes into the same physical store the deployment links. +Isolate staging by selecting a different physical store. See +[Secret Stores](/guide/fastly#secret-stores) and the +[CLI lifecycle commands](/guide/cli#lifecycle-commands) for the full deploy and +staging flow. ### Local development -The repository's Viceroy configuration uses the default logical app-config name -and key. Clear production overrides for the local push: +The repository's Viceroy configuration uses the logical app-config store ID and +key. Clear any production key override for the local push: ```bash -env -u EDGEZERO__STORES__CONFIG__TRUSTED_SERVER_CONFIG__NAME \ - -u EDGEZERO__STORES__CONFIG__TRUSTED_SERVER_CONFIG__KEY \ +env -u EDGEZERO__STORES__CONFIG__TRUSTED_SERVER_CONFIG__KEY \ ts config push --adapter fastly --local ``` -`--local` writes under `[local_server.config_stores.]` in the -tracked `fastly.toml`. If you customize Viceroy's service-scoped runtime selectors, -keep that local name and the pushed key aligned with them. Review the generated -diff and do not commit deployment-specific app-config entries. Credentials belong -in secret stores; the app-config blob contains their key references. +`--local` writes under `[local_server.config_stores.trusted_server_config]` in +the tracked `fastly.toml`, the logical store ID, regardless of any `__NAME` +selector. Review the generated diff and do not commit deployment-specific +app-config entries. Credentials belong in secret stores; the app-config blob +contains their key references. ### Rollback diff --git a/docs/guide/fastly.md b/docs/guide/fastly.md index fa433655b9..d95d0c0f97 100644 --- a/docs/guide/fastly.md +++ b/docs/guide/fastly.md @@ -343,17 +343,35 @@ every publisher route returns 500 while `/health` keeps answering 200. When upgrading an existing service: -- Deploy only through the managed path, `ts deploy --adapter fastly ---application-release ` or EdgeZero's `deploy-fastly` action, so - the `trusted_server_secrets` link exists before activation. +- Deploy only through the managed path, so the `trusted_server_secrets` link + exists before activation: run + `ts deploy --adapter fastly --application-release ` with + `EDGEZERO_MANIFEST` set to the release's `edgezero.toml`, or use EdgeZero's + `deploy-fastly` action. +- Move each physical-name selector into the deploy environment before the + first managed deploy. Copy every service-scoped + `EDGEZERO__SERVICES____STORES______NAME` entry from + `edgezero_runtime_env` to the unscoped + `EDGEZERO__STORES______NAME` variable. An unset selector falls + back to the logical ID, so the deploy links whichever account-level store + carries that name, which can belong to another service. +- Select a KV store for logical ID `trusted_server_kv`. The managed deploy + links every declared store, and this one is usually absent on Fastly. Set + `EDGEZERO__STORES__KV__TRUSTED_SERVER_KV__NAME` to an existing KV store or + run `ts provision --adapter fastly`; otherwise the deploy stops with + "selected Fastly KV store `trusted_server_kv` does not exist". - Re-push staging app config under the logical key into the staging Config Store. Entries previously pushed under `_staging` are ignored. -- Remove any `EDGEZERO__STORES__CONFIG____KEY` selectors. The CLI now - writes to that selector when `--key` is absent, instead of ignoring it, so a - leftover selector pushes app config to a key the Fastly runtime never reads. -- Optionally delete the stale `edgezero_runtime_env` link and any `*_staging` - config entries once no active version reads them. +- Remove any `EDGEZERO__STORES__CONFIG____KEY` selectors. On Fastly the + CLI rejects any config key other than the logical store ID, so a leftover + selector makes `ts config push` and `ts deploy` fail until it is removed. +- Delete the stale `edgezero_runtime_env` link and any `*_staging` config + entries once no active version reads them. Nothing in Trusted Server reads + that store any more. If you set the optional `TS__SANDBOX__*` reuse bounds + there, move them into the app-config store under the logical ID + `trusted_server_config`, without the `EDGEZERO__SERVICES____` + prefix. ## Create EC KV Store diff --git a/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md b/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md index 428a080783..53060514ce 100644 --- a/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md +++ b/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md @@ -20,7 +20,7 @@ remove guidance for the superseded service-scoped and runtime-selector models. ## Design All EdgeZero workspace dependencies are pinned with `rev =` to the immutable -commit `c2e862f436421cdcfbac620c06995f262d6788c9` on the upstream branch +commit `0645339d1848332f4805259d29e3b4b881fccad3` on the upstream branch `fix/fastly-environment-store-selectors`. Pinning every crate to one commit ensures the adapter, CLI, core, and platform-specific crates resolve to the same revision while PR 381 is under review. Issue #1195 tracks replacing the rev with From 9b92886c538ee6cdba9a67111c5cc1fe4cee28b3 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Wed, 7 Oct 2026 23:45:52 -0700 Subject: [PATCH 26/28] Stop the Fastly deploy skill from recommending compute publish The skill's guardrails told operators to always pass `--service-id` to `fastly compute publish`. That command now strands a service: it clones the active version's resource links, so the new version lacks the logical links the runtime opens, app config fails to load, and every publisher route returns 500 while `/health` still answers 200. Point the guardrail at the managed deploy instead, and keep the `--service-id` advice for whichever deploy command is used, since a checked-in `fastly.toml` can still pin a dead service. --- .../deploying-trusted-server-to-fastly/SKILL.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/.claude/skills/deploying-trusted-server-to-fastly/SKILL.md b/.claude/skills/deploying-trusted-server-to-fastly/SKILL.md index 08609e1929..681952b322 100644 --- a/.claude/skills/deploying-trusted-server-to-fastly/SKILL.md +++ b/.claude/skills/deploying-trusted-server-to-fastly/SKILL.md @@ -40,9 +40,18 @@ accounts and harmless for single-service ones, so prefer it by default. - **Always `ts config push --dry-run` first.** It prints the exact target physical store; confirm it is the service-scoped one, not a shared default, before writing. -- **Always pass `--service-id=`** to `fastly compute publish`. A checked-in - `fastly.toml` may pin a different (or dead) `service_id`; without the flag, - publish targets that one. +- **Never deploy with `fastly compute publish`.** This app declares Config, KV, + and Secret Stores, and only EdgeZero's managed deploy links each selected + physical store to the service version under its logical ID. Publishing with + the Fastly CLI clones the active version's links, so the new version is + missing the links the runtime opens: app config fails to load and every + publisher route returns 500 while `/health` still answers 200. Deploy with + `ts deploy --adapter fastly --service-id= --application-release `, + with `EDGEZERO_MANIFEST` set to the release's `edgezero.toml`, or EdgeZero's + `deploy-fastly` action. +- **Always pass `--service-id=`** to any deploy or publish command. A + checked-in `fastly.toml` may pin a different (or dead) `service_id`; without + the flag, the command targets that one. - **`ts config push` only upserts entries**; the target store must already exist (`fastly config-store create`) before pushing. - **Verify a shared store stayed untouched** by recording its `updated` From 4a1eb281eb0f93fd5add4c1b6e9c50e2a988df6e Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Mon, 12 Oct 2026 10:12:18 -0700 Subject: [PATCH 27/28] Pin EdgeZero to v0.0.9 and address the latest review round Replace the interim `rev =` pin on the unmerged upstream branch with `tag = "v0.0.9"`, the release carrying the merged PR 381 that binds Fastly stores per deployment environment. This closes issue #1195. Verified the tag contains every API this branch depends on (`validate_fastly_config_key`, `resolve_config_store_and_key`, `desired_resource_links`, `store_name_checked`, `owns_managed_deploy`, `require_token`) and the `package-application-release-fastly` action. Review feedback: - Warn that an unchanged `ts config push --adapter fastly --staging` runbook now writes the production entry when the `__NAME` selector is unset, since `--staging` no longer selects a separate key. - Correct the `__KEY` test comment: the Fastly CLI rejects any value other than the logical ID, and the test exercises the Axum adapter, which is why the override applies there. - Replace the sandbox key-shape test with one that captures the keys `collect_raw_limits` actually requests. The previous assertions only compared string constants and could not fail without an edit to the test itself; the sibling tests match on `ends_with`, so a service-scoped lookup slipped past them. - Drop the unused `deploy` command from the Fastly adapter manifest. The schema has it optional and this app always takes the managed path, so leaving it invited a copy into a runbook. --- Cargo.lock | 16 +++--- Cargo.toml | 12 ++--- .../src/sandbox.rs | 51 ++++++++++--------- .../tests/config_store_defaults.rs | 10 ++-- docs/guide/fastly.md | 8 ++- ...-edgezero-fastly-store-selectors-design.md | 11 ++-- edgezero.toml | 9 ++-- 7 files changed, 62 insertions(+), 55 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7a7658f751..faba820f52 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1498,7 +1498,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?rev=0645339d1848332f4805259d29e3b4b881fccad3#0645339d1848332f4805259d29e3b4b881fccad3" +source = "git+https://github.com/stackpop/edgezero?tag=v0.0.9#f7176742d46aa4d1a04ce4588b606afda388fd30" dependencies = [ "serde", "serde_json", @@ -1510,7 +1510,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?rev=0645339d1848332f4805259d29e3b4b881fccad3#0645339d1848332f4805259d29e3b4b881fccad3" +source = "git+https://github.com/stackpop/edgezero?tag=v0.0.9#f7176742d46aa4d1a04ce4588b606afda388fd30" dependencies = [ "anyhow", "async-trait", @@ -1538,7 +1538,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?rev=0645339d1848332f4805259d29e3b4b881fccad3#0645339d1848332f4805259d29e3b4b881fccad3" +source = "git+https://github.com/stackpop/edgezero?tag=v0.0.9#f7176742d46aa4d1a04ce4588b606afda388fd30" dependencies = [ "anyhow", "async-trait", @@ -1561,7 +1561,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?rev=0645339d1848332f4805259d29e3b4b881fccad3#0645339d1848332f4805259d29e3b4b881fccad3" +source = "git+https://github.com/stackpop/edgezero?tag=v0.0.9#f7176742d46aa4d1a04ce4588b606afda388fd30" dependencies = [ "anyhow", "async-stream", @@ -1590,7 +1590,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?rev=0645339d1848332f4805259d29e3b4b881fccad3#0645339d1848332f4805259d29e3b4b881fccad3" +source = "git+https://github.com/stackpop/edgezero?tag=v0.0.9#f7176742d46aa4d1a04ce4588b606afda388fd30" dependencies = [ "anyhow", "async-trait", @@ -1617,7 +1617,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?rev=0645339d1848332f4805259d29e3b4b881fccad3#0645339d1848332f4805259d29e3b4b881fccad3" +source = "git+https://github.com/stackpop/edgezero?tag=v0.0.9#f7176742d46aa4d1a04ce4588b606afda388fd30" dependencies = [ "chrono", "clap", @@ -1642,7 +1642,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?rev=0645339d1848332f4805259d29e3b4b881fccad3#0645339d1848332f4805259d29e3b4b881fccad3" +source = "git+https://github.com/stackpop/edgezero?tag=v0.0.9#f7176742d46aa4d1a04ce4588b606afda388fd30" dependencies = [ "anyhow", "async-compression", @@ -1673,7 +1673,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?rev=0645339d1848332f4805259d29e3b4b881fccad3#0645339d1848332f4805259d29e3b4b881fccad3" +source = "git+https://github.com/stackpop/edgezero?tag=v0.0.9#f7176742d46aa4d1a04ce4588b606afda388fd30" dependencies = [ "log", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 786f8795a1..a9aaedc991 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,12 +56,12 @@ cssparser = "0.36" 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", rev = "0645339d1848332f4805259d29e3b4b881fccad3", default-features = false } -edgezero-adapter-cloudflare = { git = "https://github.com/stackpop/edgezero", rev = "0645339d1848332f4805259d29e3b4b881fccad3", default-features = false } -edgezero-adapter-fastly = { git = "https://github.com/stackpop/edgezero", rev = "0645339d1848332f4805259d29e3b4b881fccad3", default-features = false } -edgezero-adapter-spin = { git = "https://github.com/stackpop/edgezero", rev = "0645339d1848332f4805259d29e3b4b881fccad3", default-features = false } -edgezero-cli = { git = "https://github.com/stackpop/edgezero", rev = "0645339d1848332f4805259d29e3b4b881fccad3" } -edgezero-core = { git = "https://github.com/stackpop/edgezero", rev = "0645339d1848332f4805259d29e3b4b881fccad3", default-features = false } +edgezero-adapter-axum = { git = "https://github.com/stackpop/edgezero", tag = "v0.0.9", default-features = false } +edgezero-adapter-cloudflare = { git = "https://github.com/stackpop/edgezero", tag = "v0.0.9", default-features = false } +edgezero-adapter-fastly = { git = "https://github.com/stackpop/edgezero", tag = "v0.0.9", default-features = false } +edgezero-adapter-spin = { git = "https://github.com/stackpop/edgezero", tag = "v0.0.9", default-features = false } +edgezero-cli = { git = "https://github.com/stackpop/edgezero", tag = "v0.0.9" } +edgezero-core = { git = "https://github.com/stackpop/edgezero", tag = "v0.0.9", default-features = false } env_logger = "0.11" error-stack = "0.6" esi = "0.7.2" diff --git a/crates/trusted-server-adapter-fastly/src/sandbox.rs b/crates/trusted-server-adapter-fastly/src/sandbox.rs index 5286354595..db825427a1 100644 --- a/crates/trusted-server-adapter-fastly/src/sandbox.rs +++ b/crates/trusted-server-adapter-fastly/src/sandbox.rs @@ -353,32 +353,10 @@ pub(crate) fn read_raw_limits() -> (RawLimits, Vec) { #[cfg(test)] mod tests { - use std::cell::Cell; + use std::cell::{Cell, RefCell}; use super::*; - #[test] - fn limit_keys_are_unscoped_app_config_keys() { - // The bounds live in the application's own config store under the - // logical id a deployment links, so the keys carry no service scope and - // no reference to the removed selector store. - for key in [ - KEY_MAX_REQUESTS, - KEY_MAX_LIFETIME_MS, - KEY_TIMEOUT_MS, - KEY_MAX_MEMORY_MIB, - ] { - assert!( - key.starts_with("TS__SANDBOX__"), - "sandbox limit key `{key}` should be an application-owned key" - ); - assert!( - !key.contains("EDGEZERO__SERVICES__"), - "sandbox limit key `{key}` should carry no service scope" - ); - } - } - fn full(max_requests: u64) -> RawLimits { RawLimits { max_requests: Some(max_requests), @@ -648,6 +626,33 @@ mod tests { } } + #[test] + fn limits_are_looked_up_unscoped_in_the_app_config_store() { + // The bounds live in the application's own config store under the + // logical id a deployment links, so every lookup must use the bare + // key. Asserting on the constants alone would only fail if someone + // edited them and this test together, and the sibling tests match on + // `ends_with`, so a service-scoped or otherwise prefixed lookup would + // slip past them. Capture the exact keys requested instead. + let requested = RefCell::new(Vec::new()); + + let (_limits, _diagnostics) = collect_raw_limits::(|key| { + requested.borrow_mut().push(key.to_owned()); + Ok(None) + }); + + assert_eq!( + requested.borrow().as_slice(), + [ + KEY_MAX_REQUESTS, + KEY_MAX_MEMORY_MIB, + KEY_MAX_LIFETIME_MS, + KEY_TIMEOUT_MS, + ], + "should look up each sandbox bound by its unscoped app-config key" + ); + } + #[test] fn absent_keys_report_nothing_and_stay_single_request() { let (limits, diagnostics) = collect_raw_limits::(|_key| Ok(None)); diff --git a/crates/trusted-server-cli/tests/config_store_defaults.rs b/crates/trusted-server-cli/tests/config_store_defaults.rs index 6b7998dec1..2d120855d0 100644 --- a/crates/trusted-server-cli/tests/config_store_defaults.rs +++ b/crates/trusted-server-cli/tests/config_store_defaults.rs @@ -134,11 +134,11 @@ fn config_push_resolves_the_physical_name_and_explicit_key() { } // The canonical `__KEY` selector is the push destination when `--key` is absent. -// Under EdgeZero v0.0.8 the CLI ignored it and always wrote the logical id; the -// pinned revision returns the selector verbatim so the pushed entry and the -// runtime that reads it cannot diverge. The Fastly runtime reads the logical id -// for every target, so an operator deploying to Fastly should leave this unset, -// which the Fastly guide now states. +// Under EdgeZero v0.0.8 the CLI ignored it and always wrote the logical id; +// v0.0.9 returns the selector verbatim so the pushed entry and the runtime +// that reads it cannot diverge. This test runs the Axum adapter: the Fastly +// runtime reads the logical id for every target, and the Fastly CLI rejects +// any other `__KEY` value, so the override only applies off Fastly. #[test] fn config_push_writes_the_runtime_key_override_without_the_key_flag() { let project = project(); diff --git a/docs/guide/fastly.md b/docs/guide/fastly.md index d95d0c0f97..b4dfb9929c 100644 --- a/docs/guide/fastly.md +++ b/docs/guide/fastly.md @@ -361,8 +361,12 @@ When upgrading an existing service: run `ts provision --adapter fastly`; otherwise the deploy stops with "selected Fastly KV store `trusted_server_kv` does not exist". - Re-push staging app config under the logical key into the staging Config - Store. Entries previously pushed under `_staging` are - ignored. + Store, with `EDGEZERO__STORES__CONFIG__TRUSTED_SERVER_CONFIG__NAME` set to + that store. Entries previously pushed under `_staging` are + ignored. Do not rerun an existing `ts config push --adapter fastly --staging` + runbook unchanged: `--staging` no longer selects a separate key, so without + the `__NAME` selector it writes the production entry in the logical-ID store, + and production instances load it on their next start. - Remove any `EDGEZERO__STORES__CONFIG____KEY` selectors. On Fastly the CLI rejects any config key other than the logical store ID, so a leftover selector makes `ts config push` and `ts deploy` fail until it is removed. diff --git a/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md b/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md index 53060514ce..0dfa91648a 100644 --- a/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md +++ b/docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md @@ -19,12 +19,11 @@ remove guidance for the superseded service-scoped and runtime-selector models. ## Design -All EdgeZero workspace dependencies are pinned with `rev =` to the immutable -commit `0645339d1848332f4805259d29e3b4b881fccad3` on the upstream branch -`fix/fastly-environment-store-selectors`. Pinning every crate to one commit -ensures the adapter, CLI, core, and platform-specific crates resolve to the same -revision while PR 381 is under review. Issue #1195 tracks replacing the rev with -the release tag that contains the merged change. +All EdgeZero workspace dependencies are pinned with `tag = "v0.0.9"`, the +release that carries the merged PR 381 ("Bind Fastly stores per deployment +environment"). Pinning every crate to one tag ensures the adapter, CLI, core, +and platform-specific crates resolve to the same revision. This replaces the +interim `rev =` pin on the unmerged upstream branch and closes issue #1195. The Fastly entry point will stop reading `edgezero_runtime_env`. It will open the config and secret stores by their logical IDs, `trusted_server_config` and diff --git a/edgezero.toml b/edgezero.toml index 54d3578a79..64e6e0f1f0 100644 --- a/edgezero.toml +++ b/edgezero.toml @@ -48,12 +48,11 @@ auth-logout = "fastly profile delete" auth-status = "fastly profile list" build = "cargo build --bin trusted-server-adapter-fastly --release --target wasm32-wasip1 --color always" serve = "fastly compute serve" -# Unused by `ts deploy`: this app declares stores, so EdgeZero always takes the +# No `deploy` command: this app declares stores, so EdgeZero always takes the # managed deployment path, which links each selected physical store to the -# service version under its logical ID. Publishing with the Fastly CLI directly -# clones the active version's links and omits the logical links the runtime -# opens. -deploy = "fastly compute publish" +# service version under its logical ID. `fastly compute publish` would clone +# the active version's links and omit the logical links the runtime opens, so +# the key is omitted rather than left here for someone to copy into a runbook. # -- Axum (native dev server) ----------------------------------------------- From 3add18d8acedd4e04a52d1249ae95786ff1605eb Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Mon, 12 Oct 2026 10:24:55 -0700 Subject: [PATCH 28/28] Name the managed-deploy token and staged-version config prerequisites Address two review follow-ups on the upgrade and deployment guides. Managed deployment reads a nonempty `FASTLY_API_TOKEN` straight from the process environment through EdgeZero's `require_token`, which a Fastly CLI profile alone does not supply, so the deploy examples now name that prerequisite. The stale-entry cleanup said to delete `*_staging` config entries once no active version reads them, but an older staged version keeps a version-linked selector pointing at `_staging`. Deleting the entry while that version is deployed makes its publisher routes return 500, so the checklist now covers active, staged, and rollback versions. --- docs/guide/cli.md | 7 ++++++- docs/guide/fastly.md | 7 +++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/guide/cli.md b/docs/guide/cli.md index fcdbe072f1..9466e1f3df 100644 --- a/docs/guide/cli.md +++ b/docs/guide/cli.md @@ -221,7 +221,12 @@ requires a verified application release root via `--application-release`; a bare `ts deploy --adapter fastly` without a release is accepted only for store-free applications. The CLI loads `edgezero.toml` from the working directory unless `EDGEZERO_MANIFEST` names another file, and it rejects a -manifest outside the release root, so select the release's own manifest: +manifest outside the release root, so select the release's own manifest. + +Managed deployment also requires a nonempty `FASTLY_API_TOKEN` in the process +environment; signing in with `ts auth login` or a Fastly CLI profile alone +does not supply the token used by the adapter's direct API calls. Export the +token before running: ```bash EDGEZERO_MANIFEST="/edgezero.toml" \ diff --git a/docs/guide/fastly.md b/docs/guide/fastly.md index b4dfb9929c..6cf1e5e38c 100644 --- a/docs/guide/fastly.md +++ b/docs/guide/fastly.md @@ -371,8 +371,11 @@ When upgrading an existing service: CLI rejects any config key other than the logical store ID, so a leftover selector makes `ts config push` and `ts deploy` fail until it is removed. - Delete the stale `edgezero_runtime_env` link and any `*_staging` config - entries once no active version reads them. Nothing in Trusted Server reads - that store any more. If you set the optional `TS__SANDBOX__*` reuse bounds + entries only after no active, staged, or rollback version depends on them. + A version-linked selector on an older staged version still reads + `_staging`, so removing the entry while that version is + deployed makes its publisher routes return 500. This release no longer + reads that store. If you set the optional `TS__SANDBOX__*` reuse bounds there, move them into the app-config store under the logical ID `trusted_server_config`, without the `EDGEZERO__SERVICES____` prefix.