Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions .github/scripts/validate-action-pins.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

ACTION_FILE_GLOBS = [
".github/workflows/*.{yml,yaml}",
".github/actions/**/action.{yml,yaml}"
].freeze
LOCAL_REFERENCE_PREFIXES = ["./", "docker://"].freeze
FULL_COMMIT_SHA = /\A[0-9a-fA-F]{40}\z/
USES_PATTERN = /^\s*(?:-\s*)?uses\s*:\s*(?:"([^"]+)"|'([^']+)'|([^#\s]+))/

files = ACTION_FILE_GLOBS.flat_map { |pattern| Dir.glob(pattern) }.uniq.sort
errors = []
external_references = 0

if files.empty?
warn "未找到需要检查的 GitHub Actions 工作流或 Action 元数据。"
exit 1
end

files.each do |file|
File.foreach(file, encoding: "UTF-8").with_index(1) do |line, number|
match = line.match(USES_PATTERN)
next unless match

reference = match.captures.compact.first.to_s.strip
next if reference.start_with?(*LOCAL_REFERENCE_PREFIXES)

external_references += 1
action, separator, revision = reference.rpartition("@")
next if separator == "@" && !action.empty? && FULL_COMMIT_SHA.match?(revision)

message = "外部 Action 必须固定到完整的 40 位 Commit SHA:#{reference}"
puts "::error file=#{file},line=#{number},title=Mutable GitHub Action reference::#{message}"
errors << [file, number, reference]
end
end

if errors.empty?
puts "已验证 #{external_references} 个外部 GitHub Action 引用,全部固定到完整 Commit SHA。"
exit 0
end

warn "发现 #{errors.length} 个可移动或无效的外部 GitHub Action 引用。"
exit 1
5 changes: 4 additions & 1 deletion .github/workflows/sync-labels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,14 @@ jobs:
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
persist-credentials: false
- uses: actions/create-github-app-token@v3

- name: Create label synchronization token
id: app-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
client-id: ${{ vars.APP_CLIENT_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}

- name: Apply MathArts label synchronization
uses: ./.github/actions/sync-labels
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/validate-documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ jobs:
- name: Check Issue Form labels
run: ruby .github/scripts/validate-issue-labels.rb

- name: Check immutable GitHub Action references
run: ruby .github/scripts/validate-action-pins.rb

- name: Test label synchronization behavior
run: ruby .github/actions/sync-labels/test_sync_labels.rb

Expand Down
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,18 @@ MathArts 的组织级标签由两个权威来源共同维护:

标签自动化分为两个权限边界:

* [`preview-labels.yml`](.github/workflows/preview-labels.yml) 在推送、定时任务或手动触发时使用只读 `github.token` 预览公开可见仓库的标签漂移,不读取跨仓库写令牌
* [`preview-labels.yml`](.github/workflows/preview-labels.yml) 在推送、定时任务或手动触发时使用只读 `github.token` 预览公开可见仓库的标签漂移,不读取 GitHub App 私钥
* [`sync-labels.yml`](.github/workflows/sync-labels.yml) 只允许从 `main` 手动触发真实变更,并绑定 `label-governance-production` Environment。

真实同步所需的 `LABEL_SYNC_WRITE_TOKEN` 必须配置为 `label-governance-production` 的 Environment Secret,而不是普通仓库 Secret。该 Environment 应在仓库设置中启用 Required reviewers,并禁止发起者自行批准。
真实同步通过 GitHub App 生成短时效 Installation Access Token。`label-governance-production` Environment 必须配置:

* Environment Variable `APP_CLIENT_ID`;
* Environment Secret `APP_PRIVATE_KEY`;
* Required reviewers,并在账户方案支持时禁止发起者自行批准。

GitHub App 应只安装到参与组织级标签治理的仓库,并采用最小仓库权限;当前标签同步至少需要 `Issues: Read and write`,`Metadata: Read` 由 GitHub 自动授予。轮换 GitHub App 私钥时,应同步更新 `APP_PRIVATE_KEY`。

所有外部 GitHub Action 和可复用工作流引用必须固定到完整的 40 位 Commit SHA,并在行尾注释人类可读版本。`.github/scripts/validate-action-pins.rb` 负责强制检查,Dependabot 负责提出后续版本更新。

## 维护原则

Expand Down
Loading