Loading...
Loading...
Set up NuGet trusted publishing (OIDC) on a GitHub Actions repo — replaces long-lived API keys with short-lived tokens. USE FOR: trusted publishing, NuGet OIDC, keyless NuGet publish, migrate from NuGet API key, NuGet/login, secure NuGet publishing. DO NOT USE FOR: publishing to private feeds or Azure Artifacts (OIDC is nuget.org only). INVOKES: shell (powershell or bash), edit, create, ask_user for guided repo setup.
npx skill4agent add dotnet/skills nuget-trusted-publishingsecrets.NUGET_API_KEYNuGet/login@v1id-token: write⚠️ Bail-out rule: If any phase fails after one fix attempt on an infrastructure/auth issue, stop and ask the user. Don't loop on environment problems.
⚠️ Never delete or overwrite without confirmation: Removing API key secrets, deleting tags/releases, removing workflow steps, or changing package IDs. NuGet package IDs are permanent — mistakes can't be undone.
Fast-path for greenfield repos: When the user has a simple setup (one packable project, no existing publish workflow), don't gate on multi-turn assessment. Combine phases: create the workflow immediately, include nuget.org policy guidance, local pack recommendation, and filename-matching warning all in one response. The full phased process below is for complex or migration scenarios.
.csprojDirectory.Build.props<PackageType>Template</PackageType><PackageType>McpServer</PackageType><PackAsTool>true</PackAsTool>IsPackable=trueOutputType<OutputType>Exe</OutputType><IsPackable>true</IsPackable><OutputType>Exe</OutputType>PackAsToolIsPackable| Type | Required |
|---|---|
| All | |
| Dotnet tool | |
| MCP server | |
| Template | |
.github/workflows/dotnet nuget pushnuget pushdotnet pack.csproj<Version>server.jsonversionpackages[].versionask_user❌ See references/package-types.md for per-type details and required properties.
⚠️ Always mention this step, even if you defer running it. Tell the user: "Before your first publish, runto verify the .nupkg is created correctly."dotnet pack -c Release -o ./artifacts
dotnet pack -c Release -o ./artifacts.nupkg./artifacts--help.nupkg❌ The policy requires the exact workflow filename (e.g.,orpublish.yml) — just the filename, no path prefix. Matching is case-insensitive. Don't use the workflowpublish.yamlfield.name:
Go to nuget.org/account/trustedpublishing → Add policy
- Repository Owner:
{owner}- Repository:
{repo}- Workflow File:
{filename}.yml- Environment:
(only if the workflow usesrelease; leave blank otherwise)environment:
Repo Settings → Environments → New environment →releaseAdd environment secret: Name =, Value = nuget.org username (NOT email)NUGET_USER
⚠️ Wait for the user to confirm they've created the policy before asking them to remove old API keys/secrets or before attempting to run/publish with the workflow. Drafting or showing the workflow file itself is OK before confirmation.
publish.ymlid-token: writeNuGet/login@v1jobs:
publish:
environment: release
permissions:
id-token: write # Required — without this, NuGet/login fails with 403
contents: read # Explicit — setting permissions overrides defaults- name: NuGet login (OIDC)
id: login
uses: NuGet/login@v1
with:
user: ${{ secrets.NUGET_USER }} # nuget.org profile name, NOT email--api-key ${{ steps.login.outputs.NUGET_API_KEY }} --skip-duplicate❌ Don't delete the old API key secret until trusted publishing is verified. Removing it is a one-way door — wait for confirmation.
| Problem | Cause | Fix |
|---|---|---|
| Missing | Add to job permissions |
| "no matching policy" | Workflow filename mismatch | Verify exact filename on nuget.org |
| Push unauthorized | Package not owned by policy account | Check policy owner on nuget.org |
| Token expired | Login step >1hr before push | Move |
| "temporarily active" policy | Private repo, first publish pending | Publish within 7 days |
| Re-running same version | Add |
| GitHub Release 422 | Duplicate release for tag | Delete conflicting release (confirm first) |
| Re-run uses wrong YAML | | Delete obstacle, re-run — never re-tag |
⚠️ If any blocker persists after one fix attempt, stop and ask the user.