Skip to content

Align Fastly staging store selectors with EdgeZero PR 381 - #1175

Open
aram356 wants to merge 34 commits into
mainfrom
fix/align-edgezero-pr-381
Open

aram356 wants to merge 34 commits into
mainfrom
fix/align-edgezero-pr-381

Conversation

@aram356

@aram356 aram356 commented Sep 16, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Restore Fastly staging secret resolution by consuming the store-selection model from EdgeZero PR 381: a managed deployment links each physical store selected by a canonical EDGEZERO__STORES__<KIND>__<ID>__NAME deployment selector to the target version under its logical ID, and the runtime opens stores by that ID.
  • Open trusted_server_config and trusted_server_secrets by logical ID in the Fastly entry point and read the config entry under trusted_server_config for every target. The upstream branch removed runtime_env_config and the edgezero_runtime_env Config Store it read, and fixed the Fastly config key to the logical ID; staging isolation comes from the physical store the staging environment selects.
  • Expose the local Viceroy secret store under trusted_server_secrets and drop the edgezero_runtime_env selector store, so local runs exercise the same store-opening path as a deployed version.
  • Update operator guidance so production and staging select physical stores through their deployment environments and so ts deploy --adapter fastly passes a verified application release.
  • Watch only bundle inputs in the trusted-server-js build script. It previously emitted a rerun directive for every file under lib/, including node_modules, so any npm install invalidated the crate and Cargo re-checked 33,932 paths on every build.

The EdgeZero dependencies pin the immutable commit 0645339d1848332f4805259d29e3b4b881fccad3 on the unmerged upstream branch with rev =, so main stays reproducible and cargo update cannot move it. Issue #1195 tracks replacing the rev with the release tag after the upstream PR merges.

Changes

File Change
Cargo.toml, Cargo.lock Pin every EdgeZero crate to the immutable upstream commit 0645339d with rev =.
Fastly adapter main.rs, app.rs Replace RuntimeStoreConfig::from_env with logical(): logical store IDs and the logical config key for every target. A unit test covers the bindings.
fastly.toml, Viceroy integration fixture, template-cache script Rename the local secret store to trusted_server_secrets; remove the edgezero_runtime_env mapping.
Integration config test Verify both Viceroy configurations expose the secret store under its logical ID and define no legacy selector store.
Fastly and CLI guides Document deploy-time environment selectors, logical-ID resource links, the fixed logical config key, and the --application-release requirement for managed deploys.
Design and implementation plan Record the root cause, the logical-ID runtime model, validation, and the release-tag follow-up.
crates/trusted-server-js/build.rs Replace the recursive lib/ walk with explicit rerun-if-changed directives for lib/src, the package manifests, and the bundler configuration. No-op cargo check -p trusted-server-js drops from 1.1s to 0.15s and the script emits 7 directives instead of 33,932.

Closes

Closes #1174

Test plan

  • cargo test-fastly && cargo test-axum
  • cargo test-cloudflare && cargo test-spin
  • cargo clippy-fastly && cargo clippy-axum
  • cargo clippy-cloudflare && cargo clippy-cloudflare-wasm
  • cargo clippy-spin-native && cargo clippy-spin-wasm
  • cargo check-fastly && cargo check-axum && cargo check-cloudflare && cargo check-spin
  • cargo fmt --all -- --check
  • ./scripts/test-cli.sh
  • cargo test --manifest-path crates/trusted-server-integration-tests/Cargo.toml --test integration local_fastly --target aarch64-apple-darwin
  • cargo test --manifest-path crates/trusted-server-integration-tests/Cargo.toml --test parity --target aarch64-apple-darwin
  • JS build: cd crates/trusted-server-js/lib && npm run build
  • JS tests: cd crates/trusted-server-js/lib && npm test
  • JS format: cd crates/trusted-server-js/lib && npm run format
  • Docs format: cd docs && npm run format
  • WASM release build: cargo build --package trusted-server-adapter-fastly --release --target wasm32-wasip1
  • Manual testing via fastly compute serve

Checklist

  • Changes follow AGENTS.md conventions
  • No unwrap() added in production code
  • No production logging changes
  • New behavior has a regression test
  • No secrets or credentials committed

