fix(ci): stop nesting pypa/gh-action-pypi-publish in a composite action - #94
Merged
Merged
Conversation
Confirmed against four real release runs today: pypa/gh-action-pypi-publish is a Docker container action, and GitHub resolves its image using the wrapping action's own repository and ref rather than the Docker action's when nested inside another `uses:` -- every publish failed with `docker: invalid reference format`, trying to pull ghcr.io/reqstool/.github:<this-action's-own-sha>. The action's own maintainers say this usage is untested and unsupported. This is exactly what the workaround comment linked from #92's PR description already said -- upload as a bare step in the caller, not routed through anything else -- and actions/publish-to-pypi violated it by wrapping the publish step instead of just inlining it. Deleting the composite action rather than trimming it to only download-artifact: what remains is one actions/download-artifact call, not enough indirection to be worth a shared action, and every layer added here tonight has broken in a new way. Companion PRs inline both steps directly into each PyPI-publishing repo's release.yml. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
This was referenced Aug 23, 2026
Merged
Reworks the previous commit, which deleted the action outright on the mistaken premise that composite actions were the problem. They are not: a composite action creates no new workflow context, so the job keeps the caller's OIDC identity -- which is exactly why it works where a reusable workflow does not. Someone makes the same point for Ruby in pypi/warehouse#11096. Only pypa/gh-action-pypi-publish has to come out. It is a Docker container action, and GitHub resolves a nested Docker action's image against the wrapping action's repository rather than its own -- the action's own maintainer describes the same breakage in that thread. Renamed publish-to-pypi -> download-dists, since what remains downloads the distributions and deliberately does not publish them. Keeping the old name would have been the misleading part. RELEASING.md's PyPI notes corrected while here. Two claims in the previous commit were wrong: PyPI matches `job_workflow_ref`, the bottom-most workflow, not the top-level caller; and reusable workflows are not rejected categorically -- one in the *same* repo as its caller works by accident of that same rule. What fails is a cross-repo one like this repo's, which puts reqstool/.github in the claim where the calling project has to be. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
jimisola
added a commit
to reqstool/reqstool-client
that referenced
this pull request
Aug 23, 2026
Reworks the previous commit. Composite actions were not the problem -- one creates no new workflow context, so the job keeps this repo's own OIDC identity, which is why it works where a reusable workflow does not. Only pypa/gh-action-pypi-publish had to come out of it, because nesting a Docker container action makes GitHub resolve its image against the wrapping action's repository. So the download goes back to a shared action, renamed download-dists now that it no longer publishes, and only the publish step stays inline. Still pinned at @main here; reqstool/.github#94 has to merge before a commit SHA exists to pin to. That pin lands before this PR merges. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
jimisola
added a commit
to reqstool/reqstool-python-decorators
that referenced
this pull request
Aug 23, 2026
Reworks the previous commit. Composite actions were not the problem -- one creates no new workflow context, so the job keeps this repo's own OIDC identity, which is why it works where a reusable workflow does not. Only pypa/gh-action-pypi-publish had to come out of it, because nesting a Docker container action makes GitHub resolve its image against the wrapping action's repository. So the download goes back to a shared action, renamed download-dists now that it no longer publishes, and only the publish step stays inline. Still pinned at @main here; reqstool/.github#94 has to merge before a commit SHA exists to pin to. That pin lands before this PR merges. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
jimisola
added a commit
to reqstool/reqstool-python-hatch-plugin
that referenced
this pull request
Aug 23, 2026
Reworks the previous commit. Composite actions were not the problem -- one creates no new workflow context, so the job keeps this repo's own OIDC identity, which is why it works where a reusable workflow does not. Only pypa/gh-action-pypi-publish had to come out of it, because nesting a Docker container action makes GitHub resolve its image against the wrapping action's repository. So the download goes back to a shared action, renamed download-dists now that it no longer publishes, and only the publish step stays inline. Still pinned at @main here; reqstool/.github#94 has to merge before a commit SHA exists to pin to. That pin lands before this PR merges. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
jimisola
added a commit
to reqstool/reqstool-python-poetry-plugin
that referenced
this pull request
Aug 23, 2026
Reworks the previous commit. Composite actions were not the problem -- one creates no new workflow context, so the job keeps this repo's own OIDC identity, which is why it works where a reusable workflow does not. Only pypa/gh-action-pypi-publish had to come out of it, because nesting a Docker container action makes GitHub resolve its image against the wrapping action's repository. So the download goes back to a shared action, renamed download-dists now that it no longer publishes, and only the publish step stays inline. Still pinned at @main here; reqstool/.github#94 has to merge before a commit SHA exists to pin to. That pin lands before this PR merges. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
jimisola
added a commit
to reqstool/reqstool-python-poetry-plugin
that referenced
this pull request
Aug 23, 2026
…141) * fix(ci): inline the PyPI publish step instead of a composite action pypa/gh-action-pypi-publish is a Docker container action. Nested inside reqstool/.github's actions/publish-to-pypi composite action, GitHub resolved its image using the composite action's own repo and pinned ref instead of the Docker action's, and every real publish failed with `docker: invalid reference format`. The action's own maintainers say this usage is untested and unsupported. Both steps -- download-artifact and the actual publish -- are now inline, matching the pattern the upstream workaround comment already showed (see reqstool/.github#95 for the full writeup). There is no shared action for this step in the org at all now; what remained after removing the publish call wasn't enough to justify one. Needs reqstool/.github#94 merged first. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com> * refactor(ci): use download-dists for the artifact half Reworks the previous commit. Composite actions were not the problem -- one creates no new workflow context, so the job keeps this repo's own OIDC identity, which is why it works where a reusable workflow does not. Only pypa/gh-action-pypi-publish had to come out of it, because nesting a Docker container action makes GitHub resolve its image against the wrapping action's repository. So the download goes back to a shared action, renamed download-dists now that it no longer publishes, and only the publish step stays inline. Still pinned at @main here; reqstool/.github#94 has to merge before a commit SHA exists to pin to. That pin lands before this PR merges. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com> --------- Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
jimisola
added a commit
to reqstool/reqstool-python-hatch-plugin
that referenced
this pull request
Aug 23, 2026
…104) * fix(ci): inline the PyPI publish step instead of a composite action pypa/gh-action-pypi-publish is a Docker container action. Nested inside reqstool/.github's actions/publish-to-pypi composite action, GitHub resolved its image using the composite action's own repo and pinned ref instead of the Docker action's, and every real publish failed with `docker: invalid reference format`. The action's own maintainers say this usage is untested and unsupported. Both steps -- download-artifact and the actual publish -- are now inline, matching the pattern the upstream workaround comment already showed (see reqstool/.github#95 for the full writeup). There is no shared action for this step in the org at all now; what remained after removing the publish call wasn't enough to justify one. Needs reqstool/.github#94 merged first. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com> * refactor(ci): use download-dists for the artifact half Reworks the previous commit. Composite actions were not the problem -- one creates no new workflow context, so the job keeps this repo's own OIDC identity, which is why it works where a reusable workflow does not. Only pypa/gh-action-pypi-publish had to come out of it, because nesting a Docker container action makes GitHub resolve its image against the wrapping action's repository. So the download goes back to a shared action, renamed download-dists now that it no longer publishes, and only the publish step stays inline. Still pinned at @main here; reqstool/.github#94 has to merge before a commit SHA exists to pin to. That pin lands before this PR merges. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com> --------- Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
jimisola
added a commit
to reqstool/reqstool-python-decorators
that referenced
this pull request
Aug 23, 2026
) * fix(ci): inline the PyPI publish step instead of a composite action pypa/gh-action-pypi-publish is a Docker container action. Nested inside reqstool/.github's actions/publish-to-pypi composite action, GitHub resolved its image using the composite action's own repo and pinned ref instead of the Docker action's, and every real publish failed with `docker: invalid reference format`. The action's own maintainers say this usage is untested and unsupported. Both steps -- download-artifact and the actual publish -- are now inline, matching the pattern the upstream workaround comment already showed (see reqstool/.github#95 for the full writeup). There is no shared action for this step in the org at all now; what remained after removing the publish call wasn't enough to justify one. Needs reqstool/.github#94 merged first. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com> * refactor(ci): use download-dists for the artifact half Reworks the previous commit. Composite actions were not the problem -- one creates no new workflow context, so the job keeps this repo's own OIDC identity, which is why it works where a reusable workflow does not. Only pypa/gh-action-pypi-publish had to come out of it, because nesting a Docker container action makes GitHub resolve its image against the wrapping action's repository. So the download goes back to a shared action, renamed download-dists now that it no longer publishes, and only the publish step stays inline. Still pinned at @main here; reqstool/.github#94 has to merge before a commit SHA exists to pin to. That pin lands before this PR merges. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com> --------- Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
jimisola
added a commit
to reqstool/reqstool-client
that referenced
this pull request
Aug 23, 2026
…445) * fix(ci): inline the PyPI publish step instead of a composite action pypa/gh-action-pypi-publish is a Docker container action. Nested inside reqstool/.github's actions/publish-to-pypi composite action, GitHub resolved its image using the composite action's own repo and pinned ref instead of the Docker action's, and every real publish failed with `docker: invalid reference format`. The action's own maintainers say this usage is untested and unsupported. Both steps -- download-artifact and the actual publish -- are now inline, matching the pattern the upstream workaround comment already showed (see reqstool/.github#95 for the full writeup). There is no shared action for this step in the org at all now; what remained after removing the publish call wasn't enough to justify one. Needs reqstool/.github#94 merged first. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com> * refactor(ci): use download-dists for the artifact half Reworks the previous commit. Composite actions were not the problem -- one creates no new workflow context, so the job keeps this repo's own OIDC identity, which is why it works where a reusable workflow does not. Only pypa/gh-action-pypi-publish had to come out of it, because nesting a Docker container action makes GitHub resolve its image against the wrapping action's repository. So the download goes back to a shared action, renamed download-dists now that it no longer publishes, and only the publish step stays inline. Still pinned at @main here; reqstool/.github#94 has to merge before a commit SHA exists to pin to. That pin lands before this PR merges. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com> --------- Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
This was referenced Aug 23, 2026
Merged
jimisola
added a commit
to reqstool/reqstool-client
that referenced
this pull request
Aug 23, 2026
CodeQL flagged actions/unpinned-tag: @main is mutable, so a compromised or force-pushed reqstool/.github main would execute through this reference with no review. Pinned to the commit that added the action, matching the `@<sha> # main YYYY-MM-DD` convention used elsewhere here. Went in as @main only because no commit SHA existed to pin to until reqstool/.github#94 merged. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
jimisola
added a commit
to reqstool/reqstool-python-poetry-plugin
that referenced
this pull request
Aug 23, 2026
CodeQL flagged actions/unpinned-tag: @main is mutable, so a compromised or force-pushed reqstool/.github main would execute through this reference with no review. Pinned to the commit that added the action, matching the `@<sha> # main YYYY-MM-DD` convention used elsewhere here. Went in as @main only because no commit SHA existed to pin to until reqstool/.github#94 merged. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
jimisola
added a commit
to reqstool/reqstool-python-hatch-plugin
that referenced
this pull request
Aug 23, 2026
CodeQL flagged actions/unpinned-tag: @main is mutable, so a compromised or force-pushed reqstool/.github main would execute through this reference with no review. Pinned to the commit that added the action, matching the `@<sha> # main YYYY-MM-DD` convention used elsewhere here. Went in as @main only because no commit SHA existed to pin to until reqstool/.github#94 merged. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
jimisola
added a commit
to reqstool/reqstool-python-decorators
that referenced
this pull request
Aug 23, 2026
CodeQL flagged actions/unpinned-tag: @main is mutable, so a compromised or force-pushed reqstool/.github main would execute through this reference with no review. Pinned to the commit that added the action, matching the `@<sha> # main YYYY-MM-DD` convention used elsewhere here. Went in as @main only because no commit SHA existed to pin to until reqstool/.github#94 merged. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
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.
Description
See #95 for the full writeup, including
the corrections in the second comment — an earlier revision of this PR deleted the
composite action outright on a premise that turned out to be wrong.
Today's real release runs across four repos all failed at the publish step:
pypa/gh-action-pypi-publishis a Docker container action. Nested inside a compositeaction, GitHub resolves its image against the wrapping action's repository and pinned
ref rather than its own. Its own maintainer
describes the same breakage:
The composite action itself was never the problem — that was my misreading, and it's why
this PR no longer deletes it. A composite action creates no new workflow context, so the job
keeps the caller's own OIDC identity, which is precisely why it works where a
workflow_callreusable workflow does not. Someone makes the same point for
Ruby in that thread.
What changes
actions/publish-to-pypi→actions/download-dists. It keepsdownload-artifactandthe optional twine check, and no longer publishes — hence the rename; keeping the old name
would have been the misleading part.
pypa/gh-action-pypi-publishstep moves inline into each caller'srelease.yml(companion PRs), with a comment saying why it can't be hoisted.
PyPI matches
job_workflow_ref(the bottom-most workflow), not the top-level caller; andreusable workflows aren't rejected categorically — one in the same repo as its caller
works by accident of that same rule. What fails is a cross-repo one like this repo's, which
puts
reqstool/.githubin the claim where the calling project has to be.Companion PRs
client#445 ·
decorators#93 ·
hatch-plugin#104 ·
poetry-plugin#141
Merge order: this one first. The companions currently reference
download-dists@mainbecause no commit SHA exists to pin to until this merges; the pin goes in before they do.
Checklist
git commit -s).Test plan
tests/actions/run-tests.sh40/40,shellcheck,yamllint,zizmorandcheck-permissions.pyall clean locally. None of that would have caught the Docker nestingbug — only a real dispatch does, which is what the companion PRs' re-release is for.