repo-hardening

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Repo Hardening: GitHub Security Baseline

仓库加固:GitHub安全基线

Purpose

目的

This skill writes. It changes repository settings, creates rulesets and environments, and adds workflow files. Everything is done with
gh api
from the user's machine — no admin UI clicking. The baseline covers Actions token defaults, security features, immutable releases, a branch protection ruleset, a release tag ruleset, a workflow-linting workflow, and branch-restricted environments for deploy secrets.
audit:security-audit
is the read half of the pair. It detects the same gaps and never mutates anything — no file edit, no
gh api
write. Its findings are this skill's input. Run this skill after an audit, or standalone to set the baseline proactively on a new repo or pipeline. If the user wants gaps listed rather than changes made, that is the skill to use.
Because this skill writes, Step 0 is not optional: inventory first, show the diff, get confirmation, and skip anything already in place. The audit's reference checklists document the why for every item here in more depth, and are worth reading when a user questions an item.
该工具会执行写入操作。 它会修改仓库设置、创建规则集和环境,并添加工作流文件。所有操作均通过用户本地机器上的
gh api
完成——无需在管理UI中手动点击。基线涵盖Actions令牌默认设置、安全功能、不可变发布、分支保护规则集、发布标签规则集、工作流校验工作流,以及用于部署密钥的分支受限环境。
audit:security-audit
是配套的只读工具。它会检测相同的安全缺口,但不会进行任何修改——既不编辑文件,也不执行
gh api
写入操作。它的检测结果是本工具的输入。可在审计后运行本工具,也可主动在新仓库或流水线中独立运行以设置基线。如果用户仅希望列出安全缺口而不进行修改,则应使用该审计工具。
由于本工具会执行写入操作,步骤0是必不可少的:先进行盘点、展示差异、获取确认,跳过已配置完成的项。审计工具的参考清单更深入地说明了此处每一项的设计原因,当用户对某项有疑问时值得一读。

When to Use This Skill

使用场景

Use when the user asks to:
  • "Harden this repo", "secure the repository", "apply security settings"
  • "Protect master/main", "set up rulesets", "protect release tags"
  • "Move deploy secrets to an environment", "lock down the Cloudflare/Vercel/AWS token"
  • "Set up a new repo securely", "bootstrap repo settings"
Do NOT use when the user only wants findings without changes — that is
security-audit
. Org-level policies, SSO, and GitHub Enterprise controls are out of scope.
当用户提出以下需求时使用:
  • "加固此仓库"、"确保仓库安全"、"应用安全设置"
  • "保护master/main分支"、"设置规则集"、"保护发布标签"
  • "将部署密钥迁移到环境中"、"锁定Cloudflare/Vercel/AWS令牌"
  • "安全地设置新仓库"、"初始化仓库设置"
请勿在用户仅希望获取检测结果而不进行修改时使用——此时应使用
security-audit
工具。组织级策略、SSO和GitHub Enterprise控制不在本工具的范围内。

Prerequisites

前提条件

  • gh
    CLI authenticated as a repo admin (
    gh auth status
    ; rulesets, environments, and settings PATCHes all require admin).
  • Resolve the target once:
    gh repo view --json nameWithOwner --jq .nameWithOwner
    .
  • gh
    CLI已以仓库管理员身份认证(运行
    gh auth status
    确认;规则集、环境和设置PATCH操作均需管理员权限)。
  • 先解析目标仓库:
    gh repo view --json nameWithOwner --jq .nameWithOwner

Workflow

工作流程

Step 0: Inventory Before Touching Anything

步骤0:操作前先盘点

