Address review round 2: duplicate ids, read-only files, dangling links, safe ids

- load() rejects duplicate ids (left by the old add bug) and ids that aren't safe positive integers
- save() refuses files the user can't write, and follows dangling symlinks to their target
- CLI rejects ids beyond Number.MAX_SAFE_INTEGER
- Skip permission-based tests when running as root

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
christianandClaude Opus 5.5 committed 2026-10-21 00:33:46 +02:00
1 parent 8dc5194438
commit 089fc94e16
4 files changed
+65 -10

No files matched your search

+2 -1
View File
@@ -41,6 +41,7 @@ for (const [label, args, message] of [
["decimal id", ["1.0"], /Invalid id: 1\.0/],
["padded id", [" 1 "], /Invalid id: 1 /],
["empty id", [""], /Invalid id: \n/],
["unsafe id", ["99999999999999999999"], /Invalid id: 99999999999999999999/],
["unknown id", ["99"], /No todo with id 99/],
]) {
for (const cmd of ["done", "rm"]) {
@@ -64,7 +65,7 @@ test("unknown command prints usage even when the file is corrupt", () => {
assert.match(res.stderr, /Unknown command: --help\nUsage:/);
});
test("a failed save gives a readable error instead of a stack trace", () => {
test("a failed save gives a readable error instead of a stack trace", { skip: process.getuid?.() === 0 && "root ignores file permissions" }, () => {
const file = tempFile();
chmodSync(dirname(file), 0o500);
try {