Skip to content

docs(deploy): push-button autumn deploy walkthrough (AC-8 of #1607)#1950

Merged
madmax983 merged 9 commits into
trunk-devfrom
feat/1607-deploy-guide-ac8
Jul 15, 2026
Merged

docs(deploy): push-button autumn deploy walkthrough (AC-8 of #1607)#1950
madmax983 merged 9 commits into
trunk-devfrom
feat/1607-deploy-guide-ac8

Conversation

@madmax983

@madmax983 madmax983 commented Jul 15, 2026

Copy link
Copy Markdown
Owner

AC-8 of #1607 — the deployment guide

Adds the push-button autumn deploy journey to docs/guide/deployment.md as the primary deployment path, with the container/OCI and fly.io paths kept as documented alternatives.

What's added

A new ## Push-button deploy to your own server (autumn deploy) section (inserted between ## Prerequisites and the existing container ## Step 1), covering:

  • a verbatim autumn new → live walkthrough: scaffold → set [deploy] host → put secrets in .envautumn deploy checkautumn build --embedautumn deploy upcurl /health;
  • zero-downtime redeploy (re-run autumn deploy up — blue/green cutover, migrate-before-flip, health-gated atomic proxy flip, 0 dropped requests);
  • autumn deploy rollback and autumn deploy plan;
  • where secrets live (0600 env file on the host, sourced by systemd, never printed);
  • preconditions (key-based SSH to a stock Ubuntu LTS host; the kamal-proxy binary present at /usr/local/bin/kamal-proxy) and troubleshooting via autumn deploy check / autumn doctor;
  • an honest Limitations subsection: the kamal-proxy binary is host-bootstrapped (the deploy configures+supervises the unit but doesn't download the binary), migrations run on redeploys not the first deploy, single-host only, and the remote-state atomicity gap (Deploy: harden remote-state consistency across cutover and rollback (post-flip marker-write window) #1938).

Every command/flag/config key was verified against the shipped CLI.

Notes for reviewers / docs

Completes #1607 AC-8.

…deployment path — Part of #1607

Adds the AC-8 push-button deployment journey to docs/guide/deployment.md — a verbatim `autumn new` → `[deploy] host` → secrets in `.env` → `autumn deploy check` → `autumn build --embed` → `autumn deploy up` → live walkthrough, plus zero-downtime redeploy, `autumn deploy rollback`, `autumn deploy plan`, where secrets live (0600 env file), preconditions (key-based SSH to stock Ubuntu; kamal-proxy binary present), troubleshooting via `autumn deploy check`/`autumn doctor`, and honest limitations (kamal-proxy binary is host-bootstrapped, migrations run on redeploy, single-host, remote-state atomicity #1938). The container and fly.io paths remain as documented alternatives. Completes #1607 AC-8.
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@madmax983
madmax983 marked this pull request as ready for review July 15, 2026 02:03
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: acfa19957a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/guide/deployment.md Outdated
Comment on lines +98 to +99
Put your secrets in a project `.env` (git-ignored — never committed). They are
read by the deploy and written to a `0600` env file **on the server only**:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Clarify that only two env vars are deployed

For apps with any runtime secret besides the signing secret and database URL (for example OAuth, SMTP, Redis, or storage credentials), this tells users to put “your secrets” in .env and expect the deploy to write them on the server. However autumn-cli/src/deploy.rs::build_env_file only serializes AUTUMN_SECURITY__SIGNING_SECRET and AUTUMN_DATABASE__URL, so the deployed systemd service will not receive other .env values and those features will fail in production unless the user provisions them separately.

Useful? React with 👍 / 👎.

…ployed to the host — Part of #1607

The push-button guide implied any `.env` secret is transferred to the server, but `autumn deploy` writes only AUTUMN_SECURITY__SIGNING_SECRET and (for DB-backed apps) AUTUMN_DATABASE__URL to the host's 0600 env file. Clarifies the secrets section and adds a Limitations bullet so operators provision other runtime secrets (OAuth/SMTP/Redis/storage/etc.) on the target separately. Addresses Codex P2 on #1950.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 29c89ace7c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/guide/deployment.md Outdated
Comment on lines +130 to +131
```bash
autumn deploy check # same graders also run inside `autumn doctor`

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Point the walkthrough at a CLI release with deploy

When a new user follows the Prerequisites exactly they install autumn-cli --version 0.5.0, but this newly added walkthrough immediately asks them to run autumn deploy check; the deploy subcommand is part of the checked-in 0.6.0 CLI (Cargo.toml is 0.6.0 and DeployCommands is in the current autumn-cli/src/main.rs). With the pinned 0.5.0 install, the primary path can fail before the first deploy command runs, so the install version needs to be updated or the deploy section needs to be marked as requiring the newer CLI.

Useful? React with 👍 / 👎.

Comment thread docs/guide/deployment.md Outdated
Comment on lines +60 to +63
- **Key-based SSH access to a stock Ubuntu LTS (or other systemd) host.** The
deploy runs non-interactively (`BatchMode=yes`) as the configured user
(`[deploy] user`, default `root`) — no password prompts, so your SSH key must
already be authorized on the target.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Require a privileged SSH user for systemd writes

If the operator sets [deploy] user to a normal non-root SSH account, this precondition implies that key-based access as that user is enough, but the deploy executor writes /etc/systemd/system/*.service and runs systemctl ... directly over SSH without sudo. On a stock Ubuntu host that user cannot create units or manage services, so deploy up fails after preflight; document that the SSH user must be root or otherwise already have direct permission for systemd and the app directory.

Useful? React with 👍 / 👎.

Comment thread docs/guide/deployment.md Outdated
Comment on lines +213 to +214
`plan` is a pure dry-run: it prints the exact systemd unit and the ordered
zero-downtime rollout steps without connecting to the host.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Don’t advertise the deploy plan’s unit as exact

The unit printed by autumn deploy plan is not the one written by a real deploy: print_plan renders render_systemd_unit, while deploy up renders slot-specific app units via render_app_unit with {service}-{blue,green}.service, AUTUMN_SERVER__HOST=127.0.0.1, and the private slot port. Users auditing the plan for unit names or port binding will see the wrong unit, so this should not be documented as the exact systemd unit unless the plan output is changed.

Useful? React with 👍 / 👎.

…nd deploy-plan-unit accuracy — Part of #1607

Addresses Codex review on #1950 — the push-button guide now (1) notes `autumn deploy` requires autumn-cli 0.6.0+ (the Prerequisites 0.5.0 install lacks the subcommand), (2) states the [deploy] user must be root or already have direct no-sudo permission for systemd + the app dir (the deploy writes /etc/systemd/system and runs systemctl without sudo), and (3) describes `autumn deploy plan`'s unit as representative rather than exact (real deploys write slot-specific {service}-{blue,green} units on a private loopback port).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 189ef92c87

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/guide/deployment.md Outdated
server until it is green:

```bash
autumn deploy check # same graders also run inside `autumn doctor`

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Point SSH checks at doctor --online

When the only deploy problem is SSH reachability, this makes autumn doctor sound equivalent to autumn deploy check, but doctor gates deploy_ssh_reachability behind --online (doctor.rs only adds that task when opts.online is true). A user can therefore get a passing default autumn doctor while autumn deploy check still fails on an unreachable SSH port; the walkthrough should say autumn doctor --online for the same network grader or avoid claiming the graders are identical.

Useful? React with 👍 / 👎.

Comment thread docs/guide/deployment.md
```

`plan` is a pure dry-run: it prints a **representative** systemd unit and the
ordered zero-downtime rollout steps for review, without connecting to the host.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Mark plan steps as representative too

The remaining mismatch is in the step order, not the unit caveat: build_deploy_plan prints [migrate] before [start-candidate], while the real deploy up path in cutover_ops starts the candidate first and then runs the migration one-shot. For users using deploy plan to review rollout ordering, this paragraph still presents the step list as the ordered deploy sequence, so either the plan output should be aligned or the docs should state that the steps are illustrative as well.

Useful? React with 👍 / 👎.

…loy plan` step order is representative — Part of #1607

Addresses Codex review on #1950 — plain `autumn doctor` skips network probes, so the SSH-reachability grader needs `autumn doctor --online` (or `autumn deploy check`); and `autumn deploy plan`'s step order is illustrative (it lists migrate before start-candidate, whereas a live redeploy starts the candidate first, then runs the pre-cutover migration).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ad235e8460

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/guide/deployment.md
Comment on lines +114 to +116
Put these two values in a project `.env` (git-ignored — never committed). The
deploy reads them and writes **only** them to a `0600` env file
(`app_dir/shared/autumn.env`) **on the server**:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Document that runtime config is not deployed

For apps that depend on any runtime autumn.toml settings beyond the defaults, this walkthrough leaves those settings behind: deploy up uploads only the release binary and writes the env file containing the signing secret/database URL, while the generated systemd unit runs from the release dir without copying autumn.toml. That means non-secret config such as auth, jobs/scheduler, health paths, telemetry, CORS, or signing-secret rotation entries resolve to defaults on the server unless users provision them separately, so the primary path can silently run a different configuration than the one tested locally.

Useful? React with 👍 / 👎.

Comment thread docs/guide/deployment.md
Comment on lines +214 to +215
```bash
autumn deploy rollback

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Document rollback's local preflight requirement

In an emergency rollback run from CI or another checkout that no longer has the same local .env/config, this command will not reach the server as implied here: run_rollback first runs the full deploy preflight and can fail on the local signing secret, database URL, or migration-safety check before resolving the previous release on the host. The rollback section should say it still requires the same local preflight inputs, otherwise operators may discover during an outage that the documented one-command rollback is blocked locally.

Useful? React with 👍 / 👎.

…s the local preflight — Part of #1607

Addresses Codex review on #1950 — clarifies that `autumn deploy up` uploads only the release binary and the env file (signing secret + database URL), so non-secret `autumn.toml` settings resolve to defaults on the host unless provisioned separately; and that `autumn deploy rollback` runs the same local preflight first, so it needs the same local secrets/config inputs where it's invoked (an emergency rollback from a bare checkout fails preflight before reaching the host).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9ead84fc92

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/guide/deployment.md
Comment on lines +114 to +116
Put these two values in a project `.env` (git-ignored — never committed). The
deploy reads them and writes **only** them to a `0600` env file
(`app_dir/shared/autumn.env`) **on the server**:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Set the production profile on deployed units

When this walkthrough is followed exactly, the host env file contains only these two values and render_app_unit only adds the slot host/port, so no AUTUMN_ENV reaches systemd. AutumnConfig::resolve_profile then falls back to dev, enabling dev smart defaults such as permissive CORS, detailed actuator output, and CSRF/session settings that differ from production on the VPS. Please set AUTUMN_ENV=prod in the generated unit/env file or document a deploy-safe way to provide it before presenting this as the primary production deploy path.

Useful? React with 👍 / 👎.

Comment thread docs/guide/deployment.md Outdated
Comment on lines +146 to +149
> configuration you actually tested, provision it on the host yourself: place
> your `autumn.toml` in the release/app dir on the server, or set the matching
> `AUTUMN_*` environment overrides in `app_dir/shared/autumn.env` (the env-file
> route persists across releases; a file dropped into a timestamped release dir

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid recommending edits to overwritten deploy files

The suggested app_dir/shared/autumn.env path is rewritten on every first deploy and redeploy: both deploy paths call WriteFile for that same env path using build_env_file(), which emits only the signing secret and database URL. Any OAuth/SMTP/Redis overrides an operator adds there will be removed by the next autumn deploy up even though this text says the env-file route persists across releases, so redeploys can silently boot without required runtime config; document a provisioning mechanism deploy does not overwrite or change deploy to merge/preserve extra entries.

Useful? React with 👍 / 👎.

… env file is regenerated each deploy — Part of #1607

Reflects the companion fix (#1956) that writes AUTUMN_ENV=prod by default (overridable via [deploy] profile / AUTUMN_DEPLOY__PROFILE), and corrects the earlier guidance that implied hand-added values in shared/autumn.env persist — the env file is rebuilt on every deploy (signing secret + database URL + AUTUMN_ENV), so it's not a durable override store; non-secret config still isn't deployed (tracked in #1952). Addresses remaining Codex review on #1950.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ef3c4428d9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/guide/deployment.md
Comment on lines +142 to +144
> signing-secret enforcement. To deploy a non-production target, set `[deploy]
> profile = "staging"` in `autumn.toml` (or `AUTUMN_DEPLOY__PROFILE=staging`);
> the deploy writes that value as `AUTUMN_ENV` instead.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Remove the unsupported deploy profile knob

For non-production deploys, this documented setting is a no-op: DeployConfig has no profile field and apply_deploy_env_overrides does not recognize AUTUMN_DEPLOY__PROFILE; build_env_file also never writes AUTUMN_ENV. With strict config enabled the TOML key hard-fails as unknown, and otherwise both TOML/env forms are ignored, so users following this escape hatch still get the default runtime profile instead of staging.

Useful? React with 👍 / 👎.

Comment thread docs/guide/deployment.md Outdated
Comment on lines +173 to +175
Run the preflight — it checks SSH reachability, the signing secret, the database
URL (when the app is DB-backed), and that pending migrations are safe for a
rolling deploy. It exits non-zero if anything fails, so nothing touches the

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Don't call the migrate check pending-only

For repos that keep an old destructive migration file after it has already been applied, this preflight can still fail: grade_migrate_check is an offline scan of migrations/, and check_migrations_in_dir reads every migration directory without consulting DB state to know what is pending. The guide's "pending migrations" wording sends users down the wrong path when an already-applied migration blocks deploy check; either filter by pending in code or document that all local migrations must be rolling-safe.

Useful? React with 👍 / 👎.

…s offline, not just pending ones — Part of #1607

The deploy migrate check (grade_migrate_check) is an offline static scan of the local migrations/ directory and does not consult the database, so it requires ALL local migration files to be rolling-safe — an already-applied destructive migration still on disk will fail `deploy check`. Corrects the "pending migrations" wording. Addresses Codex review on #1950.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0bf6ac70ae

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/guide/deployment.md Outdated
Comment on lines +60 to +61
> ships them, install the CLI from the latest source (`cargo install autumn-cli
> --git https://github.com/madmax983/autumn`) and confirm the subcommand is

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Specify the CLI package in the git install command

For users following this Version note before a release contains deploy, this cargo install --git command is still not reliably runnable for this workspace: Cargo's install --help says the [CRATE] argument selects the package from the --git source, and cargo metadata for this repo shows multiple binary packages (autumn-cli plus several examples/benchmarks). Omitting autumn-cli leaves Cargo unable to choose the package to install, so the primary deploy path can still stop before autumn deploy --help; use cargo install --git https://github.com/madmax983/autumn autumn-cli (with --force if replacing the pinned 0.5.0 install).

Useful? React with 👍 / 👎.

claude added 2 commits July 15, 2026 05:56
…m-source install command — Part of #1607

The workspace has multiple binary packages, so `cargo install --git <url>` without a crate name fails to pick one; the from-source install for the unreleased `autumn deploy` CLI now specifies `autumn-cli` and uses `--force` to replace a pinned prior install. Addresses Codex P1 on #1950.
…y — follow-up incoming

Add a short known-gap callout in the deploy config section clarifying that
values set only under [profile.prod] or .env.prod aren't yet read by
autumn deploy, which resolves config under the ambient profile while
running the service as prod. Part of #1607

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014ee9hUf7PA7p4SYdWNk8AU
@madmax983
madmax983 merged commit bacc03a into trunk-dev Jul 15, 2026
27 of 28 checks passed
@madmax983
madmax983 deleted the feat/1607-deploy-guide-ac8 branch July 15, 2026 17:46
madmax983 added a commit that referenced this pull request Jul 15, 2026
… (#1956)

* fix(cli): autumn deploy runs the app under the production profile by default — Part of #1607

The deployed systemd service never received a profile selector, so `AutumnConfig::resolve_profile` fell back to `dev` — a production deploy silently ran dev smart-defaults (permissive CORS, detailed actuators, dev CSRF/session). `build_env_file` now writes `AUTUMN_ENV=<profile>` into the 0600 host env file, defaulting to `prod` via a new `[deploy] profile` config key (overridable with `AUTUMN_DEPLOY__PROFILE`, e.g. "staging" for non-prod targets). Tests cover the prod default and the override. Addresses the Codex P1 on #1950.

* test(config): register the new deploy.profile key in the schema-keys snapshot — Part of #1607

The `[deploy] profile` config field added in this PR emits a new `deploy.profile` schema key; regenerate the schema-keys snapshot so schema_keys_snapshot_guard passes. Fixes the CI Test failure on #1956.

* fix(cli): grade deploy preflight signing secret against the resolved deploy profile — Part of #1607

The deploy preflight and the remote env-file generation used different
profile sources. `collect_preflight` graded the signing-secret strength
with `is_production_profile(config.profile)` — the LOCAL CLI runtime
profile (dev/None on a dev box) — while `build_env_file` writes
`AUTUMN_ENV=<resolved.profile>` (the `[deploy] profile`, default `prod`).

Before: running `deploy check`/`deploy up` from a dev box with a weak/demo
signing secret PASSED preflight (non-production grading), but the uploaded
unit booted with `AUTUMN_ENV=prod` and exited in
`fail_fast_on_invalid_signing_secret` — failing the deploy AFTER touching
the host.

After: preflight grades the signing secret against the SAME profile the env
file will pin (`is_production_profile(Some(&resolved.profile))`), so a weak
secret targeting a prod deploy is caught locally, before any remote call,
while a non-production deploy profile still accepts a weak secret. All three
preflight call sites (check/up/rollback) already pass `resolved`, so they
stay coherent with `build_env_file`.

Adds a regression test proving the default (prod) deploy profile fails a weak
secret and a non-prod profile passes it.

* fix(cli): canonicalize the deploy profile before grading and writing AUTUMN_ENV — Part of #1607

Before: `ResolvedDeployConfig::resolve` stored `[deploy] profile` verbatim, but
the preflight grader `is_production_profile` matches only the exact lowercase
`prod`/`production`. The app's runtime resolver `normalize_profile_name` instead
trims and case-folds aliases, so `PROD`, `Production`, and ` production ` all
boot under the canonical `prod`. A non-canonical production spelling was graded
NON-production locally (a weak/demo signing secret passed preflight), yet
`build_env_file` wrote that same raw string to `AUTUMN_ENV`; the host normalized
it to `prod` and `fail_fast_on_invalid_signing_secret` rejected the weak secret
at boot — failing the deploy only after touching the host.

After: a CLI-local `canonicalize_deploy_profile` helper mirrors the runtime
`normalize_profile_name` rules (trim; fold `production`/`prod` → `prod`,
`development`/`dev` → `dev`; preserve other non-empty values; blank → `prod`)
and is applied at resolve time, so both the preflight grade and the AUTUMN_ENV
value use one canonical spelling. Weak secrets under `PROD`/`Production`/
` production ` are now caught locally; custom profiles like `staging` are
preserved verbatim and still grade non-production.

Kept the helper private and did not touch autumn-web's public API.

* fix(cli): preserve raw deploy profile in AUTUMN_ENV and grade doctor against deploy profile — Part of #1607

Two related deploy-profile grading fixes:

1. deploy: `ResolvedDeployConfig::resolve` now stores the operator's TRIMMED
   RAW `[deploy] profile` spelling (via new `trimmed_deploy_profile`) instead of
   the alias-folded canonical form. `build_env_file` writes that raw spelling to
   `AUTUMN_ENV`, so the host's runtime override-file lookup
   (`profile_override_file_lookup_names`) keeps its precedence — e.g.
   `autumn-production.toml` over `autumn-prod.toml` when the operator wrote
   `production`. Before: canonicalizing at resolve time flipped override-file
   precedence on hosts with both files. Grading is normalized separately by
   applying `canonicalize_deploy_profile` only at the grade site, so
   `PROD`/`Production`/` production ` are still held to production strength rules.

2. autumn doctor: the deploy branch now grades the deploy signing secret against
   the resolved `[deploy] profile` (default `prod`) via a new
   `deploy_is_production` flag, instead of the ambient `AUTUMN_ENV`/`AUTUMN_PROFILE`
   flag. Before: on a dev box `doctor --strict` PASSED a weak deploy signing
   secret that `deploy check`/`deploy up` FAIL; now doctor and `deploy check`
   agree. `is_production_profile`/`canonicalize_deploy_profile` are made
   `pub(crate)` for reuse; ambient (non-deploy) doctor checks are unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014ee9hUf7PA7p4SYdWNk8AU

---------

Co-authored-by: Claude <noreply@anthropic.com>
madmax983 added a commit that referenced this pull request Jul 15, 2026
…e (Part of #1607) (#1966)

* fix(cli): resolve autumn deploy config under the target deploy profile (Part of #1607)

Before: `autumn deploy` did one `AutumnConfig::load()` under the operator's
ambient profile (dev by default) and fed that single config to both preflight
grading and the host env file. It graded and uploaded the DB URL
(`resolve_writable_db_url`) and signing secret from config resolved under the
ambient profile while running the service as the deploy profile (`prod`), so a
strong prod secret / prod DB URL living only under `[profile.prod]` /
`autumn-prod.toml` / `.env.prod` was never loaded, graded, or uploaded — a prod
deploy could ship dev secrets/DB, and #1956 (which fixed the profile the secret
is graded/written against) did not fix the profile the VALUES were loaded under.

After: `deploy check`/`rollback`/`up` reload the config under the TARGET deploy
profile via the existing autumn-web seams — a small `ForcedProfileEnv` wrapper
(reports `AUTUMN_ENV=<resolved.profile>`, delegates every other read) over
`os_env_with_dotenv_for_profile(&resolved.profile)`, fed to
`AutumnConfig::load_with_env`. The reloaded `runtime_config` (not the ambient
config) now drives preflight grading and the host env file, so `[profile.prod]`
/ `.env.prod` values are loaded, graded, and uploaded. The ambient load is kept
only to read `[deploy]` and compute `resolved.profile`; `plan` stays a pure
dry-run. #1956's behavior is preserved: grading still normalizes via
`is_production_profile(canonicalize_deploy_profile(...))` and `AUTUMN_ENV` still
carries the trimmed raw `resolved.profile`.

Also removes the interim "Known gap" callout from docs/guide/deployment.md
(added via #1950) now that this closes the gap.

Part of #1607.

* fix(cli): load .env.<profile> during deploy config reload

Before: deploy's profile reload skipped `.env.prod` because dotenv
auto-load is gated off for non-dev profiles (`should_load` needs
`AUTUMN_DOTENV=1`), so prod-only values in `.env.<profile>` were never
seen during the deploy config reload.

After: `ForcedProfileEnv` reports `AUTUMN_DOTENV=1` through a new
`autumn_web::dotenv::os_env_with_dotenv_for_profile_using(base, profile)`
seam so `.env.<profile>` loads during the deploy reload without mutating
the global process env. The profile-selector-key exclusion (the real
safety boundary) is preserved.

Adds a `.env.prod` regression test. Addresses the gemini review on #1966.

* fix(cli): canonicalize deploy profile for dotenv overlay and honor explicit AUTUMN_DOTENV

Two deploy-time config-reload fixes in autumn-cli/src/deploy.rs.

AUTUMN_DOTENV (deploy.rs:834):
Before: ForcedProfileEnv::var returned Ok("1") unconditionally for
AUTUMN_DOTENV, so `AUTUMN_DOTENV=0 autumn deploy ...` was overridden and
.env.<profile> loaded anyway.
After: synthesize "1" only when the inner env has no explicit value;
delegate to the inner env when it provides AUTUMN_DOTENV, preserving an
explicit 0/false/1/true (should_load honors 0/false as the off switch).

dotenv overlay selection (deploy.rs:864):
Before: load_runtime_config passed the RAW resolved.profile to the dotenv
overlay, so a `[deploy] profile` alias like `production`/`PROD` made the
loader look for .env.production/.env.PROD instead of the canonical
.env.prod used by AutumnConfig::load() after normalization.
After: select the overlay by canonicalize_deploy_profile(&resolved.profile);
AUTUMN_ENV and the TOML override-file precedence still carry the RAW
spelling (only the dotenv-overlay selection is canonicalized).

Adds a ForcedProfileEnv unit test (explicit 0 preserved, unset -> 1,
true delegated) and two deploy integration tests (production alias loads
.env.prod; AUTUMN_DOTENV=0 skips .env.prod).

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants