nuget-trusted-publishing

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

NuGet 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
    secrets.NUGET_API_KEY
    to OIDC-based publishing
  • 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
    NuGet/login@v1
    or
    id-token: write
在以下场景使用本技能:
  • 为NuGet包设置可信发布
  • secrets.NUGET_API_KEY
    迁移到基于OIDC的发布方式
  • 咨询无密钥或安全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.
  1. Find and classify packable projects — check
    .csproj
    files and
    Directory.Build.props
    (package metadata is often set repo-wide). Classify in this order (earlier matches win):
    • <PackageType>Template</PackageType>
      Template
    • <PackageType>McpServer</PackageType>
      MCP server (also a dotnet tool)
    • <PackAsTool>true</PackAsTool>
      Dotnet tool
    • Class library (
      IsPackable=true
      or no
      OutputType
      ) → Library
    • <OutputType>Exe</OutputType>
      with
      <IsPackable>true</IsPackable>
      Application package (not a tool, but still publishable)
    • <OutputType>Exe</OutputType>
      without
      PackAsTool
      or
      IsPackable
      → Not packable by default (ask user if they intend to publish it)
  2. Validate structure for each project's type:
    TypeRequired
    All
    PackageId
    ,
    Version
    (in .csproj or Directory.Build.props)
    Dotnet tool
    PackAsTool
    (required);
    ToolCommandName
    (optional but recommended — defaults to assembly name)
    MCP server
    PackageType=McpServer
    ,
    .mcp/server.json
    included in package
    Template
    PackageType=Template
    ,
    .template.config/template.json
    under content dir
  3. Find existing publish workflows in
    .github/workflows/
    — look for
    dotnet nuget push
    ,
    nuget push
    , or
    dotnet pack
    .
  4. Check version consistency — for MCP servers, verify
    .csproj
    <Version>
    matches both
    server.json
    version fields (root
    version
    and
    packages[].version
    ). Flag any mismatch.
  5. 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 — use
    ask_user
    before modifying project files.
