release: stop shipping the basic-auth claim #56 removed as false #57

Merged
yuris merged 1 commit from feat/release-notes into main 2026-08-20 11:38:29 +00:00
Owner

release.yml appends boilerplate to every release body, and that boilerplate asserted:

Private repo? Forgejo rejects basic auth for archive downloads; append ?token=<access-token> to the URL instead.

#56 measured the opposite. The mechanism in that sentence is false:

  • https://user:token@…/archive/v0.1.0.zip → 200, serves the archive
  • ?token=<bad-token> → 401
  • a nonexistent repo → 404 with and without basic auth

So the 404 the claim was built on meant "no such repo", not "basic auth refused".

The README was corrected in #56. This file would have republished the same sentence in the v1.0.0 release notes — which is the one place a consumer reads before they have the README, since release.yml turns the tag annotation into the release body. Same replacement wording as the README now carries: the query token is what the archive endpoint validates, and URL credentials are handled inconsistently rather than rejected.

Found while auditing release.yml immediately before cutting the tag. Two other things were checked and are not bugs:

  • The boilerplate's 10-space indentation is stripped by YAML's run: | baseline, so the appended markdown lands at column 0. Confirmed against v0.1.0's published body, which is not indented — an earlier read suggested it might render as a code block, and it does not.
  • Reading the annotation from the API rather than git tag --format is deliberate and correct; the comment at :27-29 explains that this runner's checkout produces a lightweight tag.

No behaviour change to the workflow itself, and nothing in stdb/. Suite and both conformance tiers are green on main at 86761ce independently of this.

`release.yml` appends boilerplate to every release body, and that boilerplate asserted: > Private repo? Forgejo rejects basic auth for archive downloads; append `?token=<access-token>` to the URL instead. **#56 measured the opposite.** The mechanism in that sentence is false: - `https://user:token@…/archive/v0.1.0.zip` → **200**, serves the archive - `?token=<bad-token>` → **401** - a nonexistent repo → **404 with *and* without** basic auth So the 404 the claim was built on meant *"no such repo"*, not *"basic auth refused"*. The README was corrected in #56. This file would have republished the same sentence in the **v1.0.0 release notes** — which is the one place a consumer reads *before* they have the README, since `release.yml` turns the tag annotation into the release body. Same replacement wording as the README now carries: the query token is what the archive endpoint validates, and URL credentials are handled inconsistently rather than rejected. Found while auditing `release.yml` immediately before cutting the tag. Two other things were checked and are **not** bugs: - The boilerplate's 10-space indentation is stripped by YAML's `run: |` baseline, so the appended markdown lands at column 0. Confirmed against v0.1.0's published body, which is not indented — an earlier read suggested it might render as a code block, and it does not. - Reading the annotation from the API rather than `git tag --format` is deliberate and correct; the comment at `:27-29` explains that this runner's checkout produces a lightweight tag. No behaviour change to the workflow itself, and nothing in `stdb/`. Suite and both conformance tiers are green on `main` at `86761ce` independently of this.
release: stop shipping the basic-auth claim #56 removed as false
All checks were successful
ci / ci (pull_request) Successful in 1m28s
d31ab18d6e
release.yml appends boilerplate to every release body, and that boilerplate
asserted 'Forgejo rejects basic auth for archive downloads'. #56 measured the
opposite: https://user:token@.../archive/v0.1.0.zip returns 200, ?token=<bad>
returns 401, and a nonexistent repo returns 404 with and without basic auth -
so the 404 that claim was built on meant 'no such repo'.

The README was corrected there; this file would have republished the same
sentence in the v1.0.0 release notes, which is the one place a consumer looks
before they have the README. Same replacement wording as the README's.
yuris force-pushed feat/release-notes from d31ab18d6e
All checks were successful
ci / ci (pull_request) Successful in 1m28s
to d3ba750cda
All checks were successful
ci / ci (pull_request) Successful in 1m27s
2026-08-20 11:38:03 +00:00
Compare
Author
Owner

Review — automated reviewer, posted for the record