@aram356 aram356 self-assigned this Sep 16, 2026
@aram356 aram356 added this to the 202609 milestone Sep 16, 2026
@aram356
aram356 marked this pull request as draft September 16, 2026 16:30
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.
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.
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.
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.
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.
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.
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.
The two upstream commits since 7162b7e2 only reorganize the EdgeZero CI
test workflows. No crate source changed, so this is a lockfile-only
update.
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.
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.
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.
aram356 added a commit that referenced this pull request Sep 19, 2026
# Conflicts:
#	crates/trusted-server-adapter-fastly/src/app.rs
#	crates/trusted-server-adapter-fastly/src/main.rs
#	crates/trusted-server-integration-tests/fixtures/configs/viceroy-template.toml
#	fastly.toml
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.
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.
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.
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.
@aram356
aram356 requested a review from dhruv8sh September 21, 2026 16:12
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.
@aram356

aram356 commented Sep 24, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed all findings from the latest review in a1710a0.

Blocking, mutable branch pin. All six EdgeZero dependencies now use rev = "12c3215c2637d961a27eefa12e235033fadb4c4a", the commit the lockfile already resolved. cargo metadata --locked passes and the lockfile source is now git+…?rev=12c3215c…#12c3215c…, byte-identical to what the branch pin resolved to. No unrelated dependency edges moved. Follow-up tracked in #1195, and the PR body now describes the rev pin rather than the branch.

Non-blocking, leftover guidance contradicts the new model. The two lines at fastly.md are replaced: the deployment creates the trusted_server_secrets link from the selected physical store, so operators are told not to create it by hand.

Non-blocking, Config Store selector undocumented for Fastly. The Config Store section now exports EDGEZERO__STORES__CONFIG__TRUSTED_SERVER_CONFIG__NAME alongside the secrets selector, and says staging isolation comes from selecting a different physical store because the entry key is the logical ID on every target.

The two inline P3 items are answered on their threads.

Verification. cargo metadata --locked, check-fastly, and all eight clippy targets including the new clippy-cli and clippy-codegen pass. Docs format passes. The new test assertion was checked against a deliberately reinserted ts_secrets block, which fails it, then passes once removed. Full test suites are still running locally; CI covers the same gates.

@aram356
aram356 requested a review from prk-Jr September 24, 2026 06:05
aram356 added a commit that referenced this pull request Sep 24, 2026

@prk-Jr prk-Jr left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

The logical Fastly store bindings match the pinned EdgeZero implementation. One deployment-documentation correction is required; no confirmed runtime regressions were found.

The inline comment carries one GitHub suggestion that can be applied with Commit suggestion.

Blocking

  • 🔧 Correct the application-release instructions — see inline at docs/guide/cli.md:227–232.

Non-blocking

None.

CI Status

All 20 reported checks pass:

  • PASS: integration tests
  • PASS: browser integration tests
  • PASS: integration tests (Fastly EC lifecycle)
  • PASS: CodeQL
  • PASS: cargo test (ts CLI, native)
  • PASS: cargo check (cloudflare native + wasm32-unknown-unknown)
  • PASS: Analyze (javascript-typescript) (both reported runs)
  • PASS: cargo test (cross-adapter parity)
  • PASS: cargo fmt
  • PASS: cargo test (axum native)
  • PASS: Analyze (actions)
  • PASS: format-typescript
  • PASS: cargo test
  • PASS: CLAUDE.md symlink guard
  • PASS: format-docs
  • PASS: cargo check/build/test (spin native + wasm32-wasip1)
  • PASS: Analyze (rust)
  • PASS: prepare integration artifacts
  • PASS: vitest

The documentation suggestion was scratch-checked with Prettier; the reviewer worktree was restored clean.

Comment thread docs/guide/cli.md Outdated

@dhruv8sh dhruv8sh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Reviewed head a1710a05 against EdgeZero at the pinned 12c3215.

The runtime change is correct and small: the Fastly entry point opens trusted_server_config / trusted_server_secrets by logical ID and reads the config entry under the logical ID for every target, which matches how EdgeZero links stores at that commit and matches edgezero.toml. The blocking issues are in the operator docs: one staging instruction can overwrite production config, and there is no upgrade path for services already deployed from main.

