关于 ci-cd
ci-cd 是面向工程团队的 CI/CD 工作流编写、审查与架构技能,覆盖 GitHub Actions、GitLab CI/CD、Forgejo Actions、Gitea Actions 和 Woodpecker。内容包括安全加固、合规、迁移、运行器配置和故障排查。
主要功能
- 01编写和审查多平台流水线
- 02加固供应链与流水线安全
- 03配置运行器、缓存和制品
- 04设置安全扫描与审查关卡
- 05支持 PCI-DSS 4.0 合规
适用场景
- 01在不同 CI 平台间迁移流水线
- 02检查配置中的权限与密钥风险
- 03排查失败任务和运行器问题
- 04设计符合合规要求的发布流水线
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ iuliandita/ skills --skill ci-cd安装后在 Claude Code 中输入/ci-cd确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/agent-hygiene.mdbest-practices.mdforgejo-gitea-actions.mdgithub-actions.mdgitlab-ci.mdoutput-contract.mdrunners.mdsupply-chain.mdtarget-versions.md详细介绍
CI/CD 流水线:多平台生产基础设施
编写、审查并设计适用于 GitHub Actions、GitLab CI/CD、Forgejo Actions、Gitea Actions 和 Woodpecker 的 CI/CD 流水线。目标是构建安全、快速、可审计的流水线, 满足工程需求和合规要求(PCI-DSS 4.0)。
目标版本:2026 年 10 月快照。在固定 forge、runner、CI 或供应链工具版本之前,请阅读 references/target-versions.md。
此技能涵盖工作流设计、安全、合规、跨平台迁移、runner、依赖更新、扫描、审查关卡和推出顺序。
适用场景
- 编写或审查 CI/CD 流水线配置(GitHub/Forgejo/Gitea Actions、
.gitlab-ci.yml、.woodpecker/*.yaml) - 设计流水线架构(阶段、并行处理、缓存、部署策略)
- 加固流水线以抵御供应链攻击(SHA 固定、镜像签名、来源证明)
- 在 CI 中设置安全扫描(SAST、SCA、容器扫描、密钥检测)
- 配置 runner(安装、注册、执行器选择、加固)——请参阅
references/runners.md - 设置缓存策略或制品管理
- 确保 CI/CD 符合 PCI-DSS 4.0(要求 6.2.1、6.2.4、6.3.2、6.4.2、6.5.3)
- 在平台之间迁移流水线(GitLab -> GitHub、GitHub -> Forgejo)
- 排查流水线失败、间歇性作业故障或 runner 问题
不适用场景
- Kubernetes 清单、Helm chart、集群架构——使用 kubernetes
- Dockerfile、Compose 堆栈、容器镜像优化——使用 docker
- Terraform/OpenTofu 基础设施即代码——使用 terraform
- Ansible playbook、配置管理——使用 ansible
- 应用代码安全审计(SAST 发现项、身份验证漏洞)——使用 security-audit
- 审查与流水线相关的应用代码正确性——使用 code-review。 流水线配置审查、调试、架构设计和 CI 专属加固仍属于此技能范围。
- 数据库迁移或架构工作——使用 databases
AI 自检
AI 工具总是会犯同样的 CI/CD 错误。返回任何生成的流水线配置之前,请对照此列表进行核查。
**审查模式:**如果审计的是现有流水线,而非生成新配置,请反向使用此检查清单——每项未通过的内容都属于发现项。从上到下逐项检查,并报告每项失败及对应的文件和行号。
- SHA 固定:所有第三方操作和镜像都固定到完整提交 SHA 或摘要,而不是可变标签。添加
# vX.Y.Z注释以便阅读。tj-actions、reviewdog 和 Trivy 遭入侵时都使用了可变标签。 - 权限:每个 GitHub Actions 工作流都显式设置
permissions:区块(默认只读)。GitLab:正确限定受保护变量的作用范围。 - 配置中不含机密信息:不硬编码令牌、密码或 API 密钥。使用 CI/CD 机密变量或保险库集成。
- 不使用
latest标签:运行器镜像、工具镜像和基础镜像都固定到特定版本或 SHA256 摘要。 - 缓存策略:正确缓存依赖项(基于锁文件的键);构建输出使用制品,而非缓存。
- 尽早进行安全检查:SAST、依赖项扫描和机密信息检测要尽早运行,而非部署后才运行。
- 生产环境授权:遵守必需的环境审批和仓库部署策略;保留已为此次发布授予的明确授权,但该授权不能豁免必需的环境保护措施。
- 生成 SBOM:发布流水线生成并附加 SBOM(SPDX 或 CycloneDX)。这是有用的清单证据;只有适用的控制措施或策略要求此格式时才是强制要求。
- 最小化范围:作业仅具备所需的最低权限、仅访问必要的机密信息,并且只运行必要的步骤。
- 未经说明,不得使用
allow_failure:如果作业允许失败,请在注释中说明原因。 - 固定工具版本:使用特定版本而非浮动别名——使用
node:22,而不是node:lts;使用python:3.13,而不是python:3。特定版本可避免静默故障;上述 SHA 固定要求仍然适用。 - 限定触发范围:不带分支或路径过滤器的
on: push会在每次推送到所有分支时运行——应限定为branches: [main]和/或使用paths:过滤器。GitLab 也一样:使用带if条件的rules:,而不是裸用only: [pushes]。 - 避免表达式注入(GitHub Actions):不得在
run:区块中直接使用${{ }}表达式。应先赋值给env:。github.event.*由攻击者控制。在安全敏感场景中避免使用github.ref_name(攻击者可通过精心构造的标签或分支名称注入)。 - 公共/不可信仓库上的自托管运行器应为临时运行器:在接受外部 PR 的仓库上使用非临时 Shell 运行器,是自托管运行器遭入侵的首要途径。确认使用了
--ephemeral(GitHub、Gitea),或者在 Forgejo 上确认已验证单作业退出生命周期,并确保每个作业都有全新的主机/容器状态——仅设置容量上限或重启守护进程并不代表运行器是临时的。为外部贡献者添加审批关卡。请参阅references/runners.md。 - Docker 套接字挂载范围:将
/var/run/docker.sock挂载到作业中,会使其获得主机上的 root 权限。仅适用于可信的内部流水线。公共/共享运行器应改用 DinD sidecar 或 rootless buildkit。 - 扫描关卡应设有基线,而非一刀切地阻止:引入容器/IaC/SAST 扫描器时,如果设置
exit-code 1且不允许任何抑制项,最终总会被禁用。应采用references/best-practices.md中的逐步加严模式(先不阻止 → 建立基线 → 仅阻止新增问题)。 - 忽略列表条目应注明到期日期:每个
.trivyignore、.grype.yaml、Dependabotignore或 RenovateignoreDeps条目都应附带注释,注明复查日期和负责人。没有日期 = 僵尸技术债。 - 提交锁文件:应用程序的
package-lock.json、bun.lock、Cargo.lock、go.sum和uv.lock应纳入版本控制。只提交清单文件会破坏可复现性。 - 自动合并应以测试为门槛,而不只是 lint:如果没有覆盖更改部分的测试,Dependabot/Renovate 自动合并就是供应链捷径。
- 检查运行器信任级别:工作流建议应区分托管、自托管、Fork 和受保护分支执行环境。
- 控制可变引用:在供应链风险较高的场景中,固定操作、镜像、包含项和模板的版本。
- 应用跨领域 Agent 卫生规范——请参阅
references/agent-hygiene.md。
性能
- 根据锁文件和工具链版本设置缓存键;避免使用过于宽泛、会还原过期依赖项的缓存。
- 将快速 lint/单元测试检查与耗时较长的集成测试、镜像和部署任务拆分开。
- 使用路径过滤器和矩阵限制,让单体仓库流水线的规模与变更相称。
最佳实践
- 云部署使用 OIDC 或短期联合身份验证,而不是长期静态密钥。
- 除非明确隔离,否则让来自 fork 的拉取请求工作流保持只读。
- 如果代码托管平台支持,为发布制品生成来源信息或证明。
工作流
复制此清单并跟踪进度:
- 步骤 1:已识别平台(或已询问)
- 步骤 2:已选择领域
- 步骤 3:已收集触发条件、构建、测试、部署、合规性和运行器要求
- 步骤 4:已阅读平台参考资料并编写配置
- 步骤 5:lint 检查通过,且 AI 自检通过(失败时返回步骤 4)
步骤 1:识别平台
| 信号 | 平台 |
|---|---|
.github/workflows/*.yml | GitHub Actions |
.gitlab-ci.yml | GitLab CI/CD |
.forgejo/workflows/*.yml | Forgejo Actions |
.gitea/workflows/*.yml | Gitea Actions |
.woodpecker/*.yaml 或 .woodpecker.yaml | Woodpecker(Gitea/Forgejo) |
用户说“work”/“gitlab”/glab | GitLab CI/CD |
用户说“home”/“forgejo”/fj | Forgejo Actions |
| 用户说“gitea” | Gitea Actions(1.20 及更早版本则为 Woodpecker) |
用户说“github”/“ghcr”/gh | GitHub Actions |
如果不明确,请询问。尽管表面相似,这些平台之间存在显著差异。
步骤 2:确定领域
- “为我的项目创建 CI 流水线” -> 工作流设计
- “加固我的流水线”/“固定 Actions 版本” -> 安全
- “使其符合 PCI”/“SBOM” -> 合规性
- “将其从 GitLab 移植到 GitHub” -> 跨平台
步骤 3:收集需求
编写流水线配置前:
- 什么会触发流水线? 推送、PR/MR、标签、计划任务、手动触发
- 要构建什么? 语言、运行时、包管理器、构建工具
- 要测试什么? 单元测试、集成测试、端到端测试、lint、类型检查
- 部署到哪里? K8s、Docker 镜像仓库、云、裸机
- 有哪些合规要求? PCI-DSS、SOC 2、内部政策
- 使用自托管还是托管运行器? 这会影响可用工具和缓存
步骤 4:应用特定平台的模式
阅读相应的参考文件:
- GitHub Actions:
references/github-actions.md - GitLab CI/CD:
references/gitlab-ci.md - Forgejo/Gitea Actions 和 Woodpecker:
references/forgejo-gitea-actions.md - 自托管运行器(全部 5 种实现):
references/runners.md - 最佳实践(依赖项、lint、扫描、审核门禁、发布):
references/best-practices.md - 供应链/合规性:
references/supply-chain.md
对于 Forgejo CI/CD,请从下方 Forgejo 部分的关键差异表开始。
对于用户要求的部署流水线,请涵盖步骤 3 中选定的每个生命周期阶段,并包含明确的部署任务或清晰标注的部署占位符。注明目标环境及其授权/保护要求。将仅包含测试/构建的输出标记为不完整,无法用于部署。仅要求 CI 时,不要添加部署阶段。
步骤 5:验证
对生成的配置运行 lint(GitHub/Forgejo/Gitea Actions 使用 actionlint,GitLab 使用 glab ci lint)。
先检测:command -v actionlint >/dev/null || echo "actionlint missing"。如果 lint 工具或 AI 自检失败,请修复配置并返回步骤 4;重复此过程,直到检查通过。报告任何无法运行的 lint 工具。
actionlint 只会自动发现 .github/workflows;请显式传入 .forgejo/workflows/*.yml 路径。在 actionlint.yaml 的 self-hosted-runner.labels 下声明自定义运行器标签;切勿仅为了通过 lint 而更改 runs-on。
跨平台模式
阶段排序(所有平台)
根据行为变更、依赖项和仓库策略选择阶段;这是排序指南,并非要求每个 PR 都运行所有阶段。从快速的受影响检查开始。
当变更可能影响集成套件的结果时,构建或运行这些套件;将无关的高成本矩阵和发布工作留给适合的定期运行、合并后运行或发布运行。
有关检查选择和有条件的必需门禁,请参阅 references/best-practices.md。
lint -> test -> build -> scan -> deploy
- Lint 首先执行——反馈最快,可尽早发现格式或语法问题
- Test——单元测试、类型检查
- Build——编译、打包、创建构件
- Scan——SAST、依赖项审计、容器扫描(对构建输出进行)
- Deploy——自动部署到暂存环境,手动部署到生产环境
缓存策略
| 内容 | 缓存键 | 平台说明 |
|---|---|---|
| npm/bun | ${{ hashFiles('**/package-lock.json') }} 或 bun.lock | GH:actions/cache。GL:cache:key:files。Forgejo:与 GH 相同。 |
| pip | ${{ hashFiles('**/requirements*.txt') }} | GH:使用 cache: pip 的 setup-python。GL:缓存 ~/.cache/pip。 |
| poetry | ${{ hashFiles('**/poetry.lock') }} | GH:使用 cache: poetry 的 setup-python。GL:缓存 ~/.cache/pypoetry。 |
| uv | ${{ hashFiles('**/uv.lock') }} | GH:astral-sh/setup-uv 内置缓存。GL:缓存 ~/.cache/uv。 |
| Go | ${{ hashFiles('**/go.sum') }} | GH:actions/setup-go 内置缓存。 |
| Docker 层 | BuildKit 缓存挂载或注册表缓存 | GH:--cache-from type=gha。GL:--cache-from $CI_REGISTRY_IMAGE:cache。 |
规则:缓存用于加速,而非保证正确性。构件用于跨作业传递数据。缓存可能随时被清除——流水线必须在没有缓存的情况下也能正常运行。
密钥管理
| 平台 | 机制 | 范围控制 |
|---|---|---|
| GitHub | 仓库/组织/环境密钥 | 按环境、仓库、组织设置。部署分支。 |
| GitLab | CI/CD 变量(项目/群组/实例) | 受保护的分支/标签、环境、日志中脱敏。 |
| Forgejo | 仓库/组织密钥 | 按仓库、组织设置。暂不支持环境范围控制。 |
所有平台:切勿回显密钥,切勿将密钥作为 CLI 参数传递(会显示在 ps 中),也切勿写入构件。使用环境变量或基于文件的注入方式。
凭据生命周期
追踪签发方信任、作业身份、密钥注入、下游权限、轮换和撤销。在获准的非生产作业中测试凭据过期或撤销的情况,并确认日志、缓存和构件中不包含任何凭据值。将配置/状态相关事项交由 terraform 处理,将工作负载刷新/重新加载交由 kubernetes 处理;记录每个边界的负责人。
部署门禁
| 环境 | 触发条件 | 审批 |
|---|---|---|
| 开发/预览 | 相关应用变更或请求预览 | 遵循项目策略 |
| 暂存 | 合并到 main | 无(自动部署) |
| 生产 | 标签或手动触发 | 需要指定审核者 |
GitLab:when: manual + environment:。GitHub:使用保护规则的 environment:。
Forgejo:手动触发(workflow_dispatch)。
Monorepo 模式
当仓库包含多个共用库的服务时:
基于路径的触发
确保必需工作流在每个适用的 PR 中都报告状态;改为在工作流内部对高成本作业设置条件。
有关必需状态挂起陷阱,请参阅 references/best-practices.md。
- GitHub Actions:使用
on.push.paths/on.pull_request.paths,按服务限定工作流范围 - GitLab CI/CD:使用
rules: changes: paths:和compare_to: refs/heads/main - Forgejo:与 GitHub Actions 相同(
on.push.paths)
共享库检测
如果 libs/common/ 发生变更,则重新构建所有依赖它的服务:
- 在矩阵中列出依赖服务,或触发所有服务工作流
paths过滤器接受 glob:paths: ['services/api/**', 'libs/common/**']
选择性构建
只构建发生变更的部分。有两种方法:
- 按服务划分工作流,使用
paths:过滤器(最简单,推荐) - 使用单个工作流搭配矩阵,再添加变更检测任务,输出哪些服务需要构建
规则:共享库发生变更时,始终重新构建。遗漏共享依赖的“无变更”优化,比全部重新构建更糟。
Python 单体仓库的具体做法(GitLab / GitHub / Forgejo)
对于多个服务共用一个通用库(libs/common/)的 Python 单体仓库:
- 缓存解析器的输出,而不是安装步骤。 使用
hashFiles('**/requirements*.txt')或**/poetry.lock/**/uv.lock作为缓存键。使用uv或pip时,缓存~/.cache/uv或~/.cache/pip,并按服务路径和锁文件哈希为每个服务的.venv/设置缓存键。 - 以可编辑模式安装共享库(
pip install -e libs/common),让服务导入仓库内的版本,而不是过时的 wheel。 - 使用路径过滤器,为每个服务限定任务范围。 GitLab:
rules: - changes: paths: ['services/api/**', 'libs/common/**'] compare_to: refs/heads/main。GitHub / Forgejo:on.push.paths/on.pull_request.paths。每个服务的过滤器都要包含libs/common/**,这样共享库发生变更时才能触发所有服务。 - 使用 YAML 锚点(GitLab)/ 可复用工作流(GitHub)定义每个服务的任务模板。 为
api、worker、scheduler编写三个几乎相同的代码块,会给维护带来隐患。
完整的单体仓库 .gitlab-ci.yml(YAML 锚点、compare_to、按服务设置变更规则、共享库检测)请参阅 references/gitlab-ci.md。
Forgejo CI/CD
Forgejo Actions 的设计目标是“熟悉,而非兼容”GitHub Actions。 它沿用工作流语法,但不保证兼容性。
与 GitHub Actions 的主要区别
| 功能 | GitHub Actions | Forgejo Actions |
|---|---|---|
permissions: | 控制 GITHUB_TOKEN 的权限范围 | 不强制执行——令牌始终拥有完整读写权限(fork PR 只读) |
continue-on-error:(任务级) | 允许任务失败而不使工作流失败 | 不支持——仅支持步骤级 |
| 运行器镜像 | 由平台管理的 ubuntu-24.04,包含 200 多种工具 | 自托管,通常使用精简的 Debian / Alpine |
| Action 解析 | actions/checkout@v7 -> github.com | 从 Forgejo 镜像解析(可配置) |
| OIDC | permissions: id-token: write | enable-openid-connect 键 |
| 工作流调用默认值 | 会填充 inputs.<id>.default | 始终为空 |
| 矩阵 + 动态 runs-on | 支持 | 自 v14.0 起支持 |
| LXC 执行 | 不支持 | 支持(Forgejo 专属) |
请阅读 references/forgejo-gitea-actions.md(Forgejo Actions 模式),了解工作流和发布模板、在 Forgejo 镜像上查找 Action SHA、Forgejo 注意事项(TLS、缺少工具、未强制执行 permissions:),以及 fj Actions 管理。
Gitea CI/CD
Gitea 提供两种可行的 CI 路径:Gitea Actions(与 Forgejo Actions 使用相同的 act 引擎,自 Gitea 1.21 起提供)和 Woodpecker CI(独立服务、原生支持容器、由 webhook 驱动)。Drone 已属旧方案——不要开始新的安装。
简单的经验法则:如果你正从 GitHub 迁移,或希望只运行一个服务,请使用 Gitea Actions。如果你需要完善的矩阵构建、缓存原语或更低的资源使用量,请使用 Woodpecker。不要在同一仓库中同时运行两者。
请参阅 references/forgejo-gitea-actions.md,了解:Action SHA 查找、Gitea 与 Forgejo Actions 的区别、Woodpecker YAML 示例、插件与命令步骤、OAuth 设置、矩阵模式,以及 Drone 迁移指南。
PCI-DSS:CI/CD 合规性映射
对于范围内的系统,将控制措施映射到实际要求和评估证据:
| 要求 | CI/CD 的贡献 |
|---|---|
| 6.2.3 | 发布前审查定制/自定义软件;记录覆盖范围和发现项处理方式 |
| 6.3.2 | 维护软件/组件清单;SBOM 可作为支持 |
| 6.5.1 | 记录生产变更的批准、测试、影响和恢复流程 |
工具的存在并不能证明合规。工件签名和 SBOM 格式是有用的控制措施,但并非 PCI 普遍规定的实现方式。有关评估边界和一手来源,请参阅 references/supply-chain.md。
模板约定
@<sha>是 GitHub Actions 模板中的占位符。请将其替换为对应版本的真实 40 位提交 SHA。可在该 Action 的发布页面查找 SHA,或使用 Dependabot 自动管理。- 模板中的镜像标签使用浮动次版本(例如
oven/bun:1.2、docker:29.9),以便于阅读。生产环境中,请固定到具体补丁版本或 SHA256 摘要。模板展示的是最低可接受的粒度,而非理想粒度。
参考文件
references/github-actions.md- GitHub Actions 模式、模板和安全加固references/forgejo-gitea-actions.md- Forgejo Actions 模板、SHA 查找、注意事项和fj;Gitea Actions 的差异、故障排查、Woodpecker 模式和 Drone 迁移指南references/gitlab-ci.md- GitLab CI/CD 19.x 模式、SaaS 与自托管版本的差异、Catalog、Components、安全性references/runners.md- 自托管运行器(actions-runner、gitlab-runner、forgejo-runner、gitea-runner、woodpecker-agent)——安装、注册、执行器选择、Linux 与 macOS、安全加固references/best-practices.md- 依赖更新(Dependabot/Renovate)、分层 lint、扫描矩阵(密钥/SCA/容器/IaC/SAST)、审核关卡、合并队列、推出顺序references/supply-chain.md- 供应链安全、事件时间线、SHA 固定、SBOM/SLSA、PCI-DSS 合规、镜像签名、失陷后响应;关于 slopsquatting、CI/CD 中的 AI Agent 和流水线中的提示词注入,请阅读其中的 AI 时代供应链风险章节references/target-versions.md- Forge、运行器、CI 系统和供应链工具的带日期版本快照
输出约定
完整约定请参阅 references/output-contract.md。
- 技能名称: CI-CD
- 交付物类别:
audits - 模式: 条件式。当用于分析、审查、审计或改进现有仓库内容时,应用
references/output-contract.md中的报告篇幅和证据规则,并将交付物写入docs/local/audits/ci-cd/<YYYY-MM-DD>-<slug>.md。当用于回答问题、讲解概念、构建新工件或生成内容时,可自由作答,无需遵循该约定。 - 严重性级别:
P0 | P1 | P2 | P3 | info(参见共享约定;仅用于审计/审查模式)。
相关技能
- code-review - 审查应用代码的正确性。流水线 YAML、表达式、运行器行为、缓存和部署作业中的错误属于本技能范围。
- security-audit - 用于审计应用代码,而非流水线代码
- docker - 用于优化 Dockerfile 和容器镜像
- kubernetes - 用于流水线部署的 K8s 清单和 Helm chart
- git - 用于触发流水线的 git 操作(提交、PR/MR、标签、发布)。 CI/CD 会响应 git 事件;git 负责执行产生这些事件的操作。
规则
AI 自检涵盖 SHA 固定、配置中的密钥、生产环境授权和扫描顺序;缓存策略和 PCI 部分涵盖缓存与构建产物的区别,以及合规证据。这些内容还包括:
- 平台优先。 编写配置前,务必先确认 CI/CD 平台。适用于 GitHub Actions 的语法在 Forgejo 上即使「大体可用」,也会在边缘情况下悄然出错。
- 密钥不得出现在日志、构建产物和 argv 中。 切勿在不受保护的分支上使用受保护变量;GitLab 在此类分支上会悄然将其留空。
- 测试流水线本身。 对 GitHub Actions 使用
act,对 GitLab 使用gitlab-ci-local,也可以使用平台的试运行模式。不要等到生产环境才发现流水线错误。