GitHub Actions 工作流

让 Agent 编写带 `permissions` 最小化、`actions` 版本 pin(commit SHA 优先)、复用 workflow 与环境保护规则的安全 YAML。

SKILL 规定 `on` 触发器范围、路径过滤、`concurrency` 组名;第三方 action 需审查供应商并优先官方或已 pin 版本。

使用 `GITHUB_TOKEN` 默认权限时显式降级;需跨仓或云资源时用 OIDC 与 cloud provider 配置,避免长期 secrets。

可复用 workflow 与 composite action 的拆分准则;自托管 runner 标签与隔离要求若适用须写明。

  • 缓存:`actions/cache` 键与 restore-keys 策略,避免错误命中。
  • 容器作业:镜像来源与 pull policy;与 Dockerfile 技能一致。
  • 复用:`workflow_call` 输入校验与文档化默认值。

GHA 主流程(skill-flow-block)

  [ 事件:push / PR / schedule / workflow_dispatch / 调用方 workflow_call ]
                    │
                    ▼
         [ 解析:workflow 文件匹配分支 / 路径 / activity types ]
                    │
                    ▼
    [ 并发:concurrency 组取消或排队;避免与部署 job 竞态 ]
                    │
                    ▼
         [ Job:runs-on、permissions 降级、environment 与必要 secrets ]
                    │
           ┌────────┴────────┐
           ▼                 ▼
  [ 内联 steps:uses pin(SHA)+ 显式 with ]     [ 复用:workflow_call / composite / 可重用 job 模板 ]
           │                 │
           └────────┬────────┘
                    ▼
         [ 产出:artifact、摘要、状态检查;失败时保留日志与复现命令 ]
Agent 改 YAML 时应同时检查:默认分支保护规则、required status checks 名称是否与 jobs.*.name 一致,以及是否会意外扩大 pull_request_target 风险面。

可复用工作流对照矩阵

下表对比常见「复用」形态:点击行可在下方查看 SKILL 中建议写明的要点(仅本地高亮,无网络请求)。

形态 入口 输入 / 密钥 权限边界 典型用途
可复用 Workflow on.workflow_call,由调用方 uses: org/repo/.github/workflows/x.yml@ref inputs / secrets 显式传入;支持 outputs 调用方与 callee 的 permissions 各自独立;跨仓需信任 ref 与 CODEOWNERS 多仓统一 CI、发布流水线模板
Composite Action action.ymlruns.using: compositeuses: ./path 或公开 action inputs;密钥经 secrets 从调用 workflow 注入 与调用 job 同一 actor;适合打包多步 shell,不宜塞整条流水线 重复 shell 步骤、工具链安装、缓存封装
容器 / JS Action uses: owner/action@vX 或 SHA;可选 docker:// with;敏感项走 secrets 审查供应商、pin SHA;注意 post step 与缓存副作用 官方或社区封装好的单责任步骤
Job 矩阵 同一 workflow 内 strategy.matrix / fail-fast 矩阵维度作 env;不自动共享 secrets 到子组合以外 注意矩阵爆炸与 minutes;大矩阵拆 workflow_call 分批 多版本语言、多 OS、参数化测试

当前选中:点击表格中的一行以查看建议写入 SKILL 的侧重点。

触发器、concurrency 与路径过滤

  • on为 PR 与 push 分别写清 paths/paths-ignoreworkflow_dispatch 的 inputs 要有类型、默认值与说明。
  • concurrency组名包含环境或分支占位,避免不同 PR 互相取消;部署类 job 慎用 cancel-in-progress
  • 复用入口:workflow_call 调用的 workflow 应校验 inputs 枚举,拒绝空字符串或危险默认分支名。

完整的可复用 workflow(reusable workflow with inputs/outputs)示例:

# .github/workflows/reusable-build.yml  — 可复用 workflow
name: Reusable Build

on:
  workflow_call:
    inputs:
      node-version:
        description: 'Node.js 版本'
        type: string
        default: '20'
        required: false
      environment:
        description: '部署目标环境'
        type: string
        required: true
    secrets:
      REGISTRY_TOKEN:
        required: true
    outputs:
      image-tag:
        description: '构建产物镜像 tag'
        value: ${{ jobs.build.outputs.tag }}

jobs:
  build:
    runs-on: ubuntu-24.04
    timeout-minutes: 20
    outputs:
      tag: ${{ steps.tag.outputs.tag }}
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: ${{ inputs.node-version }}
          cache: 'npm'

      - name: Restore build cache
        uses: actions/cache@v4
        with:
          path: |
            .next/cache
            node_modules/.cache
          key: build-${{ runner.os }}-${{ inputs.node-version }}-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            build-${{ runner.os }}-${{ inputs.node-version }}-
            build-${{ runner.os }}-

      - run: npm ci --prefer-offline
      - run: npm run build

      - id: tag
        run: |
          echo "tag=$(node -p "require('./package.json').version")-${{ github.sha }}" >> "$GITHUB_OUTPUT"

# ---- 调用方 workflow ----
# .github/workflows/deploy.yml
# jobs:
#   build:
#     uses: ./.github/workflows/reusable-build.yml
#     with:
#       node-version: '20'
#       environment: staging
#     secrets:
#       REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}

矩阵测试配置:多版本 × 多平台并行测试:

# 矩阵测试:Node 18/20/22 × ubuntu/windows
jobs:
  test:
    strategy:
      fail-fast: false      # 一个组合失败不停止其他
      matrix:
        node: ['18', '20', '22']
        os: [ubuntu-24.04, windows-latest]
        exclude:
          - node: '18'
            os: windows-latest   # 排除特定组合
    runs-on: ${{ matrix.os }}
    name: Test Node ${{ matrix.node }} on ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
          cache: 'npm'
      - run: npm ci
      - run: npm test

permissions、OIDC 与 action pin

  • 最小权限:顶层 permissions 先收紧,再在 job 级按需放宽;需要写内容库时显式 contents: write 并说明理由。
  • OIDC:云角色信任策略绑定 sub/aud;避免把环境名或可伪造 claim 单独作为唯一条件。
  • Pin:优先完整 commit SHA;标签需配合组织级允许列表或 dependabot 更新策略。

Secrets 安全传递:environments + required reviewers 手动审批配置:

# 最小权限顶层收紧 + 各 job 按需放宽 + environment 手动审批
permissions: {}   # 顶层全部关闭

jobs:
  test:
    runs-on: ubuntu-24.04
    permissions:
      contents: read    # 仅读源码
    steps:
      - uses: actions/checkout@v4
      - run: npm test

  deploy-prod:
    runs-on: ubuntu-24.04
    needs: test
    # environment 绑定保护规则:在仓库 Settings > Environments 配置
    # Required reviewers: 至少 1 人审批后 job 才能继续运行
    environment:
      name: production
      url: https://myapp.example.com
    permissions:
      id-token: write   # OIDC token
      contents: read
    steps:
      - uses: actions/checkout@v4

      # Pin action 到完整 commit SHA,而非 @v4 标签
      - uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502
        with:
          role-to-assume: ${{ vars.AWS_DEPLOY_ROLE_ARN }}
          aws-region: ${{ vars.AWS_REGION }}

      - run: |
          # Secrets 通过 environment 隔离,此处 ${{ secrets.DB_PASSWORD }}
          # 仅在 production environment 的 job 中可见
          aws ssm put-parameter \
            --name "/myapp/prod/db-password" \
            --value "${{ secrets.DB_PASSWORD }}" \
            --type SecureString --overwrite

缓存、容器与环境保护

  • 缓存:键包含 lockfile 哈希与 runner OS;restore-keys 仅作降级,文档中写明可接受的「部分命中」行为。
  • 容器 job:镜像 digest、非 root、与供应链技能一致的 SBOM/扫描门禁。
  • Environment:保护规则、required reviewers 与 secrets 分环境;生产部署 workflow 与仅 CI 的 workflow 分离。

缓存优化:actions/cache 的正确键设计与多层 restore-keys:

# npm 依赖缓存:精确键 + 两级降级
- name: Cache npm dependencies
  uses: actions/cache@v4
  id: npm-cache
  with:
    path: ~/.npm
    # 精确键:OS + node版本 + lockfile哈希
    key: npm-${{ runner.os }}-node20-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      npm-${{ runner.os }}-node20-
      npm-${{ runner.os }}-
  # cache-hit: true 时跳过 npm install

- run: npm ci --prefer-offline
  # --prefer-offline: 优先使用 ~/.npm 缓存,降低网络依赖

# Docker layer 缓存(BuildKit)
- name: Build with layer cache
  uses: docker/build-push-action@v6
  with:
    context: .
    push: false
    cache-from: type=gha,scope=myapp-build
    cache-to: type=gha,mode=max,scope=myapp-build
    tags: myapp:${{ github.sha }}

# Terraform provider 缓存
- name: Cache Terraform providers
  uses: actions/cache@v4
  with:
    path: ~/.terraform.d/plugin-cache
    key: tf-${{ runner.os }}-${{ hashFiles('**/.terraform.lock.hcl') }}
    restore-keys: |
      tf-${{ runner.os }}-
---
name: github-actions-workflows
description: 安全、可复用的 GitHub Actions YAML
tags: [github-actions, ci-cd, security]
---
# 触发器与并发
1. on.push/pull_request 分别配置 paths 过滤,降低无关变更触发
2. concurrency.group 含 workflow + ref,PR 之间不互相取消
3. workflow_dispatch inputs 必须有 type、description 与合理默认值
4. workflow_call inputs 校验枚举,拒绝空字符串或保留分支名

# 权限最小化
5. 顶层 permissions: {} 全部关闭,job 级按需放宽
6. OIDC federation:id-token: write + 云 provider configure-credentials action
7. 信任策略绑定 sub(repo:org/repo:ref:refs/heads/main)+ aud 双重条件
8. Action pin:优先完整 commit SHA,配合 dependabot 自动更新

# 可复用与缓存
9. reusable workflow:inputs/secrets/outputs 显式声明,调用方 uses: ./.github/workflows/x.yml
10. Composite action:打包多步 shell,不含独立部署权限
11. actions/cache 键 = OS + 工具版本 + lockfile 哈希,restore-keys 两级降级
12. Docker layer cache via BuildKit type=gha,scope 按服务区分

# 环境与密钥
13. environment 绑定 required reviewers,生产 deploy 需人工审批
14. 生产 secrets 仅在绑定 environment 的 job 中可见,与 CI job 隔离
15. pull_request_target 触发时不执行 checkout 或运行 fork 代码
16. 不在 workflow 中输出 secrets,避免 echo / cat 暴露在日志

返回技能库 更多技能入口