From bc13f2773ba97e8de07f7ba6ef6f3d0a3e37427f Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Mon, 20 Jul 2026 16:38:03 -0700 Subject: [PATCH 01/10] Upgrade EdgeZero to the deploy-actions branch Point the edgezero-* dependencies at the feature/edgezero-deploy-actions branch (PR #316) and adapt Trusted Server to its API changes: - Wire the new ts CLI subcommands surfaced by edgezero-cli: active-version, healthcheck, and rollback, plus deploy --stage and a --version flag, with argument-parsing coverage. - Migrate TrustedServerAppConfig to the AppConfigMeta::secret_fields() method that replaces the removed SECRET_FIELDS associated constant. --- Cargo.lock | 37 +++-- Cargo.toml | 12 +- crates/trusted-server-cli/src/run.rs | 174 ++++++++++++++++++++++- crates/trusted-server-core/src/config.rs | 4 +- 4 files changed, 205 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 68f14e753..bd92ec5ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1398,7 +1398,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?tag=v0.0.4#9e661ae520a8130660f18fd10f42703d7f3e050b" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#145f1699d8e8f51027804f21faddbf985cff9a1e" dependencies = [ "toml", ] @@ -1406,7 +1406,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?tag=v0.0.4#9e661ae520a8130660f18fd10f42703d7f3e050b" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#145f1699d8e8f51027804f21faddbf985cff9a1e" dependencies = [ "anyhow", "async-trait", @@ -1434,7 +1434,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?tag=v0.0.4#9e661ae520a8130660f18fd10f42703d7f3e050b" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#145f1699d8e8f51027804f21faddbf985cff9a1e" dependencies = [ "anyhow", "async-trait", @@ -1449,7 +1449,7 @@ dependencies = [ "log", "serde_json", "tempfile", - "toml_edit", + "toml_edit 0.25.12+spec-1.1.0", "walkdir", "worker", ] @@ -1457,7 +1457,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?tag=v0.0.4#9e661ae520a8130660f18fd10f42703d7f3e050b" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#145f1699d8e8f51027804f21faddbf985cff9a1e" dependencies = [ "anyhow", "async-stream", @@ -1479,14 +1479,14 @@ dependencies = [ "serde_json", "sha2 0.10.9", "thiserror 2.0.18", - "toml_edit", + "toml_edit 0.25.12+spec-1.1.0", "walkdir", ] [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?tag=v0.0.4#9e661ae520a8130660f18fd10f42703d7f3e050b" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#145f1699d8e8f51027804f21faddbf985cff9a1e" dependencies = [ "anyhow", "async-trait", @@ -1506,14 +1506,14 @@ dependencies = [ "subtle", "thiserror 2.0.18", "toml", - "toml_edit", + "toml_edit 0.25.12+spec-1.1.0", "walkdir", ] [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?tag=v0.0.4#9e661ae520a8130660f18fd10f42703d7f3e050b" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#145f1699d8e8f51027804f21faddbf985cff9a1e" dependencies = [ "chrono", "clap", @@ -1538,7 +1538,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?tag=v0.0.4#9e661ae520a8130660f18fd10f42703d7f3e050b" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#145f1699d8e8f51027804f21faddbf985cff9a1e" dependencies = [ "anyhow", "async-compression", @@ -1569,7 +1569,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?tag=v0.0.4#9e661ae520a8130660f18fd10f42703d7f3e050b" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#145f1699d8e8f51027804f21faddbf985cff9a1e" dependencies = [ "log", "proc-macro2", @@ -5074,6 +5074,19 @@ dependencies = [ "winnow 0.7.15", ] +[[package]] +name = "toml_edit" +version = "0.25.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" +dependencies = [ + "indexmap 2.14.0", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 1.0.3", +] + [[package]] name = "toml_parser" version = "1.1.2+spec-1.1.0" @@ -5339,7 +5352,7 @@ dependencies = [ "tokio", "tokio-rustls", "toml", - "toml_edit", + "toml_edit 0.23.10+spec-1.0.0", "trusted-server-core", "url", "webpki-roots", diff --git a/Cargo.toml b/Cargo.toml index 695099d49..54569599b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,12 +53,12 @@ criterion = { version = "0.5", default-features = false, features = ["cargo_benc 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.4", default-features = false } -edgezero-adapter-cloudflare = { git = "https://github.com/stackpop/edgezero", tag = "v0.0.4", default-features = false } -edgezero-adapter-fastly = { git = "https://github.com/stackpop/edgezero", tag = "v0.0.4", default-features = false } -edgezero-adapter-spin = { git = "https://github.com/stackpop/edgezero", tag = "v0.0.4", default-features = false } -edgezero-cli = { git = "https://github.com/stackpop/edgezero", tag = "v0.0.4" } -edgezero-core = { git = "https://github.com/stackpop/edgezero", tag = "v0.0.4", default-features = false } +edgezero-adapter-axum = { git = "https://github.com/stackpop/edgezero", branch = "feature/edgezero-deploy-actions", default-features = false } +edgezero-adapter-cloudflare = { git = "https://github.com/stackpop/edgezero", branch = "feature/edgezero-deploy-actions", default-features = false } +edgezero-adapter-fastly = { git = "https://github.com/stackpop/edgezero", branch = "feature/edgezero-deploy-actions", default-features = false } +edgezero-adapter-spin = { git = "https://github.com/stackpop/edgezero", branch = "feature/edgezero-deploy-actions", default-features = false } +edgezero-cli = { git = "https://github.com/stackpop/edgezero", branch = "feature/edgezero-deploy-actions" } +edgezero-core = { git = "https://github.com/stackpop/edgezero", branch = "feature/edgezero-deploy-actions", default-features = false } env_logger = "0.11" error-stack = "0.6" fastly = "0.12" diff --git a/crates/trusted-server-cli/src/run.rs b/crates/trusted-server-cli/src/run.rs index 1b0bdfa29..b3be949a5 100644 --- a/crates/trusted-server-cli/src/run.rs +++ b/crates/trusted-server-cli/src/run.rs @@ -2,8 +2,8 @@ use std::process; use clap::{Parser, Subcommand}; use edgezero_cli::args::{ - AuthArgs, BuildArgs, ConfigDiffArgs, ConfigPushArgs, ConfigValidateArgs, DeployArgs, - ProvisionArgs, ServeArgs, + ActiveVersionArgs, AuthArgs, BuildArgs, ConfigDiffArgs, ConfigPushArgs, ConfigValidateArgs, + DeployArgs, HealthcheckArgs, ProvisionArgs, RollbackArgs, ServeArgs, }; use trusted_server_core::config::TrustedServerAppConfig; @@ -13,7 +13,7 @@ use crate::commands::config::init::{ConfigInitArgs, run_config_init}; use crate::prebid_bundle::{NpmPrebidBundleGenerator, PrebidBundleArgs, run_bundle}; #[derive(Debug, Parser)] -#[command(name = "ts", about = "Trusted Server CLI")] +#[command(name = "ts", version, about = "Trusted Server CLI")] struct Args { #[command(subcommand)] command: Command, @@ -21,6 +21,8 @@ struct Args { #[derive(Debug, Subcommand)] enum Command { + /// Print the currently active deployment version for a target adapter. + ActiveVersion(ActiveVersionArgs), /// Audit a public page and write draft Trusted Server artifacts. Audit(AuditArgs), /// Sign in / out / status against an `EdgeZero` adapter. @@ -32,10 +34,14 @@ enum Command { Config(ConfigCommand), /// Deploy the project through a target adapter. Deploy(DeployArgs), + /// Probe a deployed version until it reports healthy. + Healthcheck(HealthcheckArgs), /// Trusted Server Prebid commands. Prebid(PrebidArgs), /// Provision platform resources through a target adapter. Provision(ProvisionArgs), + /// Roll a service back to a previously active deployment version. + Rollback(RollbackArgs), /// Serve the project locally through a target adapter. Serve(ServeArgs), /// Local developer tools (e.g. the macOS-only production-hostname proxy). @@ -79,6 +85,7 @@ pub fn run_from_env() -> Result<(), String> { fn dispatch(args: Args) -> Result<(), String> { match args.command { + Command::ActiveVersion(args) => edgezero_cli::run_active_version(&args), Command::Audit(args) => { let stdout = std::io::stdout(); let mut out = stdout.lock(); @@ -102,6 +109,7 @@ fn dispatch(args: Args) -> Result<(), String> { edgezero_cli::run_config_validate_typed::(&args) } Command::Deploy(args) => edgezero_cli::run_deploy(&args), + Command::Healthcheck(args) => edgezero_cli::run_healthcheck(&args), Command::Prebid(prebid) => { let mut generator = NpmPrebidBundleGenerator; let mut stdout = std::io::stdout(); @@ -113,6 +121,7 @@ fn dispatch(args: Args) -> Result<(), String> { } } Command::Provision(args) => edgezero_cli::run_provision(&args), + Command::Rollback(args) => edgezero_cli::run_rollback(&args), Command::Serve(args) => edgezero_cli::run_serve(&args), Command::Dev(command) => crate::commands::dev::run(command), } @@ -131,6 +140,165 @@ mod tests { Args::try_parse_from(args).expect("should parse args") } + #[test] + fn parses_active_version() { + let args = parse(&[ + "ts", + "active-version", + "--adapter", + "fastly", + "--service-id", + "service-123", + ]); + let Command::ActiveVersion(active_version) = args.command else { + panic!("expected active-version command"); + }; + assert_eq!(active_version.adapter, "fastly"); + assert_eq!(active_version.service_id, "service-123"); + } + + #[test] + fn parses_healthcheck_with_retry_defaults() { + let args = parse(&[ + "ts", + "healthcheck", + "--adapter", + "fastly", + "--service-id", + "service-123", + "--version", + "7", + "--domain", + "edge.example", + ]); + let Command::Healthcheck(healthcheck) = args.command else { + panic!("expected healthcheck command"); + }; + assert_eq!(healthcheck.domain, "edge.example"); + assert_eq!(healthcheck.version, "7"); + assert_eq!(healthcheck.retry, 3, "should default to 3 retries"); + assert_eq!( + healthcheck.retry_delay, 5, + "should default to a 5s retry delay" + ); + assert_eq!(healthcheck.timeout, 10, "should default to a 10s timeout"); + assert!(!healthcheck.staging, "should probe production by default"); + } + + #[test] + fn parses_healthcheck_with_staging_overrides() { + let args = parse(&[ + "ts", + "healthcheck", + "--adapter", + "fastly", + "--service-id", + "service-123", + "--version", + "7", + "--domain", + "edge.example", + "--staging", + "--retry", + "9", + "--retry-delay", + "2", + "--timeout", + "30", + ]); + let Command::Healthcheck(healthcheck) = args.command else { + panic!("expected healthcheck command"); + }; + assert!(healthcheck.staging); + assert_eq!(healthcheck.retry, 9); + assert_eq!(healthcheck.retry_delay, 2); + assert_eq!(healthcheck.timeout, 30); + } + + #[test] + fn healthcheck_requires_domain() { + Args::try_parse_from([ + "ts", + "healthcheck", + "--adapter", + "fastly", + "--service-id", + "service-123", + "--version", + "7", + ]) + .expect_err("should reject healthcheck without a domain"); + } + + #[test] + fn parses_rollback_with_explicit_target() { + let args = parse(&[ + "ts", + "rollback", + "--adapter", + "fastly", + "--service-id", + "service-123", + "--version", + "8", + "--rollback-to", + "7", + ]); + let Command::Rollback(rollback) = args.command else { + panic!("expected rollback command"); + }; + assert_eq!(rollback.version, "8"); + assert_eq!(rollback.rollback_to, Some("7".to_owned())); + assert!(!rollback.staging); + } + + #[test] + fn parses_staging_rollback_without_target() { + let args = parse(&[ + "ts", + "rollback", + "--adapter", + "fastly", + "--service-id", + "service-123", + "--version", + "8", + "--staging", + ]); + let Command::Rollback(rollback) = args.command else { + panic!("expected rollback command"); + }; + assert!(rollback.staging); + assert_eq!( + rollback.rollback_to, None, + "staging rollback should not need an explicit target" + ); + } + + #[test] + fn rollback_requires_service_id() { + Args::try_parse_from(["ts", "rollback", "--adapter", "fastly", "--version", "8"]) + .expect_err("should reject rollback without a service id"); + } + + #[test] + fn parses_deploy_with_staging_flags() { + let args = parse(&[ + "ts", + "deploy", + "--adapter", + "fastly", + "--service-id", + "service-123", + "--stage", + ]); + let Command::Deploy(deploy) = args.command else { + panic!("expected deploy command"); + }; + assert_eq!(deploy.service_id, Some("service-123".to_owned())); + assert!(deploy.stage); + } + #[test] fn parses_audit_with_default_outputs() { let args = parse(&["ts", "audit", "https://publisher.example"]); diff --git a/crates/trusted-server-core/src/config.rs b/crates/trusted-server-core/src/config.rs index 7bbecd747..991ed7a2f 100644 --- a/crates/trusted-server-core/src/config.rs +++ b/crates/trusted-server-core/src/config.rs @@ -110,7 +110,9 @@ impl edgezero_core::app_config::AppConfigMeta for TrustedServerAppConfig { // app-config blob. Migrating app-level secrets to `EdgeZero` secret-store // references needs nested/array extraction support and operator migration // work tracked separately. - const SECRET_FIELDS: &'static [edgezero_core::app_config::SecretField] = &[]; + fn secret_fields() -> Vec { + Vec::new() + } } /// Runs Trusted Server deploy-time validation for pushed app config. From b743345fd7d43eaf36e0fce86ba448e27e9e5b6e Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Mon, 3 Aug 2026 17:51:39 -0700 Subject: [PATCH 02/10] Update EdgeZero to latest deploy-actions branch tip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Re-resolve the six edgezero-* deps from 145f1699 to bb441162 (current tip of feature/edgezero-deploy-actions, PR #316). The deploy staging flag was renamed there from --stage to --staging, standardizing on the same verb healthcheck/rollback/config-push already use; update the deploy CLI parse test to match. No production dispatch change is needed — ts passes the edgezero-cli arg structs through, so the renamed flag is picked up automatically. --- Cargo.lock | 26 +++++++++++++------------- crates/trusted-server-cli/src/run.rs | 4 ++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 72fa293ce..e5caa1a7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -767,7 +767,7 @@ version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.48.0", ] [[package]] @@ -1398,7 +1398,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#145f1699d8e8f51027804f21faddbf985cff9a1e" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#bb4411625856472b1279a3db49aeeac5e8b1507e" dependencies = [ "toml", ] @@ -1406,7 +1406,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#145f1699d8e8f51027804f21faddbf985cff9a1e" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#bb4411625856472b1279a3db49aeeac5e8b1507e" dependencies = [ "anyhow", "async-trait", @@ -1434,7 +1434,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#145f1699d8e8f51027804f21faddbf985cff9a1e" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#bb4411625856472b1279a3db49aeeac5e8b1507e" dependencies = [ "anyhow", "async-trait", @@ -1457,7 +1457,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#145f1699d8e8f51027804f21faddbf985cff9a1e" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#bb4411625856472b1279a3db49aeeac5e8b1507e" dependencies = [ "anyhow", "async-stream", @@ -1486,7 +1486,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#145f1699d8e8f51027804f21faddbf985cff9a1e" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#bb4411625856472b1279a3db49aeeac5e8b1507e" dependencies = [ "anyhow", "async-trait", @@ -1513,7 +1513,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#145f1699d8e8f51027804f21faddbf985cff9a1e" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#bb4411625856472b1279a3db49aeeac5e8b1507e" dependencies = [ "chrono", "clap", @@ -1538,7 +1538,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#145f1699d8e8f51027804f21faddbf985cff9a1e" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#bb4411625856472b1279a3db49aeeac5e8b1507e" dependencies = [ "anyhow", "async-compression", @@ -1569,7 +1569,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#145f1699d8e8f51027804f21faddbf985cff9a1e" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#bb4411625856472b1279a3db49aeeac5e8b1507e" dependencies = [ "log", "proc-macro2", @@ -3604,7 +3604,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" dependencies = [ "heck", - "itertools 0.13.0", + "itertools 0.10.5", "log", "multimap", "once_cell", @@ -3624,7 +3624,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.13.0", + "itertools 0.10.5", "proc-macro2", "quote", "syn 2.0.118", @@ -3637,7 +3637,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf" dependencies = [ "anyhow", - "itertools 0.13.0", + "itertools 0.10.5", "proc-macro2", "quote", "syn 2.0.118", @@ -5908,7 +5908,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.48.0", ] [[package]] diff --git a/crates/trusted-server-cli/src/run.rs b/crates/trusted-server-cli/src/run.rs index b3be949a5..7374c56a7 100644 --- a/crates/trusted-server-cli/src/run.rs +++ b/crates/trusted-server-cli/src/run.rs @@ -290,13 +290,13 @@ mod tests { "fastly", "--service-id", "service-123", - "--stage", + "--staging", ]); let Command::Deploy(deploy) = args.command else { panic!("expected deploy command"); }; assert_eq!(deploy.service_id, Some("service-123".to_owned())); - assert!(deploy.stage); + assert!(deploy.staging); } #[test] From 54203900d8fb7da9338a39c5e47822d55aba6219 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Sat, 15 Aug 2026 13:59:57 -0700 Subject: [PATCH 03/10] Sync EdgeZero to latest deploy-actions tip and adopt config gc Re-resolve the six edgezero-* deps from bb441162 to 908e229a (current tip of feature/edgezero-deploy-actions, PR #316), and adapt the ts CLI to its surface changes: - Wire the new `ts config gc` subcommand (reclaims orphaned config-store chunk entries) to edgezero_cli::run_config_gc, with parse coverage for the preview default, destructive --yes/--older-than sweep, and the --dry-run/--yes conflict. - Lock the hardened deploy staging behavior: --stage was renamed to --staging and deploy passthrough is now last=true, so a stray --stage fails closed at parse time instead of routing a staging-intended deploy to production. Add tests for the rejection and for post---- passthrough capture. --- Cargo.lock | 33 +++++++---- crates/trusted-server-cli/src/run.rs | 88 +++++++++++++++++++++++++++- 2 files changed, 108 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e5caa1a7a..32e0bd696 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -767,7 +767,7 @@ version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] @@ -1398,7 +1398,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#bb4411625856472b1279a3db49aeeac5e8b1507e" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#908e229a424e837717450c36c656d73891466d08" dependencies = [ "toml", ] @@ -1406,7 +1406,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#bb4411625856472b1279a3db49aeeac5e8b1507e" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#908e229a424e837717450c36c656d73891466d08" dependencies = [ "anyhow", "async-trait", @@ -1434,7 +1434,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#bb4411625856472b1279a3db49aeeac5e8b1507e" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#908e229a424e837717450c36c656d73891466d08" dependencies = [ "anyhow", "async-trait", @@ -1457,7 +1457,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#bb4411625856472b1279a3db49aeeac5e8b1507e" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#908e229a424e837717450c36c656d73891466d08" dependencies = [ "anyhow", "async-stream", @@ -1486,7 +1486,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#bb4411625856472b1279a3db49aeeac5e8b1507e" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#908e229a424e837717450c36c656d73891466d08" dependencies = [ "anyhow", "async-trait", @@ -1513,7 +1513,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#bb4411625856472b1279a3db49aeeac5e8b1507e" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#908e229a424e837717450c36c656d73891466d08" dependencies = [ "chrono", "clap", @@ -1538,7 +1538,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#bb4411625856472b1279a3db49aeeac5e8b1507e" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#908e229a424e837717450c36c656d73891466d08" dependencies = [ "anyhow", "async-compression", @@ -1569,14 +1569,14 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#bb4411625856472b1279a3db49aeeac5e8b1507e" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#908e229a424e837717450c36c656d73891466d08" dependencies = [ "log", "proc-macro2", "quote", "serde", "serde_json", - "syn 2.0.118", + "syn 3.0.3", "toml", "validator", ] @@ -4769,6 +4769,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "sync_wrapper" version = "1.0.2" @@ -5908,7 +5919,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/crates/trusted-server-cli/src/run.rs b/crates/trusted-server-cli/src/run.rs index 7374c56a7..a395281be 100644 --- a/crates/trusted-server-cli/src/run.rs +++ b/crates/trusted-server-cli/src/run.rs @@ -2,8 +2,8 @@ use std::process; use clap::{Parser, Subcommand}; use edgezero_cli::args::{ - ActiveVersionArgs, AuthArgs, BuildArgs, ConfigDiffArgs, ConfigPushArgs, ConfigValidateArgs, - DeployArgs, HealthcheckArgs, ProvisionArgs, RollbackArgs, ServeArgs, + ActiveVersionArgs, AuthArgs, BuildArgs, ConfigDiffArgs, ConfigGcArgs, ConfigPushArgs, + ConfigValidateArgs, DeployArgs, HealthcheckArgs, ProvisionArgs, RollbackArgs, ServeArgs, }; use trusted_server_core::config::TrustedServerAppConfig; @@ -55,6 +55,8 @@ enum ConfigCommand { Init(ConfigInitArgs), /// Diff `trusted-server.toml` against the live `EdgeZero` config. Diff(ConfigDiffArgs), + /// Reclaim orphaned chunk entries leaked from prior oversized pushes. + Gc(ConfigGcArgs), /// Push `trusted-server.toml` as a blob envelope through `EdgeZero`. Push(ConfigPushArgs), /// Validate `edgezero.toml` and the typed Trusted Server config. @@ -102,6 +104,7 @@ fn dispatch(args: Args) -> Result<(), String> { Err(err) => Err(err), } } + Command::Config(ConfigCommand::Gc(args)) => edgezero_cli::run_config_gc(&args), Command::Config(ConfigCommand::Push(args)) => { edgezero_cli::run_config_push_typed::(&args) } @@ -299,6 +302,39 @@ mod tests { assert!(deploy.staging); } + #[test] + fn deploy_rejects_renamed_stage_flag_before_separator() { + // `--stage` was renamed to `--staging`, and adapter passthrough is + // `last = true` (only captured after `--`). A stray `--stage` before the + // separator must fail closed at parse time rather than being swallowed as + // passthrough, which would leave `staging` false and route a + // staging-intended deploy to production. + Args::try_parse_from(["ts", "deploy", "--adapter", "fastly", "--stage"]) + .expect_err("should reject the renamed-away --stage flag, not route it to production"); + } + + #[test] + fn deploy_captures_adapter_passthrough_after_separator() { + let args = parse(&[ + "ts", + "deploy", + "--adapter", + "fastly", + "--", + "--comment", + "ci", + ]); + let Command::Deploy(deploy) = args.command else { + panic!("expected deploy command"); + }; + assert!(!deploy.staging, "should default to a production deploy"); + assert_eq!( + deploy.adapter_args, + vec!["--comment", "ci"], + "should capture args after -- as adapter passthrough" + ); + } + #[test] fn parses_audit_with_default_outputs() { let args = parse(&["ts", "audit", "https://publisher.example"]); @@ -438,6 +474,54 @@ mod tests { assert!(!diff.no_env); } + #[test] + fn config_gc_previews_by_default() { + let args = parse(&["ts", "config", "gc", "--adapter", "fastly"]); + let Command::Config(ConfigCommand::Gc(gc)) = args.command else { + panic!("expected config gc command"); + }; + assert_eq!(gc.adapter, "fastly"); + assert_eq!( + gc.older_than, None, + "should not require an older-than window to preview" + ); + assert!(!gc.dry_run); + assert!(!gc.no_env); + } + + #[test] + fn config_gc_parses_destructive_sweep() { + let args = parse(&[ + "ts", + "config", + "gc", + "--adapter", + "fastly", + "--yes", + "--older-than", + "7d", + ]); + let Command::Config(ConfigCommand::Gc(gc)) = args.command else { + panic!("expected config gc command"); + }; + assert!(gc.yes); + assert_eq!(gc.older_than, Some("7d".to_owned())); + } + + #[test] + fn config_gc_rejects_dry_run_with_yes() { + Args::try_parse_from([ + "ts", + "config", + "gc", + "--adapter", + "fastly", + "--dry-run", + "--yes", + ]) + .expect_err("should reject conflicting --dry-run and --yes"); + } + #[test] fn config_validate_uses_edgezero_app_config_flag() { let args = parse(&[ From fe5767e61aa8cdbeb17cb1b2b5e59a00a03640d1 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Sun, 16 Aug 2026 00:14:38 -0700 Subject: [PATCH 04/10] Sync EdgeZero to deploy-actions tip 5f3d648c Re-resolve the six edgezero-* deps from 908e229a to 5f3d648c (current tip of feature/edgezero-deploy-actions, PR #316). The upstream change is an internal review-addressing pass (redact config-store errors, fix version parse, log cleanup, docs) confined to the Fastly adapter CLI; no ts CLI surface change, so no run.rs adaptation is needed. --- Cargo.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7ea08f4cc..5e3388bd0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -767,7 +767,7 @@ version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.48.0", ] [[package]] @@ -1398,7 +1398,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#908e229a424e837717450c36c656d73891466d08" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" dependencies = [ "toml", ] @@ -1406,7 +1406,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#908e229a424e837717450c36c656d73891466d08" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" dependencies = [ "anyhow", "async-trait", @@ -1434,7 +1434,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#908e229a424e837717450c36c656d73891466d08" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" dependencies = [ "anyhow", "async-trait", @@ -1457,7 +1457,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#908e229a424e837717450c36c656d73891466d08" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" dependencies = [ "anyhow", "async-stream", @@ -1486,7 +1486,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#908e229a424e837717450c36c656d73891466d08" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" dependencies = [ "anyhow", "async-trait", @@ -1513,7 +1513,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#908e229a424e837717450c36c656d73891466d08" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" dependencies = [ "chrono", "clap", @@ -1538,7 +1538,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#908e229a424e837717450c36c656d73891466d08" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" dependencies = [ "anyhow", "async-compression", @@ -1569,7 +1569,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#908e229a424e837717450c36c656d73891466d08" +source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" dependencies = [ "log", "proc-macro2", @@ -5920,7 +5920,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.48.0", ] [[package]] From f90f638464c8f1b3935d4880dc237f885c5bfcab Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Thu, 20 Aug 2026 21:57:19 -0700 Subject: [PATCH 05/10] Pin edgezero dependencies to immutable rev instead of branch Replace the mutable branch = "feature/edgezero-deploy-actions" reference with rev = "5f3d648c", the exact commit the lockfile already resolved, so cargo update or an unlocked resolve cannot silently retarget the branch tip. Rebuild the lock from main with a scoped update of the six edgezero packages. The re-resolve of the edgezero subtree unifies wide version ranges onto co-present lower majors (prost-build/prost-derive onto itertools 0.10.5, colored/winapi-util onto windows-sys 0.48.0); restore those five dependency edges to main's picks so the only non-edgezero lock changes are syn 3.0.3 and toml_edit 0.25.12, both required by the new edgezero tree. Verified with cargo metadata/check --locked and the host CLI test suite. --- Cargo.lock | 26 +++++++++++++------------- Cargo.toml | 12 ++++++------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5e3388bd0..d1e185558 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -767,7 +767,7 @@ version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] @@ -1398,7 +1398,7 @@ dependencies = [ [[package]] name = "edgezero-adapter" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" +source = "git+https://github.com/stackpop/edgezero?rev=5f3d648c3c6c38fc6e6b22b5c65c66177363aad8#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" dependencies = [ "toml", ] @@ -1406,7 +1406,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-axum" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" +source = "git+https://github.com/stackpop/edgezero?rev=5f3d648c3c6c38fc6e6b22b5c65c66177363aad8#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" dependencies = [ "anyhow", "async-trait", @@ -1434,7 +1434,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-cloudflare" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" +source = "git+https://github.com/stackpop/edgezero?rev=5f3d648c3c6c38fc6e6b22b5c65c66177363aad8#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" dependencies = [ "anyhow", "async-trait", @@ -1457,7 +1457,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-fastly" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" +source = "git+https://github.com/stackpop/edgezero?rev=5f3d648c3c6c38fc6e6b22b5c65c66177363aad8#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" dependencies = [ "anyhow", "async-stream", @@ -1486,7 +1486,7 @@ dependencies = [ [[package]] name = "edgezero-adapter-spin" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" +source = "git+https://github.com/stackpop/edgezero?rev=5f3d648c3c6c38fc6e6b22b5c65c66177363aad8#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" dependencies = [ "anyhow", "async-trait", @@ -1513,7 +1513,7 @@ dependencies = [ [[package]] name = "edgezero-cli" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" +source = "git+https://github.com/stackpop/edgezero?rev=5f3d648c3c6c38fc6e6b22b5c65c66177363aad8#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" dependencies = [ "chrono", "clap", @@ -1538,7 +1538,7 @@ dependencies = [ [[package]] name = "edgezero-core" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" +source = "git+https://github.com/stackpop/edgezero?rev=5f3d648c3c6c38fc6e6b22b5c65c66177363aad8#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" dependencies = [ "anyhow", "async-compression", @@ -1569,7 +1569,7 @@ dependencies = [ [[package]] name = "edgezero-macros" version = "0.1.0" -source = "git+https://github.com/stackpop/edgezero?branch=feature%2Fedgezero-deploy-actions#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" +source = "git+https://github.com/stackpop/edgezero?rev=5f3d648c3c6c38fc6e6b22b5c65c66177363aad8#5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" dependencies = [ "log", "proc-macro2", @@ -3604,7 +3604,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" dependencies = [ "heck", - "itertools 0.10.5", + "itertools 0.13.0", "log", "multimap", "once_cell", @@ -3624,7 +3624,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools 0.13.0", "proc-macro2", "quote", "syn 2.0.118", @@ -3637,7 +3637,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools 0.13.0", "proc-macro2", "quote", "syn 2.0.118", @@ -5920,7 +5920,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index a5a63ca3a..f2baf59f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,12 +54,12 @@ criterion = { version = "0.5", default-features = false, features = ["cargo_benc 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 = "feature/edgezero-deploy-actions", default-features = false } -edgezero-adapter-cloudflare = { git = "https://github.com/stackpop/edgezero", branch = "feature/edgezero-deploy-actions", default-features = false } -edgezero-adapter-fastly = { git = "https://github.com/stackpop/edgezero", branch = "feature/edgezero-deploy-actions", default-features = false } -edgezero-adapter-spin = { git = "https://github.com/stackpop/edgezero", branch = "feature/edgezero-deploy-actions", default-features = false } -edgezero-cli = { git = "https://github.com/stackpop/edgezero", branch = "feature/edgezero-deploy-actions" } -edgezero-core = { git = "https://github.com/stackpop/edgezero", branch = "feature/edgezero-deploy-actions", default-features = false } +edgezero-adapter-axum = { git = "https://github.com/stackpop/edgezero", rev = "5f3d648c3c6c38fc6e6b22b5c65c66177363aad8", default-features = false } +edgezero-adapter-cloudflare = { git = "https://github.com/stackpop/edgezero", rev = "5f3d648c3c6c38fc6e6b22b5c65c66177363aad8", default-features = false } +edgezero-adapter-fastly = { git = "https://github.com/stackpop/edgezero", rev = "5f3d648c3c6c38fc6e6b22b5c65c66177363aad8", default-features = false } +edgezero-adapter-spin = { git = "https://github.com/stackpop/edgezero", rev = "5f3d648c3c6c38fc6e6b22b5c65c66177363aad8", default-features = false } +edgezero-cli = { git = "https://github.com/stackpop/edgezero", rev = "5f3d648c3c6c38fc6e6b22b5c65c66177363aad8" } +edgezero-core = { git = "https://github.com/stackpop/edgezero", rev = "5f3d648c3c6c38fc6e6b22b5c65c66177363aad8", default-features = false } env_logger = "0.11" error-stack = "0.6" fastly = "0.12" From bf47680d38e819b5cde6cdc1d695ad411afb6a5f Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Thu, 20 Aug 2026 21:57:19 -0700 Subject: [PATCH 06/10] Document new CLI lifecycle and config gc commands Cover active-version, healthcheck, rollback, deploy --staging with the -- passthrough boundary, and the destructive config gc surface (preview default, --yes with a required --older-than window, and gc's different --no-env meaning). Drop the stale EdgeZero v0.0.4 qualifier from the env-overlay note; the leaves-only behavior is unchanged at the pinned rev. --- docs/guide/cli.md | 63 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/docs/guide/cli.md b/docs/guide/cli.md index b6829895e..fe442ed40 100644 --- a/docs/guide/cli.md +++ b/docs/guide/cli.md @@ -65,8 +65,8 @@ ts config push --adapter fastly `config validate`, `config diff`, and `config push` use EdgeZero's typed app-config loader. By default that loader applies `TRUSTED_SERVER__...` -environment overlays before validation, comparison, and blob creation. EdgeZero -v0.0.4 only overrides leaves already present in the TOML; add newly introduced +environment overlays before validation, comparison, and blob creation. The +overlay only overrides leaves already present in the TOML; add newly introduced fields to existing configs before relying on their overrides. Pass `--no-env` for file-only operation. See [Configuration](/guide/configuration#environment-variable-overrides-typed-cli) for migration and rollback guidance. @@ -76,6 +76,29 @@ Trusted Server settings JSON. This blob model is intentional because full Trusted Server configs can exceed Fastly limits when split into one config-store entry per setting. +Reclaim orphaned chunk entries leaked from prior oversized pushes: + +```bash +ts config gc --adapter fastly +``` + +Without `--yes`, `config gc` only previews: it reports what it would delete and +deletes nothing. `--dry-run` states that intent explicitly and conflicts with +`--yes`. To actually delete, pass `--yes` together with `--older-than ` +(`s`/`m`/`h`/`d` suffixes, e.g. `7d`; a bare number means seconds): + +```bash +ts config gc --adapter fastly --yes --older-than 7d +``` + +`config gc` sweeps every root in the selected physical store, so `--older-than` +is a safety assertion about the whole store: nothing in it changed within the +window and no writer is targeting it. Unlike the other `config` subcommands, +`gc` never loads the typed app config; its `--no-env` flag instead ignores +`EDGEZERO__STORES__CONFIG____NAME` when resolving which physical store to +sweep. On a destructive run, check the store id `gc` reports before passing +`--yes`. + ## Lifecycle commands Lifecycle commands delegate to the selected EdgeZero adapter: @@ -88,6 +111,42 @@ ts deploy --adapter fastly ts serve --adapter fastly ``` +`ts deploy` accepts `--staging` (Fastly only) to build and upload a staged +draft version cloned from the active one instead of activating a production +deploy. Adapter passthrough arguments must follow a `--` separator; unknown +flags before `--` (including the renamed-away `--stage`) are rejected at parse +time rather than forwarded: + +```bash +ts deploy --adapter fastly --service-id --staging +ts deploy --adapter fastly -- --comment "release" +``` + +Inspect and verify deployments with the deploy lifecycle commands: + +```bash +# Print the currently active deployment version +ts active-version --adapter fastly --service-id + +# Probe a deployed version until it reports healthy +ts healthcheck --adapter fastly --service-id \ + --version --domain edge.example + +# Re-activate a previously active version +ts rollback --adapter fastly --service-id \ + --version --rollback-to +``` + +`healthcheck` probes `/` by default (`--path` overrides) and retries 3 times +with a 5 second delay and 10 second timeout (`--retry`, `--retry-delay`, +`--timeout`). With `--staging` it resolves the staged version's IP from the +service id and probes that instead of the production endpoint. + +`rollback` cannot infer the production rollback target: Fastly exposes no +metadata to tell a previously live version from a staged one, so pass the +version to re-activate via `--rollback-to`. With `--staging`, it deactivates +the staged `--version` instead and needs no `--rollback-to`. + ## Audit a public page `ts audit` loads a public page in a fresh headless Chrome/Chromium session, From 40dd9b37a6f2e1aff2fe75fb7006f00a5f56d7a8 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Thu, 20 Aug 2026 21:58:36 -0700 Subject: [PATCH 07/10] Drop stale EdgeZero v0.0.4 qualifiers from env-overlay docs The dependency is no longer pinned at v0.0.4. The leaves-only overlay behavior is unchanged at the pinned rev (apply_env_overlay still only overrides keys already present in the parsed tree), so keep the behavior claims and remove the version qualifier. --- docs/guide/auction-orchestration.md | 4 ++-- docs/guide/configuration.md | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/guide/auction-orchestration.md b/docs/guide/auction-orchestration.md index b4ba6b797..df79b2ee1 100644 --- a/docs/guide/auction-orchestration.md +++ b/docs/guide/auction-orchestration.md @@ -757,8 +757,8 @@ timeout_ms = 500 # Mediator budget (called after providers) ### Environment Variable Overrides The typed `ts config validate`, `ts config diff`, and `ts config push` flows can -override auction values that already exist in the TOML. EdgeZero v0.0.4 does -not create missing leaves, so existing configs must add **both** +override auction values that already exist in the TOML. EdgeZero's env overlay +does not create missing leaves, so existing configs must add **both** `rewrite_creatives = true` and `sanitize_creatives = false` under `[auction]` before relying on the corresponding environment overrides — an override for a missing leaf is silently ignored. diff --git a/docs/guide/configuration.md b/docs/guide/configuration.md index ddb6544ce..16008e8a6 100644 --- a/docs/guide/configuration.md +++ b/docs/guide/configuration.md @@ -114,7 +114,7 @@ base TOML configuration by `ts config validate`, `ts config diff`, and stored in the app-config blob. Changing an environment variable requires rerunning validation and pushing the resolved config, not rebuilding the binary. -EdgeZero v0.0.4 only overrides leaves that already exist in the parsed TOML; it +EdgeZero's env overlay only overrides leaves that already exist in the parsed TOML; it does not create missing fields. Add newly introduced defaulted fields to an existing config before relying on their environment overrides. Pass `--no-env` to use file values without the overlay. @@ -1292,7 +1292,7 @@ remove that field's non-default value (and any environment override), run `ts config validate`, push the resulting default-compatible blob, and only then roll back the binary. -**Environment overlays:** EdgeZero v0.0.4 overlays cannot create missing TOML +**Environment overlays:** EdgeZero's env overlays cannot create missing TOML leaves. Existing configs must add **both** leaves under `[auction]` (`rewrite_creatives` and `sanitize_creatives`) before `TRUSTED_SERVER__AUCTION__REWRITE_CREATIVES` / @@ -1638,7 +1638,7 @@ trusted-server.dev.toml # Development overrides **Environment Variables Not Applied**: - Run the override through `ts config validate`, `ts config diff`, or `ts config push` -- Verify the target leaf already exists in `trusted-server.toml`; EdgeZero v0.0.4 does not create missing fields +- Verify the target leaf already exists in `trusted-server.toml`; the env overlay does not create missing fields - Verify prefix: `TRUSTED_SERVER__` - Check separator: `__` (double underscore) - Confirm the variable is exported: `echo $VARIABLE_NAME` From 87546d36d7c138e4d0e6e8463cddc5aa39bc840d Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Fri, 21 Aug 2026 22:27:23 -0700 Subject: [PATCH 08/10] Document the staged-deploy config leg and correct healthcheck retry wording A staged deploy only redirects the staged version's config selector at the _staging key; it does not copy the production blob. Add the config push/diff --staging step to the staging sequence so following the guide no longer stages a version whose config key nothing wrote, and note the --key conflict. Reword the healthcheck defaults: --retry 3 is 3 total attempts (attempts = retry.max(1) upstream), not 3 retries after a first try. --- docs/guide/cli.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/docs/guide/cli.md b/docs/guide/cli.md index fe442ed40..cf28803f9 100644 --- a/docs/guide/cli.md +++ b/docs/guide/cli.md @@ -122,6 +122,21 @@ 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 +there. Push the staged config before probing the staged version, or it comes up +with no config at all: + +```bash +ts config push --adapter fastly --staging +ts config diff --adapter fastly --staging +``` + +`--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. + Inspect and verify deployments with the deploy lifecycle commands: ```bash @@ -137,8 +152,9 @@ ts rollback --adapter fastly --service-id \ --version --rollback-to ``` -`healthcheck` probes `/` by default (`--path` overrides) and retries 3 times -with a 5 second delay and 10 second timeout (`--retry`, `--retry-delay`, +`healthcheck` probes `/` by default (`--path` overrides) and makes 3 total +attempts — not 3 retries after a first try — with a 5 second delay between +attempts and a 10 second per-attempt timeout (`--retry`, `--retry-delay`, `--timeout`). With `--staging` it resolves the staged version's IP from the service id and probes that instead of the production endpoint. From 01d7f611bebe1e185ccfecfe2ae07b5b9196f7fb Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Fri, 21 Aug 2026 22:27:23 -0700 Subject: [PATCH 09/10] Extend CLI parse tests for staging config flags, gc gate, and --version Add parse coverage for config push/diff --staging including the --key conflict, assert healthcheck's path default and reword the retry assertion to total attempts, assert config gc's yes default since --yes is the only destructive gate, and pin the top-level --version flag via ErrorKind::DisplayVersion. --- crates/trusted-server-cli/src/run.rs | 66 +++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/crates/trusted-server-cli/src/run.rs b/crates/trusted-server-cli/src/run.rs index a395281be..ae10ae014 100644 --- a/crates/trusted-server-cli/src/run.rs +++ b/crates/trusted-server-cli/src/run.rs @@ -143,6 +143,17 @@ mod tests { Args::try_parse_from(args).expect("should parse args") } + #[test] + fn top_level_version_flag_is_available() { + let err = Args::try_parse_from(["ts", "--version"]) + .expect_err("should short-circuit parsing on --version"); + assert_eq!( + err.kind(), + clap::error::ErrorKind::DisplayVersion, + "should print the version rather than fail to parse" + ); + } + #[test] fn parses_active_version() { let args = parse(&[ @@ -179,7 +190,11 @@ mod tests { }; assert_eq!(healthcheck.domain, "edge.example"); assert_eq!(healthcheck.version, "7"); - assert_eq!(healthcheck.retry, 3, "should default to 3 retries"); + assert_eq!(healthcheck.path, "/", "should default to probing `/`"); + assert_eq!( + healthcheck.retry, 3, + "should default to 3 total attempts, not 3 retries after a first try" + ); assert_eq!( healthcheck.retry_delay, 5, "should default to a 5s retry delay" @@ -474,6 +489,51 @@ mod tests { assert!(!diff.no_env); } + #[test] + fn config_push_parses_staging_and_rejects_explicit_key() { + let args = parse(&["ts", "config", "push", "--adapter", "fastly", "--staging"]); + let Command::Config(ConfigCommand::Push(push)) = args.command else { + panic!("expected config push command"); + }; + assert!(push.staging, "should target the derived staging key"); + + Args::try_parse_from([ + "ts", + "config", + "push", + "--adapter", + "fastly", + "--staging", + "--key", + "custom", + ]) + .expect_err("should reject --key with --staging; the staging key is derived"); + } + + #[test] + fn config_diff_parses_staging_and_rejects_explicit_key() { + let args = parse(&["ts", "config", "diff", "--adapter", "fastly", "--staging"]); + let Command::Config(ConfigCommand::Diff(diff)) = args.command else { + panic!("expected config diff command"); + }; + assert!( + diff.staging, + "should compare against the derived staging key" + ); + + Args::try_parse_from([ + "ts", + "config", + "diff", + "--adapter", + "fastly", + "--staging", + "--key", + "custom", + ]) + .expect_err("should reject --key with --staging; the staging key is derived"); + } + #[test] fn config_gc_previews_by_default() { let args = parse(&["ts", "config", "gc", "--adapter", "fastly"]); @@ -487,6 +547,10 @@ mod tests { ); assert!(!gc.dry_run); assert!(!gc.no_env); + assert!( + !gc.yes, + "should not delete without an explicit --yes; --yes is the only destructive gate" + ); } #[test] From 4aee0527221cbabd3ef99c65b6c65e035ad0e5bc Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Fri, 21 Aug 2026 22:27:23 -0700 Subject: [PATCH 10/10] Refresh secret-fields comment and drop last v0.0.4 qualifiers The pinned edgezero rev ships nested/array secret extraction, so the secret_fields comment no longer names it as the blocker; what remains is spelling out the paths in this hand-written impl (it does not inherit the derive's) plus operator migration. Drop the stale v0.0.4 qualifiers the earlier docs pass missed in the example config and the env-overlay test. --- crates/trusted-server-cli/tests/config_env_overlay.rs | 2 +- crates/trusted-server-core/src/config.rs | 5 +++-- trusted-server.example.toml | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/trusted-server-cli/tests/config_env_overlay.rs b/crates/trusted-server-cli/tests/config_env_overlay.rs index 35263c0eb..851110ca7 100644 --- a/crates/trusted-server-cli/tests/config_env_overlay.rs +++ b/crates/trusted-server-cli/tests/config_env_overlay.rs @@ -44,7 +44,7 @@ fn migrated_legacy_project() -> MigratedProject { let mut document = LEGACY_CONFIG .parse::() .expect("should parse legacy integration config"); - // EdgeZero v0.0.4 environment overlays cannot create missing TOML leaves, + // EdgeZero environment overlays cannot create missing TOML leaves, // so a migrated config must carry both creative-processing leaves for the // corresponding environment variables to take effect. document["auction"]["rewrite_creatives"] = value(true); diff --git a/crates/trusted-server-core/src/config.rs b/crates/trusted-server-core/src/config.rs index b983c0ab6..331f7ab33 100644 --- a/crates/trusted-server-core/src/config.rs +++ b/crates/trusted-server-core/src/config.rs @@ -110,8 +110,9 @@ impl edgezero_core::app_config::AppConfigMeta for TrustedServerAppConfig { // Phase 1 intentionally preserves the existing inline-settings model: // `ts config push` publishes the validated Trusted Server config as one // app-config blob. Migrating app-level secrets to `EdgeZero` secret-store - // references needs nested/array extraction support and operator migration - // work tracked separately. + // references needs the secret-field paths spelled out here (this + // hand-written impl does not inherit the derive's nested/array paths) + // plus operator migration work tracked separately. fn secret_fields() -> Vec { Vec::new() } diff --git a/trusted-server.example.toml b/trusted-server.example.toml index 717b4d54b..4c2fa302e 100644 --- a/trusted-server.example.toml +++ b/trusted-server.example.toml @@ -147,7 +147,7 @@ enabled = false [auction] enabled = false -# Defaults to true. Keep this leaf present when using the EdgeZero v0.0.4 +# Defaults to true. Keep this leaf present when using the EdgeZero # environment override. Set false to return unre-written winning-bid adm, # skipping proxy/click URL conversion and creative TSJS injection. # Sanitization is controlled separately by `sanitize_creatives` below.