mcpField
N
nuget-trusted-publishing

nuget-trusted-publishing

github.com/dotnet云与 DevOps5.8k3.5k 次安装1 天前更新
代码仓库

关于 nuget-trusted-publishing

一项指导通过 GitHub Actions 使用 OIDC 配置 NuGet 可信发布的技能,以短期令牌取代长期 API 密钥。内容涵盖仓库评估、本地包验证、nuget.org 策略设置及工作流创建或迁移。

主要功能

  1. 01评估包类型和项目配置
  2. 02使用 dotnet pack 验证包
  3. 03指导配置 nuget.org 策略
  4. 04创建或迁移 GitHub Actions 工作流
  5. 05排查 OIDC 发布问题

适用场景

  1. 01为 NuGet 包配置可信发布
  2. 02将工作流从 API 密钥发布迁移
  3. 03创建新的 NuGet 发布工作流
  4. 04发布 dotnet 工具或 MCP 服务

MCP 相关

该技能涵盖 MCP 服务的 NuGet 包发布,但没有描述 MCP 服务或客户端。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dotnet/skills --skill nuget-trusted-publishing

安装后在 Claude Code 中输入/nuget-trusted-publishing确认已加载。

附带文件references/package-types.mdreferences/publish-workflow.md

详细介绍

NuGet 可信发布设置

在 GitHub Actions 仓库上设置 NuGet 可信发布。用基于 OIDC 的短期令牌替代长期有效的 API 密钥——无需轮换或担心泄露密钥。

前提条件

  • GitHub Actions — 本技能仅涵盖 GitHub Actions 设置
  • nuget.org 账户 — 用户需要有权限创建可信发布策略

何时使用此技能

在以下情况下使用此技能:

  • 为 NuGet 包设置可信发布
  • 从 secrets.NUGET_API_KEY 迁移到基于 OIDC 的发布
  • 询问无密钥或安全的 NuGet 发布
  • 从头开始创建新的 NuGet 发布工作流
  • 被要求“移除 NuGet API 密钥”或“使用 NuGet/login”
  • 为 dotnet 工具、MCP 服务或模板包设置发布
  • 询问 NuGet/login@v1 或 id-token: write

安全规则

⚠️ 停止规则:如果基础设施或身份验证问题在尝试修复一次后仍导致任何阶段失败,请停止并询问用户。不要反复尝试解决环境问题。

⚠️ 未经确认,绝不删除或覆盖:移除 API 密钥机密、删除标签/发行版、移除工作流步骤或更改包 ID。NuGet 包 ID 是永久的——错误无法撤销。

流程

全新仓库的快速路径:如果用户的设置简单(一个可打包项目,没有现有发布工作流),不要要求经过多轮评估。合并各阶段:立即创建工作流,并在同一条回复中提供 nuget.org 策略指导、本地打包建议和文件名匹配警告。以下完整分阶段流程适用于复杂场景或迁移场景。

阶段 1:评估

检查仓库,并在进行任何更改前报告发现的问题。

  1. 查找并分类可打包项目 — 检查 .csproj 文件和 Directory.Build.props(包元数据通常在整个仓库范围内设置)。按以下顺序分类(越靠前的匹配优先级越高):

    • <PackageType>Template</PackageType> → 模板
    • <PackageType>McpServer</PackageType> → MCP 服务(也是 dotnet 工具)
    • <PackAsTool>true</PackAsTool> → Dotnet 工具
    • 类库(IsPackable=true 或没有 OutputType)→ 库
    • <OutputType>Exe</OutputType> 且包含 <IsPackable>true</IsPackable> → 应用程序包(不是工具,但仍可发布)
    • <OutputType>Exe</OutputType> 且不包含 PackAsTool 或 IsPackable → 默认不可打包(询问用户是否打算发布)
  2. 验证结构,检查每种项目类型:

    类型必需项
    全部PackageId、Version(位于 .csproj 或 Directory.Build.props 中)
    Dotnet 工具PackAsTool(必需);ToolCommandName(可选但建议设置 — 默认值为程序集名称)
    MCP 服务PackageType=McpServer,包中包含 .mcp/server.json
    模板PackageType=Template,内容目录下包含 .template.config/template.json
  3. 查找现有发布工作流:在 .github/workflows/ 中查找 dotnet nuget push、nuget push 或 dotnet pack。

  4. 检查版本一致性 — 对于 MCP 服务,验证 .csproj 中的 <Version> 是否与 server.json 的两个版本字段(根级 version 和 packages[].version)一致。标记任何不匹配之处。

  5. 向用户报告发现的问题:分类、缺失的属性、版本不匹配和现有工作流。对于多项目仓库,说明需要一个工作流还是为每个包分别设置工作流。提出修复缺失项——修改项目文件前使用 ask_user。