Run the read-only sweep and build a diff of already set vs to apply. Never apply blind — existing rulesets or environments may encode deliberate choices, and re-creating them duplicates rules.
bash
gh api repos/<owner>/<repo> --jq '{private, default_branch, security_and_analysis}'
gh api repos/<owner>/<repo>/actions/permissions/workflow
gh api repos/<owner>/<repo>/rulesets --jq '[.[] | {id, name, target, enforcement}]'
gh api repos/<owner>/<repo>/actions/secrets --jq '[.secrets[].name]'
gh api repos/<owner>/<repo>/environments --jq '[.environments[].name]'
gh api repos/<owner>/<repo>/private-vulnerability-reporting
gh api repos/<owner>/<repo>/immutable-releases
ls .github/workflows/ 2>/dev/null
Present the diff and confirm scope with the user before applying (see Asking the User). Skip every step whose target state is already in place, and say so in the final report.
运行只读扫描,构建已配置项与待应用项的差异。绝不能盲目应用——现有规则集或环境可能包含特意配置的规则,重新创建会导致规则重复。
bash
gh api repos/<owner>/<repo> --jq '{private, default_branch, security_and_analysis}'
gh api repos/<owner>/<repo>/actions/permissions/workflow
gh api repos/<owner>/<repo>/rulesets --jq '[.[] | {id, name, target, enforcement}]'
gh api repos/<owner>/<repo>/actions/secrets --jq '[.secrets[].name]'
gh api repos/<owner>/<repo>/environments --jq '[.environments[].name]'
gh api repos/<owner>/<repo>/private-vulnerability-reporting
gh api repos/<owner>/<repo>/immutable-releases
ls .github/workflows/ 2>/dev/null
在应用前向用户展示差异并确认范围(参考向用户提问部分)。跳过所有已处于目标状态的步骤,并在最终报告中说明。

Step 1: Actions Token Defaults

步骤1:Actions令牌默认设置

bash
gh api -X PUT repos/<owner>/<repo>/actions/permissions/workflow \
  -f default_workflow_permissions=read -F can_approve_pull_request_reviews=false
