Skip to content

A-14: Secret scan dual-layer + release-preflight digest verification (deferred from v2.8.0) #445

@vencil

Description

@vencil

Context

v2.8.0 Phase .a 軌道二 Policy-as-Code 自動化 8 提案中,A-14(secret scan 雙層 + release-preflight 強化)原排 v2.8.0 落地,Q2 sprint planning 重評估後延 v2.8.1。

2026-05-12 closure audit + Claude/Gemini review pass 發現:原 issue prose 有 3 條與現實不符的描述(見下方 Pre-flight findings),本次 v2 rewrite 修正並擴充 SOP + 守備邊界 + CI scope policy。

Pre-flight findings(v2 rewrite 期間發現,2026-05-12)

原 issue 說的 現實 影響
「v2.8.0 期間 secret scan 仍走舊單層 pre-commit hook」 .pre-commit-config.yaml grep 結果:沒有 secret scan hook,只有 codename-leak-check 本 issue 是 create-new 不是 enhance
「driver = scripts/tools/lint/check_secrets_staged.sh 或同類」 檔案不存在 AC (i) 是 create-new
「yq appVersionroot VERSION 文件 對齊」 沒有 root VERSION 檔案,五線版號 SoT 是 git tag AC (iii) 第二項重寫成 git tag vs Chart.yaml
release-preflight.yml 強化」 檔案不存在;release.yaml line 52-58 已有 Chart.yaml vs tag check AC (iii) 改為「在 release.yaml 既有 version-check job 加強 digest verification step」
Repo public + Secret Scanning / Push Protection 都 disabled 免費官方防護沒開 拆 Phase 0 sub-issue 立即止血(#470

v2.8.1 strategic alignment

v2.8.0 ship 後立刻進 v2.8.1,眼前最大(可能也唯一)客戶非常重視 security。在 v2.8.1 把 enterprise-grade secret hygiene + release supply-chain integrity 補齊是商業必要動作,不是 nice-to-have。

雙保險守備邊界(核心 framing — 客戶資安部門 review 一定問)

工具 守什麼 不守什麼 成本
L0 Native(Phase 0 sub-issue) GitHub Secret Scanning + Push Protection 已知格式 token(AWS / GitHub / Slack / GCP / Azure / Stripe / ...) 自家高熵值 secret(MariaDB root password / 自家 JWT secret) 免費(public repo)
L1 Pre-commit(本票 AC i) Trufflehog filesystem on staged files 高熵值 + 已知格式(local shift-left) --no-verify 可繞 自家 lint 工時
L2 Server-side GHA(本票 AC ii) Trufflehog full-repo + diff,SARIF → Code Scanning 同 L1,但 server-side 不可繞 攻擊者已知 secret format = GHAS 才有 自家 workflow 工時
L3 Release-time(本票 AC iii) release.yaml digest verification 供應鏈 integrity(published digest = Chart.yaml) secret 本身 自家 workflow 工時

L0 是 L1+L2 不可替代的前置(Phase 0 sub-issue 必先做),L1+L2 是 L0 不可替代的補強(守 L0 抓不到的高熵值)。

Acceptance criteria

AC (i) — L1 Pre-commit hook

  • 新增 pre-commit hook(路徑待設計,初步建議 scripts/tools/lint/check_secrets_staged.sh,需與既有 lint script 風格一致)
  • staged files only(不跑全 repo,避免 commit 卡 30s+)
  • 失敗時印明確錯誤訊息:「🚨 偵測到疑似 secret。若為誤判(test fixture),請見 .trufflehogignore 或加 inline comment。嚴禁使用 --no-verify 硬推 — server-side L2 + L0 仍會擋。
  • .trufflehogignore 提供 false-positive 排除機制(test fixture 友善)
  • Hook 跑時間 P95 ≤ 5s(staged files 規模下)

AC (ii) — L2 GitHub Actions secret-scan.yml

  • 新增 .github/workflows/secret-scan.yml
  • PR event:diff-only scangit diff origin/main..HEAD),跑時間 ≤ 1 min
  • Schedule event(nightly 02:00 UTC):full-repo scan
  • Verified / Unverified policy 明訂
    • Verified finding(活的 key)→ CRITICAL,Block Merge + 觸發 SOP(見 AC v)
    • Unverified finding(格式符合但 API 測失敗)→ WARNING,不擋 PR 但 SARIF upload
    • 兩者都 SARIF upload 進 Code Scanning(需 Phase 0 開 Code Scanning)
  • Forked-PR 政策
    • pull_request event 從 fork 來無寫權限 token — diff-scan 仍跑但 SARIF upload 走 actions/upload-artifact fallback(不寫 Code Scanning,security tab 在 nightly full-scan 補上)
    • 不用 pull_request_target(執行 fork 程式碼 + 高權限 = 自殺)
  • Workflow permissions: 顯式宣告(contents: read, security-events: write, pull-requests: read),不要繼承 default

