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
21 changes: 13 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,23 @@ jobs:
- name: 相對連結必須指得到檔案
run: python3 tools/check-links.py

# 安全掃描接在基礎驗證之後:`links` 紅燈時整組 **skipped**
# **本倉庫是公開的,所以掃描與 `links` 同時起跑**,不等它綠燈
#
# 本倉庫沒有 CodeQL(沒有程式碼可以建),所以這道閘擋掉的不是
# 四十分鐘——是「同一顆 commit 上收到兩顆紅燈,而第二顆與根因無關」。
# 十五個倉庫維持同一個形狀,掃描本身的定義在 `security.yml`,
# 那支同時還掛著每週排程(**不**經過這道閘)。
# 公開倉庫的 Actions 分鐘數不計費,所以「基礎驗證紅燈時整組 skipped、
# 省下執行器時間」在這裡換不到任何東西,只換到更晚才知道掃描的結論。
# 本倉庫的代價比其餘四個公開倉庫更小:這裡沒有 CodeQL 也沒有 govulncheck
# (沒有程式碼可以建),而 Gitleaks 與 Trivy 本來就不建置任何東西——
# 連結壞掉不會讓它們吐出第二顆與根因無關的紅燈。
#
# 不必再寫一次草稿 PR 的 `if`:`links` 因為草稿而 skipped 時,
# `needs:` 它的 job 一併 skipped。
# **私有倉庫維持 `needs:` 那道閘**——那裡的分鐘數要付錢。兩種形狀是刻意的,
# 不是漂移;判準與理由見 workspace `AGENTS.md` §1.9.1。
#
# 掃描本身的定義在 `security.yml`,那支同時還掛著每週排程。
security:
# 草稿 PR 不跑。**這一行不能省**:沒有 `needs:` 之後,草稿的 skip 不再從
# 基礎驗證那邊傳遞過來,少了它草稿 PR 會開始跑掃描。
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false
name: 安全掃描
needs: [links]
uses: ./.github/workflows/security.yml
permissions:
contents: read
Expand Down
32 changes: 16 additions & 16 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
# 新的 advisory 是對著既有的相依發布的,而那時候沒有人在推 commit。
# 少了排程,一個服務可以整季不被掃到。
#
# 排程還多守一件事:它是**唯一不經過基礎驗證那道閘**的進入點(見下方 `on:`)。
# main 編不過的那幾天,掃描仍然照跑。
# **本倉庫是公開的,所以隨 `ci.yml` 觸發的那一次不經過任何閘門**——掃描與基礎
# 驗證同時起跑(見 `ci.yml` 的 `security` job)。排程仍然是獨立的第二個進入點:
# 它有自己的時鐘,沒有人推 commit 的那幾週也照跑。
#
# ## SARIF 上傳為什麼容許失敗
#
Expand All @@ -29,29 +30,28 @@
name: 安全掃描

on:
# **本支不自己掛 push 與 pull_request**,改由 `ci.yml` 在基礎驗證
# (lint/format → 單元測試 → 建置)綠燈之後呼叫。
# **本支不自己掛 push 與 pull_request**,改由 `ci.yml` 的 `security` job
# 呼叫。**本倉庫是公開的,所以那個 job 沒有 `needs:`**——掃描與基礎驗證
# 同時起跑,不等它綠燈。私有倉庫留著那道閘(分鐘數要付錢),
# 判準見 workspace `AGENTS.md` §1.9.1。
#
# 理由是 `needs:` 只在同一個 workflow 檔內成立,跨檔案沒有辦法表達
# 「前一支綠了再跑」。改成可被呼叫的 workflow 之後,ci.yml 的 `security`
# job 用 `needs:` 把順序寫出來——基礎驗證紅燈時,這裡整組 **skipped**。
# 既然不必表達順序了,為什麼還留著 `workflow_call`,不乾脆自己掛
# push/pull_request?因為那會把檢查名稱從 `安全掃描 / Gitleaks` 變回
# `Gitleaks`,動到按名字釘住的分支保護;而且同一顆 commit 會變成兩次 run,
# PR 的檢查清單裡就少了「這一組屬於同一次驗證」這件事。留在同一次 run 裡、
# 只是沒有 `needs:`,拿到的並行是一樣的,這兩個代價一個都不用付。
#
# 換掉的是什麼:CodeQL 的 autobuild 與 govulncheck **都要先建置得起來**,
# 建置壞掉時它們吐的是同一個編譯錯誤換一種包裝,四十分鐘換到一顆
# 與根因無關的第二紅燈。而多餘的紅燈會稀釋掉真的那一顆——同 `ci.yml`
# 檔頭與 workspace `AGENTS.md` §1.9 講的是同一件事。
#
# 用 `workflow_call` 而不是 `workflow_run` 是刻意的:`workflow_run` 只讀
# 用 `workflow_call` 而不是 `workflow_run` 也是刻意的:`workflow_run` 只讀
# **預設分支**上的 workflow 檔,所以改這支檔案的 PR 驗不到自己的改動,
# 而且它的執行不會掛回那個 PR 的檢查清單。本地 `uses: ./…` 讀的是
# **被呼叫那一顆 commit** 的檔案,兩件事都不會發生。
workflow_call:
schedule:
# 每週一次。各倉庫的分鐘與小時刻意錯開,十五個倉庫同時醒來只會互相排隊。
#
# **排程這一條刻意不經過基礎驗證。** 它回答的是「沒有動過的程式今天有沒有
# 變成有問題的」,那個問題與 main 現在編不編得過無關;讓它也跟著基礎驗證
# 一起 skipped,等於一個紅著的 main 可以讓掃描停擺一整週
# 排程是**獨立於 `ci.yml` 的第二個進入點**。它回答的是「沒有動過的程式
# 今天有沒有變成有問題的」,而新的 advisory 發布的那天沒有人在推 commit——
# 所以它要有自己的時鐘,不依賴任何一次 push
- cron: "47 3 * * 1"
workflow_dispatch:

Expand Down