Skip to content

Switch NuGet publishing to trusted publishing - #6573

Merged
thomhurst merged 1 commit into
mainfrom
agent/nuget-trusted-publishing-20260809
Aug 9, 2026
Merged

Switch NuGet publishing to trusted publishing#6573
thomhurst merged 1 commit into
mainfrom
agent/nuget-trusted-publishing-20260809

Conversation

@thomhurst

Copy link
Copy Markdown
Owner

Summary

  • request GitHub OIDC tokens for NuGet trusted publishing
  • use NuGet/login@v1 with ${{ secrets.NUGET_USER }} to exchange for a short-lived NuGet API key
  • pass steps.login.outputs.NUGET_API_KEY into the existing publish step or pipeline input

Validation

  • parsed the modified workflow YAML files locally
  • ran git diff --check

Follow-up

A matching trusted publishing policy must be configured on nuget.org for this repository and workflow file before the next publish run.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@thomhurst, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 24 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b9db5ee0-1860-431e-8709-2fb6c2a1c3e3

📥 Commits

Reviewing files that changed from the base of the PR and between fca5ee9 and 30b2df6.

📒 Files selected for processing (1)
  • .github/workflows/dotnet.yml

Comment @coderabbitai help to get the list of available commands.

@thomhurst
thomhurst marked this pull request as ready for review August 9, 2026 12:51
@thomhurst
thomhurst merged commit f824dd6 into main Aug 9, 2026
12 of 14 checks passed
@thomhurst
thomhurst deleted the agent/nuget-trusted-publishing-20260809 branch August 9, 2026 12:51
@greptile-apps

greptile-apps Bot commented Aug 9, 2026

Copy link
Copy Markdown

Greptile Summary

The PR replaces the long-lived NuGet API-key secret with an OIDC trusted-publishing login and forwards the resulting short-lived key into the existing pipeline.

  • Grants the workflow matrix repository-write and OIDC-token permissions.
  • Runs NuGet/login on main-branch Ubuntu publishing executions.
  • Passes the login output to the existing package-publishing pipeline.

Confidence Score: 4/5

The PR appears safe to merge functionally, with non-blocking security hardening needed around permission scope and immutable action pinning.

The login and publishing conditions align and the pipeline safely handles an absent API key, but unrelated matrix executions inherit publishing privileges and the new login action can change without a repository-reviewed commit update.

Files Needing Attention: .github/workflows/dotnet.yml

Security Review

The trusted-publishing flow is wired consistently, but elevated permissions currently apply to the entire matrix and the new privileged login action uses a mutable tag. Scope publishing permissions to a dedicated job and pin the login action to an immutable commit.

Important Files Changed

Filename Overview
.github/workflows/dotnet.yml Correctly wires trusted NuGet publishing into the existing pipeline, but broadens permissions across the full matrix and references the privileged login action through a mutable tag.

Sequence Diagram

sequenceDiagram
  actor Maintainer
  participant GHA as GitHub Actions
  participant NuGetLogin as NuGet/login
  participant NuGet as nuget.org
  participant Pipeline as TUnit.Pipeline
  Maintainer->>GHA: "Dispatch main workflow with publish-packages=true"
  GHA->>NuGetLogin: Run Ubuntu login with OIDC permission
  NuGetLogin->>GHA: Request GitHub OIDC token
  NuGetLogin->>NuGet: Exchange identity for temporary API key
  NuGet-->>NuGetLogin: NUGET_API_KEY
  NuGetLogin-->>GHA: Expose action output
  GHA->>Pipeline: Pass NuGet__ApiKey and ShouldPublish
  Pipeline->>NuGet: Publish generated packages
Loading

Reviews (1): Last reviewed commit: "Switch NuGet publishing to trusted publi..." | Re-trigger Greptile

Comment on lines +29 to +31
permissions:
contents: write
id-token: write

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 security Publishing permissions span full matrix

The job-level contents: write and id-token: write permissions apply to pull-request, non-publishing, Windows, and macOS executions even though OIDC login and release operations are restricted to the main/Ubuntu publishing path. Scoping these capabilities to a dedicated publishing job would reduce the impact of compromised actions or unintended pipeline behavior.

