feat(core): add the PyPI release workflow, and fix two packaging defects - #71
Merged
Conversation
Publishing needs no credentials. The house pattern in agent-manifest already uses
Trusted Publishing, where PyPI verifies the workflow's OIDC identity, so there is no
API token to leak or rotate. This matches it.
Two defects found while validating the artifact rather than assuming it:
The wheel shipped no LICENSE. Apache-2.0 requires the licence travel with the
distribution, and pyproject declared the licence as text with no file. Now
packaged, verified present at dist-info/licenses/LICENSE.
The classifiers claimed Typing :: Typed with no py.typed marker, so consumers got
no annotations from a package written entirely with them. The marker now ships and
the claim is true.
Tag-scoped to capture-core-v*, not a bare python-v*, because this repository holds
several packages and a shared pattern would fire this job for an unrelated release.
Three guards before anything uploads, because a PyPI version is claimed forever the
moment it lands and cannot be replaced:
guard the tag must equal the version in pyproject.toml, so a mistyped tag
cannot publish a version nobody asked for
consistency the vendored copies must match the package, or the installed path and
the fallback path would ship different code under one version
smoke test installs the built wheel into a clean venv, asserts nothing
third-party came with it, and runs the suite against the installed
copy rather than the source tree
Verified locally: builds clean, twine check passes on both artifacts, installs into
an empty venv, imports, and pulls in no third-party dependency.
One thing worth flagging in review. My first draft pinned upload-artifact,
download-artifact and action-gh-release to SHAs I wrote from memory. None of those
three actions appear in any committed workflow here, so all three were invented.
Replaced with commits resolved through the GitHub API, and every pin in the file now
verifies against it: checkout, setup-python, upload-artifact, download-artifact,
gh-action-pypi-publish, action-gh-release.
Two human steps remain, both on PyPI rather than here: configure a Trusted Publisher
for this repository, workflow filename capture-core-publish.yml and environment pypi,
then push the tag capture-core-v0.1.0. The name agentrust-capture-core is currently
unclaimed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Imran Siddique <imran.siddique@opaque.co>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Publishing needs no credentials
I said several times today that publishing needed credentials and was therefore yours. That was wrong in an important way: the house pattern in
agent-manifest/.github/workflows/publish.ymlalready uses Trusted Publishing, where PyPI verifies the workflow's OIDC identity. There is no API token to leak or rotate. This workflow matches that pattern.Which is also the right answer on the merits: hand-uploading a provenance and integrity package from a laptop with a long-lived token would be the supply-chain practice this project exists to argue against.
Two packaging defects, found by validating the artifact instead of assuming it
The wheel shipped no LICENSE. Apache-2.0 requires the licence travel with the distribution, and
pyproject.tomldeclared the licence as inline text with no file. Now packaged, verified present atdist-info/licenses/LICENSE.The classifiers claimed
Typing :: Typedwith nopy.typedmarker. Consumers got no annotations from a package written entirely with them. The marker ships now, so the claim is true.Three guards before anything uploads
A PyPI version is claimed forever the moment it lands and cannot be replaced, so the workflow refuses more than it accepts:
guardpyproject.toml, so a mistyped tag cannot publish a version nobody asked forconsistencybuildsmoke testTag-scoped to
capture-core-v*rather than a barepython-v*, because this repository holds several packages and a shared pattern would fire this job for an unrelated release.Verified locally
python -m buildsucceeds;twine checkpasses on both wheel and sdist.LICENSEandpy.typedboth confirmed inside the wheel.One thing I got wrong, flagged for review
My first draft pinned
upload-artifact,download-artifactandaction-gh-releaseto SHAs I wrote from memory. None of those three actions appear in any committed workflow in this repo, so all three were invented and would have pinned to nothing or to something unintended.Replaced with commits resolved through the GitHub API, and every pin in the file now verifies against it:
Worth a second look from you regardless, since a fabricated pin in a publish workflow is the worst place for one.
Two human steps left, both on PyPI
agentrust-io/integrations, workflowcapture-core-publish.yml, environmentpypi. The nameagentrust-capture-coreis currently unclaimed, so this also reserves it.capture-core-v0.1.0.Nothing else changes on publish: every engine keeps its vendored fallback, so the installed path is an upgrade rather than a dependency.