Skip to content

Commit e709311

Browse files
author
wildleo91
committed
docs(checklist): tighten §8 Step 3b + §3.5 per QA review
QA review of 7ef42da..4f6d7c5 (Phase 0 completion) flagged three documentation-clarity gaps in the release checklist. All three are about making procedures runnable cold by an operator who has never executed them before — they don't affect the COMPLETE claim itself, but they would have wasted time on the first signed-release dry-run. 1. §8 Step 3b — added explicit curl -LO commands for the foreign artifact + .crt + .sig (previously the doc named a URL pattern in a comment but left the operator to figure out the actual fetch). Added ls -l sanity check so a silent 404 doesn't surface as a confusing cosign error later. 2. §8 Step 3b — split "Expected outcome" into PRIMARY / SECONDARY / NOT-acceptable categories. The original wording lumped identity-regex mismatch and OIDC-issuer mismatch together, but cosign short-circuits at the first mismatch — operators need to know that observing EITHER one is acceptable, while a hash mismatch means they ran the wrong test, and a PASS means the identity pin is broken. 3. §3.5 — extended the version-tag pre-flight to also verify [package].id == [id].name. AppInspect 4.2.0 (check_for_valid_package_id) enforces this equality and would otherwise surface only at the AppInspect step, after the tag is cut. Cheap check; piggybacks on the existing awk pulls. No code changes. Doc-drift guard passes; both modified bash blocks parse clean (`bash -n`).
1 parent 4f6d7c5 commit e709311

1 file changed

Lines changed: 65 additions & 17 deletions

File tree

docs/RELEASE_CHECKLIST.md

Lines changed: 65 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,24 @@ INTENDED_VERSION="${INTENDED_TAG#v}"
113113
LAUNCHER_VER=$(awk -F= '/^\[launcher\]/{flag=1; next} /^\[/{flag=0} flag && /^version/{gsub(/[[:space:]]/,""); print $2}' default/app.conf)
114114
ID_VER=$(awk -F= '/^\[id\]/{flag=1; next} /^\[/{flag=0} flag && /^version/{gsub(/[[:space:]]/,""); print $2}' default/app.conf)
115115

116+
# AppInspect 4.2.0 also enforces [package].id == [id].name. Cheap to
117+
# check here so a future rename of one stanza doesn't fail AppInspect
118+
# silently at the last step.
119+
ID_NAME=$(awk -F= '/^\[id\]/{flag=1; next} /^\[/{flag=0} flag && /^name/{gsub(/[[:space:]]/,""); print $2}' default/app.conf)
120+
PKG_ID=$(awk -F= '/^\[package\]/{flag=1; next} /^\[/{flag=0} flag && /^id/{gsub(/[[:space:]]/,""); print $2}' default/app.conf)
121+
116122
if [[ "$LAUNCHER_VER" != "$INTENDED_VERSION" || "$ID_VER" != "$INTENDED_VERSION" ]]; then
117123
echo "VERSION DRIFT: tag=$INTENDED_TAG app.conf[launcher]=$LAUNCHER_VER app.conf[id]=$ID_VER"
118124
echo "Fix app.conf before cutting the tag."
119125
exit 1
120126
fi
121-
echo "OK: app.conf version matches tag $INTENDED_TAG"
127+
128+
if [[ "$ID_NAME" != "$PKG_ID" ]]; then
129+
echo "ID DRIFT: app.conf[id].name=$ID_NAME app.conf[package].id=$PKG_ID"
130+
echo "AppInspect 4.2.0 (check_for_valid_package_id) requires these to match."
131+
exit 1
132+
fi
133+
echo "OK: app.conf version matches tag $INTENDED_TAG; [package].id == [id].name == $ID_NAME"
122134
```
123135

124136
**Expected:** the script exits 0 with `OK: ...`. Any non-zero exit means
@@ -128,7 +140,10 @@ to be edited to match `${INTENDED_TAG#v}` BEFORE you run `git tag` /
128140

129141
**Maintenance note:** keep this check in sync with `package.sh:33`
130142
(the grep that reads `^version` from app.conf). If `package.sh` ever
131-
switches to reading from `$GITHUB_REF` instead, retire this section.
143+
switches to reading from `$GITHUB_REF` instead, retire the
144+
version-drift portion of this section — the `[package].id == [id].name`
145+
check stays regardless, since it's an AppInspect rule independent of
146+
how the tag is derived.
132147

133148
---
134149

@@ -273,11 +288,25 @@ Actions). Then attempt to verify it against THIS repo's identity
273288
regex.
274289