Findings already raised by earlier reviews are not repeated here (branch pin → rev =, EDGEZERO_MANIFEST, Config Store selector example, ts_secrets assertion, runtime-env doc comment, and the package-fastly-application-release action name thread at cli.md:232).

Blocking

🔧 wrench

  • Staging config push docs can overwrite production config — see inline at docs/guide/cli.md:245
  • No upgrade path for services on main; fastly compute publish still documented — see inline at docs/guide/fastly.md:325

Non-blocking

⛏ nitpick / 🏕 camp site / 📝 note

  • --staging / --key wording — see inline at docs/guide/cli.md:255
  • Design spec still says branch dependency — see inline at the design spec
  • scripts/smoke-fastly.sh still targets ts_secrets and fails — see cross-cutting
  • Pin is one commit behind PR 381 head — see cross-cutting
  • Stale "derived staging key" test messages — see cross-cutting

Cross-cutting / body-level findings

  • 🔧 docs/guide/edgezero.md:19 (outside diff) still says --staging "writes LOGICAL_ID_staging in the same physical store", contradicting the new cli.md.
  • 🏕 scripts/smoke-fastly.sh:93,134-142 and docs/guide/fastly.md:386 still use [local_server.secret_stores.ts_secrets], which nothing opens any more. Running the smoke on this head fails (expected HTTP 500 ... received 200, exit 1). To be fair: it fails identically on main (a4e01eb5) — the base fastly.toml already contains the three secrets and the awk only strips the appended unindented blocks, so the base values still resolve — and renaming the store alone does not fix it. Fix both (rename + strip/override base entries in the copied fastly.toml) or file a follow-up; CI does not run this script.
  • 📝 Pin is one upstream commit behind PR 381. Upstream head is 61e8444 ("address managed Fastly deployment review"), which changes config gc store resolution (manifest defaults, rejects empty selectors) and touches provision and the release verifier. Low impact for Trusted Server, but worth bumping or noting in #1195.
  • ⛏ crates/trusted-server-cli/src/run.rs:482,494,505,518 (outside diff) still say "derived staging key" in test messages.

Verification

Isolated worktree at a1710a05:

Check Result
cargo fmt --all -- --check pass
cargo clippy-fastly pass
cargo build -p trusted-server-adapter-fastly --release --target wasm32-wasip1 pass (unchecked in the PR test plan)
cargo test-fastly -p trusted-server-adapter-fastly runtime_store_config 1 passed
integration local_fastly tests 3 passed
./scripts/smoke-fastly.sh (PR head / main) fails the same way on both

EdgeZero source read at 12c3215: resolve_config_store_and_key, validate_fastly_config_key, ConfigPushArgs --staging, and the custom-entrypoint migration guide.

CI Status

All 20 checks pass on a1710a05, including required cargo fmt, cargo test, format-typescript, and format-docs.

Comment thread docs/guide/cli.md Outdated
Comment thread docs/guide/cli.md Outdated
Comment thread docs/guide/fastly.md
Comment thread docs/superpowers/specs/2026-09-16-edgezero-fastly-store-selectors-design.md Outdated
Comment thread crates/trusted-server-adapter-fastly/src/app.rs
…-381

# Conflicts:
#	crates/trusted-server-adapter-fastly/src/app.rs
#	crates/trusted-server-integration-tests/fixtures/configs/viceroy-template.toml
#	docs/guide/fastly.md
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__<ID>__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__<ID>__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.
@aram356

aram356 commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed the review in 86695c3, and resolved the conflict with main in ae434d4.

Conflict resolution

Three files conflicted. Each needed a decision rather than a side:

  • app.rs: took main's new test imports but dropped its EnvConfig import, which existed only for the from_env tests this PR removes.
  • Viceroy fixture: kept this PR's deletion of the edgezero_runtime_env store that main re-added, with main's comment rewording.
  • fastly.md: kept main's new service-ID prerequisites, dropped its claim that provisioning persists a runtime mapping in a Config Store.

Cross-cutting findings

