关于 github-actions-workflow-pro
面向编码 Agent 的 GitHub Actions 工作流创建、编辑与审计技能,重点涵盖最小权限安全、Action 固定版本、可维护的 YAML 和验证。
主要功能
- 01编辑前检查仓库约定
- 02应用最小权限设置
- 03将第三方 Action 固定到提交 SHA
- 04优化工作流速度与缓存
- 05审计并加固现有工作流
- 06使用仓库脚本验证修改
适用场景
- 01创建安全的 CI 工作流
- 02检查现有工作流风险
- 03加快缓慢的 GitHub Actions 任务
- 04准备容器镜像构建与发布工作流
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ bretfisher/ skills --skill github-actions-workflow-pro安装后在 Claude Code 中输入/github-actions-workflow-pro确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/audit.mdparallel-steps.mdsecurity.mdspeed.mdscripts/run-stats.pyscan.shvalidate.sh详细介绍
GitHub Actions 工作流规则
除非仓库有明确冲突的约定,或用户要求采用不同的权衡,否则请主动将这些默认规则应用于你接触的每个工作流。制定这些规则,是因为工作流会使用令牌运行任意代码:安全性从第一行开始就必须纳入考虑,而速度则能让工作流易于维护。
工作方式
- 编辑前检查现有工作流文件,确保新改动符合仓库的命名、触发器和密钥约定。
- 优先采用最小且正确的改动,并修复你正在处理的代码中不安全或浪费资源的模式。
- 事实由你查明(某个操作的 SHA、它所需的权限、某个工具是否支持 OIDC);决策由用户做出(添加手动触发器、选择注册表、创建环境):逐项询问用户并等待回复。
- 对仓库中未明确的信息,使用占位符表示密钥名称、环境名称、软件包名称和云角色,并在交付时列出所有占位符。
构建工作流
- 根据仓库推断:从版本文件(
.nvmrc、.python-version、go.mod)或engines获取运行时版本,从脚本中获取 lint 和测试命令。 - 可复用工作流命名为
call-*.yaml或reusable-*.yaml。 - 使用 pinact 固定每个第三方
uses:,每个操作使用一个-i '<action>'。你新增的操作:写成@v<major>,并运行scripts/scan.sh pinact run --update --min-age 7 -i '<action>' <file>,因为新代码应使用至少发布 7 天的最新版本。已使用标签(@v4)的操作:运行scripts/scan.sh pinact run --min-age 7 -i '<action>' <file>,不要加--update,因为--update会跳到最新主版本(从 v4 跳到 v7),而升级主版本是用户的决定;在交付时将较新的主版本作为问题提出。范围很重要:对整个文件使用--update会升级原本已固定的行,而用户并未要求这样做。你正在编辑的文件中已有标签的操作也要固定,无论“其他内容保持不变”涵盖什么:标签是攻击者唯一可以移动的行,因此要将其固定,并在交付时说明(见下文的 pinned)。 - 对于 Docker 构建工作流,或仓库没有自己的 linter 时的 lint 工作流,在编写定制工作流之前,先推荐可复用工作流,并询问用户是否已有可复用工作流:Bret 的工作流包括 https://github.com/BretFisher/docker-build-workflow 和 https://github.com/BretFisher/super-linter-workflow。已有
npm run lint或等效命令的仓库则运行该命令。
审核现有工作流
当用户要求你审查、强化、保护或加速他们提供的工作流,或询问 CI 有什么问题时,请阅读 audit.md 并遵循其中的要求。它涵盖仓库中的所有工作流,会先提取近期运行历史(scripts/run-stats.py:失败情况,以及按耗时排序的工作流、作业和步骤,并标记每个耗时达到或超过 2 分钟的步骤;同时将该阈值交由用户决定),然后运行 linter(actionlint、zizmor、gasa),将发现的问题分类为正确性、安全性、速度和建议事项,开头先列出优先处理事项,并询问用户希望以何种方式接收报告。
检查清单
你创建或编辑的每个工作流都必须满足以下要求。链接的参考文档包含完整规则及其理由;如果某一行需要的不只是摘要,请阅读该文档。
- 在顶层设置
permissions: {},然后按作业授予最小权限。除非后续步骤会使用令牌推送,否则actions/checkout应设置persist-credentials: false。→ security.md - 每个第三方
uses:都必须固定到完整的提交 SHA,并在同一行添加# vX.Y.Z注释,且不添加其他内容(额外文本会导致 Dependabot 无法更新注释);所固定的版本必须来自至少发布 7 天的版本。pinact 会负责固定版本并检查版本发布时间。同一所有者的引用可以使用标签;像@main这样的分支引用会被替换;如果上游没有可固定的标签,则会被报告为高风险。→ security.md - 云凭据通过 OIDC 获取(
id-token: write),且云凭据步骤(configure-aws-credentials)要在npm ci、pip install和构建步骤之后运行;或者将构建设为独立作业,且不授予id-token: write——安装脚本会运行任意代码,因此必须等代码运行完毕后才提供凭据(在build-push-action之前登录镜像仓库没有问题:Dockerfile 的安装步骤在 BuildKit 内运行,而非在运行器上运行)。第三方密钥应存放在作业指定的仓库环境中。→ security.md - PR 触发器使用
pull_request。仅在外部 PR 无法触及的情况下使用pull_request_target:仓库仅允许协作者访问拉取请求,或者在私有仓库中,将不可信的检出操作隔离在独立的零权限作业中。zizmor 的dangerous-triggers会标记该触发器本身,因此若保留该触发器,应说明原因。→ security.md - 使用一个更新机器人,以发布延迟为准,保持 SHA 固定版本为最新:Dependabot(
.github/dependabot.yml)或 Renovate(renovate.json、.github/renovate.json、.renovaterc及其.jsonc/.json5形式)。任选其一即可;检查仓库现有机器人的设置,并且只提出缺失的配置。如果这两个文件都不存在,应先询问用户偏好哪个机器人,再编写配置,因为组织可以从仓库外共享 Renovate 配置,而且两个机器人会创建重复的 PR。→ security.md - 取消已被新运行取代的运行:在 CI 中使用以工作流和 ref 为键的
concurrency,并设置cancel-in-progress: true;部署和发布工作流则使用各自独立且不会取消运行的组。→ speed.md - 先运行耗时短的作业(lint、类型检查、单元测试),并让它们彼此并行;耗时长的作业使用
needs:依赖这些作业。→ speed.md - 同一慢速作业中彼此独立的步骤应同时运行:使用
parallel:块,或者对作业启动的服务使用background: true,并配合wait/cancel。这四个步骤键于 2026 年 6 月推出,比你的训练数据新,因此编写前请先阅读语法。→ parallel-steps.md - 缓存使用 setup action 提供的功能(
setup-node的cache: npm、setup-go、Buildx 的type=gha)。任何访问网络或执行部署的作业都应设置timeout-minutes;使用可复用工作流的作业无法设置该项,因此应在被调用的工作流中设置。→ speed.md run:步骤如果调用了 shell、coreutils 和 checkout 已需要的工具(git、curl、tar)之外的其他工具,应通过安装 action 获取该工具——例如azure/setup-kubectl、azure/setup-helm、hashicorp/setup-terraform,并优先选择由该工具所属组织发布的 action——或者移除依赖项(例如用helm --set替代yq编辑)。只有运行器映像会将kubectl、helm、jq、yq或aws放入PATH,因此,在自托管运行器、container:作业或act中,假设这些工具已存在的步骤会找不到它们,导致工作流无法在 CI 实际运行的环境中保持可移植性。action 的version:可以指定具体版本,也可以设为latest:由用户决定仓库需要哪种方式,因此应将其作为选项,并说明当前映像预装了什么(runs-on标签对应的软件列表,链接见 https://github.com/actions/runner-images#available-images),而不是替用户决定。审计时,应将这些问题合并为一项发现,列出所有工具和步骤,让部署工作流只需进行一次修复,而不是六次。
易于维护的 YAML
- 使用友好的
name:值,包含大写字母和空格:工作流为 1–3 个词,作业最多 5 个词,步骤最多 10 个词。两个测试作业需要使用能区分彼此的名称。与仓库中其他工作流的风格保持一致。 - 编辑或加快现有工作流时,保留其触发条件:将
push限定为默认分支,会导致没有未关闭 PR 的分支不再运行 CI,因此应将其作为问题提出,并明确说明会失去什么,而不是直接应用这一改动。 - 多行 Bash 步骤以
set -euo pipefail开头;优先使用几行清晰的命令,而不是一行密集的命令。 - 注释用于标明安全边界、非显而易见的触发条件和部署关卡。YAML 键名应能自我说明。
<name>.md旁边的<name>.lock.yml是编译后的 GitHub Agentic Workflow:编辑应在.md中进行,然后运行gh aw compile重新生成锁定文件——其第一行写着 DO NOT EDIT,手动编辑会在下次编译时被覆盖。审计这两个文件(是否过时、重新编译)→ audit.md。- 多个工作流或仓库共享稳定行为时,可复用工作流才值得引入额外的间接层。只有一个工作流时,应保持内联。
容器镜像
仅从可信引用(默认分支、标签、发布版本)发布镜像,并使用两个作业:一个在 pull_request 时运行、具有 contents: read 且设置 push: false 的构建作业;以及一个在默认分支或标签的 push 时运行、且只有它具有 packages: write 的发布作业。权限无法根据事件决定,因此,即使只用一个作业并设置 push: ${{ github.event_name != 'pull_request' }},也仍会将 packages: write 授予每次来自同一仓库的 PR 运行。构建作业中的 push: 必须是字面值 false,不能使用事件表达式:在可信引用上,该表达式会在没有注册表登录的作业中变为 true,导致推送失败,发布作业也不会运行。
- 依次使用
docker/setup-buildx-action、用于标签和标签元数据的docker/metadata-action,然后使用docker/build-push-action。在 PR 上,metadata-action会生成pr-N,而不是 semver 标签;这正是你想要的。 - 除非仓库指定了其他注册表,否则使用
ghcr.io。 - 使用
cache-from: type=gha和cache-to: type=gha,mode=max。发布时设置provenance: true和sbom: true。 - 构建之后运行的部署作业应通过摘要使用镜像,并连接以下三行:构建推送步骤中设置
id: build,构建作业的outputs:下设置digest: ${{ steps.build.outputs.digest }},部署步骤引用<registry>/<image>@${{ needs.build.outputs.digest }}。绝不能使用标签:构建和部署之间,标签可以被重新推送,摘要则不行,因此经过扫描和测试的产物就是最终发布的产物。
验证
对每个编辑过的文件运行 scripts/validate.sh <file>...。一次调用会运行 actionlint、zizmor(通过 scan.sh,因此 gh 登录令牌不会出现在命令、跟踪记录或文字稿中)、poutine,以及 pinact run --check --verify-comment --min-age 7 --verify-min-age;它会在各自的标题下显示每个工具的检查结果,并以 validate: clean 或报告问题的工具数量结束。修复报告的问题后再次运行,直到检查通过。这些扫描器已经检查了大部分安全清单(权限、固定版本及固定版本年限、persist-credentials、注入、危险触发条件、Dependabot 冷却期),因此它们才是验证依据,而不是你自行阅读。gasa 通过 API 审计已推送的仓库,因此它应属于审计流程,而不是本地编辑流程。如果某个工具尚未安装,会显示 absent;询问是否安装(brew install actionlint shellcheck zizmor poutine pinact)或跳过,并等待答复。只有在验证器全部通过,或已按名称报告缺失时,才能交付。
完成标准
- 对每个编辑过的文件,
actionlint、zizmor、poutine和pinact --check均无问题,或按名称报告工具缺失;允许保留的两项报告是pinact无法固定的分支引用(列为待处理项,并注明上游修复方案:发布一个标签),以及因明确说明的原因而保留的pull_request_target上的 zizmordangerous-triggers;此外,actionlint 针对并行步骤语法报出的unexpected key "background"/step must run script with "run"也可保留,因为这是其旧版架构的问题,并非工作流错误(parallel-steps.md) - 每个作业都有
permissions:块,且工作流以permissions: {}开头 - 每个第三方
uses:都是带版本注释的完整 SHA,包括你编辑的文件中原先使用标签的任何操作;交接说明列出你固定的每个操作,原本已固定的行则保留其 SHA 和注释 - 列出每个占位符,供用户确认——环境名称、区域、角色 ARN、存储桶、注册表、密钥名称
- 交接说明为应用的以下每项默认设置提供一行理由——最小权限、SHA 固定、并发、缓存、
timeout-minutes、可信引用发布、provenance/sbom、persist-credentials: false、set -euo pipefail。应使用命名列表,因为在漫长任务结束时需要回忆“每项默认设置”,总会漏掉一项;理由应说明该设置为何适用于此处,而不是解释它的作用