From ab5807d1b7ffa65155b8dd15d193ebbca77a0f7b Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Mon, 24 Aug 2026 08:48:14 -0700 Subject: [PATCH 1/2] Reuse one release id in every local verification example Each of the three build-and-verify snippets in OPERATIONS.md, README.md, and deploy/README.md omitted EXPECT_RELEASE, so the live check never verified the running Caddy rules belonged to the release the command just built. Each now captures one RELEASE value and passes it to both commands. --- OPERATIONS.md | 12 +++++++----- README.md | 5 +++-- deploy/README.md | 5 +++-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/OPERATIONS.md b/OPERATIONS.md index 0a839aa..af0e964 100644 --- a/OPERATIONS.md +++ b/OPERATIONS.md @@ -77,16 +77,18 @@ So release to the local mirror and run the live check **before** opening a pull ```sh set -a; . ~/.secrets/Blog.local.production.env; set +a -ENV_FILE=~/.secrets/Blog.local.production.env deploy/make-release.sh -checks/check-live-urls.sh "$SITE_BASE_URL" +RELEASE="$(git rev-parse --short HEAD)" +ENV_FILE=~/.secrets/Blog.local.production.env deploy/make-release.sh "" "$RELEASE" +EXPECT_RELEASE="$RELEASE" checks/check-live-urls.sh "$SITE_BASE_URL" ``` -Name the file in both places, even when it is the default, since `make-release.sh` sources `ENV_FILE` independently of the shell above and a value already exported earlier in the same session would otherwise win silently over the sourced one: +Name the file in both places, even when it is the default, since `make-release.sh` sources `ENV_FILE` independently of the shell above and a value already exported earlier in the same session would otherwise win silently over the sourced one. The empty first argument leaves the deploy root at the sourced `DEPLOY_ROOT`, and `RELEASE` is reused so `EXPECT_RELEASE` verifies the release the command just built rather than skipping the release-stamp guard: ```sh set -a; . ~/.secrets/Blog.local.staging.env; set +a -ENV_FILE=~/.secrets/Blog.local.staging.env deploy/make-release.sh -checks/check-live-urls.sh "$SITE_BASE_URL" +RELEASE="$(git rev-parse --short HEAD)" +ENV_FILE=~/.secrets/Blog.local.staging.env deploy/make-release.sh "" "$RELEASE" +EXPECT_RELEASE="$RELEASE" checks/check-live-urls.sh "$SITE_BASE_URL" ``` **There is no restart step, and that depends on one flag.** The container runs `caddy run --watch`, which re-adapts the config on a timer and reloads it in process. Re-adapting re-executes every `import`, so a new release's `Caddyfile` and `maps/*.map` are picked up through the unchanged `/config/Caddyfile` that the watcher actually names. Measured on this host: content is live the instant the symlink moves, and the rules follow within about a quarter of a second. diff --git a/README.md b/README.md index 6996220..81360e4 100644 --- a/README.md +++ b/README.md @@ -179,8 +179,9 @@ Build a release and verify it against a running server: ```sh set -a; . ~/.secrets/Blog.local.production.env; set +a -ENV_FILE=~/.secrets/Blog.local.production.env deploy/make-release.sh -checks/check-live-urls.sh "$SITE_BASE_URL" +RELEASE="$(git rev-parse --short HEAD)" +ENV_FILE=~/.secrets/Blog.local.production.env deploy/make-release.sh "" "$RELEASE" +EXPECT_RELEASE="$RELEASE" checks/check-live-urls.sh "$SITE_BASE_URL" ``` The deploy root and the base URL come from a file per environment in `~/.secrets/`, named `Blog...env`, copied from [example.env][env-example] and selected with `ENV_FILE`. `~/.secrets/Blog.local.production.env` is the one read when `ENV_FILE` is unset. The real files live on the host, never in this checkout. diff --git a/deploy/README.md b/deploy/README.md index 6c36bad..ad4d55b 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -54,8 +54,9 @@ neither. Seven facts are the whole contract: ```sh set -a; . ~/.secrets/Blog.local.production.env; set +a -ENV_FILE=~/.secrets/Blog.local.production.env deploy/make-release.sh -checks/check-live-urls.sh "$SITE_BASE_URL" +RELEASE="$(git rev-parse --short HEAD)" +ENV_FILE=~/.secrets/Blog.local.production.env deploy/make-release.sh "" "$RELEASE" +EXPECT_RELEASE="$RELEASE" checks/check-live-urls.sh "$SITE_BASE_URL" ``` The deploy root and the base URL are the only host-specific values, and they pair per From 5abc2e17d77a6adc235960f54d91da4296945cf2 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Mon, 24 Aug 2026 09:04:11 -0700 Subject: [PATCH 2/2] Fail closed in every release snippet's git rev-parse A failed git rev-parse left RELEASE empty in every snippet, which the builder covers with its own timestamp fallback while check-live-urls.sh silently skips its release-stamp verification on an empty EXPECT_RELEASE. set -e now stops each snippet at that failure instead. --- OPERATIONS.md | 5 ++++- README.md | 1 + deploy/README.md | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/OPERATIONS.md b/OPERATIONS.md index af0e964..f59fa7e 100644 --- a/OPERATIONS.md +++ b/OPERATIONS.md @@ -76,15 +76,17 @@ So release to the local mirror and run the live check **before** opening a pull | `hugo.yaml`, `layouts/` | Permalink and taxonomy changes move URLs underneath the redirects that point at them. | ```sh +set -e set -a; . ~/.secrets/Blog.local.production.env; set +a RELEASE="$(git rev-parse --short HEAD)" ENV_FILE=~/.secrets/Blog.local.production.env deploy/make-release.sh "" "$RELEASE" EXPECT_RELEASE="$RELEASE" checks/check-live-urls.sh "$SITE_BASE_URL" ``` -Name the file in both places, even when it is the default, since `make-release.sh` sources `ENV_FILE` independently of the shell above and a value already exported earlier in the same session would otherwise win silently over the sourced one. The empty first argument leaves the deploy root at the sourced `DEPLOY_ROOT`, and `RELEASE` is reused so `EXPECT_RELEASE` verifies the release the command just built rather than skipping the release-stamp guard: +Name the file in both places, even when it is the default, since `make-release.sh` sources `ENV_FILE` independently of the shell above and a value already exported earlier in the same session would otherwise win silently over the sourced one. The empty first argument leaves the deploy root at the sourced `DEPLOY_ROOT`, and `RELEASE` is reused so `EXPECT_RELEASE` verifies the release the command just built rather than skipping the release-stamp guard. `set -e` matters here too: a failed `git rev-parse` would otherwise leave `RELEASE` empty, which silently skips the check's own release-stamp verification instead of failing loud: ```sh +set -e set -a; . ~/.secrets/Blog.local.staging.env; set +a RELEASE="$(git rev-parse --short HEAD)" ENV_FILE=~/.secrets/Blog.local.staging.env deploy/make-release.sh "" "$RELEASE" @@ -144,6 +146,7 @@ Three properties of how the credential is handled, each there for a reason worth ## Deploying ```sh +set -e RELEASE="$(git rev-parse --short HEAD)" SITE_BASE_URL= deploy/make-release.sh "$RELEASE" EXPECT_RELEASE="$RELEASE" checks/check-live-urls.sh diff --git a/README.md b/README.md index 81360e4..b36127e 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,7 @@ checks/check-url-parity.py public Build a release and verify it against a running server: ```sh +set -e set -a; . ~/.secrets/Blog.local.production.env; set +a RELEASE="$(git rev-parse --short HEAD)" ENV_FILE=~/.secrets/Blog.local.production.env deploy/make-release.sh "" "$RELEASE" diff --git a/deploy/README.md b/deploy/README.md index ad4d55b..63411ac 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -53,6 +53,7 @@ neither. Seven facts are the whole contract: ## Building a release ```sh +set -e set -a; . ~/.secrets/Blog.local.production.env; set +a RELEASE="$(git rev-parse --short HEAD)" ENV_FILE=~/.secrets/Blog.local.production.env deploy/make-release.sh "" "$RELEASE"