Skip to content

test(cli): pin deploy init scaffold env.secret round-trip (#3158)#3204

Merged
bpamiri merged 1 commit into
developfrom
peter/issue-3158-init-envsecret-roundtrip
Jun 13, 2026
Merged

test(cli): pin deploy init scaffold env.secret round-trip (#3158)#3204
bpamiri merged 1 commit into
developfrom
peter/issue-3158-init-envsecret-roundtrip

Conversation

@bpamiri

@bpamiri bpamiri commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator

What

#3158 reported that wheels deploy init scaffolds an env.secret: [WHEELS_RELOAD_PASSWORD] block (cli/lucli/templates/deploy/init/deploy.yml.mustache) that, since the #3008 $rejectEnvSecrets guard, hard-failed any non-empty env.secret with Wheels.Deploy.EnvSecretUnsupported — so the freshly-scaffolded config couldn't be deployed without manual editing.

Verify-first finding

The premise is already resolved on develop by #3167 (df62f4683), which:

  • removed Base.$rejectEnvSecrets (grep finds zero rejectEnvSecrets/EnvSecretUnsupported references anywhere in cli/), and
  • implemented env.secret delivery via a remote --env-file (created at 600 perms, content over SFTP only, referenced by docker run --env-file).

So the scaffolded env.secret block is now correct — the issue's original "remove the block" direction would now break a shipped feature. The fix reduces to pinning the round-trip so the scaffold and the deploy engine can't drift apart again. No template or engine change is needed.

Reproduced empirically on the lucee7 docker harness:

  • The scaffold's .kamal/secrets declares WHEELS_RELOAD_PASSWORD= (empty); the SecretResolver still exports it (structKeyExists true), so env_file_content() does not raise EnvSecretMissing.
  • A fresh initconfig()deploy --dry-run succeeds and routes the secret through --env-file .kamal/apps/<service>/env/roles/<role>.env.

Change

Two DeployMainCliSpec regression tests:

  1. the init scaffold round-trips through config() and deploy --dry-run with no EnvSecretUnsupported/EnvSecretMissing, and the dry-run references the --env-file path;
  2. a deploy of the scaffold delivers WHEELS_RELOAD_PASSWORD to the role env file over SFTP (FakeSshPool uploadString), never in argv.

Red-proof: both tests fail if the scaffold drops its env.secret block (verified by temporarily removing it from the template), so they genuinely guard the scaffold→delivery contract.

Plus a changelog.d fixed fragment.

Tests

CLI suite (lucee7 docker harness): 1071 pass / 0 fail / 2 tolerated docker-env artifacts (SshClientSpec/SshPoolSpec require docker-in-docker, pre-existing/environmental). DeployMainCliSpec 66 → 68 pass.

Fixes #3158

🤖 Generated with Claude Code

#3008 added a $rejectEnvSecrets guard that hard-failed any non-empty
env.secret with Wheels.Deploy.EnvSecretUnsupported, which made the
env.secret block scaffolded by `wheels deploy init` (WHEELS_RELOAD_PASSWORD)
un-deployable without manual editing. #3167 then retired that guard and
implemented env.secret delivery via a remote --env-file (600 perms, SFTP),
so the scaffolded block is now correct and deploys end-to-end.

This pins that contract with two DeployMainCliSpec regression tests:

- the init scaffold round-trips through config() and deploy --dry-run with
  no EnvSecretUnsupported/EnvSecretMissing, and the dry-run routes the
  secret through the --env-file path;
- a deploy of the scaffold delivers WHEELS_RELOAD_PASSWORD to the role env
  file over SFTP (FakeSshPool uploadString), never in argv.

Both tests fail if the scaffold drops its env.secret block (verified by
temporarily removing it), so they guard the scaffold and the deploy engine
against drifting apart again. No template or engine change is needed: the
scaffold is correct as shipped now that env.secret is a delivered feature.

CLI suite (lucee7 docker harness): 1071 pass / 0 fail / 2 tolerated
docker-env artifacts (SshClientSpec/SshPoolSpec require docker-in-docker).

Refs #3008, #3167
Fixes #3158

Signed-off-by: Peter Amiri <petera@pai.com>
@bpamiri bpamiri enabled auto-merge (squash) June 13, 2026 18:16
@github-actions github-actions Bot added the docs label Jun 13, 2026
@bpamiri bpamiri merged commit 45e0fc5 into develop Jun 13, 2026
8 checks passed
@bpamiri bpamiri deleted the peter/issue-3158-init-envsecret-roundtrip branch June 13, 2026 18:19

@wheels-bot wheels-bot Bot 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.

Wheels Bot — Reviewer

TL;DR — This PR pins the wheels deploy init scaffold to the deploy-engine env.secret contract (#3158) with two DeployMainCliSpec regression tests plus a fixed changelog fragment. No production code changes: the underlying fix landed in #3167 (remote --env-file delivery), so this is purely a guard against future drift. I re-verified every API the new tests touch against the actual deploy engine and everything lines up. Verdict: approve.

Tests

The two new specs are well-targeted and accurately model the real engine:

  • DeployMainCliSpec.cfc:357 — round-trip test. Constructor new DeployMainCli(fake, {projectRoot: tmpCwd}) matches DeployMainCli.cfc:17 init(any sshPool = "", struct opts = {}); init_stub({cwd, service, image}) matches DeployMainCli.cfc:469; deploy({..., dryRun: true}) is honored (DeployMainCli.cfc:73 var dryRun = arguments.opts.dryRun ?: false). The expect(arrayLen(fake2.calls())).toBe(0) assertion correctly encodes "dry-run issues no SSH calls."
  • DeployMainCliSpec.cfc:391 — delivery test. The asserted env-file path .kamal/apps/demo/env/roles/web.env matches the engine layout (AppCommands.cfc:158 .kamal/apps/<service[-destination]>/env/roles/<role>.env, default role web, no destination). The uploadString call-record fields the test reads (.remote, .content) and the c.cmd scan match FakeSshPool.cfc:179-181. The "value never in argv" loop is a genuine secret-leak guard.

Red-proof is documented in the PR body (both fail if the scaffold drops its env.secret block), so they exercise the contract rather than passing vacuously.

Conventions

  • (##3158) in the it() descriptions correctly escapes to a literal # — matches existing prior art in the same file ((##3085) at DeployMainCliSpec.cfc:33). The #chr(10)# interpolation in the secrets-file write is a proper expression, not the comment/#-escape hazard.
  • These are CLI-runtime specs (cli/lucli/tests), outside the vendor cross-engine matrix, so the Lucee/Adobe/BoxLang invariants do not apply here.

Docs

  • Minor, non-blocking: changelog.d/3158-deploy-init-envsecret-roundtrip.fixed.md is a fixed fragment, but the actual user-facing fix shipped in #3167 — this PR only adds the regression tests. The wording reads slightly as if this PR performed the fix. It is defensible (it documents real now-pinned behavior and the slug/type follow the convention), so not a change request — just flagging in case you would prefer it phrased as "regression coverage for the #3167 fix."

Commits

test(cli): pin deploy init scaffold env.secret round-trip (#3158) — valid type, scope, subject length, casing. Good.

Clean test-only change with verified API usage and red-proofed coverage. Approving.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

deploy: init template still scaffolds env.secret, so a fresh wheels deploy init config hard-fails with EnvSecretUnsupported

1 participant