我們安裝套件的管道是不加密的,只要有人能插進公司內網那條線,就能在我們安裝時把惡意程式掉包進來,直接拿下開發機與打包機——而打包機產出的東西是要送到客戶手上的。
第二件事:全站唯一那道「密碼遮罩」,遇到含有雙引號的密碼會遮一半、剩下半截原文寫進資料庫,而那張表要留 90 天。
好消息有一個:卡片原本列為「本棒最重要」的那條(信封組裝失敗把錯誤原文當資料回前端)經查不成立,那段程式進不去。詳見第 4 節 C3-5。
jedi-common 是所有 jedi 套件與主產品共用的底層。這一棒看的是它的**「輸出面」**——資料整形完之後,要交出去的那一段:
{"status": ..., "data": ...} 那層)要回答的是四個問題:回給前端的東西會不會夾帶不該有的欄位、分頁參數能不能拿來拖垮資料庫、共用工具裡有沒有不該存在的東西、打包腳本會不會把憑證帶出去。
只找問題、不修問題——所有修法都只寫建議,這一棒不動任何程式碼。
| # | 這是什麼問題 | 出事會怎樣 | 要先有什麼才打得到 | 在哪裡 | 嚴重度 | 來源 |
|---|---|---|---|---|---|---|
| C3-1 | 安裝套件走的是沒加密的連線,別人可以中途掉包 | 惡意程式裝進開發機與打包機,打包機產出的是要給客戶的東西 | 能插進內網那條線(公司 LAN、被入侵的網路設備) | pyproject.toml:50 |
MEDIUM (一位檢查員評 HIGH) |
工具 3/3 票 |
| C3-2 | 分頁的「一頁幾筆」沒有上限 | 一個請求就能叫資料庫把整張表撈出來,重複幾次服務就癱 | 任何登入者 | interfaces/schema/common.py:13 |
MEDIUM | 工具 3/3 票 |
| C3-3 | 密碼遮罩遇到含雙引號的密碼只遮一半,剩下原文進資料庫 | LDAP 綁定密碼、SSH 密語等強密碼的後半段明文留 90 天 | 密碼裡有 ";能讀到 log 表或備份的人 |
utils/common_utils.py:160 |
MEDIUM | 工具 3/3 票 |
| C3-4 | 同一道遮罩,JSON 跳脫形式的引號也一樣漏 | 同上,且 log 紀錄變成壞掉的 JSON、後續解析不可靠 | 同上 | utils/common_utils.py:159 |
LOW | 工具 3/3 票 |
| C3-5 | 信封組裝失敗把錯誤原文當資料回前端 | 經查不成立——該分支進不去 | — | utils/response_util.py:26 |
無問題 | runner 人工查證 |
| C3-6 | 一支開發輔助工具混在正式套件裡,且會把整個檔案覆寫成空 | 目前無人呼叫,但它跟著出貨,且拖著 openai 成為產品必需依賴 |
需有人真的去執行它 | utils/gen_comment.py:49 |
LOW | runner 人工查證 |
| C3-7 | 序列化工具原樣吐出整個物件,沒有欄位過濾 | 物件上有什麼就回什麼,前端會拿到內部欄位 | 呼叫端沒有自己收斂欄位 | utils/serialization_util.py:18 |
LOW(套件層) 個案在別處 |
runner 人工查證 |
| C3-8 | .env 受版控(CM-1598 已知) |
經查:值是真的可連線設定,但密碼與 DEV 主庫不同 | — | .env |
LOW(維持原評) | 密鑰專項+人工比對 |
沒有發現的項目:⑥ savepoint 靜默吞例外——查了,結論寫在第 4 節 C3-9。⑦ 兩套信封並存——查了,舊信封零使用者,結論同節。
這是什麼問題(白話)
我們所有的套件(包含 25 支 jedi-* 自製套件,以及 Flask、SQLAlchemy 這些外部套件)都從公司內部的一台套件伺服器下載。問題是這條下載連線用的是 http:// 而不是 https://——白話說就是沒有加密、也沒有驗對方身分。
這代表:只要有人能插進「我們的機器」到「那台套件伺服器」中間的網路路徑上(術語叫網路中間人,例如同一個辦公室網段、一台被入侵的交換器、或假冒的 DHCP/DNS 伺服器),他就可以假裝自己是套件伺服器,回一個被動過手腳的套件給我們,而我們的工具完全分辨不出來。
更要緊的是這一行還標了 priority = "primary"(:51),意思是優先用它——所以不只是自家套件,連外部套件都走這條線。
出事會怎樣
被掉包的套件一旦裝上去,程式碼在 import 的當下就會執行。所以:
publish.sh 發版時,發版用的帳密也走同一條沒加密的線,一併被看光要先有什麼才打得到
poetry install、poetry update 或 publish.sh——這是每天都在發生的事在哪裡
pyproject.toml:50 — url = "http://192.168.50.171:8082/repository/pypi-group/simple"pyproject.toml:51 — priority = "primary"(所以所有套件都走這條)jedi-* 套件與主專案的 pyproject.toml 內都有一份怎麼修
pyproject.toml 內的 http:// 全部改成 https://http://嚴重度說明:評 MEDIUM 而非 HIGH,是因為需要先取得內網中間人位置這個前提。三位檢查員中有一位評 HIGH(理由是打包機的產出會流向客戶),工具取三票的中位數記為 MEDIUM。以我們的實際情境看,這條的投報率最高——修法明確、影響面最大、而且是一次改完 25 支就永久解決。
首腦核對註記:pyproject.toml 不在本棒 30 檔的 scope 內(scope 只含 .env 與 publish.sh 兩支根目錄檔)。工具是為了追 publish.sh 的發版行為而越界讀到它。判定為真實且應報——publish.sh 的內容就是 poetry publish --build -r nexus,那個 nexus 指的正是 pyproject.toml:50 這一行,兩者是同一件事的兩半,不算離題。
這是什麼問題(白話)
所有列表 API(專案列表、稽核列表、POA&M 列表……)都吃同一組分頁參數:「要第幾頁」和「一頁幾筆」。「第幾頁」有檢查(至少要 1),但**「一頁幾筆」完全沒有上限**。
所以任何登入的人都可以說「給我一頁一億筆」,系統就真的會去資料庫撈一億筆。
出事會怎樣
一個請求就能讓資料庫把整張表讀進記憶體、再轉成物件、再轉成 JSON。同時送幾個這種請求,應用程式的記憶體與資料庫連線就被吃光,其他客戶跟著一起卡住。
另一個角度:分頁本來也有「限制一次能撈走多少資料」的作用,沒上限等於這個限制不存在。
要先有什麼才打得到
RequestMetaSchema 的列表端點(feedback、module_frame、information_system、audit、poam 等)size,救不到這裡)在哪裡
jedi_common/interfaces/schema/common.py:13 — page_size = fields.Int(missing=25):12 — page = fields.Int(missing=1, validate=validate.Range(min=1)),有檢查🔴 這個上限是被刻意拿掉的,不是忘了寫
我查了 git 紀錄,commit a79d002(2026-03-03,標題「update pager max limit」)把這一行從:
page_size = fields.Int(missing=25, validate=validate.Range(min=1, max=100))改成:
page_size = fields.Int(missing=25)原本有 max=100,被整個移除了。 這件事很重要:修的時候要先弄清楚當初為什麼拿掉(很可能是某個頁面需要一次撈超過 100 筆),否則改回去會把那個功能弄壞。
怎麼修
schema/common.py:13 加回上限,但值要放寬到實際需要的量: page_size = fields.Int(missing=25, validate=validate.Range(min=1, max=200))base_repository_impl.py 的分頁實作裡再夾一層保險——在 .limit() 之前把值壓到上限內。這樣即使將來又有人把 schema 的檢查拿掉,資料庫也不會被打爆a79d002 當初為何移除,確認真正需要的上限值這是什麼問題(白話)
系統會把每個 API 請求與回應的內容寫進資料庫的 api_logs 表存 90 天,方便除錯。為了不把密碼一起寫進去,中間有一道遮罩:看到欄位名稱像 password、secret、token 這類,就把值換成 ***。
問題出在這道遮罩是用文字比對做的,它認的格式是 "欄位名":"值",而它判斷「值到哪裡結束」的方式是**「找到下一個雙引號就算結束」**。
所以如果密碼本身含有雙引號——例如 ab"cdSUPERSECRET——遮罩會在密碼中間那個引號就停住,只遮掉前半段,後半段 cdSUPERSECRET 原文寫進資料庫。
諷刺的地方:越是強度高、含特殊符號的密碼,越容易踩到這個洞。
出事會怎樣
api_logs.request 與 api_logs.response 這兩個欄位會留著密碼的後半段明文,保留 90 天。會受影響的包括 LDAP 綁定帳號密碼、SSH 私鑰密語、各種偵測工具的憑證。
能看到的人:資料庫管理者、任何有 log 匯出權限的人、以及拿到資料庫備份的人(含 90 天內的任何一份備份)。
要先有什麼才打得到
" 這個字元。目前 LDAP 的 secret 欄位與工具憑證欄位都沒有限制可用字元,所以使用者完全可能設出這種密碼common/middleware/app_mw.py——這是全域註冊的,每個請求都會過api_logs 表、備份或匯出檔在哪裡
jedi_common/utils/common_utils.py:160 — 那一行的值比對寫成 "[^"]*",[^"] 的意思就是「不是引號的字元」,所以碰到引號就停:150 mark_passwordcompliance-manager-be/common/middleware/app_mw.py:51(request)與 :101(response)怎麼修
不要用文字比對來遮密碼。 正確做法是把內容當成 JSON 解析成結構,然後逐層走訪,看到欄位名是密碼類的就整個值換掉,最後再轉回文字。解析不了的就整包不要寫。
這個改法同時修掉同一道遮罩的另外兩個漏遮情形(見下方 C3-4 與補充):
"token": 123456789(數字)、"secret": ["abc"](陣列)都會原封不動寫進去,因為比對式只認 "值" 這種字串形態password=xxx 整包漏掉首腦核對註記:這兩個補充情形(非字串值、表單格式)在面板被單獨列為一條候選(C5/F6),三位檢查員以 2:1 否決。否決理由是:目前系統裡所有標記為 secret 的欄位在資料庫 seed 裡都是字串型別、前端也只送字串;而表單格式的請求在到達遮罩之前內容已被讀空,實際寫進 log 的是空的。所以那條不成立——但既然遮罩要重寫,順手把這兩種形態一起處理掉,成本是零。
這是什麼問題(白話)
這是 C3-3 的同一個根因,差別在密碼裡的引號寫進 JSON 之後會變成 \" 這種形式(前面多一個反斜線)。那道遮罩同樣不認識這種寫法,一樣在那裡停住。
分開記錄是因為它多一個副作用:產生出來的紀錄變成壞掉的 JSON,後續要解析 log 的程式會出錯。
出事會怎樣
密碼後半段留在 log 裡(同 C3-3),加上 log 紀錄本身格式壞掉、不能可靠地被解析。影響範圍比 C3-3 窄——只有引號之後那一段會漏。
在哪裡
jedi_common/utils/common_utils.py:159 — return re.sub( 那一段的值比對式怎麼修
同 C3-3,改成結構化解析。如果基於某些理由一定要保留文字比對當備援,值的比對式要改成能認得跳脫字元的形式:"(?:\\.|[^"\\])*"。
嚴重度說明:評 LOW 而非 MEDIUM,是因為只有「引號之後」那一段會漏,且要密碼剛好含引號。C3-3 評 MEDIUM 是因為它涵蓋的情境更廣(包含未跳脫的原始形態,以及整個密碼以引號開頭時全部外漏的情形)。
卡片把這條列為「本棒最重要」,結論是不成立。
卡片的疑慮是什麼
utils/response_util.py:23-27 有一段:
except Exception as e:
status = False
current_app.logger.exception(e)
data = e.args[0]
return {"status": status, "data": data}擔心的是:如果信封組裝過程出錯,e.args[0](錯誤的原文,可能含檔案路徑、資料表名稱)會被當成 data 回給前端。
為什麼不成立
我把 try 區塊裡的程式逐行看過,裡面只有三件事:
isinstance(data, dict) — 型別判斷,不會拋例外data.keys() — 前一行已確認是 dict 才會執行data.get(...) 與組一個新的 dict — 都不會拋例外這個 try 區塊裡沒有任何會失敗的操作,所以 except 分支實際上進不去。真正的序列化(把 dict 轉成 JSON)發生在這個函式回傳之後,由 Flask 處理,不在這個 try 的範圍內——那裡出錯會走 Flask 自己的錯誤處理,不會走到這一行。
還是值得做的小事
這段程式碼本身是個誤導——它看起來像在防某件事,實際上什麼也沒防,反而讓後來的人(包含開卡的首腦)以為有風險。建議直接把 try/except 拿掉,或者改成重新拋出例外。這不是資安問題,是可讀性問題,優先度低。
這是什麼問題(白話)
jedi_common/utils/gen_comment.py 是一支開發時用來自動產生程式註解的小工具——它把程式碼送給 OpenAI,請 AI 寫註解,再把結果寫回原始檔案。
這種東西不該放在正式出貨的套件裡。它現在造成三個具體問題:
① 它會把檔案覆寫成空的。 :49 那一行寫 with open(file_path, "w"),但 file_path 這個變數在那個函式裡根本沒有定義(函式收到的參數叫 path,不是 file_path)。"w" 的意思是「開啟並清空」——所以真的有人去執行它,檔案會先被清空,然後才因為變數不存在而出錯,內容就沒了。
② 錯誤被整個吞掉。 :54 except Exception as e: return f"Error: {str(e)}",出了任何事都只回一個字串,不會有人發現。
③ 它讓 openai 變成產品的必要依賴。 pyproject.toml:24 把 openai 列在正式依賴裡,而整個套件只有這支檔案用到它。等於每個客戶的機器都裝了一套 OpenAI 用戶端,只為了一支沒人呼叫的開發工具。
出事會怎樣
目前沒有立即的外洩風險——我已確認(grep 過整個 monorepo 25 支套件與主專案)零個地方 import 它,而且它需要 OPENAI_API_KEY 這個環境變數才會動,客戶機上不會有。
實際的問題是:它會跟著出貨。它放在 jedi_common/utils/ 底下,而打包設定 pyproject.toml:44 寫的是 packages = [{ include = "jedi_common" }]——整個目錄都包進去,所以這支檔案確實會進到客戶機器上的 wheel 裡。加上多一個沒必要的依賴、多一份攻擊面。
要先有什麼才打得到
在哪裡
jedi_common/utils/gen_comment.py:8 — 模組載入時就讀 OPENAI_API_KEYjedi_common/utils/gen_comment.py:49 — with open(file_path, "w"),用未定義的變數開檔覆寫jedi_common/utils/gen_comment.py:54 — 吞光所有錯誤pyproject.toml:24 — "openai (>=2.8.0,<3.0.0)" 列在正式依賴怎麼修
直接把 gen_comment.py 從套件刪掉,同時把 openai 從 pyproject.toml 的正式依賴移除。如果這支工具還有人要用,搬到 monorepo 的 scripts/ 或開發工具目錄,不要放在會出貨的套件內。
這跟 CM-1515 當初把 pytest/testcontainers 從正式依賴搬進 dev group 是同一類問題(pyproject.toml:29-35 的註解有記錄那次),只是這次漏了 openai。
卡片點名要回答的問題:「to_serializable 是套件層的系統性問題,還是那一支的個案?」
答案:是「套件提供的工具本身不做過濾」(套件層事實),但目前只有一支套件在用它(使用面是個案)。
這是什麼問題(白話)
to_serializable 是一支把任意物件轉成 JSON 的工具。它的轉換方式是:物件上有什麼欄位,就全部吐出來——只跳過三個資料庫框架的內部欄位(metadata、registry、sa_instance_state)和底線開頭的私有欄位。
換句話說,它沒有「哪些欄位不該給前端」的概念。如果丟一個資料庫物件給它,物件上有密碼鹽值、有內部識別碼,它就原樣一起吐出來。
使用面的實際情形(grep 全 monorepo 25 支套件 + 主專案的結果)
| 範圍 | 使用處數 |
|---|---|
主專案 compliance-manager-be |
0 處 |
| 其他 24 支 jedi 套件 | 0 處 |
jedi-ai-dashboard |
2 處 |
兩處都在 jedi-ai-dashboard:
app/service/ai_dashboard_app_service.py:191 — 取樣本資料送給 AI 當提示詞。這裡吐出的整包內容會進到送往 AI 模型的訊息裡domain/service/dashboard_generation_domain_service.py:249 — 在 _build_dynamic_table() 內,把每一筆資料轉好之後直接放進要回給前端的表格資料(table_data.append(serialized)),而且下一行 _auto_extract_columns(table_data[0]) 是拿第一筆有什麼欄位就自動生成表格欄位所以 FR-083 D1 F2(AI 儀表板回傳夾帶 salt)的成因是什麼
是這兩件事相乘的結果:
to_serializable 不做欄位過濾(這是事實,但它是一支通用工具,不過濾本身是合理的設計)jedi-ai-dashboard 拿它的輸出未經收斂就直接當回應資料,且欄位還是自動推導的修哪一邊?建議修呼叫端,不要修套件。 因為 to_serializable 是通用工具,加上寫死的欄位黑名單會讓它在別的情境失準;而且「哪些欄位不能給前端」是業務知識,屬於呼叫端的責任。
怎麼修
在 dashboard_generation_domain_service.py:249 附近,改成白名單:只把 columns_config 指定的欄位放進 table_data,而不是整包塞進去再自動推導欄位。ai_dashboard_app_service.py:191 送 AI 的樣本同理,先挑欄位再送。
若要在套件層補一層保險(非必要,可選):給 to_serializable 加一個選用參數 exclude_keys,讓呼叫端可以指定要排除哪些欄位,預設行為維持不變。
.env 受版控——值是真的,但不是主庫密碼卡片要求:確認值是真憑證還是佔位符,只做相等性比對、不印值。
查了,結果如下(全程未印出任何值):
| 項目 | 結果 |
|---|---|
| 是否受版控 | 是,git ls-files .env 有列出 |
| 共幾個設定 | 6 個:DB_HOST/DB_PORT/DB_NAME/DB_SCHEMA/DB_USERNAME/DB_PASSWORD |
| 值是空的嗎 | 都不是空的,六個都有實際內容(用字元長度確認,未讀取內容) |
| 密碼是否等於 DEV 主庫密碼 | 不相等——與主專案 .env 的 DB_PASSWORD 做相等性比對,結果為「不同」 |
判讀:這是一組真的可以拿來連線的設定(不是 xxx、changeme 這種佔位符),但密碼與主專案 DEV 主庫用的那組不同。合理推測是這支套件跑測試時用的獨立資料庫帳號。
是否會被打包出去:不會。 打包設定 pyproject.toml:44 只收 jedi_common/ 這個目錄(packages = [{ include = "jedi_common" }]),而 .env 在套件根目錄、不在 jedi_common/ 裡面,不會進到 wheel。所以它的外洩途徑只有一條:任何拿得到這個 git repo 的人都看得到。
維持 CM-1598 原本的 LOW 評級,本棒不重報。 建議的處置照舊:從版控移除、加進 .gitignore、改該帳號密碼,並在 README 註明要自建 .env。
卡片的疑慮:utils/savepoint.py:30-35 的 rollback 失敗時 except Exception: pass 靜默吞掉,擔心資料庫連線會停在壞掉的交易狀態,連累後續請求。
查了,這個寫法是對的。 完整程式碼是:
try:
yield
sp.commit()
except Exception:
try:
sp.rollback()
except Exception:
pass
raise # ← 關鍵在這一行理由:
raise 會把它往外拋,呼叫端一定會知道出事了@transaction 會在請求結束時關閉整個 session,不會把壞掉的連線留給下一個請求這是處理巢狀交易的標準寫法,不需要改。 唯一可以做的小改善:在 except Exception: pass 那裡補一行 logger.warning,讓回滾失敗這件事至少留下痕跡,方便日後追查。優先度很低。
卡片的疑慮:utils/response_util.py(新,status/data)與 utils/common_response.py(舊,code/msg/data)兩套信封並存,擔心兩套的錯誤處理不一致(一套遮、一套不遮)。
查了,舊信封目前沒有任何人在用。
grep 全 monorepo 25 支套件與主專案的結果:common_response 只出現在 2 個地方,而且兩處都是 response_util.py:7 與 :9 的註解文字(那份註解正是在說明「這兩支不是同一支、不要搞混」),沒有任何一行實際的 import 或呼叫。
所以不存在「兩套行為不一致」的風險——只有一套在跑。
建議:既然零使用者,可以直接刪掉 common_response.py,連同 response_util.py 檔頭那段說明註解一起清掉。這是整理工作不是資安修補,優先度低。
卡片列了八個觀察點,逐項回答如下(不留白):
| # | 卡片的觀察點 | 查證結果 |
|---|---|---|
| ① | 信封組裝失敗把例外訊息當 data 回前端(卡片標「本棒最重要」) | 不成立。try 區塊內沒有任何會拋例外的操作,except 分支進不去。詳見 C3-5。(工具未報,runner 人工查證) |
| ② | gen_comment.py 不該進 runtime 套件 |
成立。零 importer(已 grep 25 支套件+主專案),但確實會被打包進 wheel(在 jedi_common/ 目錄內),且拖著 openai 成為正式依賴。詳見 C3-6。(工具未報,runner 人工查證) |
| ③ | 分頁 page_size 沒有上限 |
成立,且是被刻意移除的——commit a79d002 把 max=100 拿掉。工具三票一致確認。詳見 C3-2 |
| ④ | 序列化不濾敏感欄位;卡片指定要答「系統性還是個案」 | 答案:套件層工具確實不過濾(系統性事實),但使用面只有 jedi-ai-dashboard 2 處(個案)。主專案與其餘 24 支套件皆 0 處。 FR-083 D1 F2 是「工具不過濾」×「呼叫端未收斂」相乘的結果,建議修呼叫端。詳見 C3-7。(工具未報,runner 人工查證) |
| ⑤ | 密碼遮罩只吃一種格式 | 成立,且比卡片預期的更嚴重——不只漏掉非字串與表單格式,連字串值本身含引號都會遮一半。工具報了兩條(C3-3/C3-4,各 3/3 票)。卡片原本擔心的非字串/表單情形被面板 2:1 否決,理由見 C3-3 末段 |
| ⑥ | savepoint.py rollback 失敗靜默 |
不成立。最後有 raise,原始例外照常往外拋;被吞的只有「回滾本身失敗」,那是標準寫法。詳見 C3-9。(工具未報,runner 人工查證) |
| ⑦ | 兩套並存的回應信封 | 不成立。舊信封 common_response 零使用者,只在註解裡被提到。不存在行為不一致風險。詳見 C3-10。(工具未報,runner 人工查證) |
| ⑧ | 打包與發布:.env 是否真憑證、會否打進 wheel |
值是真的可連線設定(六項皆非空),但密碼與主專案 DEV 主庫不同;不會打進 wheel(不在 jedi_common/ 內)。另外查出發版腳本走的是沒加密的連線(C3-1,本棒最高投報率的發現)。詳見 C3-8 與 C3-1 |
分兩層回答,這兩層的可信度差很多,不要混在一起看。
verifieda79d002 移除上限、C3-7 的 grep 計數,這些是可以重現的查詢但要講清楚:沒有任何一條做過實際攻擊驗證。 掃描過程完全沒有執行任何程式碼,所有結論都來自讀程式碼。例如 C3-1 沒有真的架中間人測試、C3-2 沒有真的送 page_size=一億 打看看。要實測的話需要另外開一棒。
enums/ 與 constants/ 這兩個目錄沒有任何發現。這符合預期(純常數定義),但我沒有逐檔讀完,只能說「工具讀過、沒報」low effort:只派一位研究員讀完整個範圍,沒有威脅建模、沒有廣度掃描。這是為了讓面板跑得完而刻意選的設定(見首腦手冊第一節),代價就是研究深度C3-1 的 pyproject.toml:50 不在本棒 30 檔的 scope 內。
工具是為了追 publish.sh(在 scope 內)的發版行為而讀到它的。我判定應該保留這條,理由是 publish.sh 的全部內容就是 poetry publish --build -r nexus,那個 nexus 指向的正是 pyproject.toml:50——兩者是同一件事的兩半,拆開來看沒有意義。
但要提醒首腦:這個問題不是 jedi-common 專有的,同樣的 http:// 設定在其餘 24 支套件與主專案的 pyproject.toml 內都有一份。開修正卡時應該當成一張跨全 monorepo 的卡,不要當成 FR-085 的子問題。
其餘 9 條(C3-2~C3-10)全部落在 scope 內,無越界。
| 項目 | 數字 |
|---|---|
| 掃描範圍 | 30 檔(git ls-files 實測,與卡片一致) |
| 版本 | commit 8aa6f060 |
| effort/focus | low/attack-surface(含密鑰專項) |
| 研究員派出/回報 | 2/2(零陣亡) |
| 候選發現 | 6 條 |
| 面板票數 | 18 票(6 條 × 3 位檢查員),全數投出,零漏投 |
| 通過(3:3 一致) | 4 條 |
| 否決 | 2 條(一條 0:3、一條 1:2) |
| 嚴重度被面板下修 | 0 條 |
stamp verification.status |
verified |
| 驗證輪數 | 1 輪(無候選遺失、無待驗) |
| 工具耗時 | 約 41 分鐘 |
| runner 人工追加 | 6 條(卡片八項中工具未答的部分) |
| 產物位置 | jedi-common/CLAUDE-SECURITY-20260911-034053/ |
被否決的兩條是什麼(值得記錄,這是三人面板的價值):
test_api_log_secret_masking.py:14-37 為證(那個測試就是在驗巢狀密碼有被遮掉)這正是面板的用處:沒有它,會有人花時間去修兩個實際上不存在的問題。
按投報率排序(這是建議,開卡與排序由首腦裁決):
pyproject.toml),一次解決永久有效,而且它威脅的是打包機,產出要送客戶。建議開成跨 monorepo 的獨立卡,不掛在 FR-085 底下a79d002 為何移除——直接改回去可能弄壞某個需要大量撈資料的頁面gen_comment.py + 移除 openai 依賴) — 低風險的清理,可以順手做try/except 與 C3-10 的零使用者舊信封建議順手清掉,避免下一個人又被誤導(C3-5 這次就誤導了開卡的首腦)這一棒到此結束,FR-085 三棒全部掃完。