Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
25 changes: 25 additions & 0 deletions OPERATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,31 @@ Shipping the config inside the release is what makes a rollback honest. The rule

`current` is a **relative** symlink. That frees the host path, so one bundle works at whatever root each environment mounts, with no rewriting.

## Local Verification Before a Pull Request

**CI cannot prove a redirect.** The validation workflow builds the site and checks the render half of the contract, which is every URL that must return a page. The other 917 URLs are the web server's job, and nothing in a build exercises them. A change to the Caddy config or to a generated map is therefore invisible to CI: the workflow goes green while the redirect it broke stays broken until someone follows a sixteen-year-old link.

So release to the local mirror and run the live check **before** opening a pull request that touches any of these:

| Path | Why it needs a running server |
| --- | --- |
| [`deploy/Caddyfile`](./deploy/Caddyfile) | The redirect rules. Rule order is load-bearing, and a regex that matches too much is silent. |
| [`deploy/maps/`](./deploy/maps/) | The lookup tables. A regenerated map can lose entries and still parse. |
| `content/`, `static/` | A moved or renamed page turns a redirect destination into a 404, which the build gate does not follow. |
| `hugo.yaml`, `layouts/` | Permalink and taxonomy changes move URLs underneath the redirects that point at them. |

```sh
set -a; . secrets/.env; set +a
deploy/make-release.sh
checks/check-live-urls.sh "$HUGO_BASEURL"
```

Sourcing `secrets/.env` first puts the deploy root and the base URL in the environment, so no literal value is typed. `make-release.sh` then takes no arguments, and it refuses to install a release that fails the build gate. `check-live-urls.sh` does take a base URL, which is where the sourced `$HUGO_BASEURL` goes. It follows all 1,245 URLs against the running mirror, checking each redirect's destination rather than trusting its status code.

Expect `PASS - 1245 URLs honored`. Anything less is a finding, and the output names each URL that failed and what it answered.

A documentation-only or workflow-only change does not need this. A change to the four paths above does, because for those CI's green is not evidence.

## Deploying

```sh
Expand Down
1 change: 1 addition & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ The site is built and gated in CI. It is on GitHub, and it is not yet serving it
## Next, in dependency order

- Dispatch `publish-release.yml` once to prove the release path, which exists but has never run.
- Re-derive the rule counts in `deploy/README.md`. It says "11 regex rules plus 5 map files", while the Caddyfile carries 13 `redir` directives, so the R1 to R11 numbering does not map one-to-one onto what the file actually does. Found by review on #5, where the same count was quoted and has since been dropped rather than guessed at.
- Provision the VPS: an unprivileged `blogdeploy` user, the deploy root, and `unattended-upgrades` with automatic reboot.
- Restrict the deploy key with `restrict,command=...`, no pty and no forwarding, so it can do nothing but rsync into `releases/` and swap the symlink. Generate per-environment keys so staging cannot reach production.
- Choose the staging FQDN, add its DNS record, and expose it through Pangolin as a public resource with **no auth**, since CI's live-URL check has to reach it. Authentication defaults to on for a public resource and has to be turned off deliberately.
Expand Down
12 changes: 10 additions & 2 deletions reports/Blog/audit.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,15 @@ Floor assertions are present and below the real counts, so a truncated list fail
checks/check-live-urls.sh:18 FLOOR=(["golden-urls.txt"]=320 ["redirect-urls.txt"]=900)
```

**The live redirect gate has still not run.** `checks/check-live-urls.sh` is what proves the 917 redirects, and a redirect is the web server's job that no build can prove. It has passed against the local mirror for all 1,245 URLs, but not against this build and not from CI. The redirect half of the contract remains asserted rather than currently proven, and it stays that way until the VPS exists.
**The redirect half is proven, against a running server rather than a build.** `deploy/make-release.sh` installs the build on the local mirror, then `checks/check-live-urls.sh` follows all 1,245 URLs against it, checking each redirect's destination rather than trusting its status code:

```text
==> checking 328 URLs that must render
==> checking 917 URLs that must redirect
PASS - 1245 URLs honored
```

That is a local mirror, not CI and not production. CI cannot run it, because the validation workflow has no server to point at, so this remains a pre-pull-request step documented in [OPERATIONS.md](../../OPERATIONS.md) rather than an automated gate. It becomes automatable once staging exists.

## Baseline File Presence

Expand Down Expand Up @@ -113,7 +121,7 @@ Both are recorded in [AUDIT.md](../../AUDIT.md) and reported upstream, so neithe

Carried forward rather than closed:

- The live redirect gate has not run against this build, so 917 of the 1,245 contracted URLs are asserted rather than proven.
- The redirect half of the contract is proven only against the local mirror, by hand, before a pull request. CI has no server to point at, so nothing enforces it automatically until staging exists.
- `publish-release.yml` has never been dispatched, so the release path is untested.
- No deploy exists, so the publish surface stays deferred and the registry entry stays `publish: []`.
- `checks/README.md` carries a small prose backlog of `dash` and `semicolon` findings, left for the next edit of that file per the correct-as-you-next-edit rule.
Expand Down