From 80e899a6f85f0d8ab4a7720417a44827e7bf4e82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Miralles=20Ranca=C3=B1o?= <68760931+FlagshipDev@users.noreply.github.com> Date: Fri, 7 Aug 2026 15:01:57 +0200 Subject: [PATCH] The documentation describes 0.1.0a7, and the tag trap that cutting it found MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Post-release, in the order `docs/releasing.md` requires because each step needs the one before it: ask the new image what it accepts — 26 commands, read off `ghcr.io/easybytehub/hullwork:0.1.0a7` rather than off this checkout — then move the five pins in `README.md`, `docker-compose.yml`, `docs/install.md` and `PRIVACY.md`. Doing it the other way round fails `tests/test_the_documentation_describes_the_published_artefact.py` in both directions, which is the whole reason the recording is stored rather than the sequence trusted. ## And a warning earned the hard way `docs/releasing.md` now carries the trap that cutting this release walked into: **the tag goes on the public commit, and `git push vX` does not do that.** Development happens on a private forge and this repository is a *derivation* of it, so a tag created in the development checkout points at a commit this repository does not have. Pushing it brings the objects the tag needs — and for about ten minutes the withheld paths were browsable at that ref. No credential was exposed: the deployment's environment file is not tracked. What was exposed is the internal item ledger and the deployment's own compose, which name a private address, a port and two hostnames — exactly the set the publish script guards. Two things made it worse before they made it better, and both are in the warning: the tag ruleset **refused the deletion**, which is the rule working as intended, and the tag push started **two** release runs — one building from the private commit. That one was cancelled inside a minute and published nothing. The release came from the derived commit: the image has no `work/`, no `deploy/` and no `scripts/`, and `gh attestation verify` passes on it. The procedure now spells out the three API calls that create a tag on this repository pointing at its own `main`. The four earlier tags were cut that way and none of them exposes anything. Signed-off-by: Javier Miralles Rancaño <68760931+FlagshipDev@users.noreply.github.com> --- PRIVACY.md | 2 +- README.md | 2 +- docker-compose.yml | 2 +- docs/install.md | 4 ++-- docs/published-surface.json | 9 +++++++-- docs/releasing.md | 33 +++++++++++++++++++++++++++++++-- 6 files changed, 43 insertions(+), 9 deletions(-) diff --git a/PRIVACY.md b/PRIVACY.md index 360fe8a..d7e1264 100644 --- a/PRIVACY.md +++ b/PRIVACY.md @@ -15,7 +15,7 @@ and there is no tenth: "schema": 1, "exception": "ManifestError", "frames": [{"module": "hullwork.manifest", "function": "parse_manifest", "lineno": 707}], - "release": "0.1.0a6", + "release": "0.1.0a7", "python": "3.12.13", "platform": "linux", "operation": "receiver", diff --git a/README.md b/README.md index c473d9d..43850e0 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,7 @@ code, and writes nothing outside a directory you name. → above, and [docs/install.md § 1](docs/install.md#1-try-the-agent-half) **2. The evaluation stack — recommended for a first look.** Needs Docker and nothing else, with **no -clone and no build**: one compose file and a published image (`ghcr.io/easybytehub/hullwork:0.1.0a6`, +clone and no build**: one compose file and a published image (`ghcr.io/easybytehub/hullwork:0.1.0a7`, amd64 and arm64). One container — the half that answers webhooks — which starts with no credentials at all and says in a sentence what it cannot do yet. → [docs/install.md § 2](docs/install.md#2-the-evaluation-stack) diff --git a/docker-compose.yml b/docker-compose.yml index 70e02bf..5e0b022 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,7 +25,7 @@ services: # # To run your own build instead — a change you are testing, or an architecture with no published # image — add `build: .` beside this line from a checkout, and `docker compose up -d --build`. - image: ghcr.io/easybytehub/hullwork:0.1.0a6 + image: ghcr.io/easybytehub/hullwork:0.1.0a7 ports: - "127.0.0.1:8000:8000" restart: unless-stopped diff --git a/docs/install.md b/docs/install.md index 1943540..87694c6 100644 --- a/docs/install.md +++ b/docs/install.md @@ -93,10 +93,10 @@ is the half that answers webhooks. Nothing here can push to anything. curl -O https://raw.githubusercontent.com/easybytehub/hullwork/main/docker-compose.yml docker compose up -d curl http://127.0.0.1:8000/health -# {"status":"ok","version":"0.1.0a6"} +# {"status":"ok","version":"0.1.0a7"} ``` -The image is `ghcr.io/easybytehub/hullwork:0.1.0a6`, built for amd64 and arm64, pinned in that compose +The image is `ghcr.io/easybytehub/hullwork:0.1.0a7`, built for amd64 and arm64, pinned in that compose file rather than floating on `latest`. From a clone, `docker compose up -d --build` builds your own instead — which is what you want if you are testing a change. diff --git a/docs/published-surface.json b/docs/published-surface.json index 1725e29..e0a546f 100644 --- a/docs/published-surface.json +++ b/docs/published-surface.json @@ -1,7 +1,7 @@ { "_": "Generated by scripts/record-the-published-surface.py from the image itself. Do not hand-edit: a documented capability that is not in here is one nobody can run, and editing this file would make that true silently.", - "image": "ghcr.io/easybytehub/hullwork:0.1.0a6", - "version": "0.1.0a6", + "image": "ghcr.io/easybytehub/hullwork:0.1.0a7", + "version": "0.1.0a7", "recorded": "2026-08-07", "commands": { "hullwork": [ @@ -118,6 +118,11 @@ "--help", "--rotate" ], + "hullwork password": [ + "--end-sessions", + "--help", + "--stdin" + ], "hullwork prune": [ "--help", "--older-than-days" diff --git a/docs/releasing.md b/docs/releasing.md index 5d1fdfb..4c749de 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -123,10 +123,39 @@ not prove the artefact is good — that is what the gates and `docs/status.md` a ./scripts/publish.sh # build the public tree and read the diff ./scripts/publish.sh --pr MESSAGE_FILE # gate it, then open the pull request gh pr merge --squash --delete-branch # once the checks are green -git tag -a v0.1.0aN -m "…" # the annotation is the release notes -git push origin v0.1.0aN +git tag -a v0.1.0aN -m "…" # here, for the record; the annotation is the notes +# then create the same tag ON THE PUBLIC REPO, pointing at its own main — see the warning below. +# Pushing this tag to the public remote publishes the private history it points at. ``` +> [!warning] **The tag goes on the public commit, and `git push vX` does not do that.** +> Measured on 2026-08-07, cutting `0.1.0a7`: the tag was created in the development checkout — where it +> points at a **private** commit — and pushed to the public remote. Git pushed the objects the tag +> needed, so for about ten minutes the withheld paths were browsable at that ref: `work/` (41 files) +> and `deploy/` (the deployment's compose and the relay). No credential was in them — `deploy.env` is +> not tracked — but the tailnet address, the port, the host's name and the private forge's hostname +> were, which is exactly the set `publish.sh` guards. +> +> Two things made it worse before they made it better. The tag ruleset **refused the deletion**, which +> is the rule doing its job and meant disabling it for the length of one API call. And the tag push +> started **two** release runs: one building from the private commit, which would have published an +> image with those paths inside it. It was cancelled at 40 seconds; the derived one produced the +> release. +> +> So: after the pull request merges, create the tag **on the public repository, pointing at its own +> `main`** — not in this checkout. The four earlier tags were cut that way and none of them exposes +> anything. +> +> ```bash +> head=$(gh api repos///commits/main --jq .sha) +> obj=$(gh api -X POST repos///git/tags \ +> -f tag=v0.1.0aN -f message="…" -f object="$head" -f type=commit --jq .sha) +> gh api -X POST repos///git/refs -f ref=refs/tags/v0.1.0aN -f sha="$obj" +> ``` +> +> The tag in the development repository is still worth having — it is where the release was cut from — +> and it must never be pushed to the public remote. + The workflow refuses a tag whose version disagrees with `hullwork.__version__`, before it pushes anything — a release whose image says one version and whose wheel says another is unusable for anybody pinning either, and the bug report arrives months later from somebody who cannot reproduce it.