ci-audit

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

CI Audit (GitHub Actions)

CI 审核(GitHub Actions)

Audit the workflows in
.github/workflows/
for wall clock, spend, and whether the gating actually gates. This skill reads and reports; it never edits a workflow.
Scoped to GitHub Actions deliberately. The checks below are about Actions' own semantics — skipped results counting as passing, matrix legs in check names,
concurrency
groups, artifact retention — and none of it transfers to another CI system. On a repository with no
.github/workflows/
, say so and stop rather than guessing at a Jenkinsfile or a
.gitlab-ci.yml
.
审核
.github/workflows/
中的工作流,检查耗时、成本开销以及门控是否真正起到拦截作用。本技能仅读取和报告信息;绝不编辑工作流。
专门针对GitHub Actions设计。以下检查均围绕Actions自身的语义展开——跳过的结果计为通过、检查名称中的矩阵分支、
concurrency
组、制品留存等——这些内容无法迁移到其他CI系统。如果仓库中没有
.github/workflows/
,则直接说明并终止操作,无需猜测是否存在Jenkinsfile或
.gitlab-ci.yml

What this owns, and what it does not

本技能的职责范围

security-audit
has its own GitHub Actions auditor and the two overlap on the same files. The split is by consequence, and it is stated in both skills:
This skill
security-audit
Performance, spend, and gating correctnessThe security surface
Cache hit rate — key derivation, fallbacksCache poisoning and cross-branch scope
Whether a required check can fail the runWhether a workflow can be made to run attacker code
Job graph, matrix design, artifact flow
permissions:
,
persist-credentials
,
pull_request_target
, OIDC
Action pinning: SHA vs tag vs branch, with severities
Two consequences worth stating plainly. Do not report action pinning — it looks like a maintenance finding and is a supply-chain one,
security-audit
grades it, and duplicating it here produces two different severities for one line of YAML. And when a required check name matches no workflow, report the observation and hand it over: reconciling rulesets against triggers needs the
gh api
calls that skill already makes.
security-audit
拥有独立的GitHub Actions审核功能,与本技能在文件层面存在重叠。两者的划分依据是影响后果,且在两个技能中均有明确说明:
本技能
security-audit
性能、成本开销与门控正确性安全面
缓存命中率——键值推导、降级策略缓存投毒与跨分支作用域
必填检查是否能终止流水线运行工作流是否可被攻击者利用执行恶意代码
作业图、矩阵设计、制品流转
permissions:
persist-credentials
pull_request_target
、OIDC
Action版本固定:SHA、标签、分支对比及风险等级
有两个需要明确说明的影响后果。请勿报告Action版本固定问题——这属于供应链安全范畴,由
security-audit
负责评估,若在此处重复报告,会导致同一行YAML出现两种不同的风险等级。当必填检查名称与任何工作流不匹配时,只需报告该观察结果并移交处理:规则集与触发器的协调需要
security-audit
已实现的
gh api
调用逻辑。

When to use

使用场景

  • "Audit my CI", "review the workflows", "why is CI slow"
  • "Cut our Actions minutes", "parallelize the pipeline"
  • "Fix caching in CI", "the cache never hits"
  • "Why did that merge when the tests failed" — gating correctness, family A
Trigger phrases:
ci audit
,
github actions
,
workflow performance
,
actions minutes
,
ci slow
,
parallelize ci
,
ci caching
,
required check
.
  • "审核我的CI"、"评审工作流"、"为什么CI这么慢"
  • "减少Actions分钟数"、"并行化流水线"
  • "修复CI缓存问题"、"缓存从未命中"
  • "为什么测试失败了还能合并"——门控正确性,属于A类检查
触发短语:
ci audit
github actions
workflow performance
actions minutes
ci slow
parallelize ci
ci caching
required check

Phase 1: Inventory

阶段1:盘点

