Skip to content

Publishing rehearsal: rename to agentguard, TestPyPI dry run, out-of-band settings checklist - #20

Merged
amic25 merged 3 commits into
mainfrom
release/rename-and-rehearsal
Jul 31, 2026
Merged

Publishing rehearsal: rename to agentguard, TestPyPI dry run, out-of-band settings checklist#20
amic25 merged 3 commits into
mainfrom
release/rename-and-rehearsal

Conversation

@amic25

@amic25 amic25 commented Jul 30, 2026

Copy link
Copy Markdown
Owner

Three units. Nothing tagged, nothing published. Don't merge this yourself.

1. Distribution renamed to agentguard

Nine sites, not the six a textual reading finds. Three arrived with #19 and are the ones that would have failed loudest:

src/agentguard/__init__.py:16     importlib.metadata lookup
tests/test_cli.py:65              metadata assertion
.github/workflows/release.yml:31  tag/version check inside verify

Renaming without those leaves __version__ falling back to 0.0.0+unknown — so --version, the JSON tool.version, and the SARIF driver version all report a version that doesn't exist — and the release fails its own tag check after the tag is pushed. Exactly the failure #19 exists to prevent, reintroduced by a rename that looks like string replacement.

Verified after uninstalling the old distribution first, since a stale editable install would hide a broken lookup: metadata resolves to agentguard, the old name raises PackageNotFoundError, both artifacts build and pass twine check, a clean venv reports AgentGuard 0.2.0.

WORKLOG.md keeps its seven references deliberately — it records what was true at the time.

Also found and fixed: [Unreleased] had two ### Changed and two ### Fixed sections, accumulated across earlier commits. Consolidated; every relocated bullet verified still present.

2. TestPyPI dry run

workflow_dispatch publishes to TestPyPI through the same trusted-publishing shape, same verify → build gate, differing only in repository-url and environment.

Writing it exposed a hole in the existing gating. workflow_dispatch can run against a tag ref, so production gated only on startsWith(github.ref, 'refs/tags/') would have been satisfied by a manual dispatch on a tag — the one irreversible action in this pipeline, reachable from a dropdown. Production now also requires github.event_name == 'push', checked across every event/ref combination.

The tag check had to split: declared vs installed runs on both triggers, tag vs declared is tag-only, because GITHUB_REF_NAME is a branch name on a dispatch. skip-existing: true on TestPyPI only — a version conflict there is noise, on production it's a real signal.

I have not run it. It needs a TestPyPI trusted publisher and a testpypi environment, both yours. Residual gap stated in WORKLOG.md: a green dry run validates the mechanism, not the production publisher, which has its own separate record.

3. Settings outside version control

Checking each setting rather than describing it found three things wrong right now:

  • No GitHub environments exist ([]), though release.yml names two. A publish would still work — implicitly, with no protection rules, so anyone able to push a tag can publish.
  • The About field still advertises "vulnerable dependencies", AG009 having been deleted in Make the scanner safe to run on untrusted code, and its findings measurable #17. Not fixed here — it's a setting — but corrected wording is in the doc to paste.
  • GITHUB_SETUP.md:6 was recommending the test check, one of the three phantom contexts that blocked every merge for two sessions. The onboarding document was teaching the incident.

Six surfaces documented with a verify command and a recoverability verdict each; the PyPI trusted publisher is marked unrecoverable. Plus a pre-tag sequence ordered so the unrecoverable item is checked last and twice.

Two DECISIONS.md entries: one on the settings surface — stating plainly that an inspection checklist is a weak control and exists because the alternative is nothing — and one on corpus containment being per-consumer, with four readers and no two sharing a mechanism.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Q5nXA9BJKdmye9a9FaHdc6

claude added 3 commits July 30, 2026 11:55
Both names are unclaimed on PyPI, and renaming is free exactly once. After
0.2.0 ships it costs a shim package, a deprecation notice, split download
statistics, and two names in search results permanently.

Nine sites, not the six a textual reading finds. Three of them arrived with
#19 and are the ones that would have failed loudest: the importlib.metadata
lookup in __init__.py, its assertion in tests/test_cli.py, and the tag
check inside release.yml's verify job. Renaming without those would leave
__version__ falling back to 0.0.0+unknown - so --version, the JSON
tool.version and the SARIF driver version would all report a version that
does not exist - and the release would fail its own tag check after the tag
was pushed. The failure #19 exists to prevent, reintroduced by a rename
that looked like string replacement.

Verified after uninstalling the old distribution first, since a stale
editable install would have hidden a broken lookup: metadata resolves to
agentguard, the old name raises PackageNotFoundError, both artifacts build
and pass twine check, and a clean venv reports AgentGuard 0.2.0.

WORKLOG.md keeps its references on purpose. It records what was true at the
time.

CHANGELOG had two Changed and two Fixed sections under [Unreleased],
accumulated across earlier commits; adding the rename note made it three,
which is how it surfaced. Consolidated, with every relocated bullet checked
to still be there.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5nXA9BJKdmye9a9FaHdc6
workflow_dispatch now publishes to TestPyPI through the same
trusted-publishing shape as production - same verify -> build gate, same
OIDC permissions, differing only in repository-url and environment. It
exercises what a local venv install cannot: metadata validation on receipt,
the token exchange, and page rendering.