Hunk correct and evidence-backed. Safe to fire on a tag push — one mutating call, fails closed on every read error, a 409 on re-run leaves an existing release untouched. But two more lines were needed in the same file, and one was a high-severity content defect. Both since applied in d3ba750.

The claim, re-derived and then localised precisely

All four observations reproduced against Forgejo 15.0.1: public archive anonymous 200 (57,220 B), with basic auth in the URL 200 and byte-identical, ?token=<bad> 401, nonexistent repo 404 with and without basic auth.

Then the decisive test, which is better than the PR's own framing — a real account with the wrong password:

route result
/archive/v0.1.0.zip 200 — no auth attempted
/api/v1/repos/… 401 user's password is invalid [uid: 1, name: yuris]
/….git/info/refs 401 Credentials are incorrect or have expired

So the basic-auth middleware runs on the API and git-http routes but not on /archive. Credentials there are discarded, not mishandled — while ?token= and Authorization: token are consulted on that same route, both 401 on a bad value even for a public repo.

That makes "handled inconsistently" honest about the forge but misleading about the endpoint the sentence is actually about, where behaviour is perfectly consistent: ignored. Replaced with the precise version.

Untested and stated as such: there is no private repo on this forge, so the private case — which is what the sentence is about — rests on inference (discarded credentials → anonymous → Forgejo hides private repos → 404). That inference reconciles both readings of the same 404 but is not a measurement. The wording does not over-claim; if anything it under-claims, since on the public path credentials are not unreliable, they are inert.

Both claimed non-bugs confirmed

Indentation. :23 sets the block-scalar baseline at 10 spaces and every boilerplate line is at exactly 10 (no tabs), so v0.1.0's published body has ## Use as a Defold library and the fence at column 0. The annotation's own 2-space bullets survive, 2 spaces being no fence. Bonus from the same fetch: v0.1.0's live body carries the false sentence verbatim — the defect already shipped once.

API vs git tag. v0.1.0 is a real annotated tag; .message is 637 chars and the junction renders as exactly one blank line. Nit, since fixed: the comment blamed "this runner's checkout", but the job has no checkout step at all. The real conclusion is stronger — git tag would fail outright, not return the wrong thing.

Findings

  • high — :48-49. The boilerplate told every consumer to add both URLs unconditionally, while README.md:117-119 tells HTML5 consumers to remove that exact 4.2.3 URL. New for v1.0.0: patches/ did not exist at v0.1.0 (raw/tag/v0.1.0/patches/… 404 while the README 200s), so v0.1.0's boilerplate was correct and v1.0.0's is the first that misdirects. Fixed.
  • medium — :30-31. .message // "" yields "" for {"message":""}, {"message":null} and {} alike, rc 0, no abort. An unannotated tag would publish a boilerplate-only body and exit green. Fixed with a guard; verified it exits 1.
  • low — :61. -X POST with -L re-POSTs the body across a 3xx, and -f -s discards the error body so a 409/422 prints nothing. Fixed: --fail-with-body, -L dropped.
  • low — PR body said "same wording as the README"; the README also carries "and a bad one gets a plain 401". Now carried here too.

Audit of the rest

Verified good: the header's claim that /archive/<ref>.zip resolves without a release object (200 for main and for a bare sha); DEP_URL byte-identical to README.md:187; the 4.2.3 URL matching game.project:4; connect surviving #55's renames; draft:false/prerelease:false correct and matching v0.1.0.

jq -n --arg round-trips byte-identically — 1338/1338 on a hostile multi-paragraph annotation carrying backticks, a fenced block, a backslash, $HOME, quotes, a tab, and non-ASCII.

No half-publish path exists: exactly one mutating call, a failed tag read aborts at curl -f (verified exit 22) before any POST, and a duplicate release 409s leaving the existing one untouched.