Safe when workflows declare their own
permissions:
blocks (they should — flag any that don't rather than skipping this step).
bash
gh api -X PUT repos/<owner>/<repo>/actions/permissions/workflow \
  -f default_workflow_permissions=read -F can_approve_pull_request_reviews=false
当工作流自行声明
permissions:
块时(理应如此——标记未声明的工作流,而非跳过此步骤),此操作是安全的。

Step 2: Security Features

步骤2:安全功能

bash
gh api -X PATCH repos/<owner>/<repo> --input - <<'EOF'
{"security_and_analysis": {"secret_scanning": {"status": "enabled"}, "secret_scanning_push_protection": {"status": "enabled"}}}
EOF
gh api -X PUT repos/<owner>/<repo>/vulnerability-alerts
gh api -X PUT repos/<owner>/<repo>/automated-security-fixes
gh api -X PUT repos/<owner>/<repo>/private-vulnerability-reporting
gh api -X PATCH repos/<owner>/<repo>/code-scanning/default-setup -f state=configured
Then immutable releases, when the repo publishes GitHub Releases or has a tag-triggered release workflow:
bash
gh api -X PUT repos/<owner>/<repo>/immutable-releases
Once enabled, a published release's tag and assets can no longer be moved or replaced, so swapping content requires a new version number. Two things to tell the user before applying: it is not retroactive (releases published earlier stay mutable), and any release automation that edits or re-uploads assets after publishing will start failing. Revert is
gh api -X DELETE repos/<owner>/<repo>/immutable-releases
.
Plan-related errors (private repo without Advanced Security) are informational — record and continue. If the repo has a
SECURITY.md
, verify the reporting channel it advertises is now actually enabled.
bash
gh api -X PATCH repos/<owner>/<repo> --input - <<'EOF'
{"security_and_analysis": {"secret_scanning": {"status": "enabled"}, "secret_scanning_push_protection": {"status": "enabled"}}}
EOF
gh api -X PUT repos/<owner>/<repo>/vulnerability-alerts
gh api -X PUT repos/<owner>/<repo>/automated-security-fixes
gh api -X PUT repos/<owner>/<repo>/private-vulnerability-reporting
gh api -X PATCH repos/<owner>/<repo>/code-scanning/default-setup -f state=configured
如果仓库发布GitHub Releases或有标签触发的发布工作流,则启用不可变发布:
bash
gh api -X PUT repos/<owner>/<repo>/immutable-releases
启用后,已发布版本的标签和资产将无法移动或替换,修改内容需要使用新版本号。应用前需告知用户两点:该设置不具有追溯性(之前发布的版本仍可修改),任何在发布后编辑或重新上传资产的版本自动化流程将开始失败。如需恢复,可运行
gh api -X DELETE repos/<owner>/<repo>/immutable-releases
与计划相关的错误(无高级安全功能的私有仓库)仅作信息提示——记录后继续执行。如果仓库有
SECURITY.md
文件,需验证其宣传的报告渠道已实际启用。

Step 3: Branch Protection Ruleset

步骤3:分支保护规则集

Template:
assets/ruleset-branch.json
. Fill in the required status checks from a recent green run — check names must match exactly as GitHub reports them, including expanded matrix legs:
bash
gh api "repos/<owner>/<repo>/commits/$(git rev-parse origin/<default-branch>)/check-runs?per_page=50" \
  --jq '[.check_runs[].name] | unique'
Exclude non-blocking checks (benchmarks, deploys) from the required list. Then:
bash
gh api -X POST repos/<owner>/<repo>/rulesets --input ruleset-branch.json
Decisions baked into the template (adjust per answers from Asking the User):
  • ~DEFAULT_BRANCH
    targets the default branch without hardcoding its name.
  • Bypass actor
    {"actor_id": 5, "actor_type": "RepositoryRole", "bypass_mode": "always"}
    is Repository Admin — right for a solo maintainer (never blocked, while a leaked non-admin token or Actions token still is). For teams, drop the bypass and set
    required_approving_review_count
    to 1+.
  • Warn the user: matrix check names are verbatim — reshaping the CI matrix requires a matching ruleset update, or merges block (admin bypass still works).
模板:
assets/ruleset-branch.json
。从最近一次成功运行中填写所需的状态检查——检查名称必须与GitHub报告的完全一致,包括展开的矩阵分支:
bash
gh api "repos/<owner>/<repo>/commits/$(git rev-parse origin/<default-branch>)/check-runs?per_page=50" \
  --jq '[.check_runs[].name] | unique'
将非阻塞检查(基准测试、部署)从必填列表中排除。然后执行:
bash
gh api -X POST repos/<owner>/<repo>/rulesets --input ruleset-branch.json
模板中内置的决策(可根据用户回答调整):
  • ~DEFAULT_BRANCH
    无需硬编码名称即可定位默认分支。
  • 绕过角色
    {"actor_id": 5, "actor_type": "RepositoryRole", "bypass_mode": "always"}
    为仓库管理员——适合单人维护者(永远不会被阻止,而泄露的非管理员令牌或Actions令牌仍会被阻止)。对于团队,可移除绕过设置并将
    required_approving_review_count
    设为1或更高。
  • 提醒用户:矩阵检查名称是精确匹配的——调整CI矩阵需要同步更新规则集,否则会阻止合并(管理员绕过仍可生效)。

Step 4: Release Tag Ruleset

步骤4:发布标签规则集

Apply when a workflow triggers on tag push (
on.push.tags
), or when the user plans one. With a tag-triggered publish, tag creation is effectively "publish" — this ruleset is the single most important control in the file.
Template:
assets/ruleset-tag.json
(restricts
creation
,
update
,
deletion
,
non_fast_forward
on
refs/tags/v*
to the bypass actors).
bash
gh api -X POST repos/<owner>/<repo>/rulesets --input ruleset-tag.json
The user's local
git tag && git push
flow keeps working through the admin bypass; the Actions token and non-admin credentials cannot mint release tags.
当工作流在标签推送时触发(
on.push.tags
),或用户计划配置此类工作流时应用此规则集。对于标签触发的发布,标签创建相当于“发布”——此规则集是本文件中最重要的控制项。
模板:
assets/ruleset-tag.json
(限制
refs/tags/v*
creation
update
deletion
non_fast_forward
操作仅允许绕过角色执行)。
bash
gh api -X POST repos/<owner>/<repo>/rulesets --input ruleset-tag.json
用户本地的
git tag && git push
流程可通过管理员绕过正常工作;Actions令牌和非管理员凭证无法创建发布标签。

Step 5: Deploy Secrets into a Branch-Restricted Environment

步骤5:将部署密钥迁移到分支受限环境

Applies when Step 0 found deploy-provider credentials (
CLOUDFLARE_*
,
VERCEL_*
,
AWS_*
,
NETLIFY_*
,
FLY_*
, …) as repository-level secrets. Why this is critical: a push-triggered workflow executes the workflow file from the pushed ref, so any branch push can rewrite it to use repo-level secrets — including deploying that branch over production.
Order matters; follow exactly:
  1. Create the environment before any workflow references it (a workflow run naming a nonexistent environment auto-creates it unprotected):
bash
gh api -X PUT repos/<owner>/<repo>/environments/<env-name> --input - <<'EOF'
{"deployment_branch_policy": {"protected_branches": false, "custom_branch_policies": true}}
EOF
gh api -X POST repos/<owner>/<repo>/environments/<env-name>/deployment-branch-policies \
  -f name=<default-branch> -f type=branch
  1. Secret values are write-only — they cannot be copied via API. Have the user re-enter them in their own terminal (never paste values into the conversation):
    gh secret set <NAME> --env <env-name> -R <owner>/<repo>
  2. Update the deploy workflow: split an uncredentialed
    build
    job (all branches) from a
    deploy
    job with
    environment: <env-name>
    , gated by
    if: github.ref == 'refs/heads/<default-branch>'
    , consuming the build artifact.
  3. Only after the workflow change is pushed and env secrets confirmed, delete the repo-level copies:
    gh secret delete <NAME> -R <owner>/<repo>
    . The hole stays open until they are gone.
Tell the user the cost up front: branch preview deploys stop working. Restoring them safely needs a second provider project with its own scoped token in a separate unprotected environment.
当步骤0检测到仓库级别的部署提供商凭证(
CLOUDFLARE_*
VERCEL_*
AWS_*
NETLIFY_*
FLY_*
等)时应用此步骤。这一点至关重要的原因是:推送触发的工作流会执行推送分支中的工作流文件,因此任何分支推送都可重写工作流以使用仓库级密钥——包括将该分支部署到生产环境。
顺序至关重要,请严格遵循:
  1. 先创建环境,再让任何工作流引用它(工作流运行时引用不存在的环境会自动创建一个未受保护的环境):
bash
gh api -X PUT repos/<owner>/<repo>/environments/<env-name> --input - <<'EOF'
{"deployment_branch_policy": {"protected_branches": false, "custom_branch_policies": true}}
EOF
gh api -X POST repos/<owner>/<repo>/environments/<env-name>/deployment-branch-policies \
  -f name=<default-branch> -f type=branch
  1. 密钥值是仅可写入的——无法通过API复制。请让用户在自己的终端中重新输入(切勿在对话中粘贴值):
    gh secret set <NAME> --env <env-name> -R <owner>/<repo>
  2. 更新部署工作流:将无凭证的
    build
    任务(所有分支)与带有
    environment: <env-name>
    deploy
    任务分离,通过
    if: github.ref == 'refs/heads/<default-branch>'
    进行限制,并使用构建产物。
  3. 仅在工作流变更推送完成且环境密钥确认无误后,删除仓库级副本:
    gh secret delete <NAME> -R <owner>/<repo>
    。在删除之前,安全漏洞仍然存在。
提前告知用户此操作的影响:分支预览部署将停止工作。如需安全恢复预览部署,需要第二个提供商项目,并在单独的未受保护环境中使用其自身的范围令牌。

Step 6: Keep Workflows Linted

步骤6:保持工作流合规

Applies when
.github/workflows/
exists. The rulesets and settings above are enforced by GitHub; the workflow files themselves are not, so nothing stops the next PR from reintroducing a tag-pinned
uses:
or a
pull_request_target
that checks out PR code.
Clear the existing findings first — do not add a check that fails on day one:
bash
docker run --rm -t -v "$(pwd):/repo:ro" ghcr.io/zizmorcore/zizmor:latest /repo/.github/workflows
If Docker is unavailable, ask the user to run it and paste the output. Fix what it reports, re-run until clean, then add
.github/workflows/check-workflows.yml
:
yaml
name: Lint CI workflows
on:
  push:
    branches: ['<default-branch>']
  pull_request:
    branches: ['**']
jobs:
  zizmor:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      actions: read
    steps:
      - uses: actions/checkout@<sha>
        with:
          persist-credentials: false
      - uses: zizmorcore/zizmor-action@<sha>
        with:
          advanced-security: false
Resolve both
<sha>
values to real 40-char commit SHAs before writing the file — a workflow-linting workflow that is itself tag-pinned will fail its own check. Set
advanced-security: false
unless the repo has GitHub Advanced Security, or the SARIF upload step errors.
If Step 3 added
required_status_checks
, decide with the user whether
Lint CI workflows
joins the required list. Adding it means a linter regression blocks merges; leaving it out means the check is advisory. Either is defensible — but if it goes in the ruleset, the check name must match the workflow's
name:
exactly, or every PR blocks permanently.
Two related items this does not cover, because neither is a
gh api
write:
  • Stale branches still carrying pre-hardening workflow files. Old refs are reachable by
    workflow_dispatch
    and by
    push:
    filters that match them, and the Nx compromise ran through a workflow version already fixed on the default branch. List them and let the user decide:
    bash
    git branch -r --format='%(refname:short) %(committerdate:short)' | grep -v HEAD
    Deleting someone's branch is not this skill's call — report and ask.
  • sha_pinning_required
    (Actions setting). Flip it only once zizmor reports every
    uses:
    SHA-pinned; enabling it earlier breaks every workflow run. See Common Mistakes.
.github/workflows/
目录存在时应用此步骤。上述规则集和设置由GitHub强制执行,但工作流文件本身不受此限制,因此后续PR仍可能重新引入标签固定的
uses:
或拉取PR代码的
pull_request_target
先清除现有问题——不要添加一个第一天就失败的检查:
bash
docker run --rm -t -v "$(pwd):/repo:ro" ghcr.io/zizmorcore/zizmor:latest /repo/.github/workflows
如果无法使用Docker,请让用户运行此命令并粘贴输出。修复报告的问题,重新运行直到无问题,然后添加
.github/workflows/check-workflows.yml
yaml
name: Lint CI workflows
on:
  push:
    branches: ['<default-branch>']
  pull_request:
    branches: ['**']
jobs:
  zizmor:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      actions: read
    steps:
      - uses: actions/checkout@<sha>
        with:
          persist-credentials: false
      - uses: zizmorcore/zizmor-action@<sha>
        with:
          advanced-security: false
在写入文件前,将两个
<sha>
值替换为真实的40位提交SHA——如果工作流校验工作流自身使用标签固定,会无法通过自身的校验。除非仓库拥有GitHub Advanced Security(否则SARIF上传步骤会报错),否则设置
advanced-security: false
如果步骤3添加了
required_status_checks
,请与用户决定是否将
Lint CI workflows
加入必填列表。加入意味着校验器回归会阻止合并;不加入则表示该检查仅作参考。两种选择都合理——但如果加入规则集,检查名称必须与工作流的
name:
完全一致,否则所有PR都会被永久阻止。
本步骤不涵盖以下两项内容,因为它们无法通过
gh api
写入:
  • 陈旧分支仍带有加固前的工作流文件。旧分支可通过
    workflow_dispatch
    和匹配它们的
    push:
    过滤器被访问,Nx漏洞事件就是通过默认分支已修复的旧版本工作流触发的。列出这些分支并让用户决定:
    bash
    git branch -r --format='%(refname:short) %(committerdate:short)' | grep -v HEAD
    本工具不会擅自删除用户的分支——仅作报告并询问用户。
  • sha_pinning_required
    (Actions设置)。仅当zizmor报告所有
    uses:
    均已固定SHA后再启用;提前启用会导致所有工作流运行失败。参考常见错误部分。

Step 7: Manual Items — Report, Don't Skip Silently

步骤7:手动项——报告,切勿静默跳过

These cannot be done via
gh
; list them for the user in the final report:
  • npm (when the repo publishes packages), at
    https://www.npmjs.com/package/<name>/access
    — give the user the resolved URL, one per public package in a monorepo, not a generic "your package settings":
    • Trusted Publisher pinned to the exact
      owner/repo
      + release workflow filename.
    • Enable only "Allow npm stage publish", so a plain
      npm publish
      from that workflow is rejected and every release has to pass through a maintainer's 2FA approval (
      npm stage approve <stage-id>
      , or Staged Packages on npmjs.com). This is the control a fully compromised CI job cannot forge — the workflow holds a legitimate OIDC identity, and staging is what stops that identity from being enough. It only binds if it is set registry-side; the workflow using
      npm stage publish
      without this restriction is a convention, not a control.
    • Publishing access set to require 2FA and disallow bypass tokens once OIDC is the only publish path. Warn first: this revokes existing tokens, so any other automation publishing with a token breaks.
    • Requires npm CLI >= 11.15.0 and Node >= 22.14.0 in the release workflow. Check the workflow's
      node-version
      before recommending the switch.
  • Provider token scope: the deploy token itself should be least-privilege (e.g. Cloudflare: only
    Account · Cloudflare Pages · Edit
    ). Verified in the provider dashboard, not the repo.