Writing it exposed a hole in the existing gating. workflow_dispatch can be
run against a tag ref, so a production job gated only on
startsWith(github.ref, 'refs/tags/') would have been satisfied by a manual
dispatch on a tag - putting the one irreversible action in this pipeline
behind a dropdown. Production now also requires the push event, checked
across every event and ref combination.

The dispatch takes no input selecting a target. A dry run that can be aimed
at production by picking the wrong entry is a worse hazard than the one it
exists to remove.

Two things the rehearsal forced. The tag check is split: declared-versus-
installed runs on both triggers, and tag-versus-declared is tag-only,
because GITHUB_REF_NAME is a branch name on a dispatch and would fail every
dry run for the wrong reason. And skip-existing is set on TestPyPI only,
since it accepts a version once - on production a version conflict is a
real signal and must not be swallowed.

The run itself is not done: it needs a TestPyPI trusted publisher and a
testpypi environment. Recorded, with the residual gap stated - a green dry
run validates the mechanism, not the production publisher, which has its
own separate record and is verifiable only by inspection.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5nXA9BJKdmye9a9FaHdc6
…sumer

Checking each setting rather than describing it found three things wrong
now. No GitHub environments exist, though release.yml names two - a publish
would still work, implicitly and with no protection rules, so anyone able
to push a tag can publish. The About field still advertises "vulnerable
dependencies" although AG009 was deleted in #17, which is the clearest
demonstration of why this checklist exists: nothing in CI renders that
string, so nothing could fail. And GITHUB_SETUP.md line 6 was telling
maintainers to require the `test` check - one of the three phantom contexts
that blocked every merge for two sessions. The onboarding document was
teaching the incident.

The checklist covers six surfaces with a verify command and a
recoverability verdict each. The PyPI trusted publisher is marked
unrecoverable, because it fails the OIDC exchange after the tag is pushed
and a spent version cannot be reused.

Two DECISIONS entries. The first states plainly that an inspection
checklist is a weak control - manual, staleable, run only by someone who
remembers - and that it exists because the alternative is nothing; four
incidents share one shape, the repository green and the fault outside it.
The second records that corpus containment cannot be solved once: four
readers so far, no two sharing a mechanism, and the directory irrelevant to
all of them.

The About field is not changed here. It is a setting, and settings are
yours; the corrected wording is in GITHUB_SETUP.md to be pasted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5nXA9BJKdmye9a9FaHdc6

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6f1f914aed

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/GITHUB_SETUP.md
Comment on lines +55 to +57
There is no API to read this back. Verify by eye at
`https://pypi.org/manage/project/agentguard/settings/publishing/`, and rehearse the
mechanism first with the TestPyPI dry run (Actions → Release → Run workflow), which has

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use the pending-publisher form for the first release

Because this commit states that agentguard has never been published, the project-specific settings URL does not exist yet: PyPI does not create an empty project before its first upload. The initial OIDC identity must instead be registered as a pending publisher under /manage/account/publishing/; otherwise a maintainer following this pre-tag checklist cannot configure or verify the publisher, and the first release will fail authentication.

Useful? React with 👍 / 👎.

Comment thread docs/GITHUB_SETUP.md
Comment on lines +51 to +53
`pypi`. A mismatch fails the OIDC exchange — and it fails *after* the tag has been pushed,
which means the version is spent. PyPI versions can be yanked but never replaced, so the
recovery is a new version number and a permanent gap in the history.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Permit rerunning an upload after fixing OIDC settings

When a publisher mismatch fails the OIDC exchange, no distribution has reached PyPI, so the version has not been claimed; the publisher can be corrected and the workflow rerun against the same tag and version. The prohibition on replacing files applies only after an upload succeeds, so this instruction would unnecessarily force a version bump and create the permanent history gap it warns about.

Useful? React with 👍 / 👎.

Comment thread docs/GITHUB_SETUP.md
4. Enable Discussions categories: Announcements, Q&A, Ideas, Show and tell, and Rule proposals.
5. Pin an introductory Discussion using `.github/DISCUSSION_TEMPLATE/welcome.yml` as the guide.
6. Protect `main`: require pull requests, one approval, conversation resolution, and the `test`, `package`, and `CodeQL` checks; disallow force pushes and deletions.
6. Protect `main`: require pull requests, conversation resolution, and the `ci-ok`, `build`, and `CodeQL` checks; disallow force pushes and deletions. **Pick every required context from GitHub's suggestion list, never by typing it** — `test` and `package` are not check-run names and can never report. See below.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restore the required approving review

For a repository configured from these instructions, requiring pull requests without requiring any approving reviews allows a collaborator with merge access to merge their own PR as soon as the checks pass. The previous version explicitly required one approval, and this context-name correction silently removes that protection; retain the one-approval requirement while updating the required checks.

Useful? React with 👍 / 👎.

@amic25
amic25 merged commit dddb595 into main Jul 31, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants