fix(ci): publish without attestations from the called workflow - #80
Merged
Conversation
Merged
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.
v0.1.1was tagged and a GitHub Release was created, but nothing reached PyPI(all three projects still show only
0.1.0) and no image reached GHCR.What failed
Run 34077955471,
publish / pypi (nl2sql-adapter-sdk, ...):The matrix's default fail-fast then cancelled the
nl2sql-apiandnl2sql-enginelegs, andghcranddocswere skipped. Docs still deployed —that is the separate Publish Docs workflow.
Why: auth and attestation disagree about which workflow "this" is
release_please.ymlreachespublish_pypi.yamlthroughworkflow_call, becauseGitHub will not start a workflow from a tag pushed with the default
GITHUB_TOKEN. In that arrangement the two halves of trusted publishing resolveto different workflows:
job_workflow_refclaim — the called workflowpublish_pypi.yaml— the registered publisher, so auth succeedsrelease_please.yml— not a registered publisherThe action itself printed both claims in the same run, before the upload:
Auth was never the problem: the request reached
upload.pypi.org/legacy/and wasrejected with a
400about the attestation, not a403about the credential —and PyPI's own message names
publish_pypi.yamlas the publisher itauthenticated as. The upload signed and logged both artifacts to Rekor
successfully; only PyPI's verification of them failed.
The fix
attestations: falseon thepypa/gh-action-pypi-publishstep. Theinput defaults to
'true'inaction.yml,which is why nothing had to opt in to break. The step carries a comment
explaining the asymmetry so nobody re-enables it.
fail-fast: falseon thepypimatrix, so one package's failure can nolonger cancel the other two and take
ghcranddocswith it.Trade-off
Published artifacts lose PEP 740 provenance. That is a real, if modest, loss.
Trusted publishing itself is unaffected — the OIDC credential still
authenticates every upload, and no API token or stored secret is introduced.
Alternatives ruled out
Re-register the Trusted Publisher as
release_please.yml— breaks auth.Warehouse matches a GitHub publisher on the
job_workflow_refclaim(
warehouse/oidc/models/github.py:"job_workflow_ref": _check_job_workflow_ref),and that claim stays
publish_pypi.yamlhowever the workflow is entered. Thistrades a failing attestation check for a failing credential check.
Register both workflows as publishers — does not help. PyPI verifies the
attestation against the publisher that authenticated the request, not against
any registered publisher.
warehouse/attestations/services.py:A second registration is simply never consulted for this comparison.
Make
publish_pypi.yamlthe entry point via a PAT-pushed tag — would keepattestations, but reintroduces exactly the stored credential that trusted
publishing exists to remove. Not worth PEP 740 provenance.
Upstream tracking issue for official reusable-workflow support:
pypa/gh-action-pypi-publish#166.
Also in this PR
docs/observability/error-handling.md— line 5 still carried thepre-fix(pipeline): keep the error code when a routing error reaches the runtime #78 claim that
run_with_graph()foldsPipelineExecutionErrorintostate as an
UNKNOWN_ERROR, contradicting line 43 in the same file. Correctedto the shipped behaviour in
packages/nl2sql/src/nl2sql/pipeline/runtime.py(return {"errors": [e.error]}).docs/architecture/failure_recovery.mdanddocs/architecture/pipeline.mdwere checked and are already correct.
docs/development/releasing.md— documents recovering a release thattagged but never uploaded (dispatch the existing tag;
workflow_dispatchwitha required
taginput is present in the workflow'son:block), and recordswhy attestations are off.
Verification
publish_pypi.yamlstill exposespush,workflow_callandworkflow_dispatch, andfail-fast: false/attestations: falseare set where intended.The publish path itself is not verifiable from CI. No workflow run
exercises a PyPI upload, so the real test is a
workflow_dispatchofpublish_pypi.yamlafter this merges — a deliberate, irreversible, publicaction left to the maintainer:
$ gh workflow run publish_pypi.yaml -f tag=v0.1.1