I3 檢查結果:附件上傳下載

I3 檢查結果:附件上傳下載

檢查日期 2026-09-09|耗時 91 分鐘|對應卡片 CM-1615


§1

🔴 一句話結論

附件功能本身沒有新問題(工具找到的兩條都是前一棒報過的)。但首腦不同意工具的一項判斷,另外揪出一個「守門只做了一半」的程式錯誤。


§2

這一棒在檢查什麼

使用者送意見回饋時可以夾帶附件。這些檔案有三種存法:存在自己的機器上、傳到 GitLab、傳到 GitHub。

這一棒檢查這 14 個檔案——檔案會不會被放到不該放的地方、能不能讀到別人的檔。


§3

找到什麼

# 嚴重度 這是什麼問題 狀態 修正卡
1 🟡 中 連 GitHub 沒檢查對方身分(從附件功能這條路再次碰到同一支檔) 和 I1 重複,不重複計算 ✅ 已修(CM-2066;原卡 CM-1632 作廢)
2 🟡 中 舊設定檔的密碼留在版控歷史 和 I1 重複(CM-1573 舊案) ✅ 已修(CM-2048;原卡 CM-1607 作廢)
3 ⚪ 低 (首腦補查)刪除附件時,安全檢查只做了一半 工具的檢查員 3 票全數否決,首腦不同意 ✅ 已修(CM-2066;原卡 CM-1633 作廢)

工具在這 14 個檔裡找到的新問題:0 個。


§4

🔴 首腦不同意工具否決的那一條

開卡時,首腦特別點名要查「刪除附件會不會刪到別人的檔」。工具查了,三個檢查員全數判定「這不是問題」。

首腦逐點核對他們的理由:

檢查員說 核對結果
網址只能傳一個檔案編號進來 ✅ 對(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))

§5

💡 這一棒換到的教訓

工具的檢查員判斷「現在打不到」是可信的,但他們的推論停在「打得到嗎」——不會告訴你這段程式碼本身是不是寫錯的。

所以:卡片點名要查的重點,就算被工具否決了,首腦仍然要自己打開檔案看一眼。

(這條已經寫進首腦手冊,給後面的棒次用。)


§6

這份結果可信到什麼程度

「這些是真的嗎」→ ✅ 可信

工具找到的兩條都是 3 票全過。首腦補查的那條是自己打開檔案看到的。

關於報告上的 unverified 標記:原因是「第 2 條指的檔案已經從最新版刪掉了,工具找不到所以拒絕寫進正式報告」——投票本身是完整的(9 票全投、零漏投)。

「是不是只有這些」→ ❌ 不可信

快篩模式。14 個檔裡有 6 個是幾乎空白的檔案,實際有內容的只有 8 個。

這一棒的真正價值是「排除」:附件功能經過檢查,沒有發現路徑穿越、任意檔案讀取這類問題。這是有價值的結論,不是零產出。


§7

執行概況(技術細節)

項目 數字
檢查範圍 14 個檔案(六棒中最小)
派出/回報的研究員 2 / 2
候選問題 → 去除重複 4 → 3
投票數 9
沒投到票的 0
被檢查員否決的 1(首腦不同意,見上)
耗時 91 分鐘