How this was verified: The permissions are assigned to the matrix job, while the OIDC-dependent login is gated to main, publishing enabled, and Ubuntu.

Knowledge Base Used: Build and CI

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!


- name: NuGet login
if: ${{ github.ref == 'refs/heads/main' && github.event.inputs.publish-packages == 'true' && matrix.os == 'ubuntu-latest' }}
uses: NuGet/login@v1

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 security Publishing action uses mutable tag

NuGet/login@v1 can resolve to different executable code without a repository-reviewed change, while this step receives the NuGet identity and can request an OIDC token. Pinning the action to a reviewed commit would make changes to this security-sensitive publishing dependency explicit.

How this was verified: The publishing step references the mutable v1 tag and runs with NUGET_USER plus job-level OIDC permission.

Knowledge Base Used: Build and CI

@claude

claude Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Code review

Reviewed the switch to NuGet trusted publishing (OIDC via NuGet/login@v1). Note: this PR is already merged, so these are retrospective/follow-up notes rather than blockers.

Verified as sound:

  • The NuGet login step's if condition (ref == main && publish-packages == 'true' && ubuntu-latest) doesn't match the broader publish-packages flag passed to Run Pipeline (which omits the ref == main check). I initially flagged this as a mismatch that could leave nuget-apikey empty on a non-main dispatch, but UploadToNuGetModule (tools/TUnit.Pipeline/Modules/UploadToNuGetModule.cs) already guards with [RunOnlyOnBranch("main")] and skips cleanly via WithSkipWhen when the API key is empty — so this is a non-issue, no dead-key publish attempt occurs.

Worth a follow-up (non-blocking):

  1. Elevated permissions apply to the whole OS matrix, not just the leg that needs them. contents: write / id-token: write are declared at the job level (.github/workflows/dotnet.yml line ~29), but the matrix runs on ubuntu-latest, windows-latest, and macos-latest. The modules that actually use these permissions (UploadToNuGetModule, CreateReleaseModule, PushVersionTagModule) are all [RunOnLinuxOnly]. Since GitHub Actions permissions can't be scoped per matrix-leg, the Windows/macOS jobs now carry a write-scoped + OIDC-minting token they never use, unnecessarily widening the blast radius if a dependency in those legs is ever compromised. Splitting publish/release into a dedicated job that runs after the test matrix (ubuntu-only) would let the test matrix stay on minimal default permissions while only the publish job gets the elevated scope.
  2. NuGet/login@v1 is pinned to a mutable tag. This action mints a live, trusted NuGet-publish credential, so it's a high-value supply-chain target — if the v1 tag is ever repointed, this workflow would silently run whatever it points to with that trust. Standard hardening practice (and likely what a scorecard/pinned-dependencies check would flag) is to pin third-party actions used in privileged contexts to a full commit SHA.

Both were also flagged by greptile-apps' automated review; I independently verified them against the pipeline source rather than taking that at face value.

