Core Principles
- Read the project first, then generate the workflow. Do not guess the runtime, package manager, test commands, or deployment target from the project name.
- By default, generate read-only CI only. For Releases, deployments, image pushes, writes back to the repository, and calls to external webhooks, you must first confirm the target, credentials, environment protection, and rollback approach.
- Isolate untrusted PR code from Secrets, write permissions, and self-hosted Runners. Do not switch to
pull_request_targetto execute PR code for convenience. - Pin all Actions to a verified full 40-character commit SHA, and keep a version comment alongside it. Do not use
@main、@master、@latestor a movable@vNtag。 - Set the minimum
permissionsandtimeout-minutesfor each job; do not rely on the repository default permissions. - After generation, run real syntax and project command verification; do not treat "the configuration looks correct" as passing.
Workflow
1. Inventory project evidence
- Read manifests, lockfiles, wrappers, runtime files, and existing workflows, such as
package.json、.nvmrc、pyproject.toml、go.mod、Cargo.toml、Dockerfileand.github/workflows/。 - Confirm the lint, test, build, and package commands from project scripts, contribution docs, and existing CI. If a command does not exist, point out the gap first.
- Identify monorepo boundaries, working directories, matrix dimensions, service containers, cache paths, and artifacts.
- Ask about the necessary decisions: trigger branches, supported runtimes, deployment targets, cloud accounts, GitHub Environments, failure handling, and release authorization.
- Check the current working tree and preserve the user's existing changes; only edit the workflows and necessary configuration authorized for this task.
2. Build a threat model
pull_request: Treat as untrusted code, use a read-only token, do not provide Secrets, and do not execute fork code on a highly privileged self-hosted Runner.pull_request_target: Only handle trusted base-branch logic such as labels and comments; never checkout the PR head, run PR scripts, or install PR dependencies.push/ tag /workflow_dispatch: Still restrict branches, inputs, Environments, and permissions; put write operations in a separate job.- Avoid inserting untrusted expressions such as
${{ github.event.* }}directly intorun:. Pass values throughenv:and handle them as data in the script. - Do not write Secrets into command lines, logs, caches, Artifacts, or PR comments; the absence of Secrets in fork PRs is a normal security boundary.
3. Design the minimal pipeline
Prefer separating responsibilities:
ci.yml:lint、test、build;pull_requestand controlledpushtriggers, with read-only permissions.release.yml: Generate only when the user explicitly requests it; use protected tags or manual triggers.deploy.yml: Generate only when the deployment target is clear; use GitHub Environments, concurrency control, and minimal OIDC / Secrets permissions.
Set cancellation policies and timeouts for long-running jobs. The matrix should only cover versions the project actually supports; cache keys must include the lockfile, and credentials and build secrets must not be cached.
4. Verify and pin Actions
- Resolve the full commit SHA from the Action's official repository release / tag, and verify the repository owner, version notes, and runtime requirements.
- Use the
uses: owner/action@<40位SHA> # vX.Y.Zformat. The version comment is for reading; the SHA is the execution boundary. - To
actions/checkoutdefault settingpersist-credentials: false. Only retain credentials when subsequent steps actually need to perform authorized Git writes, and restrict job permissions. - Use Dependabot or a manual maintenance process to update the SHA; re-read the release notes when updating, do not replace blindly.
- The example SHA in this article was verified on 2026-07-22; the official release should be re-verified at actual generation time.
5. Generate the workflow
The examples below assume the project already has .nvmrc、package-lock.json、lint、test and build scripts:
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: 配置 Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: .nvmrc
cache: npm
cache-dependency-path: package-lock.json
- name: 安装依赖
run: npm ci
- name: 代码检查
run: npm run lint
- name: 运行测试
run: npm test
- name: 构建
run: npm run build
Do not copy the examples mechanically. If the project uses pnpm, Yarn, uv, Poetry, Gradle, Go or Rust, its real lockfile, wrapper and commands should be used.
6. Protect release and deployment separately
- Put release / deployment into a separate job, and grant only that job the necessary
contents: write、packages: writeorid-token: write。 - Prefer short-lived OIDC over long-lived cloud keys; restrict the cloud audience, subject, branch, repository and Environment.
- Use required reviewers, a protected Environment, concurrency locks and verifiable rollback for production.
- Set the type, options and default values for
workflow_dispatchinputs; re-validate the target environment and version before execution. - Verify artifact provenance before release, and generate attestations / provenance when necessary; do not deploy artifacts from unverified PRs.
7. Verification
- Run
actionlint; if the tool is unavailable, clearly state that this gate was not completed, do not claim the syntax passes. - Run a YAML parse check, and verify all
${{ }}, shell, paths, matrix andneedsreferences. - Run the lint, test and build commands referenced in the workflow locally, or explain the environment limitations.
- Search all
uses:, confirm that third-party Actions all use full SHAs; check checkout'spersist-credentials。 - Use scenarios such as fork PRs, internal PRs, push, tag and manual deployment to check whether Secrets and permissions behave as expected.
- Review the final diff, and confirm that no Token, account, real webhook,
.envor unrelated configuration has been written.
Delivery format
Explain in Chinese:
- Added or modified workflows and their trigger conditions;
- Each job's permissions, Secrets / OIDC and Environment boundaries;
- The version source and verification time of the Action SHA;
- Verifications run, results, and items not covered;
- Manual confirmation points and rollback methods for release / deployment.
Unless the user explicitly requests it, do not create additional README-CICD.md or other auxiliary documents.
Quality checklist
- Commands, runtime and lockfile come from real project evidence
- All Actions use full 40-character SHAs and version comments
- checkout defaults to
persist-credentials: false - Workflow / job permissions are minimized and timeouts are set
- Fork PRs do not touch Secrets, write permissions or highly privileged Runners
-
pull_request_targetDoes not execute untrusted PR content - Untrusted contexts are not directly interpolated into the shell
- Release / deployment goes through explicit authorization and Environment protection
-
actionlintValidation with project commands is completed or gaps are truthfully recorded