From 7d1f5f0c14f803308739fc7ec739abba75ffa3e2 Mon Sep 17 00:00:00 2001 From: Steve Oh Date: Sat, 12 Sep 2026 21:46:46 +0900 Subject: [PATCH 1/2] chore: let the maintainer past the CLA, and fix what the release docs got wrong The CLA check failed on every pull request from this repository's own maintainer. The allowlist named `memtomem`, which owns the repository, but commits are authored under an e-mail GitHub resolves to `tsdata`. Both are the same person; both are allowlisted now. Publishing 0.2.0 turned up two errors in what these documents claim, and both cost a failed run today rather than being spotted by reading. The token scopes were wrong. The checklist asked for Pull requests *read*, derived from the endpoints the script calls -- it posts to `/issues/{n}/comments`, which reads like an Issues permission. When that number is a pull request GitHub enforces the Pull requests permission instead, and the token fails with `Resource not accessible by personal access token` until it has write. Issues write alone is not enough; the documentation now says so and says why. The Trusted Publisher form's "Environment name" is the GitHub environment, not the index. Filled in as `testpypi` on TestPyPI it produced `invalid-publisher: valid token, but no corresponding publisher`, because one environment named `pypi` serves both indexes and the tag decides where a run uploads. The runbook now states that, and that a pending publisher has to be removed and re-added rather than edited. The recovery section gained the fact that made that failure cheap: a publisher mismatch fails at the token exchange, before any upload, so the index never sees the version and the number is not consumed. The question worth asking is which step a release failed at, not whether it is reversible. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Hkm75k7g4Eaq5YvkHGgRzW --- .github/workflows/cla.yml | 4 +++- CHANGELOG.md | 12 ++++++++++++ docs/public-release-checklist.md | 9 ++++++--- docs/releasing.md | 11 +++++++++++ 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 736c2fa..b2ae8d1 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -43,5 +43,7 @@ jobs: SIGNATURES_PATH: signatures/v1/cla.json SIGNATURES_BRANCH: cla-signatures CLA_DOCUMENT_URL: https://github.com/memtomem/tracegraph/blob/tracegraph-mvp/CLA.md - CLA_ALLOWLIST: dependabot[bot],memtomem + # Both accounts are the maintainer: `memtomem` owns the repository and + # `tsdata` is the account the commit author e-mail resolves to. + CLA_ALLOWLIST: dependabot[bot],memtomem,tsdata CLA_SIGNATURE_TEXT: I have read the CLA Document and I hereby sign the CLA diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cfff07..6fa6e9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,18 @@ The **artifact** schema version and the **report**/**review-candidate** JSON sch separate contracts from this version number; changes to any of them are called out explicitly. +## Unreleased + +### Fixed + +- The CLA workflow refused every pull request from the maintainer's own commit-author + account, which is not the account that owns the repository. Both are allowlisted now. +- The release documentation asked for a personal access token with *read* access to pull + requests. Posting the CLA comment needs *write*: the call is to `/issues/{n}/comments`, + and GitHub enforces the Pull requests permission when that number is a pull request. + It also did not say that a Trusted Publisher's "Environment name" is the GitHub + environment rather than the index, which failed the first 0.2.0 rehearsal. + ## 0.2.0 - 2026-09-12 First published release. `0.1.0` was tagged but never uploaded. diff --git a/docs/public-release-checklist.md b/docs/public-release-checklist.md index 9b43077..59153ed 100644 --- a/docs/public-release-checklist.md +++ b/docs/public-release-checklist.md @@ -54,9 +54,12 @@ what stays, and rewrite history or do not publish, rather than deleting and hopi - Configure independent pending Trusted Publishers on **TestPyPI and PyPI** for `memtomem/tracegraph`, workflow `release.yml`, environment `pypi`, project `agent-tracegraph`. -- Add the `PERSONAL_ACCESS_TOKEN` secret the CLA workflow needs (fine-grained, this - repository only: Contents read/write for the signature branch, Issues read/write for PR - comments, Pull requests read for the contributor listing). +- Add the `PERSONAL_ACCESS_TOKEN` secret the CLA workflow needs: fine-grained, this + repository only, with **Contents: read/write** (the signature branch), **Issues: + read/write** and **Pull requests: read/write**. Pull requests must be *write*, not read: + the script posts to `/issues/{n}/comments`, and when that number is a pull request + GitHub enforces the Pull requests permission rather than the Issues one — measured, the + token gets `Resource not accessible by personal access token` otherwise. - Seed the signature store: `cla-check.py` writes to a `cla-signatures` branch and has no branch-creation path, so create that orphan branch first, containing only `signatures/v1/cla.json` = `{"signedContributors": []}`. diff --git a/docs/releasing.md b/docs/releasing.md index 8603bae..babc789 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -62,6 +62,13 @@ and the local gate name `twine@7.0.0` explicitly. See `CONTRIBUTING.md`. 5. Create the same pending publisher on **PyPI**. The two are separate services and both must be configured. A pending publisher does not reserve the name. + **"Environment name" means the GitHub environment, not the index.** One environment + named `pypi` serves both, because which index a run uploads to is decided by the tag, + not by the environment — so `pypi` goes in the TestPyPI form as well. Filling in + `testpypi` there fails the rehearsal with `invalid-publisher: valid token, but no + corresponding publisher`, which is what happened on the first attempt at 0.2.0. A + pending publisher cannot be edited field by field: remove it and add it again. + ## Cutting a release ### 1. The release-prep commit @@ -227,6 +234,10 @@ with the prerelease flag on; the tag and the package version are the same number the wheel smoke — re-run that workflow run from the Actions UI once the cause is fixed outside the repository, or push a new commit and a new tag if the fix is a code change. The tag still points at the same commit and nothing has been published. +- **A publisher mismatch costs nothing but time.** Trusted Publishing fails at the OIDC + token exchange, before any upload, so the index never sees the version and the number is + not consumed. Fix the publisher, re-run the same failed run, same tag, same version. + Ask *which step did it fail at*, not *is this reversible* — the answer follows. - **Do not move, delete or recreate a tag**, and do not reuse a version once anything reached an index. Fix forward with a new patch or prerelease version. PyPI refuses a re-upload, so the number is spent even if what landed was wrong. From 286e640c7ce9c3b8a49205b41835e57a7fcb3d29 Mon Sep 17 00:00:00 2001 From: Steve Oh Date: Sat, 12 Sep 2026 22:02:06 +0900 Subject: [PATCH 2/2] chore: say what was observed about the token, not why The previous commit stated a rule: that GitHub enforces the Pull requests permission when an issue-comment endpoint is called with a pull request number. GitHub's own documentation says the endpoint accepts either Issues write or Pull requests write, so the 403 seen here does not establish that rule -- a permission change that had not propagated yet produces the same symptom, and the token's effective permissions were never read back between the two attempts. What is recorded now is only what happened: with Issues at write and Pull requests at read the comment failed, and raising Pull requests to write cleared it, cause unestablished. The recommendation is unchanged, because granting all three as write makes the question moot for whoever sets this up next. Found by the review gate, which checked the claim against the endpoint's documentation rather than against the error message. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Hkm75k7g4Eaq5YvkHGgRzW --- CHANGELOG.md | 9 ++++++--- docs/public-release-checklist.md | 13 +++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fa6e9b..1419015 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,9 +13,12 @@ explicitly. - The CLA workflow refused every pull request from the maintainer's own commit-author account, which is not the account that owns the repository. Both are allowlisted now. - The release documentation asked for a personal access token with *read* access to pull - requests. Posting the CLA comment needs *write*: the call is to `/issues/{n}/comments`, - and GitHub enforces the Pull requests permission when that number is a pull request. - It also did not say that a Trusted Publisher's "Environment name" is the GitHub + requests. Posting the CLA comment failed with that configuration and succeeded after + raising it to write; the cause remains unconfirmed, since GitHub documents either Issues + write or Pull requests write as sufficient. The documentation now asks for write on + Contents, Issues and Pull requests alike and records the observation rather than + inferring a rule. +- It also did not say that a Trusted Publisher's "Environment name" is the GitHub environment rather than the index, which failed the first 0.2.0 rehearsal. ## 0.2.0 - 2026-09-12 diff --git a/docs/public-release-checklist.md b/docs/public-release-checklist.md index 59153ed..718fca2 100644 --- a/docs/public-release-checklist.md +++ b/docs/public-release-checklist.md @@ -56,10 +56,15 @@ what stays, and rewrite history or do not publish, rather than deleting and hopi `agent-tracegraph`. - Add the `PERSONAL_ACCESS_TOKEN` secret the CLA workflow needs: fine-grained, this repository only, with **Contents: read/write** (the signature branch), **Issues: - read/write** and **Pull requests: read/write**. Pull requests must be *write*, not read: - the script posts to `/issues/{n}/comments`, and when that number is a pull request - GitHub enforces the Pull requests permission rather than the Issues one — measured, the - token gets `Resource not accessible by personal access token` otherwise. + read/write** and **Pull requests: read/write**. + + GitHub documents the comment endpoint as accepting *either* Issues write or Pull + requests write, so in principle read on one of them should do. What actually happened + here, on 2026-09-12: with Issues at write and Pull requests at read, posting the comment + returned `Resource not accessible by personal access token`; raising Pull requests to + write cleared it. That is an observation, not an explanation — the cause was not + established, and a permission change that had not taken effect yet would look the same. + All three at write is the configuration observed to work. - Seed the signature store: `cla-check.py` writes to a `cla-signatures` branch and has no branch-creation path, so create that orphan branch first, containing only `signatures/v1/cla.json` = `{"signedContributors": []}`.