scripts/smoke-fastly.sh now passes. Your diagnosis was right that renaming the store alone is insufficient. The specific reason: the base fastly.toml defines the same three keys under indented table headers, while the appended blocks are unindented, so the exact-match awk only ever stripped the appended ones and a resolvable value survived. Both matchers now tolerate indentation, and the base entries are stripped on copy. The script passes end to end, including all four fail-closed cases and the positive case. My first attempt at this fix was itself wrong for the same indentation reason, and only running the script caught it.

Pin was eight commits behind, not one. Repinned to c2e862f436421cdcfbac620c06995f262d6788c9. The range includes a merge from upstream main, config gc store resolution, selector case normalization, and app-CLI build-target fixes. No public API Trusted Server uses changed. #1195 updated.

That repin surfaced a behavior change worth flagging. config_push_does_not_use_the_runtime_key_override_without_the_key_flag (from main, #879) failed. At v0.0.8, resolve_config_key returned the logical id and ignored any __KEY selector; at the pinned revision it returns the selector verbatim when --key is absent. I verified the test passes on main at v0.0.8 and fails only under the new revision, so this is upstream behavior, not a regression here. The test now asserts the new contract and the upgrade note says a leftover __KEY selector pushes to a key the Fastly runtime never reads.

Stale test messages in run.rs fixed.

Verification

Check Result
cargo fmt --all -- --check pass
8 clippy targets incl. clippy-cli, clippy-codegen pass
test-fastly, test-axum, test-cloudflare, test-spin pass
cross-adapter parity pass
./scripts/test-cli.sh pass (after the test update above)
vitest 1185 passed
docs + JS format pass
./scripts/smoke-fastly.sh pass (fails on main)

@aram356
aram356 requested review from dhruv8sh and prk-Jr October 3, 2026 02:41

@dhruv8sh dhruv8sh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Moves the Fastly runtime to logical-ID store links from EdgeZero PR 381, drops the edgezero_runtime_env selector store, renames the Viceroy secret store to trusted_server_secrets, routes deploy docs through ts deploy --application-release, and narrows the trusted-server-js build-script watch list. The runtime change is clean and well tested; one operator guide outside the diff still documents the removed model, which blocks.

2 of the inline comments below carry a one-click GitHub suggestion — use Commit suggestion (or Add suggestion to batch for several at once) to apply them as commits on the PR branch. The remaining findings describe the fix in prose because the change touches files outside the diff and can't be auto-applied.

Blocking

🔧 wrench

  • Configuration guide still documents the removed edgezero_runtime_env model — see Cross-cutting below (docs/guide/configuration.md:2799-2908)

Non-blocking

⛏ nitpick

  • Upgrade note misstates what a leftover __KEY selector does — see inline at docs/guide/fastly.md:352-354
  • Managed-path upgrade bullet omits EDGEZERO_MANIFEST and splits inline code — see inline at docs/guide/fastly.md:346-348

🏕 camp site / 📝 note

  • Stale core doc comments on Fastly store resolution — see Cross-cutting below
  • PR description and plan still name the old pin — see Cross-cutting below

👍 praise

  • Build script watches only bundle inputs — see inline at crates/trusted-server-js/build.rs:18-32
  • Smoke missing-secret cases can now actually fail — see inline at scripts/smoke-fastly.sh:34-54

Cross-cutting / body-level findings

  • 🔧 Configuration guide still documents the removed edgezero_runtime_env model — docs/guide/configuration.md:2799-2908 ("Fastly Runtime Config Store", "Initial setup with a service-specific store", "Selecting another blob key") is unchanged and still tells operators that the runtime reads EDGEZERO__SERVICES__<SERVICE_ID>__… selectors from edgezero_runtime_env, to link that store, to publish with fastly compute publish (line 2870), that a __KEY override "does not change that write destination", and to select another production key via --key plus a runtime __KEY entry. With the new pin all of that is wrong: the runtime never reads the selector store, fastly compute publish activates a version without the trusted_server_secrets link (every publisher route 500s, per this PR's own upgrade notes), and the Fastly CLI rejects a non-logical --key / __KEY (validate_fastly_config_key). The PR's spec also promises edgezero_runtime_env references are removed from current operator docs; only the link to this anchor was dropped from fastly.md.

    Proposed fix (apply manually — the file is outside the diff, so it can't be a suggestion): replace everything from ## Fastly Runtime Config Store up to, but not including, ### Local development (which is still accurate) with:

    ## Fastly Runtime Config Store
    
    After the EdgeZero cutover, the Fastly adapter always dispatches through the
    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, 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.
  • 🏕 Stale core doc comments on Fastly store resolution — crates/trusted-server-core/src/settings_data.rs:44-60: the docs on default_config_store_name and default_config_key still say Fastly resolves from service-scoped entries in edgezero_runtime_env, and that a __KEY override is ignored by a plain push. Neither holds after this PR. Proposed text (apply manually — outside the diff):

    /// Resolves the `EdgeZero` app-config store name from the process environment.
    ///
    /// 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.
    ...
    /// Resolves the app-config blob key from the process environment.
    ///
    /// Native adapters such as Axum use this wrapper. Fastly always reads the
    /// logical store ID as the key, and its CLI rejects any other `--key` or
    /// `__KEY` selector.
    
  • 📝 PR description and plan still name the old pin — the description says the EdgeZero dependencies pin 12c3215c…, but Cargo.toml / Cargo.lock pin c2e862f436421cdcfbac620c06995f262d6788c9 since 86695c3 (the spec is correct). docs/superpowers/plans/2026-09-16-edgezero-fastly-store-selectors.md:117 still shows branch = "fix/fastly-environment-store-selectors". For reference: upstream PR 381 is still open at b537495a, 3 commits ahead of the pin with c2e862f still an ancestor, so the rev is reachable today; #1195 tracks moving to a release tag.

CI Status

  • integration tests: PASS
  • browser integration tests: PASS
  • integration tests (Fastly EC lifecycle): PASS
  • CodeQL: PASS
  • cargo test (ts CLI, native): PASS
  • format-docs: PASS (required)
  • Analyze (javascript-typescript): PASS
  • cargo test (cross-adapter parity): PASS
  • cargo fmt: PASS (required)
  • cargo test (axum native): PASS
  • Analyze (actions): PASS
  • format-typescript: PASS (required)
  • cargo check (cloudflare native + wasm32-unknown-unknown): PASS
  • cargo test: PASS (required)
  • prepare integration artifacts: PASS
  • cargo check/build/test (spin native + wasm32-wasip1): PASS
  • Analyze (rust): PASS
  • CLAUDE.md symlink guard: PASS
  • vitest: PASS

Comment thread docs/guide/fastly.md Outdated
Comment thread docs/guide/fastly.md Outdated
Comment thread crates/trusted-server-js/build.rs
Comment thread scripts/smoke-fastly.sh

@prk-Jr prk-Jr left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

The runtime change is small and correct. RuntimeStoreConfig::logical() opens trusted_server_config / trusted_server_secrets by logical ID and reads the config entry under the logical key. That matches what c2e862f links and what validate_fastly_config_key enforces, and local Viceroy plus the integration fixtures now take the same path. One new blocking item is in the upgrade docs. I also agree with the open blocking finding on configuration.md from the earlier review of this head, and I don't repeat it here.

1 of the inline comments below carries a one-click GitHub suggestion. Use Commit suggestion to apply it.

Blocking

🔧 wrench

  • Upgrade checklist doesn't move store selectors into the deploy environment — see inline at docs/guide/fastly.md:349-351

Cross-cutting / body-level findings

  • 📝 Agreeing with existing open items on this head (not repeated inline): the stale docs/guide/configuration.md "Fastly Runtime Config Store" section (blocking), the stale settings_data.rs doc comments, the __KEY rationale at fastly.md:352-354, the EDGEZERO_MANIFEST omission at fastly.md:346-348, and the PR description still naming pin 12c3215c while Cargo.toml / Cargo.lock pin c2e862f4. When you rewrite configuration.md, its "Local development" paragraph needs updating too. At c2e862f, push_config_entries_local writes [local_server.config_stores.<logical>] regardless of __NAME, so the <resolved-name> wording and the "service-scoped runtime selectors" sentence are both stale.

Local verification (head 870135e8)

  • cargo fmt --all -- --check: PASS
  • cargo clippy-fastly, cargo clippy-cli, cargo clippy-axum: PASS
  • cargo test-fastly: PASS (adapter 194 passed, including runtime_store_config_opens_logical_store_ids_and_key; core 2887 passed)
  • cargo test -p trusted-server-cli --target aarch64-apple-darwin: PASS (including config_push_writes_the_runtime_key_override_without_the_key_flag)
  • cargo test-axum, cargo check-cloudflare, cargo check-spin: PASS
  • Integration crate common::config tests (3): PASS
  • I traced deploy link reconciliation in the pinned EdgeZero source. I did not run it against a live Fastly service.

CI Status

  • integration tests: PASS
  • browser integration tests: PASS
  • integration tests (Fastly EC lifecycle): PASS
  • CodeQL: PASS
  • cargo test (ts CLI, native): PASS
  • format-docs: PASS
  • Analyze (javascript-typescript): PASS
  • cargo test (cross-adapter parity): PASS
  • cargo fmt: PASS
  • cargo test (axum native): PASS
  • Analyze (actions): PASS
  • format-typescript: PASS
  • cargo check (cloudflare native + wasm32-unknown-unknown): PASS
  • cargo test: PASS
  • prepare integration artifacts: PASS
  • cargo check/build/test (spin native + wasm32-wasip1): PASS
  • Analyze (rust): PASS
  • CLAUDE.md symlink guard: PASS
  • vitest: PASS

Comment thread docs/guide/fastly.md
…-381

# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	crates/trusted-server-adapter-fastly/src/main.rs
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__<SERVICE_ID>__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.
@aram356

aram356 commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed both reviews in fa0353b and resolved the conflict in c0dc08c.

The conflict was a genuine fork, not a textual one

main had moved its EdgeZero pin to 683202c6 on EdgeZero's own main, and added a sandbox-reuse subsystem calling edgezero_adapter_fastly::lifecycle — a module that existed only on EdgeZero main, not on the PR 381 branch. Resolving the merge while keeping the old pin compiled to cannot find lifecycle in edgezero_adapter_fastly. EdgeZero PR 381 has since merged main, so the branch head 0645339d carries both lifecycle and the logical-store-link model. Repinned there, and the merge compiles.

Sandbox bounds moved off the deprecated store

sandbox.rs read its reuse bounds from edgezero_runtime_env via RUNTIME_ENV_STORE_NAME, which the new pin no longer exports. That store is deprecated and this PR removes it, so rather than hard-coding the name locally, the bounds now come from the application's own config store under the logical ID trusted_server_config. The EDGEZERO__SERVICES__<SERVICE_ID>__ key prefix went with it, since it only existed to namespace entries inside the shared selector store. Keys are now plain TS__SANDBOX__*. Verified clean in both feature configurations: clippy-fastly without the feature, test-fastly-reuse with it (218 passed). The upgrade checklist tells operators to move these bounds and delete the stale link.

Findings

All three applied with your wording. On the __KEY rationale: you were right and my earlier note was backwards — validate_fastly_config_key errors on any non-logical key, so the push fails rather than writing somewhere unread. The stale configuration.md section is replaced, including its local-development paragraph, after confirming push_config_entries_local writes under the logical ID regardless of __NAME. The settings_data.rs doc comments, the design spec, the PR body pin, and #1195 are updated.

Verification

Check Result
8 clippy targets incl. clippy-cli, clippy-codegen pass
test-fastly, test-fastly-reuse pass
test-axum, test-cloudflare, test-spin pass
cross-adapter parity pass
cargo fmt --all -- --check pass
vitest 1185 passed
docs, JS, and root markdown format pass
./scripts/test-cli.sh 1 pre-existing failure

To be precise about that last one: exhausted_page_settle_budget_still_polls_gpt_registry fails here. It is browser-driven, outside this PR's diff, and reports ignored, requires local Chrome/Chromium when run outside the script. I ran the same suite on main to check: it fails there too, with three browser tests failing rather than one. Environmental on this machine, not a regression from this branch.

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.
@aram356
aram356 requested review from dhruv8sh and prk-Jr October 8, 2026 06:46

@prk-Jr prk-Jr left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

The Fastly runtime bindings match the pinned EdgeZero logical-resource-link and config-key contracts. No runtime correctness regression was found in this review, and all 22 reported GitHub checks pass. The two documentation observations below are nonblocking follow-ups.

Non-blocking

  • 🤔 Document the managed-deploy token prerequisite — see inline at docs/guide/cli.md:224.
  • 🤔 Preserve config used by legacy staged versions — see inline at docs/guide/fastly.md:369–371.

Validation

Reviewed the changed files and exact EdgeZero revision 0645339d1848332f4805259d29e3b4b881fccad3. Both proposed documentation replacements pass Prettier; both changed shell scripts pass bash -n. Rust and JS suites were not rerun locally because the remote checks passed. The isolated review worktree is clean.

CI Status

  • integration tests: PASS
  • browser integration tests: PASS
  • integration tests (Fastly EC lifecycle): PASS
  • CodeQL: PASS
  • cargo test (ts CLI, native) (macos-latest): PASS
  • cargo test (axum native): PASS
  • CLAUDE.md symlink guard: PASS
  • cargo test: PASS (required)
  • format-typescript: PASS (required)
  • Analyze (rust): PASS
  • format-docs: PASS (required)
  • cargo fmt: PASS (required)
  • Analyze (javascript-typescript): PASS
  • cargo check (cloudflare native + wasm32-unknown-unknown): PASS
  • cargo check/build/test (spin native + wasm32-wasip1): PASS
  • cargo test (cross-adapter parity): PASS
  • cargo test (ts CLI, native) (ubuntu-latest): PASS
  • prepare integration artifacts: PASS
  • vitest: PASS
  • Analyze (actions): PASS
  • Analyze (python): PASS
  • Analyze (javascript-typescript): PASS

Comment thread docs/guide/cli.md
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:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 Nonblocking follow-up — Document the managed-deploy token prerequisite. The setup guides configure a Fastly CLI profile, but the pinned EdgeZero managed deploy calls require_token() and reads a nonempty FASTLY_API_TOKEN directly from the process environment. Following the profile setup alone therefore makes these commands fail with FASTLY_API_TOKEN must be set in the environment. Please name that prerequisite beside the commands. Suggested wording:

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:

Comment thread docs/guide/fastly.md
Comment on lines +369 to +371
- 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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 Nonblocking follow-up — Preserve config used by legacy staged versions. A production upgrade can leave an older staged version deployed. Its version-linked selector still reads <logical-store-id>_staging, so removing that shared entry when no production-active version uses it can make the staged publisher routes return 500. Please retain the legacy entries until active, staged, and retained rollback versions no longer depend on them. Suggested wording:

- Delete the stale `edgezero_runtime_env` link and any `*_staging` config
  entries only after no active, staged, or rollback version depends on them.
  This release no longer reads that store. If you set the optional
  `TS__SANDBOX__*` reuse bounds

@dhruv8sh dhruv8sh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Moves the Fastly runtime to open its config and secret stores by logical ID, with deploy-time resource links replacing the edgezero_runtime_env selector store. It also narrows the trusted-server-js build-script watch set. The runtime change is clean and the EdgeZero claims check out at the pinned rev: validate_fastly_config_key rejects non-logical keys, and managed deploys require --application-release. One operator-safety gap in the upgrade docs needs to close before merge.

2 of the inline comments below carry a one-click GitHub suggestion. Use Commit suggestion (or Add suggestion to batch for both) to apply them as commits on the PR branch. The remaining comments describe the change in prose because they are questions or judgement calls for the author.

Blocking

🔧 wrench

  • A --staging config push now overwrites the production config when __NAME is unset (see inline at docs/guide/fastly.md:363)

Non-blocking

⛏ nitpick / 🤔 thinking

  • CLI test comment understates the Fastly behaviour (see inline at crates/trusted-server-cli/tests/config_store_defaults.rs:139)
  • limit_keys_are_unscoped_app_config_keys only asserts constants (see inline at crates/trusted-server-adapter-fastly/src/sandbox.rs:361)
  • deploy = "fastly compute publish" is kept but documented as unused (see inline at edgezero.toml:56)

👍 praise

  • Narrowed rerun-if-changed set in build.rs (see inline at crates/trusted-server-js/build.rs:22)

CI Status

  • Analyze (javascript-typescript): PASS
  • Analyze (rust): PASS
  • Analyze (python): PASS
  • Analyze (actions): PASS
  • CodeQL: PASS
  • CLAUDE.md symlink guard: PASS
  • browser integration tests: PASS
  • cargo check (cloudflare native + wasm32-unknown-unknown): PASS
  • cargo check/build/test (spin native + wasm32-wasip1): PASS
  • cargo fmt: PASS (required)
  • cargo test: PASS (required)
  • cargo test (axum native): PASS
  • cargo test (cross-adapter parity): PASS
  • cargo test (ts CLI, native) (ubuntu-latest): PASS
  • cargo test (ts CLI, native) (macos-latest): PASS
  • format-docs: PASS (required)
  • format-typescript: PASS (required)
  • integration tests: PASS
  • integration tests (Fastly EC lifecycle): PASS
  • prepare integration artifacts: PASS
  • vitest: PASS

Comment thread docs/guide/fastly.md
Comment on lines +363 to +365
- Re-push staging app config under the logical key into the staging Config
Store. Entries previously pushed under `<logical-store-id>_staging` are
ignored.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔧 wrench: A --staging config push now overwrites the production config when __NAME is unset.

On main, ts config push --adapter fastly --staging wrote the separate <logical-store-id>_staging key, so a staged push could not touch production's entry. With this PR, --staging only changes which physical store is selected through EDGEZERO__STORES__CONFIG__TRUSTED_SERVER_CONFIG__NAME. When that variable is unset, the push falls back to the logical-ID store, which is normally the one production links, and it overwrites production's entry. Production instances pick it up on their next start. EdgeZero allows staging and production to share a store on purpose (args.rs: "Production and staging may select the same or different physical stores"), so nothing on the CLI side stops this.

cli.md explains the hazard, but this upgrade checklist is what existing operators will follow, and an unchanged runbook that ran --staging safely before this PR would now push staging config to production. The checklist should say so explicitly:

Suggested change
- Re-push staging app config under the logical key into the staging Config
Store. Entries previously pushed under `<logical-store-id>_staging` are
ignored.
- Re-push staging app config under the logical key into the staging Config
Store, with `EDGEZERO__STORES__CONFIG__TRUSTED_SERVER_CONFIG__NAME` set to
that store. Entries previously pushed under `<logical-store-id>_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.

Separately, consider having ts config push --staging on Fastly refuse to run when the __NAME selector is unset. That would turn this from a documentation warning into a guard. It can be a follow-up issue.

Comment on lines +139 to +141
// 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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏ nitpick: This comment understates the Fastly behaviour. The Fastly CLI doesn't just recommend leaving __KEY unset, it rejects any value other than the logical ID (validate_fastly_config_key). The comment also doesn't say that this test runs the Axum adapter, which is why the override is honoured here.

Suggested change
// 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.
// 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.

"EDGEZERO__SERVICES__0000000000000000000000__TS__SANDBOX__TIMEOUT_MS",
"should scope the wait timeout the same way"
);
fn limit_keys_are_unscoped_app_config_keys() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏ nitpick: This test asserts that string literals start with TS__SANDBOX__ and don't contain EDGEZERO__SERVICES__, so it can only fail if someone edits the constants and the test together. The behaviour that matters is that read_raw_limits opens DEFAULT_CONFIG_STORE_ID and looks the keys up unscoped, and this test doesn't cover it. I'd drop it rather than keep a test that can't catch a regression. Your call.

Comment thread edgezero.toml
# 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"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 thinking: The new comment says this command is unused because EdgeZero always takes the managed path for an app with stores, and the docs now say never to deploy with fastly compute publish. If EdgeZero's manifest schema doesn't require deploy, removing the line is safer than keeping a command someone could copy into a runbook. If the schema does require it, the comment is fine as it is.

// 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 [

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 praise: Replacing the recursive lib/ walk with explicit inputs is a good fix: 7 directives instead of 33,932, and an npm install no longer invalidates the crate. Every watched path exists, which matters because a missing path would make Cargo rerun the script on every build.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Align Fastly staging store selectors with EdgeZero PR 381

4 participants