Skip to content

Commit d3bb29d

Browse files
committed
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.
1 parent 645d641 commit d3bb29d

6 files changed

Lines changed: 45 additions & 62 deletions

File tree

Cargo.lock

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,12 @@ use crate::rate_limiter::{FastlyRateLimiter, RATE_COUNTER_NAME};
9292
use edgezero_adapter_fastly::context::FastlyRequestContext;
9393
use edgezero_core::app::{App, Hooks, StoreMetadata, StoresMetadata};
9494
use edgezero_core::context::RequestContext;
95-
use edgezero_core::env_config::EnvConfig;
9695
use edgezero_core::error::EdgeError;
9796
use edgezero_core::http::{
9897
HandlerFuture, HeaderValue, Method, Request, Response, StatusCode, header,
9998
};
10099
use edgezero_core::router::RouterService;
101100
use error_stack::Report;
102-
use fastly::compute_runtime;
103101
use trusted_server_core::auction::AuctionTelemetrySink;
104102
use trusted_server_core::auction::endpoints::handle_auction;
105103
use trusted_server_core::auction::{
@@ -162,20 +160,17 @@ pub(crate) struct RuntimeStoreConfig {
162160
}
163161

164162
impl RuntimeStoreConfig {
165-
/// Store bindings for the running Fastly publication target.
163+
/// Store bindings for the Fastly runtime.
166164
///
167165
/// Fastly Compute has no process environment. `EdgeZero` links each selected
168166
/// physical store to the service version under its logical ID, so the
169-
/// runtime opens stores by logical ID and derives the config entry key from
170-
/// the target alone: production reads `<id>`, staging reads `<id>_staging`.
171-
pub(crate) fn for_target(staging: bool) -> Self {
167+
/// runtime opens stores by logical ID and reads the config entry under
168+
/// that same ID for every publication target. Staging isolation comes from
169+
/// linking a different physical store, never from a different key.
170+
pub(crate) fn logical() -> Self {
172171
Self {
173172
config_store_name: StoreName::from(DEFAULT_CONFIG_STORE_ID),
174-
config_key: EnvConfig::default().store_key_for_target(
175-
"config",
176-
DEFAULT_CONFIG_STORE_ID,
177-
staging,
178-
),
173+
config_key: DEFAULT_CONFIG_STORE_ID.to_owned(),
179174
secret_store_name: StoreName::from(DEFAULT_SECRET_STORE_ID),
180175
}
181176
}
@@ -1353,7 +1348,7 @@ impl Hooks for TrustedServerApp {
13531348
}
13541349

13551350
fn routes() -> RouterService {
1356-
let stores = RuntimeStoreConfig::for_target(compute_runtime::is_staging());
1351+
let stores = RuntimeStoreConfig::logical();
13571352
Self::router_with_state(&stores).0
13581353
}
13591354

@@ -1463,17 +1458,8 @@ mod tests {
14631458
}
14641459

14651460
#[test]
1466-
fn runtime_store_config_reads_the_staging_config_key_on_staging() {
1467-
let stores = RuntimeStoreConfig::for_target(true);
1468-
1469-
assert_eq!(stores.config_store_name.as_ref(), "trusted_server_config");
1470-
assert_eq!(stores.config_key, "trusted_server_config_staging");
1471-
assert_eq!(stores.secret_store_name.as_ref(), "trusted_server_secrets");
1472-
}
1473-
1474-
#[test]
1475-
fn runtime_store_config_opens_logical_store_ids_in_production() {
1476-
let stores = RuntimeStoreConfig::for_target(false);
1461+
fn runtime_store_config_opens_logical_store_ids_and_key() {
1462+
let stores = RuntimeStoreConfig::logical();
14771463

14781464
assert_eq!(stores.config_store_name.as_ref(), "trusted_server_config");
14791465
assert_eq!(stores.config_key, "trusted_server_config");

crates/trusted-server-adapter-fastly/src/main.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use edgezero_core::error::EdgeError;
88
use edgezero_core::http::{Request as HttpRequest, Response as HttpResponse};
99
use edgezero_core::response::IntoResponse;
1010
use error_stack::Report;
11-
use fastly::compute_runtime;
1211
use fastly::http::Method as FastlyMethod;
1312
use fastly::{Request as FastlyRequest, Response as FastlyResponse};
1413

@@ -89,7 +88,7 @@ fn main() {
8988

9089
/// Handles a request through the `EdgeZero` router path.
9190
fn edgezero_main(mut req: FastlyRequest) {
92-
let runtime_stores = RuntimeStoreConfig::for_target(compute_runtime::is_staging());
91+
let runtime_stores = RuntimeStoreConfig::logical();
9392

9493
// Short-circuit the JA4 debug probe before app construction. Must run here
9594
// because TLS/JA4 accessors are only available on FastlyRequest before

docs/guide/cli.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -131,29 +131,29 @@ ts deploy --adapter fastly --service-id <service-id> --application-release <rele
131131

132132
A staged deploy selects the physical Config Store from the staging environment
133133
and links it to the staged version under the logical store ID. The staged
134-
runtime reads the `<logical-store-id>_staging` key from that store. It does not
135-
copy the production config blob there. Push the staged config before probing
136-
the staged version:
134+
runtime reads the `<logical-store-id>` key from that store. It does not copy
135+
the production config blob there. Push the staged config before probing the
136+
staged version:
137137

138138
```bash
139139
ts config push --adapter fastly --staging
140140
ts config diff --adapter fastly --staging
141141
```
142142

143-
Config keys are deterministic on Fastly: production reads `<logical-store-id>`,
144-
staging reads `<logical-store-id>_staging`, and local Viceroy reads the
145-
production key. The binary decides which key to read from Fastly's staging
146-
signal, not from a stored selector. Production and staging may select the same
147-
physical Config Store or different stores. After `ts config push --staging`,
148-
the staged binary reads `<logical-store-id>_staging` in the store selected by
149-
the staging environment, while the active production version continues to read
150-
its production key and store.
143+
The config key is fixed on Fastly: production, staging, and local Viceroy all
144+
read `<logical-store-id>`. Staging isolation comes from the physical store the
145+
staging environment selects with `EDGEZERO__STORES__CONFIG__<ID>__NAME`, never
146+
from a different key. Production and staging may select the same physical
147+
Config Store or different stores. After `ts config push --staging`, the staged
148+
binary reads `<logical-store-id>` in the store selected by the staging
149+
environment, while the active production version continues to read the same
150+
key in its own store.
151151

152152
`--staging` on `config push` / `config diff` writes and compares the
153-
`<logical-store-id>_staging` key in the physical store selected by the staging
154-
environment. It is mutually exclusive with `--key`: the staging key is derived
155-
from the store's logical id, so an explicit key would be written where nothing
156-
reads it.
153+
`<logical-store-id>` key in the physical store selected by the staging
154+
environment. It is mutually exclusive with `--key`: Fastly accepts only the
155+
logical store ID as the key for every target, so an explicit key would be
156+
written where nothing reads it.
157157

158158
Inspect and verify deployments with the deploy lifecycle commands. All three are
159159
Fastly-only — the axum, cloudflare, and spin adapters reject them:

docs/superpowers/plans/2026-09-16-edgezero-fastly-store-selectors.md

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
- `Cargo.toml`: select the EdgeZero PR 381 branch for all EdgeZero crates.
1616
- `Cargo.lock`: lock all EdgeZero packages to the branch revision.
17-
- `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`.
17+
- `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`.
1818
- `fastly.toml`: expose the local Viceroy secret store under its logical ID and drop the runtime selector store.
1919
- `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.
2020
- `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
131131
a focused parsing or behavior test before the production edit.
132132

133133
The branch head removes `edgezero_adapter_fastly::runtime_env_config`. Replace
134-
`RuntimeStoreConfig::from_env` with `RuntimeStoreConfig::for_target(staging)`:
135-
open `trusted_server_config` and `trusted_server_secrets` by logical ID and
136-
derive the config key with `EnvConfig::store_key_for_target`. Both entry points
137-
pass `fastly::compute_runtime::is_staging()`. Cover the production and staging
138-
keys with unit tests in `app.rs`.
134+
`RuntimeStoreConfig::from_env` with `RuntimeStoreConfig::logical()`: open
135+
`trusted_server_config` and `trusted_server_secrets` by logical ID and read
136+
the config entry under `trusted_server_config` for every target. Cover the
137+
logical IDs and key with a unit test in `app.rs`.
139138

140139
- [ ] **Step 3: Verify the lockfile revision is consistent**
141140

@@ -193,11 +192,10 @@ contract:
193192

194193
- [ ] **Step 2: Update staging CLI guidance**
195194

196-
Clarify that `ts config push --staging` writes the staging key into the physical
197-
Config Store selected by the staging environment, and that the staged binary
198-
reads `<logical-store-id>_staging` because Fastly reports it as staged, not
199-
because of a stored selector. State that production and staging may select the
200-
same or different physical stores.
195+
Clarify that `ts config push --staging` writes the logical key into the
196+
physical Config Store selected by the staging environment, and that the staged
197+
binary reads the same `<logical-store-id>` key there. State that production and
198+
staging may select the same or different physical stores.
201199

202200
- [ ] **Step 3: Check for stale service-scoped guidance**
203201

docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ the release tag that contains the merged change.
2727

2828
The Fastly entry point will stop reading `edgezero_runtime_env`. It will open
2929
the config and secret stores by their logical IDs, `trusted_server_config` and
30-
`trusted_server_secrets`, and derive the config entry key from Fastly's staging
31-
signal through EdgeZero's target-key rule: production reads
32-
`trusted_server_config`, staging reads `trusted_server_config_staging`.
30+
`trusted_server_secrets`, and read the config entry under
31+
`trusted_server_config` for every target. Staging isolation comes from the
32+
physical store the staging environment selects, not from a different key.
3333

3434
Local Viceroy configuration will expose the secret store under the logical ID
3535
`trusted_server_secrets` and drop the `edgezero_runtime_env` Config Store, so

0 commit comments

Comments
 (0)