Day 26,我已經宣布 XSS 證據工作台的功能完成;但我也特別保留了「尚未整體驗收」這條界線。如果今天又加一個按鈕或第 6 種情境,我測到的就不再是昨天那份候選版。因此 Day 27 沒有新功能,只做三件事:回歸測試、重複建置與篡改負向測試。
我想確定的不是「在我的電腦上看起來正常」,而是這個作品所承諾的合約還在:5 種情境、15 組案例、5 組觀察到執行、10 組未觀察到執行、6 份表單,以及分開的 AI 自動重驗與作者核對資料。
我先執行:
.venv/bin/python -m unittest xss-evidence-workbench/test_workbench.py -v
9 個測試全數通過。第一組核對 bundle 合約,確認情境、案例、執行觀察、表單、報告重驗與作者核對數量正確,所有發布關卡都通過。第二組確認入口盤點只列候選訊號,沒有自己下漏洞結論。其餘測試涵蓋 submit override、HTML escape 與無腳本 CSP、雙建置一致性、發布檔篡改、預期案例數不符、超出專案的路徑,以及 5 份獨立作者核對紀錄。
這組測試的價值在於,它不只問「正常資料能不能產生 dashboard」。它也問「案例數被改成 16 時會不會停」、「路徑跑到專案之外時會不會拒絕」,以及「攻擊形狀的文字進入靜態頁面時會不會變回標籤」。
接著,我回到工作台所依賴的 Day 20 驗證器:
.venv/bin/python -m unittest discover -s day-20 -p 'test_*.py' -v
7 個測試也全數通過。這些案例確認表單的提交覆寫屬性會被保留,並且在對話框與 DOM 識別碼未同時相符時,不會把案例標成已確認執行。它們也會拒絕不完整的儲存型 artifact set、缺少的原始回應、被改動的回應或表單,以及引用舊實驗摘要的 AI 報告。
因此,今天不是只有新工作台的 9 個測試,而是 9+7 個全數通過。前者測發布合約,後者守住證據來源;任何一側失敗,都不應凍結 v1.0。
單元測試已包含可重現建置,我另外在兩個新的臨時目錄各執行一次 build,逐檔比對 evidence-bundle.json、report.md、index.html 與 manifest.json。四份檔案全部 byte-for-byte 相同。
這個結果來自明確的輸出規則:JSON 使用固定排序與格式,來源順序固定,發布物也沒有混入每次不同的時間戳或臨時路徑。它證明「當前同一批輸入」能產生相同結果,不是保證所有 Python 版本、所有未來程式都永遠有相同 byte。
report.md,驗證必須失敗可重現性測的是正常路徑,我還需要確定失敗路徑會關門。我只在第一個臨時發布副本中,把 report.md 的內容改成「被修改」,再執行 verify。程式立即回報:
錯誤:發布檔 SHA-256 不符:report.md
回傳狀態為 1,驗證沒有繼續宣告成功。另一個未改動副本則通過。這次負向測試只改臨時副本,沒有碰 Day 10~20 的來源或正式發布物。
最後的 manifest.json 列出 schema 版本、產品名稱、slug、1.0.0 版本,以及 bundle、Markdown、HTML 三份內容檔的 SHA-256。release ID 由 1.0.0 加上 evidence bundle 雜湊前 16 碼組成。我不把具體 ID 寫死在文章,因為只要最終 bundle 有合理變動,ID 就應跟著變;真正的發布值必須從最後一次建置的 dist/manifest.json 現讀。
release ID 是快速辨識同一份 bundle 的名稱,但它不取代完整 manifest。驗證時,我仍要確認檔案清單沒有多一份或少一份,並且逐一核對 3 份內容檔的完整 SHA-256。接著,verify 還要讀取來源、重跑驗證器、重建輸出,再比對 release ID。只對著一串短 ID 看,沒有執行這些步驟,不算驗收。
我將「凍結 v1.0」定義得很具體:release.json 的預期數量、5 個報告批次、15 份盤點來源,以及 JSON、Markdown、HTML、manifest 的輸出合約都不再改。後面的天數可以補使用手冊、故障排除、發布說明與系列回顧,但這些文字不能提高工具本來沒有的保證。如果後續發現會影響驗收的缺陷,正確做法不是悄悄修正後沿用舊結論,而是取消凍結、修復、再重跑今天全部 16 個測試與兩種手動驗收。
那就…
明天見!