refactor(release-cleanup): 將清理邏輯由 bash 改寫為 Node.js #5
@@ -26,7 +26,10 @@ import { section, info, warn } from './logger.js'
|
||||
export function loadConfig(env = process.env) {
|
||||
section('參數檢查')
|
||||
|
||||
const serverUrl = env.GITEA_SERVER_URL
|
||||
// 去除結尾多餘的 /,避免後續拼接出 `https://host//api/v1/...` 這類錯誤路徑。
|
||||
const rawServerUrl = env.GITEA_SERVER_URL
|
||||
const serverUrl =
|
||||
|
Ghost marked this conversation as resolved
Outdated
|
||||
typeof rawServerUrl === 'string' ? rawServerUrl.replace(/\/+$/, '') : rawServerUrl
|
||||
const repository = env.GITEA_REPOSITORY
|
||||
|
Ghost marked this conversation as resolved
gitea-actions
commented
嚴重等級:🔵 建議 **嚴重等級**:🔵 建議
**審查員**:Leo
**問題**:直接將 env 預設為 process.env,全域相依性可能導致難以追蹤的副作用。
**建議**:建議在複雜系統中,將環境變數讀取抽離為獨立的 Provider 或 ConfigFactory。
gitea-actions
commented
嚴重等級:🔴 嚴重 **嚴重等級**:🔴 嚴重
**審查員**:Mage
**問題**:在 loadConfig 函式中,對 GITEA_SERVER_URL 的 replace(//+$/, '') 操作假設了輸入一定是 string。雖然隨後有 requireValue 和 requireUrl 的驗證,但如果 env.GITEA_SERVER_URL 是非字串(例如數字、陣列、物件),這裡的 replace 可能會拋出 TypeError。
**建議**:應在 replace 之前確保其型別為 string,或使用 optional chaining 以及更嚴格的類型防護。例如: `typeof rawServerUrl === 'string' ? rawServerUrl.replace(//+$/, '') : rawServerUrl` 已經做了檢查,但後續的 `requireValue` 檢查順序應確保傳入的是處理後的字串。
|
||||
const keepCountRaw = env.KEEP_COUNT
|
||||
|
Ghost marked this conversation as resolved
gitea-actions
commented
嚴重等級:🟡 警告 **嚴重等級**:🟡 警告
**審查員**:Assassin
**問題**:將環境變數值直接輸出至日誌,若 `GITEA_SERVER_URL` 等變數內容被注入惡意字元或過長,可能造成 Log Injection 或日誌系統資源耗盡。
**建議**:在輸出前進行 sanitization,移除控制字元並限制長度,類似於 `gitea-client.js` 中的 `sanitizeBody`。
gitea-actions
commented
嚴重等級:🔵 建議 **嚴重等級**:🔵 建議
**審查員**:Maya
**問題**:雖然有 requireUrl 驗證,但在 loadConfig 中,對於 GITEA_SERVER_URL 的解析假設其為完整路徑。若環境變數提供的網址不含 api/v1 或路徑有變化,整合後的 releaseApiUrl 可能無效。
**建議**:建議在 loadConfig 中增加對 serverUrl 的處理,確保結尾沒有多餘的 /,避免拼接 API 路徑時產生類似 //api 的錯誤路徑。
|
||||
const token = env.GITEA_TOKEN
|
||||
|
Ghost marked this conversation as resolved
gitea-actions
commented
嚴重等級:🔴 嚴重 **嚴重等級**:🔴 嚴重
**審查員**:Assassin
**問題**:僅驗證是否為 URL 格式,未檢查傳入的 `GITEA_SERVER_URL` 是否指向內部網路敏感資源(如 localhost, 169.254.169.254 等),這在容器化環境中可能導致 SSRF(伺服器端請求偽造)。
**建議**:在 `validate.js` 的 `requireUrl` 中加入黑名單機制,禁止解析為內部 IP 位址或 loopback 位址。
|
||||
|
||||
@@ -60,12 +60,13 @@ export async function cleanupReleases(client, config) {
|
||||
for (const release of toDelete) {
|
||||
const { id, tag_name: tag, name } = release
|
||||
|
||||
if (isEmptyOrNull(id)) {
|
||||
warn(`略過沒有 id 的成品: ${tag} (${name})`)
|
||||
// 要求 id 為正整數(Gitea release id 本即正整數);非整數一律略過,不僅依賴 URL 編碼防護。
|
||||
if (isEmptyOrNull(id) || !Number.isInteger(Number(id)) || Number(id) <= 0) {
|
||||
|
Ghost marked this conversation as resolved
gitea-actions
commented
嚴重等級:🟡 警告 **嚴重等級**:🟡 警告
**審查員**:Assassin
**問題**:雖然有 encodeURIComponent,但直接將 id 拼接至 URL 是危險操作。若 id 未經妥善驗證,攻擊者可能試圖透過特殊字元擾亂 API 路徑。
**建議**:建議確保 id 在進入此函數前,已驗證為預期的整數類型或符合嚴格格式的字串,不要完全依賴 encodeURIComponent 來防範所有注入可能。
|
||||
warn(`略過沒有有效 id 的成品: ${tag} (${name})`)
|
||||
continue
|
||||
}
|
||||
|
||||
// 對 id 做編碼,避免非預期內容被拼接進 URL(防路徑穿越);正常數值 id 編碼後不變。
|
||||
// id 已驗證為正整數;仍對其編碼作為縱深防禦。
|
||||
const url = `${config.releaseApiUrl}/${encodeURIComponent(id)}`
|
||||
info(`DELETE ${tag} (${name})`)
|
||||
|
||||
|
||||
嚴重等級:🔵 建議
審查員:Bard
問題:日志信息的键值对缺少空格,排版不够整齐统一。
建議:建议加上空格以提升易读性:
info('GITEA_TOKEN = [redacted]')