Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
151 commits
Select commit Hold shift + click to select a range
0f924d7
provision --local implementation: tracking branch
aram356 Jun 29, 2026
1ffe5a9
Add ProvisionMode + ProvisionArgs.local for provision --local
aram356 Jun 29, 2026
feb607e
Add neutral ProvisionOutcome + AdapterDeployedState types + crate-roo…
aram356 Jun 29, 2026
5896a8e
Thread ProvisionMode + ProvisionOutcome through Adapter::provision
aram356 Jun 30, 2026
63f9a4d
Add Adapter::provision_typed trait method with default no-op
aram356 Jun 30, 2026
5121603
Extract run_typed_preflight; route validate/push/diff through it
aram356 Jun 30, 2026
a8e54e1
Task 5 fix: promote resolve_app_config_path_primitive to pub(crate) p…
aram356 Jun 30, 2026
d184c8f
Add path_safety module with containment helper
aram356 Jun 30, 2026
a347422
Wire path_safety into config push --local
aram356 Jul 1, 2026
d8d6622
Wire path_safety + ProvisionMode into run_provision
aram356 Jul 1, 2026
7074ac7
Add Adapter::synthesise_baseline_manifest + CLI bootstrap before vali…
aram356 Jul 1, 2026
a0bec7a
Add copy_tree helper; promote tempfile + toml_edit to CLI runtime deps
aram356 Jul 1, 2026
3fa8c22
Merge branch 'main' into feature/provision-local-impl
aram356 Jul 1, 2026
ba3f891
Move config push --local containment guard above run_shared_checks
aram356 Jul 1, 2026
619541a
Merge remote-tracking branch 'origin/feature/provision-local-impl' in…
aram356 Jul 1, 2026
1617bb8
Make provision_local accept-tests actually exercise their code paths
aram356 Jul 2, 2026
12d7129
Add run_with_staging tempdir helper for dry-run staging
aram356 Jul 2, 2026
42c198e
Wire mode x dry-run dispatch matrix into run_provision
aram356 Jul 2, 2026
cd87c24
Add dry-run allow-list diff + would-write status rewriting
aram356 Jul 2, 2026
66ab458
Add provision_local_dry_run worktree-clean + no-tempdir-leak test (ig…
aram356 Jul 2, 2026
2b3e700
Add ManifestAdapterDeployed struct + deployed field on ManifestAdapter
aram356 Jul 2, 2026
5531f72
Fix local dry-run to dispatch adapters with dry_run = false
aram356 Jul 2, 2026
6033e72
Add adapter-owned deployed_fields + Manifest-level cross-check
aram356 Jul 2, 2026
af4baa9
Task 15 followup: refresh #[expect] reasons + document case-handling
aram356 Jul 2, 2026
b3466c1
Add toml_edit-based [adapters.<name>.deployed] writeback
aram356 Jul 2, 2026
277f614
Cloudflare: cloud provision returns created namespace ids via deployed
aram356 Jul 2, 2026
d7d6b1a
Add edgezero_adapter::env_file::append_lines_dedup (used by Section 5)
aram356 Jul 2, 2026
9c21d15
Wire deployed_state_for translator + validate_deployed_field_ownershi…
aram356 Jul 2, 2026
fac82ab
Clean up misleading adapter-named tests in provision.rs
aram356 Jul 2, 2026
1e1e206
Fix three review findings: dry-run leak, baseline containment, deploy…
aram356 Jul 2, 2026
c640931
Cloudflare: primitive synthesiser for wrangler.toml + bootstrap override
aram356 Jul 2, 2026
91205a6
Cloudflare: local-mode provision emits [[kv_namespaces]] bindings (de…
aram356 Jul 2, 2026
da4a2b9
Cloudflare: local-mode provision writes .dev.vars __NAME / __KEY lines
aram356 Jul 2, 2026
140728e
Cloudflare: provision_typed appends secret placeholders to .dev.vars
aram356 Jul 2, 2026
84f8908
Fastly: primitive synthesiser for fastly.toml + bootstrap override
aram356 Jul 2, 2026
706d2cd
Fastly: local-mode provision writes [local_server.*] + edgezero_runti…
aram356 Jul 2, 2026
efd0be3
Fastly: provision_typed writes [[local_server.secret_stores.*]] entries
aram356 Jul 2, 2026
6642598
Spin: primitive synthesiser for spin.toml + runtime-config.toml + boo…
aram356 Jul 2, 2026
8f6776c
Spin: local-mode provision writes bindings + runtime-config + .env __…
aram356 Jul 2, 2026
00157fe
Spin: provision_typed writes lowercased [variables] + SPIN_VARIABLE_ …
aram356 Jul 2, 2026
84bfea9
Axum: local-mode provision creates .edgezero/ and writes .env (no axu…
aram356 Jul 2, 2026
dad90a2
Axum: provision_typed appends secret placeholders to .edgezero/.env
aram356 Jul 2, 2026
8f68180
Re-enable provision_local_dry_run worktree-clean test (Section 5 lock…
aram356 Jul 2, 2026
324c106
Fix two Section 5 contract gaps: Spin silent success + missing header
aram356 Jul 3, 2026
b00440c
Fastly: additive merge for edgezero_runtime_env on re-provision
aram356 Jul 3, 2026
0778ec9
Add run_provision_typed<C> public entry point
aram356 Jul 3, 2026
c729d93
Route Cmd::Provision through run_provision_typed (scaffold + app-demo)
aram356 Jul 3, 2026
50455b4
Scaffold: loop run_provision over every selected adapter
aram356 Jul 3, 2026
7e458aa
Scaffold: extend .gitignore with provision-owned manifests + local state
aram356 Jul 3, 2026
1a631ad
Gitignore Cloudflare/Fastly/Spin manifests; regenerate via provision …
aram356 Jul 3, 2026
9a5eb49
run_serve: adapter-scoped env-file load (axum vs spin); existing env …
aram356 Jul 3, 2026
3ad53c0
Smoke: warm-up via provision --local; drop obsolete backup_in_tree calls
aram356 Jul 3, 2026
d980113
CI: gate fastly/spin/wrangler/runtime-config.toml + .dev.vars (axum.t…
aram356 Jul 3, 2026
d0199dc
Docs: update for provision --local + gitignored adapter manifests
aram356 Jul 3, 2026
6361d87
Axum: per-adapter provision_local_ contract tests (axum.toml untouched)
aram356 Jul 3, 2026
20970d2
Fastly: per-adapter provision_local_ contract tests
aram356 Jul 3, 2026
afc6fbe
Cloudflare: per-adapter provision_local_ contract tests
aram356 Jul 3, 2026
31ca168
Spin: per-adapter provision_local_ contract tests + env-label alignment
aram356 Jul 3, 2026
492f774
Axum: split cli.rs into cli/{mod,provision_local,run}.rs
aram356 Jul 3, 2026
637e6a6
Cloudflare: split cli.rs into cli/{mod,provision_local,provision_clou…
aram356 Jul 3, 2026
9ea12d5
Fastly: split cli.rs into cli/{mod,provision_local,provision_cloud,pu…
aram356 Jul 3, 2026
09fcb85
Spin: split cli.rs; rename push_sqlite→push_local; fold housekeeping
aram356 Jul 3, 2026
20c29b7
Adapters: hoist path_mutation_guard to cli/mod.rs to fix cross-module…
aram356 Jul 3, 2026
e3657b7
Cloudflare: fix .dev.vars commented KEY placeholder value
aram356 Jul 3, 2026
d3c4b81
Fastly: fix service_id root-key positioning + populate cloud deployed…
aram356 Jul 4, 2026
2e7b0c2
CLI: merge outcome.deployed from run_provision_typed real-write path
aram356 Jul 4, 2026
ed5bf83
Deployed schema: colocate scalar+sub-table field arrays with the struct
aram356 Jul 4, 2026
6bb5c7e
Docs: correct axum.toml claim + Spin dotenv recipe + gitignore list
aram356 Jul 4, 2026
153fa7c
Fastly: template no longer seeds empty service_id; docs match cloud/l…
aram356 Jul 5, 2026
0483c00
Deep review batch 1: API hardening + PATH-guard unification + env-ove…
aram356 Jul 5, 2026
a72ff10
Deep review P1-b: cross-process advisory lock for provision + config …
aram356 Jul 5, 2026
24f2b20
Deep review batch 2: template hygiene walker + Fastly reparse asserts…
aram356 Jul 5, 2026
b766f75
Deep review batch 3: env-file hardening + case-insensitive test + Clo…
aram356 Jul 5, 2026
4a31c78
Provision status lines: name the file each mutation lands in
aram356 Jul 5, 2026
99b122c
Axum: axum.toml joins the provision-generated set
aram356 Jul 5, 2026
b9cdbd8
Provision: emit 'wrote baseline <path>' line for every synthesised ad…
aram356 Jul 5, 2026
ba9479f
Cloud path safety + provision lock in .edgezero/ + config push lock t…
aram356 Jul 5, 2026
6da249f
Axum dry-run: preview generated axum.toml + sanitise typed dry-run er…
aram356 Jul 5, 2026
10da44d
config.rs: remove all non-test #[expect] via code restructure
aram356 Jul 5, 2026
d584a23
Docs: spec + plan align on axum.toml provision-generated model
aram356 Jul 6, 2026
19c2180
Non-test #[expect] cleanup: stream module + scaffold Result + syn hel…
aram356 Jul 6, 2026
22964f5
args.rs: hoist no_diff+no_env into ConfigPushSuppressions sub-struct
aram356 Jul 7, 2026
1435d58
Remove two non-test expects in fastly + spin adapter crates
aram356 Jul 7, 2026
9cd1357
Remove missing_trait_methods expects across adapters + core manifest
aram356 Jul 7, 2026
1bddba5
Remove clippy::panic expect from canonical_form::write_number
aram356 Jul 7, 2026
9085a2e
app-demo-cli: track ConfigPushArgs.suppress hoist
aram356 Jul 7, 2026
0703a3f
Provision-local review findings: single-source axum.toml + docs + cop…
aram356 Jul 7, 2026
5e19f4f
Provision-local review v3: single-source all 5 manifests + gitignore …
aram356 Jul 7, 2026
2bb6487
Synth crate-name honours renamed adapter crates (not just <app>-adapt…
aram356 Jul 7, 2026
0dcdd13
Merge remote-tracking branch 'origin/main' into feature/provision-loc…
aram356 Jul 8, 2026
39bcb5e
Synth crate-name walks up nested manifest + Spin decouples component …
aram356 Jul 8, 2026
77fe77c
Docs formatting
aram356 Jul 8, 2026
a1e000e
Docs: split base vs typed provision --local + drop stale Spin synth m…
aram356 Jul 8, 2026
6589957
Docs sweep: primitive-synth <crate_name>, Spin override, base-vs-type…
aram356 Jul 8, 2026
7a92e57
Provision review: manifest required + diff path guard + env redaction…
aram356 Jul 8, 2026
44c9a2d
Provision review v2: redact commented env lines + require both manife…
aram356 Jul 8, 2026
c38cb54
Spin serve: load .env from adapter.manifest parent (matches provision…
aram356 Jul 8, 2026
57826a9
run_serve: path-safety guard + contract test for adapter env-file load
aram356 Jul 8, 2026
5bae973
run_serve contract test: intercept SPAWNED CHILD's env, not just pare…
aram356 Jul 8, 2026
bcd635e
Merge branch 'main' into feature/provision-local-impl
aram356 Jul 9, 2026
7d6d886
PR #287 review: config-validate path guard, symlink rejection, .env o…
aram356 Jul 9, 2026
3f340ef
Merge remote-tracking branch 'origin/main' into feature/provision-loc…
aram356 Jul 13, 2026
e0688aa
PR #287 v2 review: Windows paths, CF retry, Spin/Axum nested prefixes…
aram356 Jul 13, 2026
cc6ac4a
Merge remote-tracking branch 'origin/main' into feature/provision-loc…
aram356 Jul 16, 2026
b7ff41b
Fix Axum config push destroying sibling keys on read failure
aram356 Jul 16, 2026
65f4f62
Close symlink escapes and case-collision silent-wrong-value bugs
aram356 Jul 17, 2026
3d5c51c
Stop stale gitignored fastly.toml replacing tracked service_id
aram356 Jul 17, 2026
5af527e
Thread an exec context into the registry-fallback dispatch
aram356 Jul 17, 2026
007357e
Align provisioning to the v1 spec and close round-10 review findings
aram356 Jul 18, 2026
b4dd8b8
Add push-after-provision contract tests and fix migration docs
aram356 Jul 18, 2026
9cae021
Refresh a single-component spin.toml when the selector changes
aram356 Jul 19, 2026
ce4f6db
Harden Spin KV I/O, CF id capture, and validate/refresh split
aram356 Jul 19, 2026
c9c069d
Thread declared manifest into fallback, preserve TOML decor, compose …
aram356 Jul 19, 2026
cacda8c
Close round-12 review findings across provisioning and push
aram356 Jul 20, 2026
290c0e5
Require declared adapter manifests and harden Fastly cloud provisioning
aram356 Jul 22, 2026
b48fd6a
Fix clippy gate, nested-manifest resolution, and smoke isolation
aram356 Jul 26, 2026
467488b
Harden local-state containment and preflight the cutoff checks
aram356 Jul 26, 2026
f37413a
Close round-15 P2/P3 runtime-correctness and CI findings
aram356 Jul 26, 2026
8807a28
Close round-16 containment, preflight, and consistency findings
aram356 Jul 30, 2026
18297c1
Preflight remote mutations and tighten provision/push edge cases
aram356 Aug 1, 2026
b2ede4a
Anchor vendor CLIs, harden diffs, and make smoke backups fail-closed
aram356 Aug 3, 2026
ff19cc9
Anchor CF config path, prove the deploy lock, and fail smoke restore …
aram356 Aug 4, 2026
7f3b245
Serialize sibling lock borrowers and complete cargo target-dir parity
aram356 Aug 6, 2026
6483454
Harden provision lock auth, target resolution, and smoke cleanup
aram356 Aug 7, 2026
657d34a
Close reentrancy, resolver, and provider gaps; wire shell CI
aram356 Aug 8, 2026
df19357
Merge branch 'main' into feature/provision-local-impl
aram356 Aug 10, 2026
7b576e2
Fix cargo config parity, provider guards, and smoke ownership
aram356 Aug 11, 2026
9966115
Add explicit Spin cloud flag and fix composed-deploy deadlock
aram356 Aug 12, 2026
d4a3d04
Deliver Spin runtime overrides to the guest via spin up --env
aram356 Aug 13, 2026
008238a
Merge remote-tracking branch 'origin/feature/provision-local-impl' in…
aram356 Aug 13, 2026
babb74c
Sync app-demo Cargo.lock with the syn 3 bump
aram356 Aug 14, 2026
0c92b2c
Merge origin/main: integrate Fastly config gc into the split cli/ mod…
aram356 Aug 17, 2026
aaec172
Regenerate app-demo Cargo.lock after the merge
aram356 Aug 18, 2026
a2d0c53
Gate fastly cli test helpers on cfg(unix) for the wasm target
aram356 Aug 18, 2026
99d3bdf
Merge remote-tracking branch 'origin/main' into feature/provision-loc…
aram356 Aug 18, 2026
ab8ed5c
Fix Round-24 review: P0 build breakages + P1 provider/containment def…
aram356 Aug 19, 2026
e2c3e55
Serialize composed deploys with a depth-keyed sibling lock
aram356 Aug 19, 2026
563b9a3
Fix Round-25 review: dry-run snapshot consistency + provider/lock/con…
aram356 Aug 27, 2026
6c6e877
Merge origin/main into feature/provision-local-impl
aram356 Sep 8, 2026
022b933
Fix TMPDIR test leak that poisoned the shared env guard
aram356 Sep 11, 2026
348e57b
Fix CI: wasm clippy, commands-only adapter, and the deploy lock dirty…
aram356 Sep 13, 2026
72a961c
Merge main into provision-local implementation
aram356 Oct 19, 2026
0bd6b4c
Fix adapter crate declarations in deployment smoke fixtures
aram356 Oct 19, 2026
334dd8e
Keep immutable application releases free of project lock state
aram356 Oct 19, 2026
522ae79
Document adapter-owned CLI correctness redesign
aram356 Oct 20, 2026
ddb3306
Make adapters own CLI policy and harden local transactions
aram356 Oct 20, 2026
5e20eae
Keep dotenv encoding diagnostics separate from value bytes
aram356 Oct 20, 2026
d71d38e
Separate dotenv success and diagnostic branches explicitly
aram356 Oct 20, 2026
09733d0
fix: close local provisioning disclosure and path gaps
aram356 Oct 20, 2026
5c07986
Merge branch 'main' into feature/provision-local-impl
aram356 Oct 26, 2026
dac4838
Merge branch 'main' into feature/provision-local-impl
aram356 Oct 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .claude/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
"Bash(tail:*)",
"Bash(tree:*)",
"Bash(wc:*)",
"Bash(which:*)"
"Bash(which:*)",
"WebFetch(domain:www.fastly.com)",
"WebFetch(domain:raw.githubusercontent.com)"
]
},
"enabledPlugins": {
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/deploy-core/tests/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2479,7 +2479,7 @@ test_fastly_logical_link_documentation() {
local manifest="$REPO_ROOT/docs/guide/manifest-store-migration.md"
local blob="$REPO_ROOT/docs/guide/blob-app-config-migration.md"
local adoption="$REPO_ROOT/docs/guide/deploy-action-adoption.md"
local fastly_cli="$REPO_ROOT/crates/edgezero-adapter-fastly/src/cli.rs"
local fastly_cli="$REPO_ROOT/crates/edgezero-adapter-fastly/src/cli/staging.rs"
local corpus="$WORK_DIR/fastly-logical-link-docs.md"
local example_workflow="$WORK_DIR/application-deploy-workflow.yml"
local example_deploy="$WORK_DIR/application-deploy-job.yml"
Expand Down
3 changes: 3 additions & 0 deletions .github/actions/deploy-fastly/tests/make-smoke-fixture.sh
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,11 @@ name = "fixture-app"

[adapters.fastly.adapter]
manifest = "adapter/fastly.toml"
crate = "adapter"

[adapters.spin.adapter]
manifest = "adapter/spin.toml"
crate = "adapter"
TOML
if [[ "$mode" == store-aware ]]; then
cat >>edgezero.toml <<'TOML'
Expand Down Expand Up @@ -154,6 +156,7 @@ version = "0.1.0"
source = "fixture.wasm"
TOML

printf '\n.edgezero/\n' >>.gitignore
cargo generate-lockfile
# Path dependencies live in the enclosing EdgeZero checkout, not this Git repo.
git -C "$workspace" rev-parse HEAD >.edgezero-source-revision
Expand Down
50 changes: 50 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,60 @@ jobs:
if: matrix.suite == 'cli'
run: cargo run -q --bin check_no_nested_app_config --features nested-app-config-check -- examples/app-demo crates/edgezero-cli/src/templates

# Enforce spec §"Adapter manifests are gitignored" + §"Migration for
# downstream projects". All five generated adapter manifests
# (`axum.toml`, `wrangler.toml`, `fastly.toml`, `spin.toml`,
# `runtime-config.toml`), Cloudflare's `.dev.vars`, AND the
# provision-written secret-bearing env-line files (Spin's
# `<crate>/.env`, Axum's `.edgezero/.env`) MUST NOT be tracked --
# teammates regenerate them locally via `provision --local`.
- name: Enforce adapter manifests and secret env files are not tracked
run: |
if git ls-files | grep -E '(^|/)(axum|fastly|spin|wrangler|runtime-config)\.toml$|(^|/)\.dev\.vars$|(^|/)\.env$'; then
echo "::error::These adapter manifests AND secret-bearing env files (.dev.vars / .env) must be gitignored (spec §'Adapter manifests are gitignored' + §'Migration for downstream projects'). They carry operator secret values and must NEVER be committed."
exit 1
fi

# The step above only proves these files are not CURRENTLY tracked.
# Also prove they are actually IGNORED, so a `git add` can't slip a
# regenerated manifest (or a secret-bearing env file) into a commit.
# `git check-ignore` evaluates the ignore rules against the pathname
# whether or not the file exists.
- name: Enforce adapter manifests and secret env files are gitignored
run: |
for probe in \
crates/demo/axum.toml \
crates/demo/wrangler.toml \
crates/demo/fastly.toml \
crates/demo/spin.toml \
crates/demo/runtime-config.toml \
crates/demo/.dev.vars \
crates/demo/.env \
.edgezero/.env; do
if ! git check-ignore -q "$probe"; then
echo "::error::'$probe' is NOT gitignored. Add the pattern to .gitignore so provision-generated adapter state and secret-bearing env files can never be committed by accident."
exit 1
fi
done

# The checker's own unit tests live behind `required-features =
# ["nested-app-config-check"]`, so the unfeatured
# `cargo test --workspace` step below does not compile or run them.
# Exercise them explicitly to keep the coverage closure enforced by CI.
- name: Nested AppConfig checker tests
if: matrix.suite == 'cli'
run: cargo test -p edgezero-cli --features nested-app-config-check --bin check_no_nested_app_config

# Lint the smoke/helper shell scripts. `-x` follows `source`d libs;
# `--severity=warning` gates on warnings and errors (SC1091/SC2086-style
# info notes stay advisory). ubuntu-latest ships shellcheck.
- name: ShellCheck smoke scripts
run: shellcheck -x --severity=warning scripts/*.sh scripts/lib/*.sh

# Run the backup/restore helper's own unit tests -- fail-closed backup,
# atomic restore, symlink refusal, ownership-guarded server teardown.
- name: Smoke backup helper unit tests
run: bash scripts/lib/smoke_backup_test.sh
- name: Lifecycle fixture host tests
if: matrix.suite == 'workspace'
run: >-
Expand Down
59 changes: 50 additions & 9 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# node
# --- Node ---
node_modules/

# compiled output
# --- Cargo / Rust ---
bin/
# `bin/` above is overly broad — it also blocks Cargo's `src/bin/`
# directories, which are LEGITIMATE source (one file per binary
Expand All @@ -10,27 +10,69 @@ bin/
!**/src/bin/**
pkg/
target/
.wrangler/
.spin/
*.rlib

# --- EdgeZero core (shared across adapters) ---
# Runtime dir the CLI creates for adapter-local state:
# - `.edgezero/.env` — Axum's env-line file
# - `.edgezero/local-config-<id>.json` — Axum's local config store
# - `.edgezero/provision.lock` — cross-process advisory lock
# (`provision` + `config push`)
# The whole `.edgezero/` directory is per-machine and never committed.
.edgezero/

# --- Cloudflare adapter ---
# `wrangler.toml` is regenerated by `provision --local`; teammates
# must not commit each other's namespace ids / platform binding
# names. `.dev.vars` holds operator-filled runtime secrets and
# `.wrangler/` is `wrangler dev`'s local state directory.
wrangler.toml
.dev.vars
.wrangler/

# --- Fastly adapter ---
# `fastly.toml` is regenerated by `provision --local`. It carries
# the compute manifest + `[local_server]` Viceroy state; per-machine
# secret entries and setup blocks must not be shared via git.
fastly.toml
fastly.edgezero-*.toml

# Fastly local config-push lock and staging temp files (sidecars next to the
# manifest). `examples/app-demo` has a `fastly.toml`, so `config push --local`
# there leaves these behind; a SIGKILL/panic mid-push can also strand a temp.
# The globs cover a manifest named something other than `fastly.toml`.
.*.edgezero-lock
.*.edgezero-*.tmp

# env
# --- Spin adapter ---
# `spin.toml` (component / variables) + `runtime-config.toml` (KV
# backend paths) are regenerated by `provision --local`.
# `.spin/` is Spin's local state directory (SQLite KV, log tail).
spin.toml
runtime-config.toml
.spin/

# --- Axum adapter ---
# `axum.toml` is regenerated by `provision --local` (host / port /
# crate name defaults; operator edits are preserved because
# provision's merge path never re-writes the file after the first
# synthesis).
axum.toml

# --- Shared per-crate `.env` ---
# Spin's `<spin_crate>/.env` and any future adapter's crate-local
# `.env` land here. `.edgezero/.env` also matches via the top-level
# `.env` pattern; both are provision-owned + operator-filled and
# must never be committed.
.env

# OS
# --- OS ---
.DS_Store

# Worktrees
# --- Worktrees ---
.worktrees/

# Editors
# --- Editors ---
.claude/*
!.claude/settings.json
!.claude/commands/
Expand All @@ -42,4 +84,3 @@ target/
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.rlib
154 changes: 154 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Breaking changes

- **Adapter CLI execution and lifecycle contexts.** `Adapter::execute` takes
`&AdapterExecContext`, and `deploy` takes both `&AdapterDeployContext` and
`&AdapterExecContext`. `preflight_deploy` and `finalize_deploy` now also receive
execution context. Apply `exec.env()` to every child process and credential
lookup while retaining the adapter's selected working directory. Build
contexts with `AdapterExecContext::new().with_env(...).with_cwd(...)`; honor
declared manifest/crate/component paths instead of rediscovering them.
- **Adapter-owned local CLI metadata.** Implement `Adapter::local_layout` to
describe provision artifacts and the optional serve env file. Paths are
project-relative and receive the manifest, crate, and component declarations
through `AdapterLocalContext`. Mark secret-bearing env files with
`LocalArtifactKind::Env`, including custom filenames, and credential-bearing
TOML with `LocalArtifactKind::SensitiveToml`. The default describes
only the declared manifest. `AdapterBlueprint` literals now require
`tool_pins`, `install_notes`, and `local_ignore_patterns`; use empty slices
when unnecessary. Logging endpoints support the command template vocabulary
plus `{project_mod}`. `CommandTemplates` also requires `emit_commands`: choose
`false` when registry execution must honor the adapter manifest.
- **Explicit config cloud target.** `AdapterPushContext::cloud_target` and
`.with_cloud_target(bool)` replace deploy-command inference. Set
`[adapters.<name>.adapter].cloud = true` for a cloud target and use the context
builder instead of the removed deploy-command context field.

- **`edgezero-adapter::Adapter::provision` trait method changed shape.** Was
`fn provision(&self, root, adapter_manifest, component, stores, dry_run) -> Result<Vec<String>, String>`
with an `Ok(Vec::new())` default. Is now
`fn provision(&self, root, adapter_manifest, component, stores, deployed: Option<&AdapterDeployedState>, mode: ProvisionMode, dry_run) -> Result<ProvisionOutcome, String>`
with **no default** — every `impl Adapter` must supply it. Any
out-of-tree adapter written against the previous shape will fail to
compile with two errors: the method's arity and its return type. To
migrate:
1. Add a `mode: ProvisionMode` match arm and a `deployed: Option<&AdapterDeployedState>` parameter.
2. Return `ProvisionOutcome::from_status_lines(lines)` (or
`::with_deployed(lines, deployed_state)` when the cloud arm has
an id to write back) instead of `Ok(vec![...])`.
3. Add a fall-through arm `other => Err(...)` on the `match mode` —
`ProvisionMode` is `#[non_exhaustive]` and may gain variants.

- **`edgezero-adapter::AdapterDeployedState`, `ProvisionOutcome`,
and `ProvisionMode` are now `#[non_exhaustive]`.** Struct-literal
construction from a downstream crate (e.g.
`ProvisionOutcome { status_lines, deployed }`) no longer compiles.
Use the new constructors:
- `ProvisionOutcome::from_status_lines(status_lines)` for local mode
(which returns `deployed: None`).
- `ProvisionOutcome::with_deployed(status_lines, deployed_state)`
for cloud mode that populates the writeback.
- `AdapterDeployedState::default()` + `.fields.insert(...)` /
`.sub_tables.insert(...)` for the deployed state.

### Added

- **`edgezero provision` / `edgezero config push` cross-process advisory
lock** (`.edgezero/provision.lock` under the manifest's project root).
Serialises concurrent invocations against the same tree so
read-modify-write on `.env` / `.dev.vars` / `edgezero.toml` no
longer silently drops a competing writer's edits. Dry-run skips
the lock. Auto-released on process exit; the sentinel file itself
is git-ignored per-machine and safe to delete when no invocation
is running.

### Fixed

- Redact native TOML values and comments in local provisioning previews and
omit source excerpts from native provision parse errors. Serialize Fastly
local provision with deploy writeback under the same manifest lock.
- Preserve relative application-manifest selection across child working
directories, accept root adapter crates, and guard Spin artifact copies and
SQLite paths against intermediate symlinks, including paths containing `..`.

- Preserve quoted multiline env records and original line endings during
provisioning. Readers, writers, and preview redaction share dotenv grammar;
generated values are encoded losslessly or rejected explicitly.
- Targeted provision/config commands validate the selected adapter's policy;
whole-project config validation still checks all registered adapters. Derived
artifacts are checked in the original tree before previews are staged.
- Remove inherited project-lock borrowing and deploy-wide shell locks. Rust
provision/config transactions hold real exclusive locks. Native Fastly deploy
writes a private manifest and merges only `service_id`, preserving unrelated
concurrent edits and refusing conflicting service changes. Immutable managed
deploys use a private native startup directory and forward execution context
to both Fastly and curl. Native Fastly serve requires a `fastly.toml` basename.
- Reject symlinked Cloudflare local persistence before reads as well as writes;
Wrangler can initialize local state while reading.

- Fastly `service_id` no longer lands under `[local_server]` on
re-provision; the merged `fastly.toml` correctly carries it at the
TOML root so `fastly compute deploy` picks it up.
- Fastly cloud `provision` no longer auto-captures `service_id` from
the gitignored, per-machine `fastly.toml` into tracked
`[adapters.fastly.deployed]`. Per the v1 contract that writeback
stays a documented one-time manual copy after `fastly compute deploy`;
auto-capturing it let a stale local file silently overwrite the
team's committed service id.
- Cloudflare `.dev.vars` commented `__KEY` placeholder now uses
`<logical>_staging` (was `<placeholder-<logical>-key>`).
- Cross-adapter `path_mutation_guard` unification (`edgezero-cli`
test binary): scaffold + push-shim tests share the same mutex, no
more intermittent CI flakes from PATH-restore races.
- Cloud `config push` now honours the spec's path-containment MUST
(absolute path + `..` traversal rejection). The strict-local
"manifest inside adapter crate" check stays `--local`-gated so
existing cloud fixtures with root-level manifest paths keep
working.
- Provision `.dev.vars` / `.env` written 0600 on Unix so operator-
filled secret values are not world-readable.
- Provision line-oriented files reject values containing `\n` or
`\r` — a malicious env override can no longer split into a second
`KEY=VALUE` line and inject an unintended env-var.
- Dry-run report emits a **unified diff with 2-line context radius**
instead of the full pre-image; `.dev.vars` / `.env` operator
values no longer stream into CI logs.
- Adapter error paths inside `run_local_dry_run` sanitise raw
`/var/folders/.../edgezero-staging-*` tempdir paths back to the
project-relative form before surfacing.

### Test coverage

- End-to-end env-overlay: `EDGEZERO__STORES__<KIND>__<LOGICAL>__NAME`
now has an integration test that drives it from process env
through `EnvConfig::store_name()` into the emitted `.edgezero/.env`.
- Case-insensitive adapter arg: `--adapter AXUM` against
`[adapters.axum]` lowercase now covered (previously only the
reverse direction was locked).
- Cloudflare `wrangler.toml` schema header preserved at line 1 after
provision merge into an operator-authored doc.
- `*.toml.hbs` scaffold templates walker asserts no `KEY = ""`
placeholder leaks past `write_baseline_to_disk`.
- Fastly root-scalar assertions (`service_id`, `[[local_server.kv_stores.sessions]]`
stub row) now reparse-then-index instead of substring-match, so
the shipped `service_id`-under-`[local_server]` bug's regression
class is locked.

### Deprecated / renamed

- Three tests named `provision_local_push_after_provision_preserves_*`
were renamed to `provision_typed_local_re_run_preserves_*` —
their bodies never invoked `push_config_entries` and the prior
name misled readers looking for real push→provision coverage.
Real push→provision coverage now exists as
`push_after_provision_preserves_*` in each adapter (Axum/Cloudflare/
Fastly/Spin): each seeds an operator secret into the provision-written
file, runs `config push --local`, and asserts that file is untouched.
Loading
Loading