repo-hardening
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseRepo 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 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.
gh apiaudit:security-auditgh apiBecause 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.
该工具会执行写入操作。 它会修改仓库设置、创建规则集和环境,并添加工作流文件。所有操作均通过用户本地机器上的完成——无需在管理UI中手动点击。基线涵盖Actions令牌默认设置、安全功能、不可变发布、分支保护规则集、发布标签规则集、工作流校验工作流,以及用于部署密钥的分支受限环境。
gh apiaudit:security-auditgh 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 .
Org-level policies, SSO, and GitHub Enterprise controls are out of scope.
security-audit当用户提出以下需求时使用:
- "加固此仓库"、"确保仓库安全"、"应用安全设置"
- "保护master/main分支"、"设置规则集"、"保护发布标签"
- "将部署密钥迁移到环境中"、"锁定Cloudflare/Vercel/AWS令牌"
- "安全地设置新仓库"、"初始化仓库设置"
请勿在用户仅希望获取检测结果而不进行修改时使用——此时应使用工具。组织级策略、SSO和GitHub Enterprise控制不在本工具的范围内。
security-auditPrerequisites
前提条件
- CLI authenticated as a repo admin (
gh; rulesets, environments, and settings PATCHes all require admin).gh auth status - Resolve the target once: .
gh repo view --json nameWithOwner --jq .nameWithOwner
- CLI已以仓库管理员身份认证(运行
gh确认;规则集、环境和设置PATCH操作均需管理员权限)。gh auth status - 先解析目标仓库:。
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/nullPresent 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=falseSafe when workflows declare their own blocks (they should — flag any that
don't rather than skipping this step).
permissions: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=configuredThen immutable releases, when the repo publishes GitHub Releases or has a tag-triggered
release workflow:
bash
gh api -X PUT repos/<owner>/<repo>/immutable-releasesOnce 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-releasesPlan-related errors (private repo without Advanced Security) are informational — record
and continue. If the repo has a , verify the reporting channel it advertises
is now actually enabled.
SECURITY.mdbash
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.mdStep 3: Branch Protection Ruleset
步骤3:分支保护规则集
Template: . Fill in the required status checks from a recent
green run — check names must match exactly as GitHub reports them, including expanded
matrix legs:
assets/ruleset-branch.jsonbash
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.jsonDecisions baked into the template (adjust per answers from Asking the User):
- targets the default branch without hardcoding its name.
~DEFAULT_BRANCH - Bypass actor 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
{"actor_id": 5, "actor_type": "RepositoryRole", "bypass_mode": "always"}to 1+.required_approving_review_count - Warn the user: matrix check names are verbatim — reshaping the CI matrix requires a matching ruleset update, or merges block (admin bypass still works).
模板:。从最近一次成功运行中填写所需的状态检查——检查名称必须与GitHub报告的完全一致,包括展开的矩阵分支:
assets/ruleset-branch.jsonbash
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 - 绕过角色为仓库管理员——适合单人维护者(永远不会被阻止,而泄露的非管理员令牌或Actions令牌仍会被阻止)。对于团队,可移除绕过设置并将
{"actor_id": 5, "actor_type": "RepositoryRole", "bypass_mode": "always"}设为1或更高。required_approving_review_count - 提醒用户:矩阵检查名称是精确匹配的——调整CI矩阵需要同步更新规则集,否则会阻止合并(管理员绕过仍可生效)。
Step 4: Release Tag Ruleset
步骤4:发布标签规则集
Apply when a workflow triggers on tag push (), 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.
on.push.tagsTemplate: (restricts , , ,
on to the bypass actors).
assets/ruleset-tag.jsoncreationupdatedeletionnon_fast_forwardrefs/tags/v*bash
gh api -X POST repos/<owner>/<repo>/rulesets --input ruleset-tag.jsonThe user's local flow keeps working through the admin bypass; the
Actions token and non-admin credentials cannot mint release tags.
git tag && git push当工作流在标签推送时触发(),或用户计划配置此类工作流时应用此规则集。对于标签触发的发布,标签创建相当于“发布”——此规则集是本文件中最重要的控制项。
on.push.tags模板:(限制的、、、操作仅允许绕过角色执行)。
assets/ruleset-tag.jsonrefs/tags/v*creationupdatedeletionnon_fast_forwardbash
gh api -X POST repos/<owner>/<repo>/rulesets --input ruleset-tag.json用户本地的流程可通过管理员绕过正常工作;Actions令牌和非管理员凭证无法创建发布标签。
git tag && git pushStep 5: Deploy Secrets into a Branch-Restricted Environment
步骤5:将部署密钥迁移到分支受限环境
Applies when Step 0 found deploy-provider credentials (, ,
, , , …) 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.
CLOUDFLARE_*VERCEL_*AWS_*NETLIFY_*FLY_*Order matters; follow exactly:
- 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- 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> - Update the deploy workflow: split an uncredentialed job (all branches) from a
buildjob withdeploy, gated byenvironment: <env-name>, consuming the build artifact.if: github.ref == 'refs/heads/<default-branch>' - Only after the workflow change is pushed and env secrets confirmed, delete the
repo-level copies: . The hole stays open until they are gone.
gh secret delete <NAME> -R <owner>/<repo>
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_*顺序至关重要,请严格遵循:
- 先创建环境,再让任何工作流引用它(工作流运行时引用不存在的环境会自动创建一个未受保护的环境):
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- 密钥值是仅可写入的——无法通过API复制。请让用户在自己的终端中重新输入(切勿在对话中粘贴值):
gh secret set <NAME> --env <env-name> -R <owner>/<repo> - 更新部署工作流:将无凭证的任务(所有分支)与带有
build的environment: <env-name>任务分离,通过deploy进行限制,并使用构建产物。if: github.ref == 'refs/heads/<default-branch>' - 仅在工作流变更推送完成且环境密钥确认无误后,删除仓库级副本:。在删除之前,安全漏洞仍然存在。
gh secret delete <NAME> -R <owner>/<repo>
提前告知用户此操作的影响:分支预览部署将停止工作。如需安全恢复预览部署,需要第二个提供商项目,并在单独的未受保护环境中使用其自身的范围令牌。
Step 6: Keep Workflows Linted
步骤6:保持工作流合规
Applies when 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 or a that checks out PR code.
.github/workflows/uses:pull_request_targetClear 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/workflowsIf 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.ymlyaml
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: falseResolve both 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
unless the repo has GitHub Advanced Security, or the SARIF
upload step errors.
<sha>advanced-security: falseIf Step 3 added , decide with the user whether
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 exactly, or every PR blocks permanently.
required_status_checksLint CI workflowsname:Two related items this does not cover, because neither is a write:
gh api- Stale branches still carrying pre-hardening workflow files. Old refs are reachable by
and by
workflow_dispatchfilters 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:push:Deleting someone's branch is not this skill's call — report and ask.bashgit branch -r --format='%(refname:short) %(committerdate:short)' | grep -v HEAD - (Actions setting). Flip it only once zizmor reports every
sha_pinning_requiredSHA-pinned; enabling it earlier breaks every workflow run. See Common Mistakes.uses:
当目录存在时应用此步骤。上述规则集和设置由GitHub强制执行,但工作流文件本身不受此限制,因此后续PR仍可能重新引入标签固定的或拉取PR代码的。
.github/workflows/uses: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.ymlyaml
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在写入文件前,将两个值替换为真实的40位提交SHA——如果工作流校验工作流自身使用标签固定,会无法通过自身的校验。除非仓库拥有GitHub Advanced Security(否则SARIF上传步骤会报错),否则设置。
<sha>advanced-security: false如果步骤3添加了,请与用户决定是否将加入必填列表。加入意味着校验器回归会阻止合并;不加入则表示该检查仅作参考。两种选择都合理——但如果加入规则集,检查名称必须与工作流的完全一致,否则所有PR都会被永久阻止。
required_status_checksLint CI workflowsname:本步骤不涵盖以下两项内容,因为它们无法通过写入:
gh api- 陈旧分支仍带有加固前的工作流文件。旧分支可通过和匹配它们的
workflow_dispatch过滤器被访问,Nx漏洞事件就是通过默认分支已修复的旧版本工作流触发的。列出这些分支并让用户决定:push:本工具不会擅自删除用户的分支——仅作报告并询问用户。bashgit branch -r --format='%(refname:short) %(committerdate:short)' | grep -v HEAD - (Actions设置)。仅当zizmor报告所有
sha_pinning_required均已固定SHA后再启用;提前启用会导致所有工作流运行失败。参考常见错误部分。uses:
Step 7: Manual Items — Report, Don't Skip Silently
步骤7:手动项——报告,切勿静默跳过
These cannot be done via ; list them for the user in the final report:
gh- npm (when the repo publishes packages), at
— give the user the resolved URL, one per public package in a monorepo, not a generic "your package settings":
https://www.npmjs.com/package/<name>/access- Trusted Publisher pinned to the exact + release workflow filename.
owner/repo - Enable only "Allow npm stage publish", so a plain from that workflow is rejected and every release has to pass through a maintainer's 2FA approval (
npm publish, 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 usingnpm stage approve <stage-id>without this restriction is a convention, not a control.npm stage publish - 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 before recommending the switch.
node-version
- Trusted Publisher pinned to the exact
- Provider token scope: the deploy token itself should be least-privilege (e.g.
Cloudflare: only ). Verified in the provider dashboard, not the repo.
Account · Cloudflare Pages · Edit
这些操作无法通过完成,请在最终报告中为用户列出:
gh- npm(当仓库发布包时),访问——为用户提供解析后的URL,单仓库中的每个公共包对应一个URL,而非通用的“你的包设置”:
https://www.npmjs.com/package/<name>/access- 受信任发布者固定到精确的+ 发布工作流文件名。
owner/repo - 仅启用“Allow npm stage publish”,这样工作流中的普通会被拒绝,每个版本都必须经过维护者的2FA审批(
npm publish,或在npmjs.com的Staged Packages中操作)。这是完全被攻陷的CI作业无法伪造的控制项——工作流持有合法的OIDC身份,而预发布环节可阻止仅凭该身份完成发布。只有在注册表端设置后,此控制才生效;工作流使用npm stage approve <stage-id>但未设置此限制只是一种约定,而非控制项。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 → / / / . Include the exact commands for anything deferred.
appliedalready setskipped (reason)manual (user)以简洁表格结尾:每个基线项 → / / / 。为所有延迟执行的操作包含精确命令。
已应用已配置已跳过(原因)手动操作(需用户完成)Asking the User
向用户提问
Every question in this skill is written as 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.
AskUserQuestionBefore applying (after Step 0's inventory), confirm scope in one round:
- Ruleset strictness — Solo (admin bypass, 0 approvals; recommended for single-maintainer repos) / Team (no bypass, 1+ approvals) / Skip rulesets.
- Deploy secrets — Migrate to environment now (recommended; previews break) / Leave at repo level (records a critical finding in the report).
- 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 ) — state them in the confirmation
rather than asking. Same for the workflow linter in Step 6: apply it if
exists, and raise the required-check decision there rather than in
this round.
cloudflare-production.github/workflows/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.
本工具中的所有问题均以选项形式编写。如果宿主提供该工具,请使用它;否则使用宿主最接近的结构化选择等效工具。如果宿主均不提供,请在普通聊天中以编号列表(2-5个选项)的形式提出相同问题——推荐选项放在首位,每个选项配一行简短描述——等待用户回复编号。
AskUserQuestion应用前(步骤0盘点后),通过一轮确认范围:
- 规则集严格程度 — 单人模式(管理员绕过,0个审批;推荐单人维护仓库使用)/ 团队模式(无绕过,1个及以上审批)/ 跳过规则集。
- 部署密钥 — 立即迁移到环境(推荐;预览部署会失效)/ 保留在仓库级别(在报告中记录为严重安全缺口)。
- 不可变发布 — 启用(推荐;不具有追溯性,会中断重新上传版本资产的自动化流程)/ 跳过。仅当步骤0检测到版本或标签触发的工作流时提问。
必填状态检查和环境名称由仓库派生(CI运行检查名称;提供商名称如)——在确认时告知用户,无需提问。步骤6中的工作流校验器同理:如果目录存在则应用,在该步骤中决定是否加入必填检查,而非在此轮提问中。
cloudflare-production.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 (); rulesets need the expanded names.
${{ matrix.node-version }} - Adding a rule with
pull_requeston a solo repo without a bypass — the maintainer can never merge; nobody else can approve.required_approving_review_count: 1 - Enabling while workflows still use tag refs — every workflow run fails until all
sha_pinning_requiredentries are SHA-pinned. Pin first, then flip.uses: - 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 using
check-workflows.ymlfails its own SHA-pinning rule. Resolve real SHAs before writing the file.@v1 - 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项都固定SHA。先固定SHA,再启用该设置。uses: - 在清除工作流校验器的现有问题前就添加该工作流 — 首次运行会失败,用户会认为加固操作破坏了CI。先在本地运行、修复问题,再提交工作流。
- 为校验器自身的操作使用标签固定 — 使用的
@v1会无法通过自身的SHA固定规则。写入文件前先替换为真实SHA。check-workflows.yml - 启用不可变发布但未告知用户该设置不具有追溯性 — 用户会误以为旧版本也被密封。实际并非如此,具有长期版本历史的仓库会在启用前发布的所有版本中保留该风险。
- 擅自为用户删除陈旧分支 — 列出分支并让用户决定。看似已废弃的分支可能是某人正在进行的长期工作。