nics-dp 組織共用 mise tasks + reusable GitHub Actions workflows + 共用設定檔之 meta repo。本 repo 無可建置程式碼,純配置與 CI/CD 基礎設施。
| 目錄/檔案 | 說明 |
|---|---|
.github/workflows/ |
Reusable GitHub Actions workflows (mise-task.yml 為核心;release / sbom-image / codeql / utility 等) |
.mise/tasks/ |
共用 mise atomic tasks (ci/, iac/, go/, node/, py/, sbom/, gs/, dc/, meta/, lib/),consumer 透過 git:: remote includes 引用 |
templates/facades/ |
5 個 mise.toml facade templates (mise.go-service.toml, mise.go-lib.toml, mise.frontend.toml, mise.python.toml, mise.image.toml) — copy 後依需求加 repo-specific 即可使用 |
configs/ |
共用設定檔 (eslint.config.js, .prettierrc.json, .prettierignore, .oxfmtrc.json, lighthouserc.json, playwright.config.ts)。vitest.config.ts / knip.json 改為 repo-local(各 consumer commit 自家 root 檔,工具自動發現);.golangci.yml 亦非共享(見下方例外) |
renovate-preset.json |
Org-level Renovate preset (extends from consumer renovate.json) |
Consumer repo 採 facade pattern:自家 mise.toml 暴露標準頂層 vocabulary,底層 depends 到本 repo atoms。mise tasks ls 只看到 facade,atoms 全 hidden。
[task_config]
includes = ["git::https://github.com/nics-dp/meta.git//.mise/tasks?ref=main"]Facade templates 於 templates/facades/,包含 [settings] / [tools] / [env] / [task_config] / facade [tasks.*] 全套。Consumer 複製進自家 mise.toml 後依需求改 [env] 或加 repo-specific tasks 即可。
所有 atoms 標 #MISE hide=true,consumer 透過 depends 呼叫。Atom 簽名一旦穩定(Phase E tag v1)視為 versioned API,breaking change 須協調升 ref。
| 類別 | Atoms | 用途 |
|---|---|---|
ci:* |
semgrep, trivy-license, betterleaks, trufflehog | 通用 CI 檢查(語言中立)。ci:semgrep 引擎已改為 OpenGrep(原生 single-binary semgrep fork,無 Python;CLI/registry packs drop-in 相容,task 名與簽名不變)。ci:betterleaks=快速 secret 掃描 PR gate(Gitleaks fork,PR 上優先掃 base..HEAD,base ref fetch 失敗則 fallback 全歷史);ci:trufflehog=deep/release scan,只報經驗證的 live secrets |
iac:* |
trivy, img:hadolint, actionlint | IaC misconfig + Dockerfile lint + workflow YAML lint |
go:* |
api-fix, audit, build, bench-compare, clean, dead-code, deptree, dev, generate, install, lib-local, lib-remote, lint-check, lint-fix, report, run, sast, test, update | Go 建置/測試/Lint/安全/模組。go:test 預設只跑 unit;flags:--race、--coverage、--bench [--pattern X]、--full;go:report 從 coverage.out 產 HTML+MD(自動讀 go.mod module path 解析 component);go:bench-compare 跑 benchstat;go:dead-code 用 cmd/deadcode,預設只分析 production(root 為所有 main package,常見於 cmd/*),--whole-program 才把測試一併納入並 root(-tags "$GO_TEST_TAGS" -test,預設 test);go:deptree 用 go mod graph;路徑/tags/coverpkg 由 lib/go-env auto-detect |
node:* |
install, build, bench-compare, bundle-size, clean, deptree, run, test, e2e, e2e-install, lint-check, lint-fix, oxlint, format-check, format-fix, oxfmt-check, oxfmt-fix, typecheck, typecheck-tsgo, sast, audit, update, knip, lighthouse | JS/TS via bun。lint/format/lighthouse 拉 configs/ shared;test/knip 用 repo-local config(各 repo 自家 root 檔,工具自動發現,缺檔即報錯);e2e 用 Playwright;node:clean [--deep] 清 transient;node:bench-compare 跑 vitest bench × --count 後 merge JSON,無 flag 列對比 (mean ± rme + Welch t-test 完整 p-value);node:bundle-size 偵 .size-limit config 用 size-limit,否則 fallback du+gzip。原生 binary 平行替代(opt-in,與既有 atom 並存):oxfmt-check/oxfmt-fix ↔ prettier、oxlint ↔ eslint(script-only,不解析 .vue template)、typecheck-tsgo ↔ vue-tsc(.ts only,需 repo 自備 *.vue shim);三者皆 bunx 無版本、版本由 consumer package.json devDep 控制 |
py:* |
install, build, audit, bench-compare, clean, complexity, dead-code, deptree, format-check, format-fix, license-custom, lint-check, lint-fix, profile, report, run, safety-db, sast, sbom-custom, test, typecheck, update | Python via uv + ruff + pytest + bandit + pip-audit + ty。py:sast (bandit);py:typecheck (ty Beta / --pyrefly);py:dead-code (vulture);py:complexity (radon/xenon);py:deptree (uv tree);py:safety-db (safety<3);py:license-custom (pip-licenses);py:sbom-custom (cyclonedx-py);py:profile 預設 cProfile,flags:--instrument/--spy/--mem/--scalene;env override 由 lib/py-env |
sbom:* |
source, enrich, trivy, grype | Source SBOM 產生與漏洞掃描 |
gs:* |
clone, update | Git submodules |
dc:* |
up, down, pull, rec, clean | Docker Compose 生命週期(本機 dev stack 起/停/拉取/重建/清除) |
meta:* |
bump | 清 mise tasks cache 強制重抓 atom includes |
lib/* |
logs, go-env, go-version, py-env | 內部 sourced helper library |
mise tasks ls --hidden 列出全部 atoms。
| Facade | 語意 |
|---|---|
init |
bootstrap deps, hooks, submodules |
clean |
wipe build artifacts / caches / transient state |
build |
產 binary / artifact |
run |
本機跑 service |
test |
unit / integration tests |
bench |
benchmarks |
ci |
全部 CI 檢查(lint + sast + audit + dead-code + deptree + semgrep + ...) |
sbom |
產 enriched SBOM + 掃描 |
update |
bump deps + refresh atom includes (meta:bump) + update submodules |
all |
便利組合:init → build → test → ci |
Repo-specific concepts (stg:*, pgroll:*, benchmark:*, spec, example:* 等) 留 repo 本地,不進 facade 層。
Consumer 在自家 mise.toml 定義同名 task 即覆寫(mise 偏好近檔)。update facade 用 meta:bump 清 mise cache 強制下次 run 重抓 main;一旦 ref 改成 tag (v1),meta:bump 變 no-op,須手動改 ref。
go:test / go:report 透過 lib/go-env 自動偵測:
| Env var | Default | 用途 |
|---|---|---|
GO_TEST_TAGS |
test |
go:test/go:bench-compare 的 -tags= build tags;go:dead-code 僅 --whole-program 時帶入 |
GO_TEST_PATHS |
./test/...(如 test/ 存在)/ ./... |
測試目標 paths |
GO_TEST_MOD |
vendor(如 vendor/ 存在)/ mod |
-mod= 模式 |
GO_COVERPKG |
<go.mod module>/internal/...(如 internal/ 存在)/ empty |
-coverpkg= 範圍 |
CGO_ENABLED |
1 |
race detector 須 cgo |
go:report 額外自動讀 go.mod module path 解析 component(支援短 module 名與 hostname-style github.com/<org>/<repo> path)。
py:* 透過 lib/py-env:PY_RUNNER (default uv run --group test)、PY_TEST_PATHS、PY_LINT_PATHS、PY_BANDIT_PATHS、PY_BANDIT_EXCLUDE、PY_COVERAGE_FILE。
node:bundle-size 用 BUNDLE_SIZE_DIR 指定掃描目錄(default dist)。
Atoms 跑完會在 repo 根產 transient 檔。mise run go:clean / node:clean / py:clean 可清,但建議直接列 .gitignore:
# Go
coverage.out
coverage.html
coverage.md
bench-*.txt
bin/
# Node
dist/
build/
.next/
.turbo/
.vite/
coverage/
playwright-report/
test-results/
.lighthouseci/
.eslintcache
bench-*.json
# Python
.pytest_cache/
.ruff_cache/
.mypy_cache/
.coverage
coverage.xml
htmlcov/
sbom.json
sbom-py.json
__pycache__/
.benchmarks/
dist/
build/
.venv/
# SBOM artifacts (all langs,sbom facade 產出)
enriched-source.cdx.json
sbom-source.cdx.jsonAtoms 之 trap cleanup 結束時清 curl 下來的 shared config (eslint.config.js、.prettierrc.json、playwright.config.ts、lighthouserc.json),但 atom 中斷時可能殘留 — 若 repo 不另放可一併 ignore。(vitest.config.ts / knip.json 已改 repo-local,不再 curl,故不在此清單。)
.golangci.yml例外:由 consumer repo 自家 commit(非 curl),須含gofumpt.module-path: <repo-module>設定(v2.12.2 自動推導對無.模組名會誤判 stdlib,致 gci↔gofumpt import 互相 false positive)。範本直接 ref 既有 Go repo 之.golangci.yml。
go:lib-local/go:lib-remote注意事項: 兩 atom 由 env 驅動:GO_LIB_LOCAL = "github.com/nics-dp/libdcf=../libdcf github.com/nics-dp/ZenQuery=../ZenQuery" GO_LIB_REMOTE = "github.com/nics-dp/libdcf@dev github.com/nics-dp/ZenQuery@dev"
go:lib-local自動停用 repo 自家.golangci.yml中gomoddirectives規則並建立.semgrepignoreblock 排除 vendored libs。go:lib-remote還原。.semgrepignore不應 commit(加入.gitignore)。
封裝 actions/checkout + jdx/mise-action + 私模 git config + run + summary + enforce。Action 版本中央 pin 於此檔,下游無需各自 pin。
Consumer ci.yml 用 matrix 呼叫:
jobs:
checks:
name: ${{ matrix.name }}
strategy:
fail-fast: false
matrix:
include:
- { name: "Go Lint", task: "go:lint-check" }
- { name: "Go SAST", task: "go:sast" }
- { name: "Go Audit", task: "go:audit" }
- { name: "Go Test", task: "go:test --race --coverage" }
- { name: "Semgrep", task: "ci:semgrep golang" }
- { name: "Trivy IaC", task: "iac:trivy" }
- { name: "Hadolint", task: "iac:img:hadolint" }
- { name: "Trivy License", task: "ci:trivy-license" }
uses: nics-dp/meta/.github/workflows/mise-task.yml@main
with:
name: ${{ matrix.name }}
task: ${{ matrix.task }}
runs_on: '{"group":"releasers"}'
private-modules: true
secrets:
ci_read_app_private_key: ${{ secrets.CI_READ_APP_PRIVATE_KEY }}
# client-id is read from the CI_READ_APP_CLIENT_ID org variable (auto-available
# in reusable workflows); no need to pass it as a secret.| Input | Type | Default | 用途 |
|---|---|---|---|
task |
string | required | mise atom 名稱 (e.g., go:lint-check、ci:semgrep golang) |
name |
string | task | display name for GH job summary |
runs_on |
string | '"ubuntu-latest"' |
runner(JSON 經 fromJSON() 解析;可傳 '{"group":"X"}') |
fetch-depth |
number | 1 |
git fetch depth |
private-modules |
boolean | false |
啟用 ci-read App token git config for private modules |
App 認證(nics-dp-ci-read,用於 private-modules=true):client-id 由 org 變數 CI_READ_APP_CLIENT_ID 提供(reusable workflow 經 vars context 自動取得,毋須傳遞);caller 僅需以 secret 傳 ci_read_app_private_key(org secret CI_READ_APP_PRIVATE_KEY)。legacy ci_read_app_id 輸入已移除(不再宣告,請勿再傳)。
每 job 結尾自動 emit ## <name> block 至 GitHub Actions step summary,含 ✅/❌ 狀態 + <details> 包 tail 300 行 stdout/stderr。
| Workflow | 用途 |
|---|---|
go-release.yml |
Go binary 跨平台建置 + cosign 簽章 + 多平台 SBOM;3 jobs:prepare → build (matrix) → release |
image-release.yml |
Docker image dual registry (DockerHub + GHCR) + BuildKit SBOM + SLSA provenance + Sigstore attestation + cosign 簽章;layer 壓縮 auto:snapshot→zstd、release→gzip(compression input 可覆寫) |
sbom-source.yml |
Source 端 CycloneDX SBOM (anchore/sbom-action) + parlay 增強 + Trivy/Grype 漏洞掃描 → release-mode 上傳至 GitHub Release / snapshot-mode 留 workflow artifact |
sbom-image.yml |
Container image CycloneDX 1.6 SBOM + parlay 增強 + Trivy/Grype 漏洞掃描 → GitHub Release + Security tab |
詳見各 workflow 內 workflow_call 之 inputs / secrets 宣告。
| Workflow | 用途 |
|---|---|
codeql-reusable.yml |
CodeQL Advanced 分析 reusable workflow。Inputs:matrix-include (JSON array of {language, build-mode} entries — 例 [{"language":"actions","build-mode":"none"},{"language":"go","build-mode":"manual"}])、go-cgo-enabled、use-private-go-modules、submodules |
codeql.yml (meta 自身) |
meta repo 自家 CodeQL workflow,僅掃描 actions 語言(workflow YAML) |
Go 與 Node 的 dependency-submission 拆成兩支:go.mod GitHub 原生解析,bun.lock 則否。
| Workflow | 用途 |
|---|---|
security-sarif.yml |
Gate-only scanners(gosec、govulncheck、semgrep、trivy config、hadolint),各自上傳獨立 code-scanning SARIF category;non-blocking(只填 Security tab,不擋 CI) |
dependency-review.yml |
PR-time dependency-review-action 掃 GitHub dependency graph;引入帶已知漏洞(≥ fail_on_severity,default high)或禁用授權的相依時 擋 PR;須由 pull_request 觸發的 workflow 呼叫 |
scorecard.yml |
OpenSSF Scorecard(PRIVATE 變體),上傳 SARIF 至 code scanning(category: scorecard,non-blocking);用 nics-dp-scorecard App 對私有 repo 評分;publish_results: false |
scorecard-publish.yml |
Scorecard 的 PUBLIC 變體:另發佈結果至 OpenSSF 公開 API(badge),僅適用公開 repo(如 meta 自身) |
go-dependency-submission.yml |
送 Go 相依圖至 Dependency Submission API;用 ci-read App token 做 org-scoped 私模 git rewrite |
node-dependency-submission.yml |
送 bun 專案完整 transitive npm 圖(GitHub 不解析 bun.lock,故 bun install 後用 Syft catalog node_modules);全公開 npm,免 token |
詳見各 workflow 內 workflow_call 之 inputs / secrets 宣告。
| Workflow | 用途 |
|---|---|
artifacts-comment.yml |
PR 留言列當前 run artifacts,含 nightly.link 下載連結 |
ci.yml— meta repo 自家 CI,透過mise-task.ymlmatrix 跑iac:actionlint(workflow YAML lint)+ci:betterleaks/ci:trufflehogsecret-scan jobs。self-supply-chain.yml— meta 消費自家scorecard-publish.yml(publish: true,meta 為公開 repo);無 dependency-submission job(meta 無編譯語言 manifest,純配置)。self-dependency-review.yml— meta 的 PR-time dependency review,透過dependency-review.ymlreusable。
Atoms 跑時用 curl 抓 raw GitHub 設定,跑完 trap cleanup 清除暫存檔。
| 檔案 | 用途 | 由哪些 atom 拉取 |
|---|---|---|
eslint.config.js |
ESLint flat config + security plugin | node:lint-check, node:lint-fix |
.prettierrc.json + .prettierignore |
Prettier shared | node:format-check, node:format-fix |
.oxfmtrc.json |
Oxfmt (Oxc formatter) shared | node:oxfmt-check, node:oxfmt-fix |
lighthouserc.json |
Lighthouse CI shared | node:lighthouse |
playwright.config.ts |
Playwright base (env-driven PW_*) |
node:e2e, node:e2e-install |
Consumer 可透過 META_CONFIG_BASE env 覆寫 raw URL 來源(forking nics-dp/meta 時用)。
.golangci.yml 例外:不在 configs/ 共享。各 Go consumer repo 自家 commit .golangci.yml(含 gofumpt.module-path: <module> 顯式設定,繞過 golangci-lint v2.12.2 之 gci↔gofumpt false positive)。go:lint-check / go:lint-fix atom 不再 curl,直接讀 repo 自家檔。
vitest.config.ts / knip.json 例外:entries/ignores、setup files 等本質 repo-specific,不在 configs/ 共享。各 web consumer repo 自家 commit root vitest.config.ts / knip.json,工具自動發現。node:test / node:knip / node:bench-compare 不再 curl,並於缺檔時明確報錯(非靜默 fallback 預設行為)。
Consumer repo 之 renovate.json 引用 org preset:
{
"extends": ["github>nics-dp/meta:renovate-preset"]
}renovate-preset.json 以 native managers(github-actions、gomod、dockerfile、mise 等)為主,另加三個 regex customManagers 處理 native manager 辨識不到的釘版(清單以 renovate-preset.json 為準):
air-verse/air— dev compose(compose.ya?ml/deploy/compose.*.ya?ml內go install github.com/air-verse/air@vX).mise/tasks/*任務 header 內"aqua:<pkg>"="<ver>"/"github:<pkg>"="<ver>"釘版(generic,只配對數字開頭版本,="latest"掃描器不動).mise/tasks/*任務 header 內bun="<ver>"(映射 oven-sh/bun)
workflow(
.github/workflows/**)內以go install …@vX釘版的工具(quill、parlay、gosec、govulncheck)與mise-task.yml的jdx/mise-actionversion:pin 不在「org preset」customManager 覆蓋範圍(preset 只含上列三個,供 consumer extend),而是由 meta repo 自家renovate.json的 self customManagers 追蹤自動 bump(consumer repo 無此類 workflow 工具釘版,故 preset 不需涵蓋)。
- 從
templates/facades/mise.<archetype>.toml(go-service/go-lib/frontend/python/image) 複製為 repo 自家mise.toml - 確認
[task_config].includes = ["git::https://github.com/nics-dp/meta.git//.mise/tasks?ref=main"] - 加 repo-specific tasks/tools/env at end
- 寫
.github/workflows/ci.yml,用 matrix 呼叫nics-dp/meta/.github/workflows/mise-task.yml@main - 設 org 變數 + secrets:
- org 變數
CI_READ_APP_CLIENT_ID(nics-dp-ci-read App 的 client-id;reusable 經vars自動取得) - org secret
CI_READ_APP_PRIVATE_KEY(caller 以secrets:顯式傳ci_read_app_private_key:Go 私模 + CodeQL private repo + release/snapshot) DOCKERHUB_USERNAME+DOCKERHUB_TOKEN(Docker image repos)
- org 變數
驗證:mise tasks ls 應顯示 ~10 facade 名 + repo-specific extras(atoms hidden);mise run --dry-run ci test sbom resolve 無誤。