feat(storage-boxes): 新增 hetzner_get_storage_box_stats 與 hetzner_assert_storage_box_space 工具 - #54
Conversation
…t_storage_box_space 工具 新增兩個 Storage Box 空間管理工具(issue #115): - hetzner_get_storage_box_stats:回傳 used_bytes/used_gib、total_bytes/total_gib、 available_gib、usage_percent(2 位小數),stats.size(data+snapshots 合計)為已用空間 - hetzner_assert_storage_box_space:接受 required_gib 參數,空間不足時回傳 isError:true, 供備份 pipeline 在執行前做 pre-flight check - 抽出 computeStorageBoxStats() 共用輔助函式(exported for testing) 344/344 tests pass;lint 0 error;tsc clean
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthrough本次變更在 storage-boxes 工具模組中新增容量統計計算與兩個 MCP 工具,並補充對應測試與註冊斷言。 ChangesStorage Box 統計與容量校驗
Estimated code review effort: 2 (Simple) | ~15 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration. Comment |
There was a problem hiding this comment.
Pull request overview
此 PR 將先前僅存在於 develop 的 Storage Box 容量統計與空間斷言功能,cherry-pick 回 main 基底,以補回可用性並維持既有安全強化不被回退。
Changes:
- 新增
hetzner_get_storage_box_stats工具:回傳 Storage Box 用量統計(used/total/available/usage_percent)。 - 新增
hetzner_assert_storage_box_space工具:備份/排程前置檢查可用空間是否達到需求,空間不足時回傳isError: true。 - 補上
computeStorageBoxStats的單元測試與兩個新工具的 handler 整合測試。
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/tools/storage-boxes.ts | 新增用量統計計算函式與兩個新工具註冊/handler 實作 |
| tests/tools/storage-boxes.test.ts | 更新工具註冊數量斷言,新增 compute/tool handler 測試覆蓋 |
…iption
1. hetzner_assert_storage_box_space 補上 response_format(意見 3、4)
本檔 read-only 工具皆提供 markdown/json 切換,唯獨這個沒有。
補上後 handler 實際尊重該參數:JSON 模式回傳 { ok, required_gib, ...stats },
且 ok=false 時仍維持 isError: true,讓自動化流程可任選其一分支。
2. description 明確標示 used_* 含 snapshots(意見 2)
原文寫 "current data usage",但 computeStorageBoxStats 用的是 stats.size
(= size_data + size_snapshots)。已改為明確寫出,並補上 available_* 在
超額時為負值的說明。
3. available 改由 bytes 整數相減再換算(意見 1,部分採納)
新增 available_bytes 欄位,與既有的 used_bytes / total_bytes 對稱。
why 部分採納:意見中「浮點誤差」的理由不成立。GiB = 2^30,整數除以 2 的冪
只改指數不動尾數,是精確運算。實測 20 萬次隨機組合(含非 GiB 整數倍的 total),
(total/GiB - used/GiB) 與 (total-used)/GiB 誤差恆為 0。改寫的價值在於把
single source of truth 留在 bytes、並補上缺漏的 available_bytes,不是修 bug。
why 不 clamp 到 >= 0:Hetzner 把 snapshots 計入 stats.size,超額的 box
回報負可用空間是正確資訊。clamp 成 0 只會把「你超額 5 GiB」藏成「剩 0 GiB」,
而 assert 的結果完全不變(任何 required_gib > 0 都會失敗)。
驗證:
- 369 tests / typecheck / lint 全綠(新增 4 個測試:available_bytes 與
available_gib 在非 GiB 整數倍下完全一致、超額時回報負值、JSON 模式 ok=true
無 isError、JSON 模式 ok=false 仍有 isError)
- runtime 實打 Hetzner Storage Box 561406:
required_gib=100 → ok=true isError=false available_gib=546.27
required_gib=900 → ok=false isError=true available_gib=546.27
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/tools/storage-boxes.ts (1)
57-88: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value邏輯正確,
available_bytes不做非負鉗制的設計說明清楚。除零保護、GiB 換算與超額配額(負值)情境都處理得宜,且註解已充分說明設計動機,測試也涵蓋了這些邊界情況。
小提醒:
1024 ** 3這個魔術數字在本函式(第 71 行)與下方formatBytes(第 92 行)各自出現一次,可考慮抽成模組層共用常數(例如const BYTES_PER_GIB = 1024 ** 3)以避免未來兩處不同步。純屬錦上添花,不影響本次功能正確性。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/tools/storage-boxes.ts` around lines 57 - 88, The logic in computeStorageBoxStats is fine, but the GiB conversion literal is duplicated and should be centralized. Extract the repeated 1024 ** 3 value into a shared module-level constant (for example, a BYTES_PER_GIB symbol) and use it both in computeStorageBoxStats and formatBytes so the storage-box sizing logic stays consistent and easier to maintain.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/tools/storage-boxes.ts`:
- Around line 57-88: The logic in computeStorageBoxStats is fine, but the GiB
conversion literal is duplicated and should be centralized. Extract the repeated
1024 ** 3 value into a shared module-level constant (for example, a
BYTES_PER_GIB symbol) and use it both in computeStorageBoxStats and formatBytes
so the storage-box sizing logic stays consistent and easier to maintain.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 7eef7fa3-01d2-4ae3-b090-2fe01aa631ed
📒 Files selected for processing (2)
src/tools/storage-boxes.tstests/tools/storage-boxes.test.ts
CodeRabbit review 指出 `1024 ** 3` 在 computeStorageBoxStats 與 formatBytes
各出現一次,未來可能不同步。
實際掃描發現是三處,不是兩處——CodeRabbit 漏了 formatBytes 裡的 `1024 ** 2`
(MiB 換算)。兩個單位都抽成模組層常數。
也符合 ~/.claude/rules/common/coding-style.md 的「Magic Numbers — Use named
constants for meaningful thresholds, delays, and limits」。
驗證:
- 369 tests / typecheck / lint 全綠
- grep 確認檔內已無裸露的 `1024 ** N`(僅剩常數定義處)
- runtime 實打 Storage Box 561406,數值與重構前一致:
used_gib=477.73 total_gib=1024.00 available_gib=546.27 usage=46.65%
available_bytes=586554540032(= total_bytes - used_bytes,整數精確)
|
已採納,修正見 5df4614。 抽出模組層常數 實際掃描發現是三處而非兩處 —— 驗證:369 tests / typecheck / lint 全綠;runtime 實打 Storage Box 561406,數值與重構前完全一致( 🤖 Addressed by Claude Code |
為什麼現在才進 main
這個功能原本是
develop上的4c23c35(2026-06-25),從未合併。develop與main已雙向分歧:develop有這個功能,但缺少main後來加的 security hardening(isSafePathSegmentpath-traversal 防護、escapeHtmlXSS 轉義、SSH host-key pinning)。若直接把develop重設成main,這兩個工具就會消失。本 PR 把該 commit cherry-pick 到
main基底(零衝突),先把功能救回來,之後develop才能安全地重設對齊main。內容
兩個工具,129 行實作 + 159 行測試:
hetzner_get_storage_box_stats— 回傳用量統計(used / total / available / usage_percent)hetzner_assert_storage_box_space— 斷言剩餘空間足夠,供備份前檢查Cherry-pick 到新基底後的安全複查
這個 commit 寫在 hardening 之前,乾淨 cherry-pick 正是新功能可能悄悄繞過新防護的時機,因此逐項複查:
isSafePathSegment()id: z.number().int().positive(),非字串,/storage_boxes/${id}無 path-traversal 面。同檔案其他 handler 只對username/snapshot_id等字串參數呼叫它escapeHtml()used_gib、usage_percent等),不渲染 box name / description / labels,無未轉義的使用者可控字串src/tools/server-ssh.ts另檢查:
computeStorageBoxStats對total_bytes === 0有除零防護;size欄位在HetznerStorageBoxSchema為必要欄位,缺漏時由 zod 擋下並走handleApiError,不會產生NaN;兩個 handler 都 try/catch 並回isError: true,與同檔案其他 handler 一致。驗證
main的 security 修正確認未被覆蓋:src/utils.ts的isSafePathSegment仍在、storage-boxes.ts有 4 處呼叫它、reference.ts的escapeHtml仍在、server-ssh.ts維持 421 行tools/list回傳 42 個工具(含這兩個新的),hetzner_get_storage_box_stats(id=561406)回傳Used: 477.7 GiB / Total: 1024.0 GiB,與jurislm-backup-fsn1的實際用量相符>=邊界、API 失敗Test plan
bun run test(365 passed)bun run typecheckbun run lintdevelop即可安全重設對齊mainSummary by CodeRabbit