QA Touchstone 是一個本機優先、為 CI 做 API 安全測試的桌面工具: 對真實 API 執行身分 × 端點的 RBAC 矩陣、BOLA/IDOR 物件授權測試與速率限制 濫用檢查,跨執行管理 findings 並與 baseline 比對,再匯出 SARIF / JUnit / HTML / JSON 產物供 pipeline 把關。圍繞這個核心,它也提供完整的支援工作台 ——Postman 相容 API client(REST 與 GraphQL)、collection 真實執行、背景 monitors、k6 效能測試、AI 測試案例產生與分流、可匯出的 API 文件——整合在 同一個 Tauri app 裡。
本機優先、相容 Postman 的桌面 API QA 工作台 — API client、collection runner、 安全矩陣、monitors、效能測試與可匯出文件,全部整合在一個 app。
| 安全矩陣(RBAC) | AI 測試產生 | API client |
|---|---|---|
![]() |
![]() |
![]() |
| 產生的 API 文件 | 效能 / 負載測試 | Realtime(WebSocket / SSE) |
![]() |
![]() |
![]() |
重生指令:開著 dev server 時執行 node scripts/capture-screenshots.mjs(用系統 Chrome 透過 DevTools Protocol 驅動;介面截圖預設英文,要中文介面設 LOCALE=zh-TW)。
- Getting Started — 從 clone 專案到發出第一個 request、跑完第一次掃描
- Capability Matrix — 桌面版與 headless CLI 各自能跑什麼
- Security Workflow — RBAC/BOLA/速率限制的端到端流程
- Design System — 主題、tokens 與 UI 基礎元件
- AI 時代 API 測試評估 — 產品命題
- CHANGELOG · 架構圖
目前公開版聚焦在 API 測試:
- Generic API environments:local、staging、production,以及自訂目標
- 透過 Tauri desktop backend 執行本機 request
- Browser/dev fallback,方便測試穩定與快速 UI 迭代
- Runtime data 與 credentials 儲存在本機
- 不包含公司內部服務、內部連結,或已淘汰的非 API workflow 文件
- API client:建立 HTTP 與 GraphQL requests、切換 environments、檢視 responses、查看 call history,並把 responses 與 history 匯出成 HTML、JSON 或 CSV 報告。
- Import/export:匯入 Postman v2.1 collections 與 OpenAPI/Swagger JSON; 也可匯出為 Postman JSON。
- Authentication:No Auth、Bearer Token、OAuth 2.0(authorization-code、 client-credentials、password grants)、API Key、Basic Auth、AWS SigV4。
- Variables and cookies:解析 global、collection、environment、local variables,以及動態值({{$timestamp}}、{{$guid}}、{{$randomInt}}); 透過本機 cookie jar replay 符合 domain/path 的 cookies。
- Collection Runner:批次執行選定 requests,支援 CSV/JSON data iteration,並用 live responses 計算 assertions。
- 安全測試(Security testing):執行身分 × 端點的 RBAC 矩陣——同一批已存
requests 用多個身分各送一次——可逐格設定 allow/deny 預期、可調的拒絕狀態碼集合,
並以 response oracles 標示敏感資料外洩與 schema 偏移。矩陣 oracle 會看 body:
回 200 但內文實際拒絕(
{"error":"Access denied"})會被判定為 denied,而不是 誤報的 vuln。物件層級授權(BOLA/IDOR) 測試在不同身分間替換物件 id,支援自動偵測 id 位置、可重用的跨租戶 presets,以及 避免誤判的 negative control(物件 id 回顯只在「像身分」的 key 上才算數,且 control 改用獨立的結構 oracle 評分)。速率限制 / 濫用測試在確認關卡後送出有上限的 request bursts,並依「第一個 429 出現前放行了幾個 request」把防護分級為 none / weak / strong。 單一 執行完整安全掃描(Run full security suite) 會把六個引擎當成一次已記錄的 執行依序跑完。速率限制刻意排最後一個上場:它的測法就是對 API 狂發請求, 讓最吵的測試先跑,會弄髒矩陣與 BOLA 引擎的量測結果。 其中三個引擎——輸入 fuzzing(偵測 5xx、stack-trace 洩漏、payload 反射)、 自動推導的 BFLA(OWASP API5)掃描,與 JSON-Schema/OpenAPI conformance 驗證——以純函式、完整單元測試的模組形式出貨,SARIF 規則中繼資料已備妥於報告層。 fuzzing 與 BFLA 已同時接入桌面版安全套件與 headlessscan指令;conformance 目前僅在桌面版執行(尚無 Rust port,故 CLI 不會跑它)。各表面的支援範圍見 docs/capability-matrix.md。 - AI 安全分流(AI security triage):把整批掃描(矩陣 + 物件授權 + 速率限制) 濃縮成一份簡短、依優先序分類的清單——先看哪幾個、哪些像真的問題、哪些可能是誤判 ——僅供參考,不會更動底層 findings。
- 發現生命週期(Findings lifecycle):抑制誤判、覆寫嚴重度、指派負責人/狀態/備註, 並將每次掃描與釘選的基準(baseline)比對——新增/延續/已消失標記,加上新增高/嚴重計數。
- 安全報告 / CI 產物(Security reports / CI artifacts):將一次完整的 suite 執行
匯出為 JSON 產物、HTML 主管報告、JUnit XML(CI 測試檢查)或 SARIF(GitHub code
scanning)——以「新增的高/嚴重發現」作為 gate,並提供三段遮蔽等級給離開本機的產物:
strict完全不含佐證、redacted保留短遮罩值、evidence再附上一份結構保留、 預設遮掩(mask-by-default) 的 request/response 摘要以定位每筆發現——除了發現本身那一個 葉節點外,其餘值一律型別化,確保 token、cookie、PII 永不外洩。該佐證摘要為即時生成, 僅在明確選擇時才落地進該次執行。SARIF 輸出已可直接餵 code scanning:每條 rule 帶名稱、完整描述、helpUri、CWE/OWASP tags 與 GitHubsecurity-severity分數,每筆 result 附physicalLocation。 - Monitors:可手動觸發真實 collection checks;啟用後也會在 app 執行期間依照設定的 cadence 自動執行。
- Performance testing:產生並執行 k6 performance、load、stress tests, 提供 live metrics、SLO scoring、history 與可匯出的 reports。
- AI assistance:從 BDD、OpenAPI、PRD 或類 PDF 文字產生分類好的測試案例; 也能針對單筆 API response 對照既有 assertions 做 review;並可隨時掃描單筆 response 找出敏感資料外洩(PII、secrets、內部或 debug 欄位)。
- 可設定的 AI 供應商(Configurable AI provider):所有 AI 功能(測試產生、 response review、敏感資料掃描、安全分流)都跑在你選的供應商上——OpenAI, 或自訂 / 企業自管(on-prem)的 OpenAI 相容 endpoint——憑證只留在本機。 AI 功能是可選的:未設定供應商時,測試產生會 fallback 到內建的 heuristic 引擎,其餘功能完全可用。(「內建 Claude 免 key」供應商只在 UI 跑在 claude.ai Artifacts 沙箱內時可用——桌面版安裝檔中無法使用;設定頁會 即時顯示其可用狀態。)
- AI 隱私模式(AI privacy mode):所有 AI 呼叫都經過單一 egress chokepoint,
且預設遮蔽。三段模式——
full context、redacted(預設)、local only——決定哪些資料離開裝置。redacted在送出前於本機遮蔽 URL(去 host)、回應內容 (結構保留、值轉型別 token、保留 key 名)、headers 與識別碼(email、token、UUID、 IP、Luhn 卡號、SSN),並把 OpenAPI 規格縮成 path shape(不送真實 host、不送 example 值);local only封鎖雲端供應商、只允許自管端點(loopback/私網/已聲明)。送出前 會顯示完整 prompt 預覽,且 CI/組織 lockdown(envQA_ALLOW_EXTERNAL_AI)可強制 關閉外部 AI。 - Docs and codegen:產生 API docs、獨立 HTML 匯出,以及 request code snippets(cURL、Python、JavaScript、HTTPie)。
- Realtime testing:測試 WebSocket 與 Server-Sent Events streams。
- 雙語、可換主題的介面(Bilingual, themeable UI):完整的英文與繁體中文 介面,可在設定切換;深色 UI 提供多組 accent 配色。
下面用一條完整旅程把上面每一項功能串起來:你剛接手團隊的訂房服務 API, 從第一次匯入一路走到把整套檢查交給 CI。想知道 findings、指紋與 baseline 在底層怎麼運作,見資料模型(白話版)的三天示範故事。
接手——匯入而不是重建。前人留下一份 Postman collection 和一份 OpenAPI 規格。兩份檔案直接匯入,requests、資料夾與變數原樣進到 workspace;之後整理乾淨了,也隨時能匯出成 Postman JSON 還給團隊。
打通第一發。把 environment 切到 staging,設好 OAuth 2.0
(client-credentials),送出第一個 GET /bookings——回應、耗時與 call
history 都留在本機。同事問怎麼呼叫,直接產生 cURL 或 Python snippet
貼給他;PM 要文件,就把整份 API docs 匯出成獨立 HTML。
把測試資料變活。動態值幫你造資料——{{$guid}} 當訂位代碼、
{{$randomInt}} 當人數——cookie jar 自動 replay 登入後的 session
cookie。報表端點是 GraphQL?同一個 client 切過去就能測。
批次回歸。把冒煙測試存成 collection,交給 Collection Runner 搭配 CSV 做資料迭代,assertions 對著真實回應評分——綠燈是真的綠燈, 不是罐頭資料。
讓 AI 補位,資料不出門。把 PRD 或 OpenAPI 丟給 AI 產生分類好的
測試案例、對可疑回應做 review、掃一輪敏感資料外洩。供應商由你指定
(OpenAI 或公司自管的相容 endpoint),而且預設走 AI 隱私模式的
redacted:URL 去 host、值轉成型別 token,送出前還能看完整 prompt
預覽。
一鍵安全體檢。按下「執行完整安全掃描」,六個引擎依序上場—— RBAC 矩陣、BOLA/IDOR、fuzzing、BFLA、conformance,最吵的速率限制 壓軸——整趟記成一次執行。掃完先讓 AI 安全分流把結果濃縮成 「先看哪幾個」的優先清單。
人的判斷留下來。真問題指派給後端同事、誤判抑制掉、嚴重度該調就調; 這些決定跟著指紋走,重掃不會被洗掉。把這次結果釘成 baseline,之後 只需要盯「新增的高/嚴重」。
上線前的壓力與串流。用 k6 模擬連假訂房尖峰,live metrics 與 SLO 評分即時告訴你撐不撐得住;訂位狀態推播走 WebSocket,開 Realtime testing 盯著 stream 驗證事件順序。
交給 CI,放著讓它顧。headless CLI 在 pipeline 裡重跑 collection 與安全掃描,JUnit 進測試報告、SARIF 進 GitHub code scanning,「新增高/嚴重發現」就是 merge gate;上線後 Monitors 依 cadence 自動巡檢。而這一切——從匯入第一份 collection 到現在——都在 同一個雙語、可換主題、資料完全留在本機的桌面 app 裡完成。
- Frontend:React 19 + Vite,100% TypeScript(strict)。Workspace、
request/send、monitor 狀態都放在型別化的 React context provider
(
src/qa/state/);共用領域型別在src/qa/types.ts。 - Desktop shell:Tauri 2
- Backend commands:Rust——request execution(reqwest + 手動跟隨 redirect、
AWS SigV4,並內建 SSRF 防護:擋下對雲端 metadata 位址的簽名請求)、k6 子程序
執行器、temp-file 輔助、本機 config/data 持久化、OS keychain 機密儲存
(
keyring),以及由原生儲存對話框餵路徑的文字檔儲存指令。暴露給 renderer 的指令面刻意維持最小(無 shell、無任意網路存取);停用 TLS 驗證需要 renderer 明確確認,且會留下稽核紀錄。 - Security engine(單一事實來源):RBAC 矩陣掃描在共用的 Rust core
(
src-tauri/core)中透過 IPC 執行(run_security_matrix)——與 headless CLI 同一套引擎;TypeScript 引擎(src/qa/*.ts)則作為經 parity gate 把關的瀏覽器 fallback。其餘引擎(BOLA、rate-limit、BFLA、fuzz)目前在桌面版仍以 TypeScript 執行。 - Storage:單一版本化儲存層(
src/qa/storage.ts,讀取時自動 migrate 舊資料 形狀)透過 Rust 後端把關鍵 工作區資料鏡像到磁碟;cookie jar 套用完整 Public Suffix List(src/qa/psl.ts)。 - Performance engine:k6,會 materialize 到
src-tauri/resources/ - Tests + checks:Vitest + Testing Library 與 Rust unit tests,CI 連同
tsc --noEmit、ESLint、npm audit、cargo audit一起把關;workflow actions 全數釘在 commit SHA。
findings、指紋、baseline、雙引擎與 AI 怎麼兜在一起——不用術語也能懂,附三天示範故事
所有問題回報單長得一模一樣。六個安全引擎(矩陣、BOLA、BFLA、rate-limit、
conformance、fuzz)各自找不同種類的問題,但找到的每個問題都會改寫成同一張
標準回報單——UnionFinding(src/qa/types.ts),欄位固定:哪個引擎、多嚴重、
哪條規則、在哪裡、證據是什麼。因為所有引擎講同一種格式,畫面、報告、跨執行
比對只要寫一次就能服務全部六個引擎——之後新增引擎也完全不用動它們。
每個問題都有指紋。app 會把問題的「身分」(規則+位置)雜湊成指紋
(fp),並刻意忽略每次執行會變動的部分(例如文字描述與證據);那些細節另外
用第二個雜湊(dfp)記錄。這樣就能分辨三種情況:全新的問題、同一個問題再次
出現、同一個問題但細節變了。規則改名時走別名表(src/qa/findings.ts),
所以改名後的規則永遠保有原本的指紋。
兩個存檔位,誠實比對。app 只保留兩份快照:釘選的 baseline(你認可的
狀態)與 lastRun(最新一次)。比對指紋就得出「新增/延續/已消失」標記。
每份快照還存了一個「這次測了什麼」的雜湊(scopeHash);如果這次涵蓋的端點
或身分和 baseline 不同,報告會在「已消失」標記旁邊同時亮出「範圍變了」的
警告,免得測試範圍縮水被誤當成真的修好了。
人工判讀永不遺失。分流決定——抑制誤判、覆寫嚴重度、負責人、備註——存在
自己的表裡,以指紋為 key、不屬於任何單次執行,所以重新掃描不會洗掉它們。
格式升級時,舊的分流資料會被隔離到 legacy 欄位而不是刪除;至於重掃一次就能
重生的快照,直接重置即可。
兩個引擎、一個真相。矩陣引擎存在兩份——Rust core(src-tauri/core,
單一事實來源,桌面 IPC 與 headless CLI 都用它)與 TypeScript(fallback:
瀏覽器裡由它掃描,桌面版上核心還沒接手的少數部分也暫時由它負責)。兩個
機制防止它們走鐘:其一,Rust 端只要看到 config JSON 裡有不認得的欄位就
整份拒收;其二,CI 上的 parity gate——用凍結的時鐘和固定的亂數執行
TypeScript 引擎,產出提交進 repo 的「標準答案卷」,Rust 測試必須重現一模
一樣的答案,答案過期 CI 直接失敗。secrets 只能以環境變數引用寫進
config(變數不存在是硬錯誤,不會靜默變成空字串),而 core 經 IPC 回傳的所有
內容——findings 和錯誤訊息——都會先過同一道遮蔽關卡,因為連「連線被拒」
的錯誤訊息都可能夾帶含 API key 的 URL。
AI 是乘客,不是駕駛。上面整條 finding pipeline 是完全確定性的——可選的
AI 功能只坐在它的邊緣。資料要送往 LLM 只有一扇門(src/qa/llm.ts),組
prompt 之前先遮蔽;回來的答案採防禦性解析,格式不對就收斂成空結果、絕不
重試。AI 分流與 review 的建議寫進自己的型別,永遠不碰 findings、快照或分流
記錄。唯一刻意留的例外是隨選的 AI 敏感資料掃描:它的結果會以真正的 finding
進入 pipeline,但只在你按下按鈕時發生,而且一律標記 source: 'llm'。加上
指紋本來就忽略文字描述與證據——恰好是 AI 能影響的欄位——所以 AI 的非確定
性永遠改變不了一個 finding 跨執行的身分。
示範故事・第一天——問題被抓到。你經營一個線上商店網站,後台有一個
「查看所有訂單」的功能(網址是 GET /admin/orders)。你準備了兩種測試
身分:訪客(沒登入的人)和管理員。接著在一張表格裡寫下你的期望:
訪客用這個功能應該被擋下、管理員應該可以通過。這張「身分 × 功能」的期望
表格就叫矩陣;矩陣引擎則是一個自動測試程式,它替表格裡的每一格
真的發出一次請求,再把實際結果拿來跟你的期望對答案。這次對答案發現:
管理員看得到訂單(符合期望),但訪客竟然也看得到全部訂單(跟期望不符)
——引擎就開出一張回報單,上面固定記著:哪個引擎抓到的、違反哪條
規則、發生在哪裡、多嚴重、證據是什麼(證據會先打上馬賽克)。app 還會替
每張回報單算出一個指紋——像身分證號碼,從「哪條規則+發生在哪裡」
計算出來、跟描述文字無關,所以同一個問題以後再被抓到,號碼一定相同。
同一次檢查還發現回應裡露出顧客的 email,所以總共兩張回報單。這整批結果
存成一份快照(這次檢查的存檔,並附上一個「這次檢查了哪些項目」的
範圍代碼 scopeHash)。你把這份存檔釘選成基準(baseline,以後每次
檢查都跟它比),然後做兩個人工決定:訂單問題指派給後端同事;email 那張
其實是測試用的假資料,標成「誤判、以後不用再報」。這兩個決定記在一本
獨立的小本子上,用各張回報單的指紋當索引。
示範故事・第二天——靠指紋比對。後端同事修了一半:訪客現在看到的 畫面不一樣了,但其實還是拿得到訂單資料。再檢查一次,app 把新結果拿去跟 基準比對:訂單問題的指紋跟昨天一樣(同一條規則、同一個位置),所以標成 「延續」——是老問題,不是新問題;而記錄細節的第二個號碼變了,所以 app 還能告訴你「同一個問題,只是長相變了」。email 那張又被抓到,但小本 子裡它的指紋已經標了「誤判」,所以自動保持靜音,不用重新判斷一次。另外 這次冒出一個真正的新問題:網站沒有速率限制(不會擋下短時間內狂發 請求的人)。它的指紋在基準裡找不到,所以標成「新增」。如果新問題夠 嚴重,團隊的自動把關系統(CI)就會亮紅燈,擋下這次的程式碼變更。
示範故事・第三天——防止自欺欺人。同事為了讓紅燈變綠,乾脆把「查看 所有訂單」從檢查清單裡拿掉。再檢查一次,訂單問題當然「消失」了,甚至還會 被標成「已消失」——它的指紋確實不在這次的結果裡。但 app 不會讓這筆帳就 這樣過關:這次的範圍代碼跟基準對不上,報告會在旁邊直接標明 「檢查範圍變了」,提醒大家問題消失是因為沒檢查,不是修好了。 最後你把結果匯出成標準格式的安全報告(SARIF,GitHub 可以直接顯示在 安全頁面上):報告層把快照和小本子上的人工決定合併起來,證據依你選的 遮蔽等級輸出。這就是整套資料設計從頭到尾的運作——從一次網頁請求,到 團隊把關系統的紅綠燈。
持續維護中。前端已全面 strict TypeScript;每次 push 都會跑 ESLint、
tsc --noEmit、Vitest 測試、npm audit 與 Rust unit tests,且 release
流程在這些未通過前不會 build 安裝檔。逐版歷史見
CHANGELOG.md(近期工作:安全矩陣引擎改由 Rust core 透過
IPC 執行、OS keychain 憑證儲存、強化 RBAC/BOLA/rate-limit oracles、三個新
安全引擎——conformance、fuzzing、BFLA——更完整的 SARIF,以及 React 19
升級)。
- Node.js 20 或更新版本(CI 使用 22)
- npm
- Rust toolchain,用於 Tauri commands 與 desktop builds
- k6 由下方 setup scripts 處理
常用指令
安裝 dependencies:
npm install啟動 frontend dev server:
npm run dev以 development mode 啟動 Tauri desktop app:
npm run tauri:dev執行測試:
npm test還有幾個值得認識的測試指令:
npm run test:gui— 跨引擎 UI 測試(Playwright:WebKit ≈ macOS WKWebView、Chromium ≈ Windows WebView2),對 production bundle 執行, 含 4 種解析度的版面矩陣。詳見uitests/README.md。npm run test:install:mac— macOS 安裝鏈冒煙測試:建置 DMG、驗證 bundle、安裝到暫存目錄、以隔離的$HOME啟動(隔離 Rust 側的 config/data 路徑;WebView 內部儲存由 WebKit 自行管理)並確認 app 正常起來(僅限 macOS)。
型別檢查、lint 與格式化:
npm run typecheck
npm run lint
npm run format建置 frontend:
npm run build建置 desktop app:
npm run tauri:build不開桌面 UI,在 CI 裡執行 QA Touchstone
qa-touchstone-ci 是獨立的 headless runner,專門給 CI 使用。它不連結 Tauri
或 OS keychain layer,所以可以跑在一般 GitHub Actions、GitLab CI、Jenkins
或 container job。tag release 會在桌面版安裝檔旁邊附上這些 CLI 產物:
qa-touchstone-ci-linux-x64.tar.gzqa-touchstone-ci-macos-<arch>.tar.gzqa-touchstone-ci-windows-x64.zip- 對應的
.sha256checksum 檔
從包含 npm/action wrappers 的 release 開始,可以用這兩種方式安裝:
# npm package version 不含開頭的 "v"。
npx qa-touchstone-ci@<version> --version或在 GitHub Actions 裡:
- uses: asdfghj1237890/qa-touchstone/setup-ci@vX.Y.Z
with:
version: vX.Y.Z兩個 wrapper 都會下載對應的 GitHub Release asset、驗 .sha256、cache 或安裝
binary,最後執行同一個 qa-touchstone-ci。受限較嚴格的 CI 環境仍可使用手動
artifact 下載方式。release workflow 只有在 repository variable PUBLISH_NPM
為 true 且有 NPM_TOKEN 時,才會 publish npm launcher。
CI 可用的功能就是下面這組 qa-touchstone-ci 指令。它刻意比桌面 app 小:
CI job 會從檔案與環境變數執行可重現的 API、安全與效能檢查,不啟動 Tauri UI,
也不使用 OS keychain。
| CI 可跑的功能 | 指令 | 需要連網 | 需要 runner 有 k6 | 常見 CI 輸出 |
|---|---|---|---|---|
| 原始 smoke probe | ping |
是 | 否 | human status line |
| Postman/OpenAPI 轉換 | import |
否 | 否 | qa.json scaffold |
| 單一 API request + assertions | send |
是 | 否 | JSON result |
| Collection/API smoke suite | run |
是 | 否 | JSON + optional JUnit XML |
| k6-backed performance check | perf |
是 | 是 | JSON + optional k6 summary export |
| Security scan/report gate | scan |
是 | 否 | JSON、HTML、JUnit XML、SARIF、baseline updates |
| BOLA config candidate helper | bola-suggest |
否 | 否 | human 或 JSON candidate list |
Headless CLI 不會 bundle k6。API checks、collection runs、BOLA
suggestions、imports 與 security scans 只需要 qa-touchstone-ci binary;
perf 指令要求 CI runner 上已安裝 k6,或用 --k6-bin 明確指定 k6 路徑。
桌面專用功能不包含在 headless artifact:沒有互動式 UI、沒有背景 monitor
scheduler、沒有 OS keychain storage、沒有桌面版 bundle 的 k6 resource,也沒有
AI-assisted generation flow。CI 裡請把 secrets 放在 runner 的 secrets manager,
並在 config 用 { "env": "API_TOKEN" } 這類 environment-backed value 引用。
從本 repo 本機建置:
cargo build --manifest-path src-tauri/Cargo.toml -p qa-touchstone-ci --release
./src-tauri/target/release/qa-touchstone-ci --version最小 CI config 範例:
{
"version": 1,
"environments": [{ "name": "staging", "variables": { "baseUrl": "https://api.example.com" } }],
"identities": [
{ "id": "anon", "auth": { "type": "none" } },
{ "id": "api", "auth": { "type": "bearer", "token": { "env": "API_TOKEN" } } }
],
"requests": [
{
"id": "health",
"method": "GET",
"url": "{{baseUrl}}/health",
"assertions": [{ "type": "status", "op": "eq", "value": 200 }]
},
{
"id": "admin-users",
"method": "GET",
"url": "{{baseUrl}}/admin/users",
"privileged": true
}
],
"collections": [{ "id": "smoke", "requests": ["health"] }],
"security": {
"matrix": {
"endpoints": ["admin-users"],
"expect": { "admin-users": { "anon": "deny", "api": "allow" } }
}
}
}逐步呼叫:
# 需要時,把 Postman / OpenAPI JSON 轉成 qa.json。
qa-touchstone-ci import --input postman.json --base-url https://api.example.com --out qa.generated.json
# 送出單一 request,輸出 machine-readable JSON。
API_TOKEN="$API_TOKEN" qa-touchstone-ci send \
--config qa.json \
--request health \
--identity api \
--env staging \
--json
# 跑 collection,並寫出 JUnit 給 CI test results 使用。
API_TOKEN="$API_TOKEN" qa-touchstone-ci run \
--config qa.json \
--collection smoke \
--identity api \
--env staging \
--junit reports/qa-run.xml \
--json > reports/qa-run.json
# 跑 k6 performance check。需要 PATH 上有 k6,或傳 --k6-bin /path/to/k6。
k6 version
API_TOKEN="$API_TOKEN" qa-touchstone-ci perf \
--config qa.json \
--request health \
--identity api \
--env staging \
--stage 30s:5 \
--stage 1m:10 \
--summary-out reports/k6-summary.json \
--json > reports/k6-run.json
# 跑 security suite,並輸出 CI artifacts。
API_TOKEN="$API_TOKEN" qa-touchstone-ci scan \
--config qa.json \
--env staging \
--json \
--out reports/security.json \
--html reports/security.html \
--junit reports/security-junit.xml \
--sarif reports/security.sarif \
--fail-on highExit codes 固定:0 通過、1 runtime/network error、2 輸入或 config
錯誤、3 有高於或等於 --fail-on 的 security findings、4 assertions
失敗或 perf 收到 k6 非 0 結果。若要把目前掃描結果採納成 baseline,可執行
scan --baseline .qa/security-baseline.json --update-baseline;後續掃描會與該
檔案比對,只針對新增 findings gate。
perf --script-out 會把產生的 k6 script 留下來方便 review/debug。該 script
可能包含 auth headers 或 tokens;除非你的 secrets policy 允許,否則不要把它
上傳成 CI artifact。一般未指定 --script-out 時,臨時 script 會在 k6 結束後刪除。
在另一個 repo 的 GitHub Actions 使用 release artifact:
name: qa-touchstone
on:
pull_request:
push:
branches: [main]
jobs:
api-security:
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
env:
QA_TOUCHSTONE_VERSION: v0.23.0
API_TOKEN: ${{ secrets.API_TOKEN }}
steps:
- uses: actions/checkout@v4
- name: Install QA Touchstone CLI
uses: asdfghj1237890/qa-touchstone/setup-ci@vX.Y.Z
with:
version: ${{ env.QA_TOUCHSTONE_VERSION }}
- name: Run API smoke collection
run: |
mkdir -p reports
qa-touchstone-ci run \
--config qa-touchstone.json \
--collection smoke \
--identity api \
--env staging \
--junit reports/qa-run.xml \
--json > reports/qa-run.json
- name: Verify k6 is available
run: k6 version
- name: Run k6 performance check
run: |
qa-touchstone-ci perf \
--config qa-touchstone.json \
--request health \
--identity api \
--env staging \
--stage 30s:5 \
--summary-out reports/k6-summary.json \
--json > reports/k6-run.json
- name: Run security scan
id: scan
run: |
set +e
qa-touchstone-ci scan \
--config qa-touchstone.json \
--env staging \
--json \
--out reports/security.json \
--html reports/security.html \
--junit reports/security-junit.xml \
--sarif reports/security.sarif \
--fail-on high
code=$?
echo "exit_code=$code" >> "$GITHUB_OUTPUT"
exit 0
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: reports/security.sarif
- name: Upload QA artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: qa-touchstone-reports
path: reports/
- name: Fail on QA Touchstone gate
if: steps.scan.outputs.exit_code != '0'
run: exit ${{ steps.scan.outputs.exit_code }}正式環境若有嚴格 supply-chain 要求,建議把範例中的 Actions 版本改成固定 commit SHA。
k6 setup 與 release 驗證
Performance page 會透過 k6 執行真實 load tests。k6 binary 體積較大且與平台相依, 所以不會 commit 到 repo。
Setup script 會把 k6 materialize 到 src-tauri/resources/:
- Dev:
npm run setup:k6如果已存在 k6 就不動;否則從 PATH 複製k6, 或下載 pinned release。 - Release:
npm run setup:k6:release會下載符合 OS/arch 的官方 artifact, 使用scripts/setup-k6.mjs內建的 SHA256 checksums 驗證,並確認k6 version後才 bundle。
手動執行:
npm run setup:k6
npm run setup:k6:release若要更新 K6_VERSION=<x.y.z>,需要把該 release 的 checksums 加到
scripts/setup-k6.mjs 的 CHECKSUMS table。Release build 在 checksum
缺失或不一致時會 fail closed。
儲存檔案與 secret 處理
Runtime configuration 儲存在本機。常見產生檔案包含:
config.json:application settingsuser_data.json:關鍵工作區資料的磁碟鏡像(安全 findings 生命週期、 baseline、效能歷史、monitors)。所有讀寫經過單一版本化儲存層 (src/qa/storage.ts),webview 快取被清掉也能還原,舊資料形狀會在讀取時 自動 migrate,寫入失敗會浮出 提示而非無聲吞掉。機密(LLM API key)刻意排除在鏡像之外。
手動輸入的 AWS secret access key 不會存進 config.json:它存放在 OS keychain
(Windows Credential Manager/macOS Keychain/Linux Secret Service),以
credential profile id 為 key。舊設定中的 inline secret 讀取時仍然有效,方便
平順遷移。
LLM settings 儲存在 browser localStorage。AI 隱私模式預設遮蔽:prompt 會在本機
遮蔽、並於送出前顯示預覽,才送到你選擇的 provider;local only 模式只允許自管
端點,CI/組織 lockdown(QA_ALLOW_EXTERNAL_AI)可完全停用外部 AI。
請不要 commit credentials、generated cache files、local tokens 或
machine-specific paths。
安全執行記錄只會持久化一份壓縮、已遮蔽的 snapshot——絕不儲存 request/response body。 較完整的「已遮蔽佐證摘要」僅在當前工作階段保留在記憶體,唯有你明確選擇時才會寫入 已儲存的執行(或釘選的 baseline)。
macOS、Windows 與 Gatekeeper notes
macOS build 會在 src-tauri/target/release/bundle/dmg/ 產生 .dmg。
Windows build 會同時產生 NSIS installer(-x64-setup.exe)與一個免安裝的
portable ZIP(-x64-portable.zip,內含執行檔與旁邊的 resources/k6.exe)。
本機要組 portable ZIP 可執行 npm run package:portable,輸出到 dist/
(與 release workflow 同一套步驟)。
macOS k6 binary 會 bundle 到 app 的
Contents/Resources/resources/k6,所以 Performance testing 不需要額外安裝
system k6。
目前 macOS build 尚未使用 Apple Developer ID sign/notarize。第一次啟動時, Gatekeeper 可能會擋下。可以右鍵 app 選 Open,或清除 quarantine:
xattr -dr com.apple.quarantine "/Applications/QA Touchstone.app"若要更廣泛發佈,請 sign 並 notarize build。
- 效能測試由 Grafana k6
(
grafana/k6)提供,採 AGPL-3.0 授權。官方 k6 binary 會經下載、SHA256 驗證後 bundle 到 app 的resources/目錄(見 k6 Binary 與 Packaging Notes)。它以獨立執行檔 的方式被 app 呼叫,並未連結進 QA Touchstone 本體。感謝 Grafana Labs 團隊與 k6 contributors。 - 以 Tauri 與 React 打造。
各商標與專案名稱歸其各自所有者所有。
ISC