AC (iii) — L3 release.yaml digest verification

  • 在 release.yaml 既有 version-check job 加 digest verification step:
    • skopeo inspect docker://ghcr.io/vencil/threshold-exporter:v${VERSION} 取 digest
    • 比對 helm/threshold-exporter/Chart.yamlappVersion(Chart.yaml line 8)
    • 不一致 → fail release
  • 同樣對 tenant-api / da-portal / da-tools 四 image
  • 不用 root VERSION 檔案(不存在)— SoT 是 git tag + Chart.yaml
  • skopeo 認證走 GITHUB_TOKEN + packages: read permission(同 registry 自家 image 足夠,不用 OIDC

AC (iv) — Doc-as-Code sync(dev-rules #4

  • docs/internal/dev-rules.md 新增 §Security 條目(如尚無 section 直接建):
    • L0/L1/L2/L3 雙保險邊界表
    • --no-verify 嚴禁政策 + 罰則建議
    • .trufflehogignore 合法 escape 範例
  • docs/internal/github-release-playbook.md §版號驗證 章節更新引用新 digest verification step
  • CLAUDE.md 架構速查段補一行 Security gate(L0+L1+L2+L3 概念)
  • docs/internal/doc-map.md 新增條目:
    • secret-scan.yml workflow
    • secret-leak-remediation-sop.md(見 AC v)
  • CHANGELOG.md ### Security 條目:「Secret scan multi-layer (L0 native push-protection / L1 pre-commit / L2 server-side GHA / L3 release-time digest verification) + Remediation SOP」

AC (v) — Secret Leak Remediation SOP(最重要的 AC

  • 新增 docs/internal/secret-leak-remediation-sop.md第一條鐵律大寫粗體

    ASSUME COMPROMISE. ROTATE FIRST.

    Public repo 一旦推上含 secret 的 commit,駭客 scraper 在 2-5 秒內就抓到。git push -f / BFG / git filter-repo 是安慰劑 — refs / forks / GitHub archive / 第三方鏡像都還在。

    第一步、第二步、第三步:去 secret provider(AWS / GCP / DB / Slack / ...)Revoke / Rotate

    洗 git history 是次要善後,順序在 Rotate 之後。

  • SOP 內容明訂:

    • Step 1:identify secret 來源(哪個 provider)
    • Step 2:去 provider console rotate / revoke(不要等任何人 approve)
    • Step 3:通知 affected systems(重新部署 / refresh config)
    • Step 4(次要善後):BFG / git filter-repo 清歷史 + 通知 GitHub Support 清 cache(support ticket template)+ 通知 contributor force-pull
    • Step 5:post-mortem,更新 detection rules
  • Triage ownership:明訂 verified finding fire 時的第一聯絡人(建議:repo owner @vencil + 至少 1 個 backup contact)

  • SOP 連結從 secret-scan.yml workflow 的失敗訊息直接 link 出去

Dependencies

  • Blocked by:Phase 0 sub-issue #470 — L0 native 必先開
  • Blocks:v2.8.1 release tag

Out of scope

  • ❌ Custom secret pattern detection — 需付費 GHAS,不在本票
  • ❌ Image signing / SBOM hardening(已在 release.yaml 既有 cosign + syft 流程內,不變)
  • ❌ Runtime secret rotation automation(這是 platform 層工作,不是 lint)
  • ❌ Internal audit log / SIEM integration — 客戶端責任,repo 不負責

Sizing(v2 修訂)

AC 原估 修訂後 修訂理由
L0 Phase 0 toggle 0.05w(拆出 sub-issue) 10 min click + audit
(i) L1 pre-commit + .trufflehogignore + tests 0.3w 0.4w create-new + 設計 false-positive escape policy
(ii) L2 GHA + Verified/Unverified policy + Forked-PR + SARIF 0.3w 0.5w create-new + diff/nightly 雙 mode + fork policy + SARIF upload
(iii) L3 release digest verification 0.2w 0.2w 不變
(iv) Doc-as-Code sync 0.2w 0.3w 多 CLAUDE.md + doc-map.md
(v) Remediation SOP(新 AC 0.3w 寫 SOP + triage ownership
總計 1w ~1.7w 增加 0.7w(SOP + Verified/Unverified policy + Forked-PR 為主)

v2.8.1 sprint scope 評估:v2.8.1-dx-interim 原抓 #378+#379+#436 三張(per memory,currently paused)+ 本票 = 4 張。v2.8.0 ship 後重新評估 milestone scope,可能需拆 v2.8.1 vs v2.8.2。

Rationale for v2.8.1(不延 v2.9.0)

  • 眼前最大(可能也唯一)客戶非常重視 security — 在 v2.8.1 補齊是商業必要動作
  • v2.8.0 ship 後立刻進 v2.8.1,與客戶 evaluation 窗口對齊
  • Phase 0 sub-issue 立即止血(不等 v2.8.1 sprint)

References

  • v2.8.0 Phase .a 軌道二 A-14(Q2 修訂版延 v2.8.1)
  • v2.8.0 closure E-1 audit(本 issue 開立 trigger)
  • v2.8.0 Phase .a Policy-as-Code 8 提案 G5/G6
  • 既有 workflow: .github/workflows/release.yaml line 52-58 version-check job
  • Pre-flight finding source: .pre-commit-config.yaml(無 secret scan hook)+ gh api repos/... security_and_analysis(disabled)+ helm/threshold-exporter/Chart.yaml line 8 appVersion
  • Phase 0 sub-issue: #470

Rewritten v2 (2026-05-12) incorporating Claude + Gemini three-round review — focusing on factual corrections (3 prose errors), L0/L1/L2/L3 layered defense framing, Rotate-First SOP, Verified/Unverified policy, Forked-PR scanning policy, and v2.8.1 sprint reality.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal priority — backlogciCI / build pipelinesecuritySecurity / CVE / supply-chain

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions