Skip to content

Support optional typed secret paths and Fastly store mappings - #344

Open
ChristianPavilonis wants to merge 2 commits into
mainfrom
feature/typed-static-secret-paths
Open

Support optional typed secret paths and Fastly store mappings#344
ChristianPavilonis wants to merge 2 commits into
mainfrom
feature/typed-static-secret-paths

Conversation

@ChristianPavilonis

@ChristianPavilonis ChristianPavilonis commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add an explicit optional intermediate segment to typed secret paths so disabled or absent feature blocks do not require unrelated secrets.
  • Make Fastly's runtime environment mapping available to custom entry points.
  • Persist non-default logical-to-physical store mappings during provisioning and staged deployment, including deployment-supplied overrides.

This PR is stacked on #316 because Trusted Server currently pins that branch.

Changes

Crate / File Change
edgezero-core Add SecretPathSegment::OptionalField and teach runtime extraction to skip absent or null optional containers atomically.
edgezero-cli Mirror optional-path behavior in secret-leaf discovery and emit non-default store-name mappings into edgezero_runtime_env.
edgezero-adapter-fastly Expose env_config_from_runtime_dictionary, persist store mappings in local Fastly manifests, and overlay validated process mappings into the staged runtime-env twin before relinking.

Related

Test plan

  • cargo test --workspace --all-targets
  • cargo clippy --workspace --all-targets --all-features -- -D warnings
  • cargo fmt --all -- --check
  • cargo check --workspace --all-targets --features "fastly cloudflare spin"
  • WASM builds: wasm32-wasip1 (Fastly)
  • examples/app-demo workspace: cd examples/app-demo && cargo test --workspace --all-targets
  • Docs build: cd docs && npm run lint && npm run format && npm run build
  • Manual testing via edgezero serve --adapter axum
  • Other: cargo test -p edgezero-core, cargo test -p edgezero-cli, cargo test -p edgezero-macros, native Fastly adapter tests, Fastly WASM checks, live staged runtime mapping verification, and package-specific Clippy checks with -D warnings

Checklist

  • Changes follow CLAUDE.md conventions
  • No Tokio deps added to core or adapter crates
  • Route params use {id} syntax (not :id) — no route changes
  • Types imported from edgezero_core (not http crate)
  • Store wiring goes through registries — no runtime store wiring added
  • New code has tests
  • No secrets or credentials committed

@ChristianPavilonis ChristianPavilonis changed the title feature/typed static secret paths Support optional typed secret paths and Fastly store mappings Aug 24, 2026
@ChristianPavilonis
ChristianPavilonis force-pushed the feature/typed-static-secret-paths branch 2 times, most recently from 2b24957 to 0d6ebf9 Compare August 24, 2026 22:22
@ChristianPavilonis ChristianPavilonis self-assigned this Aug 24, 2026

@prk-Jr prk-Jr left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PR Review

Summary

Three separable changes: an OptionalField secret-path segment threaded through core + CLI, env_config_from_runtime_dictionary made public, and Fastly provision/staged-deploy persistence of non-default logical→physical store-name mappings. The secret-path half is clean and symmetric — CLI and runtime walkers grew matching arms with matching tests. The Fastly store-mapping half introduces a new write into a store the ACTIVE version reads, sourced from ambient process env, with no reconciliation of stale entries; that is where the blocking findings are.

All four CI gates pass locally on 0d6ebf9b.

😃 Praise

  • collect_secret_leaf extraction (crates/edgezero-cli/src/config.rs:1636) avoids a fourth copy of the leaf-resolution block, and threading optional_segment separately from field.optional keeps "this segment is optional" distinct from "this leaf is Option<String>" — which makes the required-Field arm provably unchanged.
  • CLI/runtime symmetry maintained exactly: collect_secret_leaves and resolve_secret_field grew the same two arms in the same order, each with a test on both sides. That lockstep is the hard part of this subsystem.
  • staging_entries_from_production kept pure, with overlay_runtime_store_name_entries as a separate testable function.

Findings

