From 3586ab380311290c8871e659cdcb3f9e4fafa7dd Mon Sep 17 00:00:00 2001 From: Jeffery Date: Fri, 26 Jun 2026 14:05:09 +0800 Subject: [PATCH] =?UTF-8?q?docs(release-cleanup):=20=E6=96=BC=20cleanupOrp?= =?UTF-8?q?hanTags=20=E8=A8=BB=E8=A8=98=20TOCTOU=20=E6=AE=98=E9=A4=98?= =?UTF-8?q?=E7=AB=B6=E6=85=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 明確文件化 release 與 tag 兩次獨立 API 呼叫間的時序競態(已知限制), 說明現行緩解與為何屬排程任務可接受範圍。僅註解變更。 Co-Authored-By: Claude Opus 4.8 (1M context) --- app/tags.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/tags.js b/app/tags.js index 22becd9..112e3d5 100644 --- a/app/tags.js +++ b/app/tags.js @@ -42,7 +42,10 @@ export function categorizeTags(tags, releaseTagNames) { export async function cleanupOrphanTags(client, config) { section('刪除未指定 release 的 tag') - // 重新取得 release 清單,得到刪除舊版本後仍指定 tag 的成品 + // 重新取得 release 清單,得到刪除舊版本後仍指定 tag 的成品。 + // 已知限制(TOCTOU):release 與 tag 為兩次獨立 API 呼叫,Gitea 無交易機制; + // 若兩次呼叫之間有新 release 關聯到某 tag,該 tag 仍可能基於過時快照被誤判為孤立。 + // 此為排程清理任務可接受的殘餘競態(下次執行會自我修正),完整原子性留待人工評估。 const currentReleases = await client.fetchAllPages(config.releaseApiUrl) const releaseTagNames = currentReleases.map((release) => release.tag_name)