Glob
.github/workflows/*.yml
and
.github/workflows/*.yaml
. An empty result — the directory is missing, or holds no YAML — means print
No GitHub Actions workflows found.
and stop.
Use globbing rather than shelling out.
fd
is not guaranteed present, and it exits non-zero with
Search path is not a directory
when
.github/workflows/
is absent, so a bare
fd
returns an error where the stop condition expects an empty result. Where a shell is preferred anyway, guard it:
bash
[ -d .github/workflows ] && ls .github/workflows/*.y*ml 2>/dev/null
For each workflow, extract the shape before reading any step. The job graph is what most findings are about, and it is not legible by reading top to bottom:
bash
yq -r '.jobs | to_entries | map(.key + " <- " + ((.value.needs // []) | tostring)) | .[]' <file>
yq -r '[.on | keys | join(",")] | join("")' <file>
yq -r '.concurrency // "none"' <file>
Record per workflow: triggers, the
concurrency
block, the
needs
graph, which jobs carry a
strategy.matrix
, which have
timeout-minutes
, and which upload or download artifacts.
Then state the critical path — the longest chain through the graph — because that is the number any parallelization finding has to move. Splitting a job that is not on it changes nothing.
Where the run history is available, get real numbers rather than guessing which job is slow:
bash
gh run list --workflow <file> --limit 20 --json databaseId,conclusion,createdAt,updatedAt
gh run view <id> --json jobs --jq '.jobs[] | "\(.name) \(.startedAt) \(.completedAt) \(.conclusion)"'
Say whether timings are measured or estimated. An estimated saving stated as a measured one is the fastest way to lose an audit's credibility.
遍历
.github/workflows/*.yml
.github/workflows/*.yaml
文件。如果结果为空——目录不存在或没有YAML文件——则输出
No GitHub Actions workflows found.
并终止操作。
使用遍历逻辑而非调用shell命令。
fd
工具并非一定存在,且当
.github/workflows/
不存在时会返回
Search path is not a directory
的非零退出码,直接使用
fd
会在终止条件需要空结果时返回错误。如果偏好使用shell命令,请添加保护逻辑:
bash
[ -d .github/workflows ] && ls .github/workflows/*.y*ml 2>/dev/null
对于每个工作流,在读取任何步骤之前先提取其结构。作业图是大多数问题的核心,无法通过自上而下阅读来理解:
bash
yq -r '.jobs | to_entries | map(.key + " <- " + ((.value.needs // []) | tostring)) | .[]' <file>
yq -r '[.on | keys | join(",")] | join("")' <file>
yq -r '.concurrency // "none"' <file>
记录每个工作流的以下信息:触发器、
concurrency
块、
needs
依赖图、包含
strategy.matrix
的作业、设置了
timeout-minutes
的作业,以及上传或下载制品的作业。
然后明确关键路径——依赖图中最长的执行链——因为任何并行化优化都需要针对这条路径。拆分不在关键路径上的作业不会带来任何改变。
如果运行历史可用,则获取真实数据而非猜测哪个作业较慢:
bash
gh run list --workflow <file> --limit 20 --json databaseId,conclusion,createdAt,updatedAt
gh run view <id> --json jobs --jq '.jobs[] | "\(.name) \(.startedAt) \(.completedAt) \(.conclusion)"'
说明耗时是实测值还是估算值。将估算的节省时间表述为实测值会最快失去审核的可信度。

Phase 2: Run the catalog

阶段2:执行检查清单

Read
references/checks.md
and work the four families. Each check there carries what to look for, the cost when it is wrong, and the shape that fixes it.
FamilyCovers
A. Gating correctnessMatrix jobs with no stable fan-in gate, jobs that cannot fail the run, gates on noisy signals, required names nothing produces
B. Critical pathSerialized independent steps, no cheap head gate, expensive jobs on every event, setup repeated instead of artifacts consumed, push and pull-request double runs
C. CachingKeys not derived from the lockfile, missing
restore-keys
, redundant or broken auto-caches, caching what is cheaper to rebuild
D. Spend and hygieneMissing
timeout-minutes
, default artifact retention, diagnostics uploaded unconditionally, no
concurrency
group,
cancel-in-progress
on irreversible work, needless full history, fixed sleeps
Family A first. A pipeline that is fast and gates nothing is worse than a slow one, and these findings fail green — nobody notices them from the run list.
Two rules on severity:
  • Rate by consequence, not by how odd the YAML looks. A missing
    timeout-minutes
    on a job that reliably finishes in 40 seconds is a low finding; the same gap on a job that can hang on a dev server is the one that burns six hours.
  • A finding needs the number it moves. "Split these jobs" is not a finding. "These three steps are independent and sit on the critical path; splitting them removes ~90s from every run" is. Where the number cannot be established, say it is an estimate.
Recognise what is already right. A workflow doing the non-obvious things well — a fan-in gate with
if: always()
,
cancel-in-progress: false
on the release, an unprivileged job producing the artifact a privileged one consumes — should be told so, in one line each. It is how the report earns the right to be believed about the rest.
读取
references/checks.md
并执行四类检查。每个检查都包含检查内容、问题带来的影响以及修复方案。
类别涵盖范围
A. 门控正确性无稳定聚合门控的矩阵作业、无法终止流水线的作业、基于噪声信号的门控、无对应工作流的必填检查名称
B. 关键路径串行执行的独立步骤、无轻量前置门控、每次事件都运行的高成本作业、重复执行的初始化步骤而非复用制品、推送和拉取请求重复运行
C. 缓存未基于锁文件生成的缓存键、缺失
restore-keys
、冗余或失效的自动缓存、缓存重建成本更低的内容
D. 成本开销与卫生性缺失
timeout-minutes
、默认制品留存策略、无条件上传诊断信息、无
concurrency
组、不可逆工作设置
cancel-in-progress
、不必要的完整历史记录、固定时长的休眠
优先执行A类检查。一个速度快但无有效门控的流水线比慢流水线更糟糕,这类问题会导致流水线“伪成功”——从运行列表中无法察觉。
关于严重程度的两条规则:
  • 根据影响后果评级,而非YAML的怪异程度。一个能稳定在40秒内完成的作业缺失
    timeout-minutes
    属于低风险问题;而一个可能在开发服务器上挂起的作业存在同样的问题,则会导致6小时的资源浪费,属于高风险。
  • 每个问题都需要明确影响的量化值。“拆分这些作业”不是有效的问题描述。“这三个独立步骤位于关键路径上;拆分它们可将每次运行的耗时减少约90秒”才是有效的描述。如果无法确定量化值,请说明是估算值。
认可已有的正确实践。如果工作流在一些非显而易见的方面做得很好——比如设置了
if: always()
的聚合门控、发布作业设置
cancel-in-progress: false
、非特权作业生成制品供特权作业使用——应在报告中用单独一行指出。这能让报告的其余内容更具可信度。

Phase 3: Report

阶段3:生成报告

undefined
undefined

CI audit: <N> workflows, <J> jobs · critical path <T> (measured|estimated)

CI 审核:<N> 个工作流,<J> 个作业 · 关键路径耗时 <T>(实测/估算)

Gating correctness

门控正确性

<finding: what is wrong, what it lets through, the shape that fixes it>
<问题描述:存在的问题、带来的影响、修复方案>

Critical path

关键路径

<finding, with the time it moves>
<问题描述,包含影响的耗时变化>

Caching

缓存

<finding>
<问题描述>

Spend and hygiene

成本开销与卫生性

<finding>
<问题描述>

Already right

已有的正确实践

  • <one line per non-obvious thing the workflows get right>
  • <每条非显而易见的正确实践单独一行>

Handed to security-audit

移交至security-audit

  • <required-check reconciliation, or anything touching the security surface>

Drop any section with no findings. Do not pad a clean result — a workflow set with nothing wrong is a
real outcome, and `Already right` carries it.

`references/ci-template.yaml` is an optimized pnpm workflow with parallel jobs, path filters and
concurrency control; `references/ci-template-vp.yaml` is the Vite+ (`voidzero-dev/setup-vp`) variant.
Offer them when a repository is starting from nothing, not as a target to converge every pipeline on.
  • <必填检查协调问题,或任何涉及安全面的内容>

删除没有问题的章节。不要为无问题的结果凑内容——工作流完全没有问题是真实的结果,“已有的正确实践”部分可以支撑这份结论。

`references/ci-template.yaml`是经过优化的pnpm工作流,包含并行作业、路径过滤和并发控制;`references/ci-template-vp.yaml`是Vite+(`voidzero-dev/setup-vp`)的变体。当仓库从零开始搭建CI时可以推荐这些模板,但不要将其作为所有流水线的统一目标。

Rules

规则

  • Read and report. Never edit a workflow. Findings are for the maintainer to apply.
  • Gating correctness before speed. A faster pipeline that checks less is a regression.
  • No finding without a consequence. Name what it costs or what it lets through.
  • Measured or estimated, always stated. Never present an estimate as a measurement.
  • Stay off the security surface. Pinning,
    permissions:
    , and trigger safety belong to
    security-audit
    . Report the boundary crossing, not the verdict.
  • Do not recommend splitting a unified check command without establishing that the toolchain does not already parallelize internally.
  • 仅读取和报告,绝不编辑工作流。问题修复由维护者自行处理。
  • 优先保证门控正确性,再优化速度。更快但检查更少的流水线是一种倒退。
  • 无影响后果的内容不列为问题。明确说明问题带来的成本或风险。
  • 始终标注是实测值还是估算值。绝不将估算值表述为实测值。
  • 不涉及安全面内容。版本固定、
    permissions:
    和触发器安全性属于
    security-audit
    的职责范围。仅报告跨边界的内容,不给出评估结论。
  • 在未确认工具链未内置并行化的情况下,不建议拆分统一的检查命令

Error handling

错误处理

SituationAction
No
.github/workflows/
Print
No GitHub Actions workflows found.
and stop
.github/workflows/
exists but holds no YAML
Same message. A directory with only a README is not a pipeline
Workflows exist but only
workflow_dispatch
Audit them, and say nothing runs automatically
A workflow fails to parseReport the parse error as the first finding and audit the rest
yq
unavailable
Read the YAML directly, and say the job graph was derived by reading
gh
unavailable or no run history
Audit statically, and mark every timing an estimate
A reusable workflow (
uses:
at job level)
Audit the caller's graph; say the callee was not read unless it is in this repository
A composite action in the repositoryRead it — its steps are on the critical path too
Only one job, doing everythingStill audit families A, C and D. A single job is not automatically wrong
场景操作
.github/workflows/
目录
输出
No GitHub Actions workflows found.
并终止
.github/workflows/
目录存在但无YAML文件
输出相同信息。仅包含README的目录不算流水线
工作流仅设置
workflow_dispatch
正常审核,并说明无自动运行的流水线
工作流解析失败将解析错误作为第一个问题报告,继续审核其余工作流
yq
工具不可用
直接读取YAML文件,并说明作业图是通过阅读推导得出
gh
工具不可用或无运行历史
执行静态审核,并将所有耗时标记为估算值
可复用工作流(作业级
uses:
审核调用方的依赖图;仅当被调用方在当前仓库时才读取其内容
仓库内的复合Action读取其内容——其步骤也属于关键路径的一部分
仅包含一个作业,执行所有任务仍需审核A、C、D类检查。单个作业并非一定存在问题