275290
```bash
276-
# Download a foreign Sigstore-signed asset for the test:
277-
# - Reference: sigstore/cosign v2.4.3 .rpm (signed via Google OIDC)
278-
# - URL pattern: https://github.com/sigstore/cosign/releases/download/v2.4.3/cosign-2.4.3-1.x86_64.rpm
291+
# Download a foreign Sigstore-signed asset and its detached signature
292+
# artifacts. Reference release: sigstore/cosign v2.4.3 .rpm — cosign
293+
# self-signs every release via Google OIDC, so its identity claim is
294+
# guaranteed not to match this repo's GitHub-Actions regex.
279295
#
280-
# Then attempt verification against THIS repo's identity-regex
296+
# If the exact filenames below 404 (sigstore renames artifact suffixes
297+
# between minor versions), open the release page in a browser and pick
298+
# any (artifact, artifact.crt, artifact.sig) triple — the test is
299+
# agnostic to which artifact you use.
300+
BASE=https://github.com/sigstore/cosign/releases/download/v2.4.3
301+
curl -sLO "$BASE/cosign-2.4.3-1.x86_64.rpm"
302+
curl -sLO "$BASE/cosign-2.4.3-1.x86_64.rpm.crt"
303+
curl -sLO "$BASE/cosign-2.4.3-1.x86_64.rpm.sig"
304+
305+
# Sanity-check all three downloads landed (curl -O is silent on 404,
306+
# which would let the cosign step below fail confusingly).
307+
ls -l cosign-2.4.3-1.x86_64.rpm{,.crt,.sig}
308+
309+
# Now attempt verification against THIS repo's identity-regex.
281310
# (NOTE: cosign-release v2.4.1 expects --new-bundle-format=false for
282311
# pre-v3 signatures; remove flag if upgrading per Phase 2.12).
283312
cosign verify-blob \
@@ -290,17 +319,36 @@ cosign verify-blob \
290319
cosign-2.4.3-1.x86_64.rpm
291320
```
292321

293-
**Expected:** verification FAILS, but with a DIFFERENT error than
294-
Step 3. The error must reference the identity-regex mismatch (the
295-
foreign cert was issued for a `sigstore/cosign` identity, not
296-
`RelativisticJet/wl_manager`) or the OIDC-issuer mismatch (Google
297-
vs GitHub Actions). The signature itself IS valid for that foreign
298-
artifact — what fails is the identity pin.
299-
300-
If this step passes (i.e., the foreign artifact is accepted), the
301-
identity pin is broken. STOP. Do not ship — any sigstore-signed
302-
artifact in the world would be accepted as if it came from this
303-
repo.
322+
**Expected:** verification FAILS, with one of two acceptable error
323+
messages (cosign short-circuits at the first mismatch it sees, so
324+
which one you observe depends on cosign's internal check order — both
325+
prove the identity pin is wired):
326+
327+
- **PRIMARY (preferred)** — `none of the expected identities matched
328+
what was in the certificate` (or similar wording referencing the
329+
identity-regex). The foreign cert was issued for a
330+
`sigstore/cosign` identity, not `RelativisticJet/wl_manager`.
331+
- **SECONDARY (also acceptable)** — `expected oidc issuer ... got
332+
...`. The foreign cert's OIDC issuer is Google
333+
(`https://accounts.google.com`), not GitHub Actions
334+
(`https://token.actions.githubusercontent.com`).
335+
336+
NOT acceptable (would mean the pin is broken or you ran the wrong
337+
test):
338+
339+
- ✅ verification PASSES → identity pin is broken; any
340+
sigstore-signed artifact in the world would be accepted as if it
341+
came from this repo. **STOP. Do not ship.**
342+
-`hash mismatch` or `signature verification failed` → this is a
343+
Step 3 failure, not a Step 3b failure. It means the foreign
344+
artifact and its `.sig`/`.crt` are out of sync (re-download all
345+
three from the same release). Re-run after fixing.
346+
-`failed to read certificate` / `no such file` → a download
347+
step 404'd silently. Re-check `ls -l` above before re-running
348+
cosign.
349+
350+
The signature itself IS cryptographically valid for that foreign
351+
artifact — what we want to fail is the identity pin, exclusively.
304352

305353
**Origin:** added 2026-05-15 as a permanent extension after the
306354
2026-05-13 dry-run discovered this gap by accident. See "Outcome

0 commit comments

Comments
 (0)