这些操作无法通过
gh
完成,请在最终报告中为用户列出:
  • npm(当仓库发布包时),访问
    https://www.npmjs.com/package/<name>/access
    ——为用户提供解析后的URL,单仓库中的每个公共包对应一个URL,而非通用的“你的包设置”:
    • 受信任发布者固定到精确的
      owner/repo
      + 发布工作流文件名。
    • 仅启用“Allow npm stage publish”,这样工作流中的普通
      npm publish
      会被拒绝,每个版本都必须经过维护者的2FA审批(
      npm stage approve <stage-id>
      ,或在npmjs.com的Staged Packages中操作)。这是完全被攻陷的CI作业无法伪造的控制项——工作流持有合法的OIDC身份,而预发布环节可阻止仅凭该身份完成发布。只有在注册表端设置后,此控制才生效;工作流使用
      npm stage publish
      但未设置此限制只是一种约定,而非控制项。
    • 一旦OIDC是唯一的发布路径,将发布访问权限设置为要求2FA并禁止绕过令牌。提前警告:这会撤销现有令牌,因此任何使用令牌发布的其他自动化流程都会失效。
    • 发布工作流中需要npm CLI >= 11.15.0和Node >= 22.14.0。在推荐切换前检查工作流的
      node-version
  • 提供商令牌范围:部署令牌本身应遵循最小权限原则(例如Cloudflare:仅
    Account · Cloudflare Pages · Edit
    )。需在提供商控制台中验证,而非仓库中。

