檢查日期 2026-09-09|耗時 91 分鐘|對應卡片 CM-1615
附件功能本身沒有新問題(工具找到的兩條都是前一棒報過的)。但首腦不同意工具的一項判斷,另外揪出一個「守門只做了一半」的程式錯誤。
使用者送意見回饋時可以夾帶附件。這些檔案有三種存法:存在自己的機器上、傳到 GitLab、傳到 GitHub。
這一棒檢查這 14 個檔案——檔案會不會被放到不該放的地方、能不能讀到別人的檔。
| # | 嚴重度 | 這是什麼問題 | 狀態 | 修正卡 |
|---|---|---|---|---|
| 1 | 🟡 中 | 連 GitHub 沒檢查對方身分(從附件功能這條路再次碰到同一支檔) | 和 I1 重複,不重複計算 | ✅ 已修(CM-2066;原卡 CM-1632 作廢) |
| 2 | 🟡 中 | 舊設定檔的密碼留在版控歷史 | 和 I1 重複(CM-1573 舊案) | ✅ 已修(CM-2048;原卡 CM-1607 作廢) |
| 3 | ⚪ 低 | (首腦補查)刪除附件時,安全檢查只做了一半 | 工具的檢查員 3 票全數否決,首腦不同意 | ✅ 已修(CM-2066;原卡 CM-1633 作廢) |
工具在這 14 個檔裡找到的新問題:0 個。
開卡時,首腦特別點名要查「刪除附件會不會刪到別人的檔」。工具查了,三個檢查員全數判定「這不是問題」。
首腦逐點核對他們的理由:
| 檢查員說 | 核對結果 |
|---|---|
| 網址只能傳一個檔案編號進來 | ✅ 對(feedback_route.py:97) |
| 中間那層把它包成「只有一個元素的清單」 | ✅ 對(feedback_service.py:285) |
| 底層有一道檢查會擋掉不屬於這張單的檔案 | ✅ 對(local_issue_attachment.py:89-90) |
他們說「現在打不到」是對的。但他們漏看了下面這件事:
# jedi-issue/.../local/local_issue_attachment.py
第 85 行 撈出「這張問題單底下有哪些檔案」
第 88 行 算出交集 → matched_file_uids ← 過濾出「真的屬於這張單的」
第 90 行 如果交集是空的就擋下來 ← 只要有「一個」對得上就放行
...
第 92 行 刪除對應關係,用的是 matched_file_uids ← 用【過濾後】的 ✅
第 99 行 刪除實體檔案,用的是 file_uids ← 用回【沒過濾】的原始清單 ❌同一個函式裡,第 92 行用了過濾後的清單,第 99 行卻用回沒過濾的原始參數。
這代表什麼:只要傳進來的清單裡混一個合法的檔案編號,安全檢查就放行,然後清單裡其他所有檔案的實體檔都會被刪掉——而對應關係還留著(因為第 92 行只刪了交集),資料庫指向一個已經不存在的檔案。症狀是靜默的資料損毀,不會報錯。
檢查員說「未來多一個呼叫的地方才會有問題」——這個說法低估了。 不是「未來會有問題」,而是這個函式的安全檢查本身就寫錯了:它算了過濾結果卻只用一半。任何傳多個檔案編號進來的呼叫者(例如未來做批次刪除功能)都會踩到。
判「低」(目前確實還打不到),開卡 CM-1633 做預防性修正——改一行就好:
- file_is_deleted = self.file_upload_service.delete_files(file_uids)
+ file_is_deleted = self.file_upload_service.delete_files(list(matched_file_uids))工具的檢查員判斷「現在打不到」是可信的,但他們的推論停在「打得到嗎」——不會告訴你這段程式碼本身是不是寫錯的。
所以:卡片點名要查的重點,就算被工具否決了,首腦仍然要自己打開檔案看一眼。
(這條已經寫進首腦手冊,給後面的棒次用。)
工具找到的兩條都是 3 票全過。首腦補查的那條是自己打開檔案看到的。
關於報告上的 unverified 標記:原因是「第 2 條指的檔案已經從最新版刪掉了,工具找不到所以拒絕寫進正式報告」——投票本身是完整的(9 票全投、零漏投)。
快篩模式。14 個檔裡有 6 個是幾乎空白的檔案,實際有內容的只有 8 個。
這一棒的真正價值是「排除」:附件功能經過檢查,沒有發現路徑穿越、任意檔案讀取這類問題。這是有價值的結論,不是零產出。
| 項目 | 數字 |
|---|---|
| 檢查範圍 | 14 個檔案(六棒中最小) |
| 派出/回報的研究員 | 2 / 2 |
| 候選問題 → 去除重複 | 4 → 3 |
| 投票數 | 9 |
| 沒投到票的 | 0 |
| 被檢查員否決的 | 1(首腦不同意,見上) |
| 耗時 | 91 分鐘 |