昨天,我把 XSS 偵測結果交給 Gemini,取得了一份 JSON 格式的風險分析。裡面包含工具分類、可能影響、成立條件,以及修正後的驗證方式。
有了固定欄位,程式已經能接收這份回答。不過,當我想閱讀整份分析時,還是得在物件與陣列之間來回找內容。
所以今天,我先完成一個很具體的功能:把已保存的 JSON 回答轉成 Markdown,讓報告可以依照標題與段落閱讀。
這次使用昨天 Gemini 3.5 Flash-Lite 的真實回答,直接在本機轉換,沒有重新呼叫模型。今天要確認的是,換成適合閱讀的格式後,原本的資訊能不能完整留下來。
我保留原始 report.json,另外產生 report.md。
JSON 繼續提供固定欄位,供程式讀取與比對;Markdown 則把相同內容安排成段落,方便我逐項閱讀。後續若要回頭確認模型到底說了什麼,仍然能找到原始回答。
今天的流程如下:
讀取 Day 7 的 report.json
↓
確認符合既有 JSON Schema
↓
把各欄位放入固定的 Markdown 段落
↓
寫入另一份 report.md
↓
核對內容與呈現結果
匯出程式只負責資料轉換。它會先使用 Day 7 的 Schema 檢查必要欄位、型別與允許值,避免缺少欄位的資料直接進入版面。
我沿用昨天的 9 個頂層欄位,沒有請模型重新摘要:
| JSON 欄位 | Markdown 中的位置 |
|---|---|
tool_verdict |
工具分類 |
summary |
摘要 |
risk_rating |
風險等級 |
rating_basis |
風險評級依據 |
evidence |
證據引用,逐筆列出來源編號與原文 |
possible_impacts |
可能影響與各自的成立條件 |
unknowns |
尚待確認事項 |
remediation |
優先順序、修正措施與驗證方式 |
limitations |
分析限制 |
其中,我特別保留兩組容易在整理時被省略的內容。
第一組是可能影響的成立條件。如果只留下「可能執行未授權腳本」,卻拿掉使用者需要開啟特定頁面等條件,讀者就容易把可能情境誤讀成已經發生的事件。
第二組是修正建議的驗證方式。報告除了說明要修改什麼,也要留下修改後如何複測,才能接回前幾天建立的探針與瀏覽器驗證流程。
這份報告分析的是 XSS,因此證據裡包含 HTML,甚至包含探針的事件處理器。如果把引用直接拼進一般段落,Markdown 預覽可能把部分內容當成 HTML。
我將每段引用放進圍欄程式碼區塊,並標示為 text。CommonMark 對這種區塊的定義,是將內容當成文字,而不是繼續解析其中的行內語法。
例如,第一段引用會輸出成下面這樣:
### 引用 1|來源 E1
```text
verdict: confirmed_xss
```
我也處理了引用本身包含反引號的情況:先找出內容中最長的連續反引號,再使用更長的圍欄,避免引用提早結束程式碼區塊。
這是匯出程式實際使用的函式:
def code_block(value):
longest = max((len(run) for run in re.findall(r"`+", value)), default=0)
fence = "`" * max(3, longest + 1)
return f"{fence}text\n{value}\n{fence}"
我在專案根目錄,使用已安裝 jsonschema 的 Python 環境執行:
python3 day-08/export_markdown.py \
day-07/results/gemini-3.5-flash-lite-live/report.json \
--output day-08/results/report.md
程式成功寫出 day-08/results/report.md。如果指定的輸出檔已經存在,再次執行會更新該檔案;輸入的 JSON 則保持原樣。
報告開頭保留了昨天的兩個分類:
## 工具分類與風險
- 工具分類:`confirmed_xss`
- 風險等級:`needs_context`
也就是說,轉換格式後,技術結果仍是本次探針已確認執行,風險判讀也仍然保留缺少真實業務情境的狀態。
接著,我把 Markdown 轉成 HTML 預覽,加入簡單的閱讀樣式,再用 Chrome 開啟並截圖。下圖是本次實際匯出的報告:

預覽中的 E3 仍顯示完整保存下來的 HTML 片段,標籤呈現為文字,沒有變成頁面上的圖片或表單。
只看到 .md 檔案產生,還不足以確認轉換過程沒有漏掉資料。因此,我把核對流程整理成可以重複執行的指令:
python3 day-08/verify_export.py
這個檢查程式需要 jsonschema 與 Python-Markdown。它會重新執行匯出,再用 Python-Markdown 的 fenced_code 擴充解析結果,逐項比對可見文字與程式碼區塊。
jsonschema 沿用前幾天的環境。若目前使用的 Python 虛擬環境尚未安裝 Python-Markdown,我會先補上套件,再執行檢查:
python3 -m pip install Markdown==3.10.2
本次使用 Python 3.14.4、jsonschema 4.19.2 與 Python-Markdown 3.10.2,實際結果如下:
| 核對項目 | 本次結果 |
|---|---|
| Schema 中的 9 個頂層欄位 | 全部涵蓋 |
| 原始報告的 19 個文字值 | 都能在解析後的內容找到 |
| 3 段引用 | 原文完整保留在程式碼區塊 |
| HTML 探針片段 | 以文字呈現,未產生檢查所列的非預期元素 |
| 原始 JSON 的 SHA-256 | 匯出前後一致 |
| 新的模型 API 請求 | 0 次 |
19 個文字值包含分類、摘要、來源編號、引用與各項說明,是這一份輸入的內容數量,不是模型品質分數。
HTML 檢查則確認解析結果沒有 script、img、iframe、object 或 embed 元素。我也查看了瀏覽器預覽,確認段落與引用能正常閱讀。這些結果適用於本次報告與使用的解析方式,不能推論所有 Markdown 預覽環境都已經過測試。
昨天的摘要提到 q 參數,但引用清單沒有包含 parameter: q。今天的格式轉換保留了這個問題;E3 原本截斷在 setAttribut 的片段,也沒有被自動補寫。
因此,我在報告開頭標示:
狀態:匯出草稿,內容仍需核對。
這份文件已經比較方便閱讀,也比較容易逐項指出問題。接下來若要補正內容,可以另存修訂版,再與原始回答比對;目前仍不能把它當成已完成語意審查的最終報告。
今天,我完成了從 JSON 到 Markdown 的匯出,保留工具分類、風險判讀、證據、條件與修正方式,也留下可重複執行的核對流程。
目前這條流程已經能從本機探針取得證據,交給 AI 整理分析,再產生一份可以閱讀的報告。後續要改進內容時,我可以直接對照報告段落、原始 JSON 與證據來源,逐項處理需要補充的地方。
那就…
明天見!