aboutsummaryrefslogtreecommitdiff
path: root/docs/design.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/design.md')
-rw-r--r--docs/design.md41
1 files changed, 40 insertions, 1 deletions
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