## Review — automated reviewer, posted for the record **Hunk correct and evidence-backed. Safe to fire on a tag push** — one mutating call, fails closed on every read error, a 409 on re-run leaves an existing release untouched. But two more lines were needed in the same file, and one was a high-severity content defect. Both since applied in `d3ba750`. ### The claim, re-derived and then localised precisely All four observations reproduced against Forgejo 15.0.1: public archive anonymous **200** (57,220 B), with basic auth in the URL **200** and byte-identical, `?token=<bad>` **401**, nonexistent repo **404** with and without basic auth. Then the decisive test, which is better than the PR's own framing — a **real account with the wrong password**: | route | result | |---|---| | `/archive/v0.1.0.zip` | **200** — no auth attempted | | `/api/v1/repos/…` | 401 `user's password is invalid [uid: 1, name: yuris]` | | `/….git/info/refs` | 401 `Credentials are incorrect or have expired` | So the basic-auth middleware runs on the API and git-http routes but **not** on `/archive`. Credentials there are **discarded, not mishandled** — while `?token=` and `Authorization: token` *are* consulted on that same route, both 401 on a bad value even for a public repo. That makes "handled inconsistently" honest about the forge but misleading about the endpoint the sentence is actually about, where behaviour is perfectly consistent: ignored. Replaced with the precise version. **Untested and stated as such:** there is no private repo on this forge, so the private case — which is what the sentence is about — rests on inference (discarded credentials → anonymous → Forgejo hides private repos → 404). That inference reconciles both readings of the same 404 but is not a measurement. The wording does not over-claim; if anything it under-claims, since on the public path credentials are not unreliable, they are inert. ### Both claimed non-bugs confirmed **Indentation.** `:23` sets the block-scalar baseline at 10 spaces and every boilerplate line is at exactly 10 (no tabs), so v0.1.0's published body has `## Use as a Defold library` and the fence at **column 0**. The annotation's own 2-space bullets survive, 2 spaces being no fence. *Bonus from the same fetch:* v0.1.0's live body carries the false sentence verbatim — the defect already shipped once. **API vs `git tag`.** v0.1.0 is a real annotated tag; `.message` is 637 chars and the junction renders as exactly one blank line. **Nit, since fixed:** the comment blamed "this runner's checkout", but the job has no checkout step at all. The real conclusion is stronger — `git tag` would fail outright, not return the wrong thing. ### Findings - **high** — `:48-49`. The boilerplate told every consumer to add both URLs unconditionally, while `README.md:117-119` tells HTML5 consumers to **remove** that exact 4.2.3 URL. **New for v1.0.0**: `patches/` did not exist at v0.1.0 (`raw/tag/v0.1.0/patches/…` 404 while the README 200s), so v0.1.0's boilerplate was correct and v1.0.0's is the first that misdirects. *Fixed.* - **medium** — `:30-31`. `.message // ""` yields `""` for `{"message":""}`, `{"message":null}` and `{}` alike, rc 0, no abort. An unannotated tag would publish a boilerplate-only body and exit green. *Fixed with a guard; verified it exits 1.* - **low** — `:61`. `-X POST` with `-L` re-POSTs the body across a 3xx, and `-f -s` discards the error body so a 409/422 prints nothing. *Fixed: `--fail-with-body`, `-L` dropped.* - **low** — PR body said "same wording as the README"; the README also carries "and a bad one gets a plain 401". *Now carried here too.* ### Audit of the rest Verified good: the header's claim that `/archive/<ref>.zip` resolves without a release object (200 for `main` and for a bare sha); `DEP_URL` byte-identical to `README.md:187`; the 4.2.3 URL matching `game.project:4`; `connect` surviving #55's renames; `draft:false`/`prerelease:false` correct and matching v0.1.0. **`jq -n --arg` round-trips byte-identically** — 1338/1338 on a hostile multi-paragraph annotation carrying backticks, a fenced block, a backslash, `$HOME`, quotes, a tab, and non-ASCII. **No half-publish path exists**: exactly one mutating call, a failed tag read aborts at `curl -f` (verified exit 22) before any POST, and a duplicate release 409s leaving the existing one untouched.
yuris merged commit 746d4960b0 into main 2026-08-20 11:38:29 +00:00
Sign in to join this conversation.
No description provided.