Publish to nuget.org when Version Increment completes - #8
Merged
TorinKS merged 1 commit intoAug 30, 2026
Merged
Conversation
Version Increment pushes its tag with GITHUB_TOKEN, and events created with that token deliberately do not start other workflows. The tag-push trigger therefore never fires for an automated release, and publishing had to be dispatched by hand after every version bump. Trigger on workflow_run instead. It fires when Version Increment finishes rather than from a token-created event, so no personal access token has to be stored to make the chain work. Two alternatives were rejected. Duplicating the publish steps inside increment-version.yaml would break Trusted Publishing, because the policy on nuget.org is bound to this workflow's file name. Converting this into a reusable workflow called from there splits the OIDC claim between workflow_ref and job_workflow_ref, and which of the two nuget.org validates is not something to discover through a live publish. Also: - the job is skipped unless the triggering run succeeded, since workflow_run fires on failure too - for workflow_run the checkout pins the triggering run's head_sha rather than the branch tip, which may already have moved - the publish decision moves into one gate step, so the three conditional steps that depend on it cannot drift apart Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XnzCrAM46SttZnU6msznyN
TorinKS
added a commit
that referenced
this pull request
Aug 30, 2026
* ci: build the native library on VS 2022, not on whatever is latest WinDevices.dll links the dynamic CRT. dumpbin on the published 0.1.1 shows MSVCP140.dll, VCRUNTIME140.dll and VCRUNTIME140_1.dll among its imports, because CMake defaults to /MD and nothing overrides it. The toolset that builds it therefore sets the minimum Visual C++ Redistributable every consumer's machine must carry: v14x runtimes are compatible forward, not backward. windows-latest silently became windows-2025-vs2026, so 0.1.1 was built with the VS 2026 toolset and shipped inside a package consumed by components that are built, and deployed, on VS 2022. It loaded during verification only because this workstation has a current redistributable installed, which a clean endpoint does not. Pin the three jobs that compile to windows-2022. The reporting job and the git-only version job keep windows-latest; neither produces a binary. Also drop the CMake 3.29 pin from increment-version.yaml, which would have failed the same way build-test.yaml did: install.cmd configures without a generator, and a CMake older than the image's Visual Studio falls back to NMake Makefiles. Static linking of the CRT would remove the redistributable question entirely, but it needs the C API checked for heap ownership crossing the DLL boundary first, so it is left to its own issue. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XnzCrAM46SttZnU6msznyN * feat(ci): publish to nuget.org when Version Increment completes (#8) Version Increment pushes its tag with GITHUB_TOKEN, and events created with that token deliberately do not start other workflows. The tag-push trigger therefore never fires for an automated release, and publishing had to be dispatched by hand after every version bump. Trigger on workflow_run instead. It fires when Version Increment finishes rather than from a token-created event, so no personal access token has to be stored to make the chain work. Two alternatives were rejected. Duplicating the publish steps inside increment-version.yaml would break Trusted Publishing, because the policy on nuget.org is bound to this workflow's file name. Converting this into a reusable workflow called from there splits the OIDC claim between workflow_ref and job_workflow_ref, and which of the two nuget.org validates is not something to discover through a live publish. Also: - the job is skipped unless the triggering run succeeded, since workflow_run fires on failure too - for workflow_run the checkout pins the triggering run's head_sha rather than the branch tip, which may already have moved - the publish decision moves into one gate step, so the three conditional steps that depend on it cannot drift apart Claude-Session: https://claude.ai/code/session_01XnzCrAM46SttZnU6msznyN Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(ci): do not check out an arbitrary commit in the publishing job CodeQL flagged actions/untrusted-checkout at high severity against the checkout I added for the workflow_run path. It is right. A workflow_run job is privileged: it holds id-token: write and can exchange it for a nuget.org publishing token. This job then builds what it checks out, running cmake and dotnet over that tree. Pinning workflow_run.head_sha means executing code from a commit this workflow did not choose, in exactly the context that can publish a package. Version Increment is dispatch-only today, so reaching it needs write access, but the shape is an escalation path to the package feed and should not exist. Take the default checkout instead, which is the default branch and therefore trusted. Version Increment tags a commit on that branch, so the tag is present when this runs. If the branch has moved past the tag in between, the exact-tag guard refuses to publish rather than releasing a mislabelled package - the correct failure, and the reason that guard was added. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XnzCrAM46SttZnU6msznyN --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.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.
Stacked on #7.
Why the tag push does not reach the publisher
increment-version.yamlpushes its tag withsecrets.GITHUB_TOKEN, and GitHub deliberately does not start workflows from events created with that token — the recursion guard. Sopublish-nuget.yaml'spush: tags: ['v*']trigger never fires for an automated release, and every version bump would need a manual dispatch afterwards.Approach, and the two rejected ones
workflow_run. It fires when Version Increment finishes, which is not a token-created event, so the chain completes without storing a PAT.Rejected: duplicating the publish steps into
increment-version.yaml. The Trusted Publisher policy on nuget.org is bound to this workflow's file name, so publishing from another file is refused.Rejected: converting this into a reusable workflow called from Version Increment. That splits the OIDC claim —
workflow_refbecomes the caller,job_workflow_refthe callee — and which of the two nuget.org validates against is not something worth discovering through a live publish.Details worth noting
workflow_runfires regardless of outcome, so the job is skipped unlessgithub.event.workflow_run.conclusion == 'success'. A failed version bump must not reach the publisher.workflow_run, checkout pinsgithub.event.workflow_run.head_sharather than the branch tip, which may already have moved.gatestep. Three separate steps depended on the same condition and could have drifted; they now read one output.Interaction with the exact-tag guard from #6
The guard still applies. On the
workflow_runpath, HEAD is the commit Version Increment just tagged, sogit describe --exact-matchsucceeds and the version resolves clean, without the-devsuffix. If the tag were somehow absent, publishing is refused rather than producing a mislabelled package.🤖 Generated with Claude Code
https://claude.ai/code/session_01XnzCrAM46SttZnU6msznyN