nuget-trusted-publishing
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseNuGet Trusted Publishing Setup
NuGet可信发布设置
Set up NuGet trusted publishing on a GitHub Actions repo. Replaces long-lived API keys with OIDC-based short-lived tokens — no secrets to rotate or leak.
在GitHub Actions仓库中设置NuGet可信发布。使用基于OIDC的短期令牌替换长期API密钥——无需轮换或担心密钥泄露。
Prerequisites
前提条件
- GitHub Actions — this skill covers GitHub Actions setup only
- nuget.org account — the user needs access to create trusted publishing policies
- GitHub Actions —— 本技能仅覆盖GitHub Actions的设置
- nuget.org账户 —— 用户需要拥有创建可信发布策略的权限
When to Use This Skill
适用场景
Use this skill when:
- Setting up trusted publishing for a NuGet package
- Migrating from to OIDC-based publishing
secrets.NUGET_API_KEY - Asked about keyless or secure NuGet publishing
- Creating a new NuGet publish workflow from scratch
- Asked to "remove NuGet API key" or "use NuGet/login"
- Setting up publishing for a dotnet tool, MCP server, or template package
- Asked about or
NuGet/login@v1id-token: write
在以下场景使用本技能:
- 为NuGet包设置可信发布
- 从迁移到基于OIDC的发布方式
secrets.NUGET_API_KEY - 咨询无密钥或安全NuGet发布相关问题
- 从零开始创建新的NuGet发布工作流
- 要求“移除NuGet API密钥”或“使用NuGet/login”
- 为dotnet工具、MCP服务器或模板包设置发布流程
- 咨询或
NuGet/login@v1相关问题id-token: write
Safety Rules
安全规则
⚠️ 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.
⚠️ 终止规则:如果在基础架构/认证问题上尝试修复一次后仍失败,请停止操作并询问用户。不要在环境问题上循环尝试。
⚠️ 未经确认请勿删除或覆盖:移除API密钥机密、删除标签/版本、移除工作流步骤或修改包ID。NuGet包ID是永久性的——错误无法撤销。
Process
操作流程
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.
新项目仓库快速路径:当用户的设置简单(一个可打包项目,无现有发布工作流)时,无需多轮评估。合并各阶段:立即创建工作流,同时提供nuget.org策略指导、本地打包建议和文件名匹配警告。以下完整分阶段流程适用于复杂或迁移场景。
Phase 1: Assess
阶段1:评估
Inspect the repo and report findings before making any changes.
-
Find and classify packable projects — checkfiles and
.csproj(package metadata is often set repo-wide). Classify in this order (earlier matches win):Directory.Build.props- → Template
<PackageType>Template</PackageType> - → MCP server (also a dotnet tool)
<PackageType>McpServer</PackageType> - → Dotnet tool
<PackAsTool>true</PackAsTool> - Class library (or no
IsPackable=true) → LibraryOutputType - with
<OutputType>Exe</OutputType>→ Application package (not a tool, but still publishable)<IsPackable>true</IsPackable> - without
<OutputType>Exe</OutputType>orPackAsTool→ Not packable by default (ask user if they intend to publish it)IsPackable
-
Validate structure for each project's type:
Type Required All ,PackageId(in .csproj or Directory.Build.props)VersionDotnet tool (required);PackAsTool(optional but recommended — defaults to assembly name)ToolCommandNameMCP server ,PackageType=McpServerincluded in package.mcp/server.jsonTemplate ,PackageType=Templateunder content dir.template.config/template.json -
Find existing publish workflows in— look for
.github/workflows/,dotnet nuget push, ornuget push.dotnet pack -
Check version consistency — for MCP servers, verify
.csprojmatches both<Version>version fields (rootserver.jsonandversion). Flag any mismatch.packages[].version -
Report findings to the user: classification, missing properties, version mismatches, existing workflows. For multi-project repos, note whether one workflow or separate workflows per package are needed. Offer to fix gaps — usebefore modifying project files.
ask_user
❌ See references/package-types.md for per-type details and required properties.
在进行任何更改前,先检查仓库并向用户报告结果。
-
查找并分类可打包项目 —— 检查文件和
.csproj(包元数据通常在仓库全局设置)。按以下顺序分类(优先匹配靠前的类型):Directory.Build.props- → 模板
<PackageType>Template</PackageType> - → MCP服务器(同时也是dotnet工具)
<PackageType>McpServer</PackageType> - → Dotnet工具
<PackAsTool>true</PackAsTool> - 类库(或无
IsPackable=true) → 类库OutputType - 且
<OutputType>Exe</OutputType>→ 应用程序包(不是工具,但仍可发布)<IsPackable>true</IsPackable> - 但无
<OutputType>Exe</OutputType>或PackAsTool→ 默认不可打包(询问用户是否打算发布)IsPackable
-
验证各项目类型的结构:
类型 必需配置 所有类型 、PackageId(在.csproj或Directory.Build.props中配置)VersionDotnet工具 (必需);PackAsTool(可选但推荐——默认值为程序集名称)ToolCommandNameMCP服务器 ,包中包含PackageType=McpServer.mcp/server.json模板 ,内容目录下包含PackageType=Template.template.config/template.json -
查找现有发布工作流 —— 在目录中查找包含
.github/workflows/、dotnet nuget push或nuget push的文件。dotnet pack -
检查版本一致性 —— 对于MCP服务器,验证中的
.csproj是否与<Version>中的两个版本字段(根节点server.json和version)匹配。如果不匹配,标记出来。packages[].version -
向用户报告结果:分类情况、缺失的属性、版本不匹配问题、现有工作流。对于多项目仓库,说明是否需要一个工作流或每个包单独的工作流。提出修复缺失配置的建议——在修改项目文件前使用询问用户。
ask_user
❌ 有关各类型的详细信息和必需属性,请参阅references/package-types.md。
Phase 2: Local Verification
阶段2:本地验证
Pack and verify locally before touching nuget.org — publishing errors waste a permanent version number.
⚠️ 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
- — verify
dotnet pack -c Release -o ./artifactsis created.nupkg - For tools/MCP servers: install from , run
./artifacts, uninstall--help - For libraries: inspect the contents (it's a zip)
.nupkg
在接触nuget.org前先在本地打包并验证——发布错误会浪费一个永久版本号。
⚠️ 务必提及此步骤,即使你暂时不执行。告诉用户:“首次发布前,运行以验证.nupkg文件是否正确创建。”dotnet pack -c Release -o ./artifacts
- —— 验证
dotnet pack -c Release -o ./artifacts文件是否创建.nupkg - 对于工具/MCP服务器:从安装,运行
./artifacts,然后卸载--help - 对于类库:检查的内容(它是一个zip文件)
.nupkg
Phase 3: nuget.org Policy
阶段3:nuget.org策略配置
This phase requires the user to act on nuget.org — guide them with exact values.
-
Determine the repo owner, repo name, and the workflow filename that will publish.❌ The policy requires the exact workflow filename (e.g.,or
publish.yml) — just the filename, no path prefix. Matching is case-insensitive. Don't use the workflowpublish.yamlfield.name: -
Guide the user to create the trusted publishing policy:Go to nuget.org/account/trustedpublishing → Add policy
- Repository Owner:
{owner} - Repository:
{repo} - Workflow File:
{filename}.yml - Environment: (only if the workflow uses
release; leave blank otherwise)environment:
Policy ownership: the user chooses individual account or organization. Org-owned policies apply to all packages owned by that org.For private repos: policy is "temporarily active" for 7 days — becomes permanent after the first successful publish. - Repository Owner:
-
Guide the user to create a GitHub Environment (recommended but optional — provides secret scoping + approval gates):Repo Settings → Environments → New environment →
releaseAdd environment secret: Name =, Value = nuget.org username (NOT email)NUGET_USEROptional: add Required reviewers for an approval gate.
⚠️ 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.
此阶段需要用户在nuget.org上操作——为他们提供精确的配置值。
-
确定仓库所有者、仓库名称和将用于发布的工作流文件名。❌ 策略要求精确的工作流文件名(例如或
publish.yml)——仅文件名,无前缀路径。匹配不区分大小写。不要使用工作流的publish.yaml字段。name: -
引导用户创建可信发布策略:前往nuget.org/account/trustedpublishing → 添加策略
- 仓库所有者:
{owner} - 仓库:
{repo} - 工作流文件:
{filename}.yml - 环境:(仅当工作流使用
release时填写;否则留空)environment:
策略所有权:用户可以选择个人账户或组织。组织所有的策略适用于该组织拥有的所有包。对于私有仓库:策略会“临时激活”7天——首次发布成功后变为永久有效。 - 仓库所有者:
-
引导用户创建GitHub环境(推荐但可选——提供机密范围限制+审批闸门):仓库 设置 → 环境 → 新建环境 →
release添加环境机密:名称 =,值 = nuget.org用户名(不是邮箱)NUGET_USER可选:添加必需审阅者以设置审批闸门。
⚠️ 等待用户确认已创建策略后,再指导他们移除旧的API密钥/机密或尝试运行/使用工作流发布。在确认前,可以起草或展示工作流文件本身。
Phase 4: Workflow Setup
阶段4:工作流设置
Create or modify the publish workflow. The workflow must always be created or shown in your response — you may draft/show it even if the nuget.org policy is not yet confirmed, but do not guide the user to actually run/publish or remove old secrets until after confirmation.
Greenfield: Create from the template in references/publish-workflow.md. Adapt .NET version, project path, and environment name. Ensure your output explicitly mentions and .
publish.ymlid-token: writeNuGet/login@v1Migration (existing workflow with API key): Modify in place —
-
Add OIDC permission and environment to the publishing job:yaml
jobs: publish: environment: release permissions: id-token: write # Required — without this, NuGet/login fails with 403 contents: read # Explicit — setting permissions overrides defaults -
Add the NuGet login step before push:yaml
- name: NuGet login (OIDC) id: login uses: NuGet/login@v1 with: user: ${{ secrets.NUGET_USER }} # nuget.org profile name, NOT email -
Replace the API key in the push step:yaml
--api-key ${{ steps.login.outputs.NUGET_API_KEY }} --skip-duplicate -
Verify: Ask the user to trigger a publish and confirm the package appears on nuget.org.
❌ Don't delete the old API key secret until trusted publishing is verified. Removing it is a one-way door — wait for confirmation.
创建或修改发布工作流。工作流必须始终在你的响应中创建或展示——即使nuget.org策略尚未确认,你也可以起草/展示它,但在确认前不要指导用户实际运行/发布或移除旧机密。
新项目场景:根据references/publish-workflow.md中的模板创建。适配.NET版本、项目路径和环境名称。确保输出中明确提及和。
publish.ymlid-token: writeNuGet/login@v1迁移场景(现有使用API密钥的工作流):就地修改——
-
在发布作业中添加OIDC权限和环境:yaml
jobs: publish: environment: release permissions: id-token: write # 必需——缺少此权限,NuGet/login会返回403错误 contents: read # 显式设置——设置权限会覆盖默认值 -
在push步骤前添加NuGet登录步骤:yaml
- name: NuGet login (OIDC) id: login uses: NuGet/login@v1 with: user: ${{ secrets.NUGET_USER }} # nuget.org用户名,不是邮箱 -
替换push步骤中的API密钥:yaml
--api-key ${{ steps.login.outputs.NUGET_API_KEY }} --skip-duplicate -
验证:要求用户触发发布并确认包已出现在nuget.org上。
❌ 在可信发布验证通过前,不要删除旧的API密钥机密。移除它是不可逆的操作——等待用户确认后再执行。
Troubleshooting
故障排除
| 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.
| 问题 | 原因 | 修复方案 |
|---|---|---|
| 缺少 | 添加到作业权限中 |
| “无匹配策略” | 工作流文件名不匹配 | 在nuget.org上验证精确的文件名 |
| Push操作未授权 | 包不属于策略账户所有 | 检查nuget.org上的策略所有者 |
| 令牌过期 | 登录步骤在push前超过1小时 | 将 |
| 策略“临时激活” | 私有仓库,首次发布待完成 | 7天内完成发布 |
Push时提示 | 重新运行相同版本 | 添加 |
| GitHub Release返回422 | 标签对应的版本重复 | 删除冲突的版本(需先确认) |
| 重新运行使用错误的YAML | | 删除障碍后重新运行——切勿重新打标签 |
⚠️ 如果任何障碍在尝试修复一次后仍存在,请停止操作并询问用户。
References
参考资料
- Package type details: references/package-types.md — detection logic, required properties, minimal .csproj examples
- Publish workflow template: references/publish-workflow.md — complete tag-triggered workflow ready to adapt
- Microsoft docs: NuGet Trusted Publishing
- 包类型详情:references/package-types.md —— 检测逻辑、必需属性、最简.csproj示例
- 发布工作流模板:references/publish-workflow.md —— 完整的标签触发式工作流,可直接适配使用
- 微软文档:NuGet Trusted Publishing