Skip to content

Commit 645d641

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

11 files changed

Lines changed: 168 additions & 173 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: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ use std::sync::Arc;
9090

9191
use crate::rate_limiter::{FastlyRateLimiter, RATE_COUNTER_NAME};
9292
use edgezero_adapter_fastly::context::FastlyRequestContext;
93-
use edgezero_adapter_fastly::runtime_env_config;
9493
use edgezero_core::app::{App, Hooks, StoreMetadata, StoresMetadata};
9594
use edgezero_core::context::RequestContext;
9695
use edgezero_core::env_config::EnvConfig;
@@ -100,6 +99,7 @@ use edgezero_core::http::{
10099
};
101100
use edgezero_core::router::RouterService;
102101
use error_stack::Report;
102+
use fastly::compute_runtime;
103103
use trusted_server_core::auction::AuctionTelemetrySink;
104104
use trusted_server_core::auction::endpoints::handle_auction;
105105
use trusted_server_core::auction::{
@@ -162,11 +162,21 @@ pub(crate) struct RuntimeStoreConfig {
162162
}
163163

164164
impl RuntimeStoreConfig {
165-
pub(crate) fn from_env(env: &EnvConfig) -> Self {
165+
/// Store bindings for the running Fastly publication target.
166+
///
167+
/// Fastly Compute has no process environment. `EdgeZero` links each selected
168+
/// 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 {
166172
Self {
167-
config_store_name: StoreName::from(env.store_name("config", DEFAULT_CONFIG_STORE_ID)),
168-
config_key: env.store_key("config", DEFAULT_CONFIG_STORE_ID),
169-
secret_store_name: StoreName::from(env.store_name("secrets", DEFAULT_SECRET_STORE_ID)),
173+
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+
),
179+
secret_store_name: StoreName::from(DEFAULT_SECRET_STORE_ID),
170180
}
171181
}
172182
}
@@ -1343,8 +1353,7 @@ impl Hooks for TrustedServerApp {
13431353
}
13441354

13451355
fn routes() -> RouterService {
1346-
let runtime_env = runtime_env_config(Self::stores());
1347-
let stores = RuntimeStoreConfig::from_env(&runtime_env);
1356+
let stores = RuntimeStoreConfig::for_target(compute_runtime::is_staging());
13481357
Self::router_with_state(&stores).0
13491358
}
13501359