Step 8: Report

步骤8:报告

End with a compact table: each baseline item →
applied
/
already set
/
skipped (reason)
/
manual (user)
. Include the exact commands for anything deferred.
以简洁表格结尾:每个基线项 →
已应用
/
已配置
/
已跳过(原因)
/
手动操作(需用户完成)
。为所有延迟执行的操作包含精确命令。

Asking the User

向用户提问

Every question in this skill is written as
AskUserQuestion
options. Use that tool where the host offers it, or the host's nearest structured-choice equivalent. Where the host has neither, ask the same question in normal chat as a numbered list of 2–5 options — recommended first, one short line of description each — and wait for the user to reply with a number.
Before applying (after Step 0's inventory), confirm scope in one round:
  1. Ruleset strictness — Solo (admin bypass, 0 approvals; recommended for single-maintainer repos) / Team (no bypass, 1+ approvals) / Skip rulesets.
  2. Deploy secrets — Migrate to environment now (recommended; previews break) / Leave at repo level (records a critical finding in the report).
  3. Immutable releases — Enable (recommended; not retroactive, and breaks automation that re-uploads release assets) / Skip. Ask only when Step 0 found releases or a tag-triggered workflow.
Required status checks and the environment name are derived from the repo (CI run check names; provider name like
cloudflare-production
) — state them in the confirmation rather than asking. Same for the workflow linter in Step 6: apply it if
.github/workflows/
exists, and raise the required-check decision there rather than in this round.
Keep it to one round. If the repo has no deploy secrets and no releases, questions 2 and 3 drop and only ruleset strictness is asked.
本工具中的所有问题均以
AskUserQuestion
选项形式编写。如果宿主提供该工具,请使用它;否则使用宿主最接近的结构化选择等效工具。如果宿主均不提供,请在普通聊天中以编号列表(2-5个选项)的形式提出相同问题——推荐选项放在首位,每个选项配一行简短描述——等待用户回复编号。
应用前(步骤0盘点后),通过一轮确认范围:
  1. 规则集严格程度 — 单人模式(管理员绕过,0个审批;推荐单人维护仓库使用)/ 团队模式(无绕过,1个及以上审批)/ 跳过规则集。
  2. 部署密钥 — 立即迁移到环境(推荐;预览部署会失效)/ 保留在仓库级别(在报告中记录为严重安全缺口)。
  3. 不可变发布 — 启用(推荐;不具有追溯性,会中断重新上传版本资产的自动化流程)/ 跳过。仅当步骤0检测到版本或标签触发的工作流时提问。
必填状态检查和环境名称由仓库派生(CI运行检查名称;提供商名称如
cloudflare-production
)——在确认时告知用户,无需提问。步骤6中的工作流校验器同理:如果
.github/workflows/
目录存在则应用,在该步骤中决定是否加入必填检查,而非在此轮提问中。
将提问控制在一轮内。如果仓库没有部署密钥和版本,则跳过问题2和3,仅询问规则集严格程度。

Common Mistakes

常见错误

  • Creating the environment after the workflow references it — GitHub auto-creates it unprotected and the branch policy silently never exists.
  • Deleting repo-level secrets before the environment migration is complete — breaks deploys; doing it in the right order but stopping halfway leaves the hole open.
  • Copying check names from workflow YAML instead of a real run — matrix names in YAML are templates (
    ${{ matrix.node-version }}
    ); rulesets need the expanded names.
  • Adding a
    pull_request
    rule with
    required_approving_review_count: 1
    on a solo repo without a bypass
    — the maintainer can never merge; nobody else can approve.
  • Enabling
    sha_pinning_required
    while workflows still use tag refs
    — every workflow run fails until all
    uses:
    entries are SHA-pinned. Pin first, then flip.
  • Adding the workflow-linting workflow before clearing its findings — the first run fails and the user's impression is that the hardening broke CI. Run it locally, fix, then commit the workflow.
  • Tag-pinning the linter's own actions — a
    check-workflows.yml
    using
    @v1
    fails its own SHA-pinning rule. Resolve real SHAs before writing the file.
  • Enabling immutable releases without saying it is not retroactive — the user assumes old releases are sealed too. They are not, and a repo with a long release history keeps that exposure on every version published before the flip.
  • Deleting a stale branch on the user's behalf — report the list and let them decide. A branch that looks abandoned may be someone's long-running work.
  • 在工作流引用环境后才创建环境 — GitHub会自动创建一个未受保护的环境,分支策略将无声无息地失效。
  • 完成环境迁移前删除仓库级密钥 — 会中断部署;即使顺序正确但中途停止,安全漏洞仍会存在。
  • 从工作流YAML中复制检查名称而非真实运行记录 — YAML中的矩阵名称是模板(
    ${{ matrix.node-version }}
    );规则集需要展开后的名称。
  • 在单人仓库中添加带有
    required_approving_review_count: 1
    pull_request
    规则且无绕过设置
    — 维护者永远无法合并;其他人无法审批。
  • 当工作流仍使用标签引用时启用
    sha_pinning_required
    — 所有工作流运行都会失败,直到所有
    uses:
    项都固定SHA。先固定SHA,再启用该设置。
  • 在清除工作流校验器的现有问题前就添加该工作流 — 首次运行会失败,用户会认为加固操作破坏了CI。先在本地运行、修复问题,再提交工作流。
  • 为校验器自身的操作使用标签固定 — 使用
    @v1
    check-workflows.yml
    会无法通过自身的SHA固定规则。写入文件前先替换为真实SHA。
  • 启用不可变发布但未告知用户该设置不具有追溯性 — 用户会误以为旧版本也被密封。实际并非如此,具有长期版本历史的仓库会在启用前发布的所有版本中保留该风险。
  • 擅自为用户删除陈旧分支 — 列出分支并让用户决定。看似已废弃的分支可能是某人正在进行的长期工作。