❌ 按类型查看详情和必需属性,请参阅 references/package-types.md。

阶段 2:本地验证

在操作 nuget.org 之前,先在本地打包并验证——发布错误会浪费一个无法挽回的版本号。

⚠️ 务必提及此步骤,即使你暂缓执行。告诉用户:“首次发布前,请运行 dotnet pack -c Release -o ./artifacts,以验证 .nupkg 是否已正确创建。”

  1. dotnet pack -c Release -o ./artifacts — 验证 .nupkg 已创建
  2. 对于工具/MCP 服务:从 ./artifacts 安装,运行 --help,然后卸载
  3. 对于库:检查 .nupkg 的内容(它是一个 zip 文件)
阶段 3:nuget.org 策略

此阶段需要用户在 nuget.org 上进行操作——请提供准确的值。

  1. 确定将执行发布的 仓库所有者、仓库名称和工作流文件名。

    ❌ 策略要求提供确切的工作流文件名(例如,publish.yml 或 publish.yaml)——仅文件名,不含路径前缀。匹配时不区分大小写。不要使用工作流的 name: 字段。

  2. 引导用户创建受信任发布策略:

    前往 nuget.org/account/trustedpublishing → Add policy

    • Repository Owner:{owner}
    • Repository:{repo}
    • Workflow File:{filename}.yml
    • Environment:release (仅当工作流使用 environment: 时填写;否则留空)

    策略归属:用户可选择个人账户或组织。归属于组织的策略适用于该组织拥有的所有包。

    对于私有仓库:策略会“暂时激活”7 天——首次成功发布后转为永久有效。

  3. 引导用户创建 GitHub Environment(推荐但非必需——可限定机密的作用范围并设置审批关卡):

    仓库 Settings → Environments → New environment → release

    添加环境机密:Name = NUGET_USER,Value = nuget.org 用户名(不是邮箱)

    可选:添加 Required reviewers 以设置审批关卡。

⚠️ 在要求用户删除旧 API 密钥/机密或尝试使用工作流运行/发布之前,请先等待用户确认已创建策略。确认前可以起草或展示工作流文件。

阶段 4:工作流设置

创建或修改发布工作流。必须始终在回复中创建或展示工作流——即使 nuget.org 策略尚未确认,也可以起草或展示工作流,但在确认后才能引导用户实际运行/发布或删除旧机密。

从零开始:根据 references/publish-workflow.md 中的模板创建 publish.yml。调整 .NET 版本、项目路径和环境名称。确保输出明确提及 id-token: write 和 NuGet/login@v1。

迁移(现有工作流使用 API 密钥):在原有工作流中修改 —

  1. 向发布作业添加 OIDC 权限和环境:

    jobs:
      publish:
        environment: release
        permissions:
          id-token: write     # Required — without this, NuGet/login fails with 403
          contents: read      # Explicit — setting permissions overrides defaults
    
  2. 在推送之前添加 NuGet 登录步骤:

    - name: NuGet login (OIDC)
      id: login
      uses: NuGet/login@v1
      with:
        user: ${{ secrets.NUGET_USER }}  # nuget.org profile name, NOT email
    
  3. 在推送步骤中替换 API 密钥:

    --api-key ${{ steps.login.outputs.NUGET_API_KEY }} --skip-duplicate
    
  4. 验证:请用户触发一次发布,并确认该包已显示在 nuget.org 上。

❌ 在验证受信任发布之前,不要删除旧的 API 密钥机密。删除后无法撤销——请等待用户确认。

故障排查

问题原因解决方法
NuGet/login 403缺少 id-token: write在作业权限中添加
"no matching policy"工作流文件名不匹配在 nuget.org 上核对准确的文件名
推送未授权包不归策略账户所有在 nuget.org 上检查策略所有者
令牌已过期登录步骤在推送前超过 1 小时执行将 NuGet/login 步骤移近推送步骤
策略处于“暂时激活”状态私有仓库,首次发布尚未完成在 7 天内发布
推送时出现 already_exists重复运行同一版本添加 --skip-duplicate
GitHub Release 返回 422此标签已有 Release删除冲突的 Release(请先确认)
重新运行时使用了错误的 YAMLgh run rerun 会重放原始提交中的 YAML删除障碍,然后重新运行——切勿重新打标签

⚠️ 如果尝试修复一次后问题仍未解决,请停止并询问用户。

参考资料

评论

支持 Markdown