@@ -1385,7 +1394,6 @@ mod tests {
13851394
use edgezero_core::app::Hooks as _;
13861395
use edgezero_core::body::Body;
13871396
use edgezero_core::context::RequestContext;
1388-
use edgezero_core::env_config::EnvConfig;
13891397
use edgezero_core::http::{Method, Response, StatusCode, header, request_builder};
13901398
use edgezero_core::key_value_store::NoopKvStore;
13911399
use edgezero_core::params::PathParams;
@@ -1455,32 +1463,17 @@ mod tests {
14551463
}
14561464

14571465
#[test]
1458-
fn runtime_store_config_maps_logical_store_names_and_config_key() {
1459-
let env = EnvConfig::from_vars([
1460-
(
1461-
"EDGEZERO__STORES__CONFIG__TRUSTED_SERVER_CONFIG__NAME",
1462-
"physical_config",
1463-
),
1464-
(
1465-
"EDGEZERO__STORES__CONFIG__TRUSTED_SERVER_CONFIG__KEY",
1466-
"active_config",
1467-
),
1468-
(
1469-
"EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME",
1470-
"ts_secrets",
1471-
),
1472-
]);
1473-
1474-
let stores = RuntimeStoreConfig::from_env(&env);
1466+
fn runtime_store_config_reads_the_staging_config_key_on_staging() {
1467+
let stores = RuntimeStoreConfig::for_target(true);
14751468

1476-
assert_eq!(stores.config_store_name.as_ref(), "physical_config");
1477-
assert_eq!(stores.config_key, "active_config");
1478-
assert_eq!(stores.secret_store_name.as_ref(), "ts_secrets");
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");
14791472
}
14801473

14811474
#[test]
1482-
fn runtime_store_config_uses_logical_defaults_without_overrides() {
1483-
let stores = RuntimeStoreConfig::from_env(&EnvConfig::default());
1475+
fn runtime_store_config_opens_logical_store_ids_in_production() {
1476+
let stores = RuntimeStoreConfig::for_target(false);
14841477

14851478
assert_eq!(stores.config_store_name.as_ref(), "trusted_server_config");
14861479
assert_eq!(stores.config_key, "trusted_server_config");

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@ use std::sync::Arc;
22

33
use edgezero_adapter_fastly::config_store::FastlyConfigStore as EdgeZeroFastlyConfigStore;
44
use edgezero_adapter_fastly::request::into_core_request;
5-
use edgezero_adapter_fastly::runtime_env_config;
6-
use edgezero_core::app::Hooks as _;
75
use edgezero_core::body::Body as EdgeBody;
86
use edgezero_core::config_store::ConfigStoreHandle;
97
use edgezero_core::error::EdgeError;
108
use edgezero_core::http::{Request as HttpRequest, Response as HttpResponse};
119
use edgezero_core::response::IntoResponse;
1210
use error_stack::Report;
11+
use fastly::compute_runtime;
1312
use fastly::http::Method as FastlyMethod;
1413
use fastly::{Request as FastlyRequest, Response as FastlyResponse};
1514

@@ -90,8 +89,7 @@ fn main() {
9089

9190
/// Handles a request through the `EdgeZero` router path.
9291
fn edgezero_main(mut req: FastlyRequest) {
93-
let runtime_env = runtime_env_config(TrustedServerApp::stores());
94-
let runtime_stores = RuntimeStoreConfig::from_env(&runtime_env);
92+
let runtime_stores = RuntimeStoreConfig::for_target(compute_runtime::is_staging());
9593

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

crates/trusted-server-integration-tests/fixtures/configs/viceroy-template.toml

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,28 +66,23 @@
6666
key = "api_key"
6767
data = "test-api-key"
6868

69-
[[local_server.secret_stores.ts_secrets]]
69+
[[local_server.secret_stores.trusted_server_secrets]]
7070
key = "integration_admin_password"
7171
data = "integration-admin-password-32-bytes-ok"
72-
[[local_server.secret_stores.ts_secrets]]
72+
[[local_server.secret_stores.trusted_server_secrets]]
7373
key = "integration_proxy_secret"
7474
data = "integration-test-proxy-secret-32-bytes-ok"
75-
[[local_server.secret_stores.ts_secrets]]
75+
[[local_server.secret_stores.trusted_server_secrets]]
7676
key = "integration_ec_passphrase"
7777
data = "integration-test-ec-secret-padded-32"
78-
[[local_server.secret_stores.ts_secrets]]
78+
[[local_server.secret_stores.trusted_server_secrets]]
7979
key = "integration_partner_token_alpha"
8080
data = "integration-test-token-alpha-32-bytes-ok"
81-
[[local_server.secret_stores.ts_secrets]]
81+
[[local_server.secret_stores.trusted_server_secrets]]
8282
key = "integration_partner_token_bravo"
8383
data = "integration-test-token-bravo-32-bytes-ok"
8484

8585
[local_server.config_stores]
86-
[local_server.config_stores.edgezero_runtime_env]
87-
format = "inline-toml"
88-
[local_server.config_stores.edgezero_runtime_env.contents]
89-
EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME = "ts_secrets"
90-
9186
# Generated integration configs inject the trusted_server_config blob
9287
# into the store required by the Fastly entry point.
9388
# GENERATED_TRUSTED_SERVER_CONFIG_STORES

crates/trusted-server-integration-tests/tests/common/config.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ pub fn cloudflare_config_json(origin_port: u16) -> TestResult<String> {
4646
mod tests {
4747
const FASTLY_CONFIG: &str = include_str!("../../../../fastly.toml");
4848
const VICEROY_TEMPLATE: &str = include_str!("../../fixtures/configs/viceroy-template.toml");
49-
const VICEROY_SECRET_STORE_MAPPING_KEY: &str =
50-
"EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME";
49+
const LOGICAL_SECRET_STORE_ID: &str = "trusted_server_secrets";
5150

5251
#[test]
5352
fn local_fastly_config_defines_runtime_kv_stores() {
@@ -74,20 +73,24 @@ mod tests {
7473
}
7574

7675
#[test]
77-
fn local_fastly_secret_store_mapping_is_canonical() {
76+
fn local_fastly_secret_store_is_exposed_under_its_logical_id() {
7877
for (name, config) in [
7978
("fastly.toml", FASTLY_CONFIG),
8079
("Viceroy integration template", VICEROY_TEMPLATE),
8180
] {
8281
let parsed: toml::Value =
8382
toml::from_str(config).expect("should parse Fastly configuration");
84-
let runtime_env =
85-
&parsed["local_server"]["config_stores"]["edgezero_runtime_env"]["contents"];
83+
let local_server = &parsed["local_server"];
8684

87-
assert_eq!(
88-
runtime_env[VICEROY_SECRET_STORE_MAPPING_KEY].as_str(),
89-
Some("ts_secrets"),
90-
"{name} should define the canonical secret-store mapping"
85+
assert!(
86+
local_server["secret_stores"][LOGICAL_SECRET_STORE_ID].is_array(),
87+
"{name} should expose the secret store under its logical ID"
88+
);
89+
assert!(
90+
local_server["config_stores"]
91+
.get("edgezero_runtime_env")
92+
.is_none(),
93+
"{name} should not define the legacy runtime selector store"
9194
);
9295
}
9396
}
@@ -96,9 +99,9 @@ mod tests {
9699
fn local_fastly_config_defines_starter_secret_references() {
97100
let parsed: toml::Value =
98101
toml::from_str(FASTLY_CONFIG).expect("should parse root fastly.toml");
99-
let entries = parsed["local_server"]["secret_stores"]["ts_secrets"]
102+
let entries = parsed["local_server"]["secret_stores"][LOGICAL_SECRET_STORE_ID]
100103
.as_array()
101-
.expect("fastly.toml should define ts_secrets");
104+
.expect("fastly.toml should define trusted_server_secrets");
102105

103106
for key in [
104107
"publisher_proxy_secret",

docs/guide/cli.md

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -118,30 +118,36 @@ deploy. Adapter passthrough arguments must now follow a `--` separator; unknown
118118
flags before `--` (including the renamed-away `--stage`) are rejected at parse
119119
time rather than forwarded. This is a change: passthrough args previously
120120
worked without the separator, so existing runbooks and CI jobs that pass
121-
adapter flags directly need the `--` added:
121+
adapter flags directly need the `--` added. Trusted Server declares Config, KV,
122+
and Secret Stores, so EdgeZero treats every Fastly deploy as managed and
123+
requires a verified application release root via `--application-release`; a
124+
bare `ts deploy --adapter fastly` without a release is accepted only for
125+
store-free applications:
122126

123127
```bash
124-
ts deploy --adapter fastly --service-id <service-id> --staging
125-
ts deploy --adapter fastly -- --comment "release"
128+
ts deploy --adapter fastly --service-id <service-id> --application-release <release-root> --staging
129+
ts deploy --adapter fastly --service-id <service-id> --application-release <release-root> -- --comment "release"
126130
```
127131

128132
A staged deploy selects the physical Config Store from the staging environment
129-
and points the staged version's config selector at the
130-
`<logical-store-id>_staging` key. It does not copy the production config blob
131-
there. Push the staged config before probing the staged version:
133+
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:
132137

133138
```bash
134139
ts config push --adapter fastly --staging
135140
ts config diff --adapter fastly --staging
136141
```
137142

138-
The staged version resolves its app-config key through a staging selector store
139-
linked under the name `edgezero_runtime_env`. Production and staging may select
140-
the same physical Config Store or different stores. After
141-
`ts config push --staging`, the staged binary reads
142-
`<logical-store-id>_staging` in the store selected by the staging environment,
143-
while the active production version continues to read its production key and
144-
store.
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.
145151

146152
`--staging` on `config push` / `config diff` writes and compares the
147153
`<logical-store-id>_staging` key in the physical store selected by the staging

docs/guide/fastly.md

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -275,27 +275,25 @@ export EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME=ts_secrets
275275
ts provision --adapter fastly
276276
```
277277

278-
Provisioning creates or reuses the physical store and the
279-
`edgezero_runtime_env` Config Store, but does not write environment selectors.
280-
Deployment copies the selected environment's declared store selectors into
281-
`edgezero_runtime_env` under their canonical names:
282-
283-
```text
284-
EDGEZERO__STORES__SECRETS__TRUSTED_SERVER_SECRETS__NAME=ts_secrets
285-
```
286-
287-
There is no Fastly service ID in the environment variable name. Each GitHub
288-
Environment or deploy process uses the same canonical names and may select
289-
different physical resources. A production deploy reconciles its selectors
290-
into `edgezero_runtime_env`. A staged deploy creates a per-service staging twin,
291-
applies the staging environment's selectors, links every selected physical
292-
store to the staged version, and links the twin under the name
293-
`edgezero_runtime_env`. Selected resources must already exist before deployment.
294-
295-
The custom streaming entry point reads the deployed mapping before loading app
296-
config, so every startup and reload resolves static credentials from
297-
`ts_secrets` while the portable manifest continues to declare
298-
`trusted_server_secrets`.
278+
Provisioning creates or reuses the physical store. A managed deployment reads
279+
the selector from its deployment environment and links the selected physical
280+
store to the target service version under the logical ID
281+
`trusted_server_secrets`. The runtime opens the store by that logical ID; no
282+
selector is stored in a Config Store and no service ID appears in the variable
283+
name.
284+
285+
Each GitHub Environment or deploy process uses the same canonical names and may
286+
select different physical resources. Production and staging can therefore run
287+
identical package bytes against different stores. A staged deploy links the
288+
staging environment's selected stores into only the staged version. Selected
289+
resources must already exist before deployment.
290+
291+
The custom streaming entry point opens `trusted_server_secrets` before loading
292+
app config, so every startup and reload resolves static credentials from the
293+
physical store linked under that ID while the portable manifest continues to
294+
declare `trusted_server_secrets`. Local Viceroy configuration exposes the store
295+
under the logical ID directly; see `[local_server.secret_stores]` in
296+
`fastly.toml`.
299297

300298
Create the separate request-signing store when that feature is enabled:
301299

0 commit comments

Comments
 (0)