mcpField
A
authoring-github-workflows

authoring-github-workflows

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

关于 authoring-github-workflows

帮助开发者安全编写和审查 GitHub Actions 工作流 YAML 的技能,重点处理 YAML 与 Actions 语法之间的差异。它强调为含表达式的特殊标量加引号,并用 actionlint 验证工作流结构。

主要功能

  1. 01识别表达式中的 YAML 注释陷阱
  2. 02判断哪些标量需要加引号
  3. 03使用 actionlint 验证工作流
  4. 04区分 YAML 解析与 Actions 校验
  5. 05提供合并前检查清单

适用场景

  1. 01编辑或审查 .github/workflows/ 文件
  2. 02排查没有启动任何作业的工作流错误
  3. 03验证包含 `${{ }}` 表达式的字段

安装

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

$npx skills add https://github.com/dotnet/skills --skill authoring-github-workflows

安装后在 Claude Code 中输入/authoring-github-workflows确认已加载。

详细介绍

安全编写 GitHub Actions 工作流

GitHub Actions 工作流文件使用 YAML,但有效的 YAML 并不等于有效的工作流。工作流可能通过 yaml.safe_load 解析(或在随意审查中看起来没有问题),却仍会在加载时被 GitHub Actions 拒绝,产生含糊不清的错误 “This run likely failed because of a workflow file issue”,并且没有任何作业启动。本技能将介绍 YAML 与 Actions 之间的陷阱(尤其是 # 被当作注释的陷阱)、如何正确为表达式标量加引号,以及如何在合并前使用 actionlint 验证。

范围:语法与语义。 本技能关注工作流 YAML 在语法和结构上的正确性,包括引号、解析,以及决定 GitHub Actions 能否加载并运行文件的 actionlint 级别有效性。本技能不涉及工作流应该做什么,也不涉及 Agent 工作流应该如何运行。有关语义和功能方面的指导(设计工作流逻辑、Agent 工作流模式、编写 gh-aw),请参阅 .github/agents/agentic-workflows.agent.md。两者相辅相成:使用 Agent 确保行为正确,使用本技能确保 YAML 正确。

适用场景

  • 编辑、添加或审查 .github/workflows/ 下的任何文件。
  • 编写包含 ${{ }} 表达式的 run-name、name、if、env、with 或 run 值。
  • 工作流运行失败,并提示 “This run likely failed because of a workflow file issue”,且没有任何作业运行。
  • 合并工作流编辑后,main 上的 Eval/CI 突然在每次运行时都失败,尽管更改“看起来没问题”。
  • 判断 YAML 标量是否需要加引号。

不适用场景

  • 编写非 Actions 的 YAML(应用配置、Kubernetes、Compose、Azure Pipelines、GitLab CI)。
  • 仅编写有效 run: 块中的 shell/脚本逻辑(这是脚本编写任务,不是工作流语法任务)。

头号陷阱:未加引号的表达式中的 # 会被当作 YAML 注释

在 YAML 中,空格后跟 # 表示注释开始。对于未加引号的普通标量,从空格和 # 开始直到行尾的所有内容都会被静默丢弃:

# BAD — the run-name is silently truncated at " #"
run-name: ${{ inputs.pr_number != '' && format('Evaluate PR #{0} @ {1}', inputs.pr_number, inputs.head_sha) || '' }}

YAML 会将其解析为 run-name: ${{ inputs.pr_number != '' && format('Evaluate PR——一个未终止的 ${{ 表达式。yaml.safe_load 会成功(它只会看到一个带有尾随注释的截断字符串),所以这个错误会通过简单的验证,但 GitHub Actions 会拒绝格式错误的表达式,并拒绝启动任何运行。

# GOOD — wrap the whole value in double quotes so '#' stays inside the scalar
run-name: "${{ inputs.pr_number != '' && format('Evaluate PR #{0} @ {1}', inputs.pr_number, inputs.head_sha) || '' }}"

内部表达式已经使用单引号,因此给标量加双引号是安全的。这正是导致 dotnet/skills 在 main 上的评估失败的错误(PR #746 → 通过加引号修复)。

其他会导致普通标量必须加引号的字符

字符 / 模式导致问题的原因修复方法
空格后跟 #(空格-井号)开始 YAML 注释;截断值为整个值加引号
开头为 *、&、!、?、|、>、@、`YAML 锚点/别名/标签/块标量为值加引号
开头为 { 或 [会被解析为流式映射/序列(裸写的 ${{ }} 以 $ 开头,因此是安全的,但在开头字符之后出现 {{ 有风险)为值加引号
值中出现 : 后跟空格(冒号-空格)会被解析为嵌套映射键为值加引号
有意义的首尾空格普通标量会移除这些空格为值加引号
值为 true/false/yes/no/on/off/数字,但必须保持为字符串YAML 类型强制转换为值加引号

经验法则: 如果 name、run-name、if、env 或 with 的值包含 ${{ }} 表达式,并且包含字面量 #、: 或开头的特殊字符,就要用双引号括起整个标量。

工作流程

步骤 1:识别已更改或编写的工作流文件
git diff --name-only origin/main... -- .github/workflows/

对于每个文件,扫描所有同时包含 ${{ 和 #、冒号-空格或开头特殊字符的行。

步骤 2:为有风险的表达式标量加引号

当值中嵌入表达式且包含 # 或其他特殊字符时(见上表),请将整个值用双引号括起来。若内部表达式使用单引号,优先使用双引号;反之亦然。不要转义 ${{ }} 大括号——为标量加引号即可。

步骤 3:使用 actionlint 验证(权威方式)

actionlint 理解 GitHub Actions 架构和表达式语法,因此可以准确捕获这类普通 YAML 检查器会漏掉的错误。下载一个固定版本并运行:

ACTIONLINT_VERSION=1.7.7
ACTIONLINT_SHA256=023070a287cd8cccd71515fedc843f1985bf96c436b7effaecce67290e7e0757
curl -fsSLo actionlint.tar.gz \
  "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz"
# Verify the download against the pinned checksum before extracting/executing it:
echo "${ACTIONLINT_SHA256}  actionlint.tar.gz" | sha256sum -c -
tar -xzf actionlint.tar.gz actionlint
# Focus on workflow/expression correctness; silence shell/py style noise:
./actionlint -shellcheck= -pyflakes= -color .github/workflows/*.yml

在 Windows PowerShell 中,请使用 actionlint_<ver>_windows_amd64.zip 文件并运行 Expand-Archive。

截断表达式错误会显示为:

got unexpected EOF while lexing end of string literal, expecting ''' [expression]

退出代码为 0 表示工作流结构有效。

步骤 4:确认仅检查 YAML 并不足够

不要依赖 yaml.safe_load、yamllint 或“能解析”来作为有效证明。它们会接受被截断为注释的形式。只有 actionlint(或推送更改并观察 GitHub Actions 是否能解析)才能验证 Actions 层。

步骤 5:保持 CI 检查通过

本仓库会自动运行 actionlint(见 .github/workflows/actionlint.yml),检查任何涉及 .github/workflows/ 的 PR。请求审查前,请确保你的更改通过此检查。如果你新增工作流,检查会自动覆盖它。

验证

  • 每个包含 #、冒号加空格或特殊字符开头的 ${{ }} 值都已加引号。
  • actionlint -shellcheck= -pyflakes= .github/workflows/*.yml 的退出代码为 0。
  • 没有工作流运行报告 "This run likely failed because of a workflow file issue"。
  • PR 中的 actionlint CI 检查已通过。

常见陷阱

陷阱解决方案
表达式中含有 # 的 run-name/name 未加引号将整个值用双引号括起来
相信 yaml.safe_load/yamllint/代码审查能够发现问题运行 actionlint;仅检查 YAML 会接受被截断的形式
转义 ${{ 大括号来“修复”问题不要这样做——改为给标量加引号;转义会破坏表达式
对包含单引号的值使用单引号外层标量请使用双引号
启用 shellcheck 添加 actionlint,结果被已有的 shell 风格警告淹没使用 -shellcheck= -pyflakes= 运行,以专注检查工作流和表达式错误
认为 YAML 检查通过就意味着工作流会运行推送更改并确认作业确实启动,或依赖 actionlint 检查

参考资料

评论

支持 Markdown