Reject a retention duration longer than about 292 years #328

Merged
clawbot merged 1 commits from issue-289-duration-overflow into next 2026-10-13 01:51:25 +02:00
Collaborator

Fixes #289.

What was wrong: parseDuration multiplied each number by the length of its unit (d, w, mo, y) and added up the parts with no limit. From 293y, 15251w, 3559mo or 106752d, or a sum such as 200y200y, the result wrapped to a negative duration. The purge cutoff then lay in the future, and every snapshot of the name was deleted with exit 0, for --older-than and --keep-newer-than alike.

What changed: before adding each part, parseDuration checks that the total still fits in a time.Duration (about 292 years) and otherwise returns an invalid-duration error. A cutoff can no longer lie in the future, and a too-large value stops the purge before anything is deleted. Go units (h, m, s) were already safe, because time.ParseDuration rejects an overflow; one test case covers that too.

The parse test gains an overflow case for each unit, two sums of parts, and 292y as the largest accepted year count. A purge test shows that 1000y returns an error and deletes nothing, and that 292y deletes nothing.

Judgement call: with snapshot create --prune --keep-newer-than 1000y the backup still runs before the duration is read; the command then fails in the prune step with nothing deleted. Checking the flag before the backup would be a separate change.

Model: opus-5-5

Fixes https://git.eeqj.de/sneak/vaultik/issues/289. **What was wrong:** `parseDuration` multiplied each number by the length of its unit (`d`, `w`, `mo`, `y`) and added up the parts with no limit. From `293y`, `15251w`, `3559mo` or `106752d`, or a sum such as `200y200y`, the result wrapped to a negative duration. The purge cutoff then lay in the future, and every snapshot of the name was deleted with exit 0, for `--older-than` and `--keep-newer-than` alike. **What changed:** before adding each part, `parseDuration` checks that the total still fits in a `time.Duration` (about 292 years) and otherwise returns an invalid-duration error. A cutoff can no longer lie in the future, and a too-large value stops the purge before anything is deleted. Go units (`h`, `m`, `s`) were already safe, because `time.ParseDuration` rejects an overflow; one test case covers that too. The parse test gains an overflow case for each unit, two sums of parts, and `292y` as the largest accepted year count. A purge test shows that `1000y` returns an error and deletes nothing, and that `292y` deletes nothing. Judgement call: with `snapshot create --prune --keep-newer-than 1000y` the backup still runs before the duration is read; the command then fails in the prune step with nothing deleted. Checking the flag before the backup would be a separate change. Model: opus-5-5
clawbot added the needs-review label 2026-10-13 00:58:30 +02:00
clawbot self-assigned this 2026-10-13 00:58:30 +02:00
clawbot added 1 commit 2026-10-13 00:58:30 +02:00
parseDuration multiplied each number by the length of its unit with no
limit, so from 293y (or 15251w, 3559mo, 106752d, or a sum such as
200y200y) the result wrapped to a negative duration. The purge cutoff
then lay in the future and every snapshot of the name was selected, for
--older-than and --keep-newer-than alike. Each part is now checked
before it is added, and a total past the largest time.Duration is
rejected as an invalid duration, so nothing is deleted. Go units were
already safe: time.ParseDuration rejects an overflow.

With --prune the backup still runs before the duration is read; only
the prune step fails.

Model: opus-5-5
Author
Collaborator

Review passed.

Model: opus-5-5

Review passed. Model: opus-5-5
clawbot merged commit c9a519c233 into next 2026-10-13 01:51:25 +02:00
clawbot deleted branch issue-289-duration-overflow 2026-10-13 01:51:26 +02:00
Sign in to join this conversation.