github-actions Bot pushed a commit to BenjaminMichaelis/TrxLib that referenced this pull request Aug 10, 2026
Updated [TUnit](https://github.com/thomhurst/TUnit) from 1.63.0 to
1.64.6.

<details>
<summary>Release notes</summary>

_Sourced from [TUnit's
releases](https://github.com/thomhurst/TUnit/releases)._

## 1.64.6

<!-- Release notes generated using configuration in .github/release.yml
at v1.64.6 -->

## What's Changed
### Other Changes
* Switch NuGet publishing to trusted publishing by @​thomhurst in
thomhurst/TUnit#6573
* Expose results directory through TestContext by @​thomhurst in
thomhurst/TUnit#6575
* Fix outcome timeline overflow in HTML reports by @​thomhurst in
thomhurst/TUnit#6574
### Dependencies
* chore(deps): update tunit to 1.64.0 by @​thomhurst in
thomhurst/TUnit#6570


**Full Changelog**:
thomhurst/TUnit@v1.64.0...v1.64.6

## 1.64.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.64.0 -->

## What's Changed
### Other Changes
* Honor cancellation tokens linked by custom test executors by
@​thomhurst in thomhurst/TUnit#6565
* Fix linked cancellation from before-test hooks by @​thomhurst in
thomhurst/TUnit#6568
* Add per-test execution cancellation by @​thomhurst in
thomhurst/TUnit#6569
### Dependencies
* chore(deps): update tunit to 1.63.25 by @​thomhurst in
thomhurst/TUnit#6559
* chore(deps): update dependency serialize-javascript to v7.1.0 by
@​thomhurst in thomhurst/TUnit#6561
* chore(deps): update dependency nsubstitute to 6.1.0 by @​thomhurst in
thomhurst/TUnit#6564
* chore(deps): bump mermaid from 11.15.0 to 11.16.1 in /docs by
@​dependabot[bot] in thomhurst/TUnit#6563
* chore(deps): bump nanoid from 3.3.16 to 3.3.18 in /docs by
@​dependabot[bot] in thomhurst/TUnit#6562


**Full Changelog**:
thomhurst/TUnit@v1.63.25...v1.64.0

## 1.63.25

<!-- Release notes generated using configuration in .github/release.yml
at v1.63.25 -->

## What's Changed
### Other Changes
* Fix Mermaid label contrast in dark mode by @​thomhurst in
thomhurst/TUnit#6531
* Enhance matrix tests documentation by @​koryphaee in
thomhurst/TUnit#6537
* fix: support nested Member after IsTypeOf by @​mvanhorn in
thomhurst/TUnit#6540
* docs: Add documentation for TestContext.Parameters by @​thomhurst with
@​Copilot in thomhurst/TUnit#6558
* fix: run event receivers on injected properties by @​thomhurst in
thomhurst/TUnit#6556
### Dependencies
* chore(deps): update tunit to 1.63.0 by @​thomhurst in
thomhurst/TUnit#6526
* chore(deps): update dependency stackexchange.redis to 3.1.0 by
@​thomhurst in thomhurst/TUnit#6529
* chore(deps): update verify to 31.28.0 by @​thomhurst in
thomhurst/TUnit#6532
* chore(deps): update dependency stackexchange.redis to 3.1.3 by
@​thomhurst in thomhurst/TUnit#6541
* chore(deps): update dependency dompurify to v3.4.13 by @​thomhurst in
thomhurst/TUnit#6542
* chore(deps): update dependency rabbitmq.client to 7.2.2 by @​thomhurst
in thomhurst/TUnit#6546
* chore(deps): update dependency polyfill to 11.0.2 by @​thomhurst in
thomhurst/TUnit#6549
* chore(deps): update dependency polyfill to 11.0.2 by @​thomhurst in
thomhurst/TUnit#6548
* chore(deps): bump fast-uri from 3.1.4 to 3.1.5 in /docs by
@​dependabot[bot] in thomhurst/TUnit#6545
* chore(deps): bump postcss from 8.5.22 to 8.5.25 in /docs by
@​dependabot[bot] in thomhurst/TUnit#6547
* chore(deps): update dependency stackexchange.redis to 3.1.11 by
@​thomhurst in thomhurst/TUnit#6550
* chore(deps): update dependency stackexchange.redis to 3.1.13 by
@​thomhurst in thomhurst/TUnit#6552

## New Contributors
* @​koryphaee made their first contribution in
thomhurst/TUnit#6537

**Full Changelog**:
thomhurst/TUnit@v1.63.0...v1.63.25

Commits viewable in [compare
view](thomhurst/TUnit@v1.63.0...v1.64.6).
</details>

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=TUnit&package-manager=nuget&previous-version=1.63.0&new-version=1.64.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
github-actions Bot pushed a commit to IntelliTect/CodingGuidelines that referenced this pull request Aug 10, 2026
Updated [TUnit.Core](https://github.com/thomhurst/TUnit) from 1.63.0 to
1.64.6.

<details>
<summary>Release notes</summary>

_Sourced from [TUnit.Core's
releases](https://github.com/thomhurst/TUnit/releases)._

## 1.64.6

<!-- Release notes generated using configuration in .github/release.yml
at v1.64.6 -->

## What's Changed
### Other Changes
* Switch NuGet publishing to trusted publishing by @​thomhurst in
thomhurst/TUnit#6573
* Expose results directory through TestContext by @​thomhurst in
thomhurst/TUnit#6575
* Fix outcome timeline overflow in HTML reports by @​thomhurst in
thomhurst/TUnit#6574
### Dependencies
* chore(deps): update tunit to 1.64.0 by @​thomhurst in
thomhurst/TUnit#6570


**Full Changelog**:
thomhurst/TUnit@v1.64.0...v1.64.6

## 1.64.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.64.0 -->

## What's Changed
### Other Changes
* Honor cancellation tokens linked by custom test executors by
@​thomhurst in thomhurst/TUnit#6565
* Fix linked cancellation from before-test hooks by @​thomhurst in
thomhurst/TUnit#6568
* Add per-test execution cancellation by @​thomhurst in
thomhurst/TUnit#6569
### Dependencies
* chore(deps): update tunit to 1.63.25 by @​thomhurst in
thomhurst/TUnit#6559
* chore(deps): update dependency serialize-javascript to v7.1.0 by
@​thomhurst in thomhurst/TUnit#6561
* chore(deps): update dependency nsubstitute to 6.1.0 by @​thomhurst in
thomhurst/TUnit#6564
* chore(deps): bump mermaid from 11.15.0 to 11.16.1 in /docs by
@​dependabot[bot] in thomhurst/TUnit#6563
* chore(deps): bump nanoid from 3.3.16 to 3.3.18 in /docs by
@​dependabot[bot] in thomhurst/TUnit#6562


**Full Changelog**:
thomhurst/TUnit@v1.63.25...v1.64.0

## 1.63.25

<!-- Release notes generated using configuration in .github/release.yml
at v1.63.25 -->

## What's Changed
### Other Changes
* Fix Mermaid label contrast in dark mode by @​thomhurst in
thomhurst/TUnit#6531
* Enhance matrix tests documentation by @​koryphaee in
thomhurst/TUnit#6537
* fix: support nested Member after IsTypeOf by @​mvanhorn in
thomhurst/TUnit#6540
* docs: Add documentation for TestContext.Parameters by @​thomhurst with
@​Copilot in thomhurst/TUnit#6558
* fix: run event receivers on injected properties by @​thomhurst in
thomhurst/TUnit#6556
### Dependencies
* chore(deps): update tunit to 1.63.0 by @​thomhurst in
thomhurst/TUnit#6526
* chore(deps): update dependency stackexchange.redis to 3.1.0 by
@​thomhurst in thomhurst/TUnit#6529
* chore(deps): update verify to 31.28.0 by @​thomhurst in
thomhurst/TUnit#6532
* chore(deps): update dependency stackexchange.redis to 3.1.3 by
@​thomhurst in thomhurst/TUnit#6541
* chore(deps): update dependency dompurify to v3.4.13 by @​thomhurst in
thomhurst/TUnit#6542
* chore(deps): update dependency rabbitmq.client to 7.2.2 by @​thomhurst
in thomhurst/TUnit#6546
* chore(deps): update dependency polyfill to 11.0.2 by @​thomhurst in
thomhurst/TUnit#6549
* chore(deps): update dependency polyfill to 11.0.2 by @​thomhurst in
thomhurst/TUnit#6548
* chore(deps): bump fast-uri from 3.1.4 to 3.1.5 in /docs by
@​dependabot[bot] in thomhurst/TUnit#6545
* chore(deps): bump postcss from 8.5.22 to 8.5.25 in /docs by
@​dependabot[bot] in thomhurst/TUnit#6547
* chore(deps): update dependency stackexchange.redis to 3.1.11 by
@​thomhurst in thomhurst/TUnit#6550
* chore(deps): update dependency stackexchange.redis to 3.1.13 by
@​thomhurst in thomhurst/TUnit#6552

## New Contributors
* @​koryphaee made their first contribution in
thomhurst/TUnit#6537

**Full Changelog**:
thomhurst/TUnit@v1.63.0...v1.63.25

Commits viewable in [compare
view](thomhurst/TUnit@v1.63.0...v1.64.6).
</details>

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=TUnit.Core&package-manager=nuget&previous-version=1.63.0&new-version=1.64.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
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.

1 participant