Blocking

  • 🔧 provision rewrites live production store resolution from ambient shell envcrates/edgezero-adapter-fastly/src/cli.rs:598. EnvConfig::from_env() (crates/edgezero-cli/src/provision.rs:96) + resolve_kind (provision.rs:145) mean any EDGEZERO__STORES__*__NAME in the operator's shell is written into edgezero_runtime_env, read by the ACTIVE version. New behavior: before this PR provision created the store but wrote no entries into it.
  • 🔧 Stale __NAME mappings never removedcli.rs:3640. Dropping an override leaves the old entry live; production has no equivalent of the staging mirror's upsert-then-delete reconciliation.
  • 🔧 Override validation weaker than the runtime's, fails opencli.rs:3487. Control characters pass the CLI check but are silently rejected by is_blank_or_control (crates/edgezero-core/src/env_config.rs:144), so the runtime falls back to the logical id — wrong store, no diagnostic.
  • OptionalField has no derive pathcrates/edgezero-core/src/app_config.rs:41. The macro only emits Field/ArrayEach, and nested_child_type (crates/edgezero-macros/src/app_config.rs:453) doesn't unwrap Option<T>, so #[app_config(nested)] x: Option<Inner> fails the AppConfigRoot bound. Reachable only from a hand-written impl AppConfigMeta — is that the intended surface?
  • 🔧 Add #[non_exhaustive] to SecretPathSegmentapp_config.rs:35-42. Public enum, exhaustively matchable; this PR is itself the breaking change.
  • 🔧 Docs now contradict the codedocs/guide/configuration.md:393-401 still states that Option<Inner> is unsupported and that "only the leaf's own Option<String> is skippable. A missing or null intermediate object/array … is a ConfigOutOfDate error, not a silent skip — both config validate and the runtime reject it." Both halves are now false for OptionalField. (No inline comment — the file is untouched by this PR.)

Non-blocking

  • 🤔 env::vars() panics on non-UTF-8 environment — cli.rs:3586.
  • ♻️ Hoist that env read into the caller so mirror_production_to_staging stays pure and end-to-end testable — currently the only untested line in the new staging path.
  • 🤔 is_runtime_store_name_key (cli.rs:3465) accepts undeclared store ids, so a typo'd override silently no-ops.
  • #[inline] on env_config_from_runtime_dictionary (crates/edgezero-adapter-fastly/src/lib.rs:184) buys nothing.
  • ⛏ The ```ignore doc example (lib.rs:177-182) references a non-existent MyApp::stores() and can never be caught rotting.
  • 🌱 Test gaps: no coverage of the non-dry-run provision write path, nor of is_runtime_store_name_key rejecting near-miss keys (…__A__B__NAME, …__NAME__EXTRA, lowercase kind). The dry-run test at cli.rs:6753 covers the happy shape only.

CI Status

Run locally against 0d6ebf9b:

  • cargo fmt --all -- --check: PASS
  • cargo clippy --workspace --all-targets --all-features -- -D warnings: PASS
  • cargo test --workspace --all-targets: PASS
  • cargo check --workspace --all-targets --features "fastly cloudflare spin": PASS

The three unchecked boxes in the PR description's test plan (cargo test --workspace --all-targets, the feature check, and examples/app-demo) — the first two pass; examples/app-demo was not run.

Comment thread crates/edgezero-adapter-fastly/src/cli.rs Outdated
Comment thread crates/edgezero-adapter-fastly/src/cli.rs Outdated
Comment thread crates/edgezero-adapter-fastly/src/cli.rs
Comment thread crates/edgezero-core/src/app_config.rs
Comment thread crates/edgezero-core/src/app_config.rs
Comment thread crates/edgezero-adapter-fastly/src/cli.rs
Comment thread crates/edgezero-adapter-fastly/src/lib.rs
Comment thread crates/edgezero-adapter-fastly/src/lib.rs Outdated
Comment thread crates/edgezero-cli/src/config.rs
Comment thread crates/edgezero-core/src/extractor.rs
Base automatically changed from feature/edgezero-deploy-actions to main August 27, 2026 04:01
@aram356
aram356 force-pushed the feature/typed-static-secret-paths branch from b47cd19 to d4dc05d Compare August 27, 2026 04:01
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.

2 participants