❌ See references/package-types.md for per-type details and required properties.
在进行任何更改前,先检查仓库并向用户报告结果。
  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

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, run
dotnet pack -c Release -o ./artifacts
to verify the .nupkg is created correctly."
  1. dotnet pack -c Release -o ./artifacts
    — verify
    .nupkg
    is created
  2. For tools/MCP servers: install from
    ./artifacts
    , run
    --help
    , uninstall
  3. For libraries: inspect the
    .nupkg
    contents (it's a zip)
在接触nuget.org前先在本地打包并验证——发布错误会浪费一个永久版本号。
⚠️ 务必提及此步骤,即使你暂时不执行。告诉用户:“首次发布前,运行
dotnet pack -c Release -o ./artifacts
以验证.nupkg文件是否正确创建。”
  1. dotnet pack -c Release -o ./artifacts
    —— 验证
    .nupkg
    文件是否创建
  2. 对于工具/MCP服务器:从
    ./artifacts
    安装,运行
    --help
    ,然后卸载
  3. 对于类库:检查
    .nupkg
    的内容(它是一个zip文件)

Phase 3: nuget.org Policy

阶段3:nuget.org策略配置

This phase requires the user to act on nuget.org — guide them with exact values.
  1. Determine the repo owner, repo name, and the workflow filename that will publish.
    ❌ The policy requires the exact workflow filename (e.g.,
    publish.yml
    or
    publish.yaml
    ) — just the filename, no path prefix. Matching is case-insensitive. Don't use the workflow
    name:
    field.
  2. Guide the user to create the trusted publishing policy:
    • Repository Owner:
      {owner}
    • Repository:
      {repo}
    • Workflow File:
      {filename}.yml
    • Environment:
      release
      (only if the workflow uses
      environment:
      ; leave blank otherwise)
    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.
  3. Guide the user to create a GitHub Environment (recommended but optional — provides secret scoping + approval gates):
    Repo SettingsEnvironmentsNew environment
    release
    Add environment secret: Name =
    NUGET_USER
    , Value = nuget.org username (NOT email)
    Optional: 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上操作——为他们提供精确的配置值。
  1. 确定仓库所有者仓库名称和将用于发布的工作流文件名
    ❌ 策略要求精确的工作流文件名(例如
    publish.yml
    publish.yaml
    )——仅文件名,无前缀路径。匹配不区分大小写。不要使用工作流的
    name:
    字段。
  2. 引导用户创建可信发布策略:
    • 仓库所有者
      {owner}
    • 仓库
      {repo}
    • 工作流文件
      {filename}.yml
    • 环境
      release
      (仅当工作流使用
      environment:
      时填写;否则留空)
    策略所有权:用户可以选择个人账户或组织。组织所有的策略适用于该组织拥有的所有包。
    对于私有仓库:策略会“临时激活”7天——首次发布成功后变为永久有效。
  3. 引导用户创建GitHub环境(推荐但可选——提供机密范围限制+审批闸门):
    仓库 设置环境新建环境
    release
    添加环境机密:名称 =
    NUGET_USER
    = nuget.org用户名(不是邮箱)
    可选:添加必需审阅者以设置审批闸门。
⚠️ 等待用户确认已创建策略,再指导他们移除旧的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
publish.yml
from the template in references/publish-workflow.md. Adapt .NET version, project path, and environment name. Ensure your output explicitly mentions
id-token: write
and
NuGet/login@v1
.
Migration (existing workflow with API key): Modify in place —
  1. 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
  2. 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
  3. Replace the API key in the push step:
    yaml
    --api-key ${{ steps.login.outputs.NUGET_API_KEY }} --skip-duplicate
  4. 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中的模板创建
publish.yml
。适配.NET版本、项目路径和环境名称。确保输出中明确提及
id-token: write
NuGet/login@v1
迁移场景(现有使用API密钥的工作流):就地修改——
  1. 在发布作业中添加OIDC权限和环境
    yaml
    jobs:
      publish:
        environment: release
        permissions:
          id-token: write     # 必需——缺少此权限,NuGet/login会返回403错误
          contents: read      # 显式设置——设置权限会覆盖默认值
  2. 在push步骤前添加NuGet登录步骤
    yaml
    - name: NuGet login (OIDC)
      id: login
      uses: NuGet/login@v1
      with:
        user: ${{ secrets.NUGET_USER }}  # nuget.org用户名,不是邮箱
  3. 替换push步骤中的API密钥
    yaml
    --api-key ${{ steps.login.outputs.NUGET_API_KEY }} --skip-duplicate
  4. 验证:要求用户触发发布并确认包已出现在nuget.org上。
在可信发布验证通过前,不要删除旧的API密钥机密。移除它是不可逆的操作——等待用户确认后再执行。

Troubleshooting

故障排除

ProblemCauseFix
NuGet/login
403
Missing
id-token: write
Add to job permissions
"no matching policy"Workflow filename mismatchVerify exact filename on nuget.org
Push unauthorizedPackage not owned by policy accountCheck policy owner on nuget.org
Token expiredLogin step >1hr before pushMove
NuGet/login
closer to push
"temporarily active" policyPrivate repo, first publish pendingPublish within 7 days
already_exists
on push
Re-running same versionAdd
--skip-duplicate
GitHub Release 422Duplicate release for tagDelete conflicting release (confirm first)
Re-run uses wrong YAML
gh run rerun
replays original commit's YAML
Delete obstacle, re-run — never re-tag
⚠️ If any blocker persists after one fix attempt, stop and ask the user.
问题原因修复方案
NuGet/login
返回403
缺少
id-token: write
权限
添加到作业权限中
“无匹配策略”工作流文件名不匹配在nuget.org上验证精确的文件名
Push操作未授权包不属于策略账户所有检查nuget.org上的策略所有者
令牌过期登录步骤在push前超过1小时
NuGet/login
步骤移至更靠近push的位置
策略“临时激活”私有仓库,首次发布待完成7天内完成发布
Push时提示
already_exists
重新运行相同版本添加
--skip-duplicate
参数
GitHub Release返回422标签对应的版本重复删除冲突的版本(需先确认)
重新运行使用错误的YAML
gh run rerun
会重播原始提交的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