1.15.9 — Provisioned nodes can finally take a deploy
Editorial identity incomplete
2026-08-20
A provisioned environment came out of apply looking finished — nodes serving, HTTPS valid — and could not accept a single deploy. /opt/api was not a git checkout, so the deploy plane's git fetch && git reset had nothing to work with; no webhook secret was ever generated, so GitHub's push deliveries were rejected as unsigned; and nothing created the webhook. All three are now part of configure. Separately, both node health probes dialled plain HTTP against a vhost that 301s everything, so the canary reported every successful deploy as a sanity-check failure and rolled it back, while the post-restart gate passed on the redirect alone with the application dead behind it. The provisioner also now builds the two things an environment needs before it can host a static WebApp: a releases bucket and a KMS key.
Breaking
EDGE_SOCKET_BASEis now published as<PROJ_PATH>/varinstead of leaving the framework default of/run/mojo. An existing edgeUpstreamwhosesocket_pathsits under/run/mojowill fail validation after upgrading. See Upgrade notes.
Added
provision applycreates a releases S3 bucket and publishes it as the sole entry inEDGE_RELEASE_BUCKETS. Without one,releases.registerrefuses to mint a WebApp release at all.provision applycreates a KMS key and publishesKMS_KEY_ID.KSMSecretsmodels raise without it, so an environment could not hold a dnsman certificate and therefore could not serve an edge vhost.provision configureconverts/opt/apiinto a real git checkout against the project's repository, at the commit the node booted from.provision applymintsgithub_webhook_secretandconfigureregisters the push webhook on the repository, creating it or rewriting an existing one at the same URL.- The node deploy key is now registered for every node rather than only the first, and is skipped when already present.
check_nodeaudits the box's consume-channel list and fails when it omitsedge.
Changed
- Both node health probes use HTTPS and skip certificate verification on the loopback only. A probe aimed at a real hostname still verifies.
post_deploy.shtreats a missingrequirements.txtas a logged skip. A project whose only dependency is django-mojo legitimately has none.- The generated secrets bundle backfills fields added by a later release, adding only what is missing and never re-minting an existing value.
- The stage-1 payload gained a fourth object recording the commit the application tarball was archived from.
- The shipped systemd units carry a
Documentation=URL.
Fixed
- The canary rolled back every successful deploy.
sanity_checkprobedhttp://127.0.0.1/api/version, the shipped:80vhost 301s everything except the ACME path, and the check does not follow redirects — so it saw the 301 and reported a failure. Releases survived only because the rollback failed too. - The post-restart health gate passed on that same redirect:
curl -fdoes not fail on a 3xx, so nginx being alive satisfied a check meant to prove the application was. configurerolled a deployed node back to its boot commit. The recorded boot SHA is now consulted only to adopt a tree that is not yet a checkout; after that the deploy plane owns HEAD.update.shcould not write its own phase timings — the file was created root-owned by the other half of the deploy — so the phase table reaching the platform was missing the half that wraps the deploy.
Upgrade notes
- Run
provision applybeforeprovision configure. Apply is what mints the webhook secret, creates the KMS key and the releases bucket, and republishes the boot payload; configure only publishes and wires what apply produced. - A node provisioned before this release has no recorded boot commit, so
configurereports it as a manual step and leaves it alone rather than guessing. Replace the node, or wire/opt/apito the repository by hand. - If you have edge upstreams pointing under
/run/mojo, move them under<PROJ_PATH>/varor setEDGE_SOCKET_BASEyourself before upgrading. - A project that overrides
JOBS_CHANNELSreplaces the framework's list rather than extending it. Confirm yours still containsedge, or push-to-deploy answers 503 with no error logged anywhere.