From e94e107071223b2504963dfa95ccd1f2293da752 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Mon, 14 Sep 2026 19:29:27 +0200 Subject: plan 8: threat model, make fuzz, race and vulncheck --- docs/design.md | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/design.md b/docs/design.md index 331993a..fb8988c 100644 --- a/docs/design.md +++ b/docs/design.md @@ -8,7 +8,8 @@ amended again 2026-09-14 for 0.0.4: `max-size` (§4.4), `(exclude ...)` (§4.2, §4.3, §4.6) and `--min-age` (§11); amended again 2026-09-14 for 0.0.5: the keyword cache (§3, §6.1, §13), and `t`, `d` and `w` in review (§8.3, §10); amended again 2026-09-14 for 0.0.6: `w` applies and quits, and -each choice is echoed in red (§8.2, §8.3). +each choice is echoed in red (§8.2, §8.3); amended again 2026-09-14 for +0.0.7: the threat model and its tests (§15.1). krino (from Greek κρίνω, "to separate, to judge, to decide") sorts files in chosen directories by rules. A rule tests a file's type, name, path, size, @@ -806,6 +807,44 @@ placeholder numbers, screenshots by date, cleaning up old installers). `make ci` is the gate: gofmt, vet, tests, the leak check, man page lint. +### 15.1 Hostile input + +krino runs on folders the internet writes into, so it treats as hostile +every file name, every file's contents, and the output of the tools it runs +on them. The configuration is trusted: it is the user's own. The state +files (the log, the keyword cache, the Trash) are the user's own too: krino +survives their corruption — a truncated line, a damaged cache, a +hand-edited trashinfo — but does not defend against another local process +with write access to them, which could already do anything krino can. + +What that means, and the tests that hold it (plan 8): + +- A name never controls the terminal. Every name, path, reason and warning + is printed through `display`, which shows C0 controls, DEL, C1 controls, + Unicode bidirectional embeddings, overrides and isolates, and invalid + UTF-8 as escapes (`\x1b`, `\u202e`). +- A name never redirects a step. A rename whose placeholders produce "", + "." or "..", and a destination whose placeholders add a ".." segment, are + skipped with a reason. +- A file is acted on only while it is still the file that was planned: + same size and modification time, still a regular file (not a symlink put + in its place), and, at its planned path, the same inode. +- A file reaches an external tool only as an absolute path, so a name + starting with `-` is never read as an option. +- A trash entry name from the log must be a plain name inside the Trash, + and a trashinfo `Path` must be absolute. +- Every decoder of outside data is fuzzed (`make fuzz`): the config reader, + sizes and durations, placeholders, ignore patterns, the log's escaping, + trashinfo paths, the keyword cache, markup and zip extraction, and text + normalisation. +- For generated trees and rules, apply then undo restores every file, and + nothing is lost in between (property test, `KRINO_PROPERTY_RUNS`). +- Every value of every enum the output, the log or planning depends on is + handled: tests read the constants from source. +- `make vulncheck` checks the standard library and dependencies against + the Go vulnerability database; `make race` runs the tests under the race + detector. + ## 16. Lessons from the prototype krino replaces a Python prototype that sorted a downloads folder by -- cgit v1.3