diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-09-17 14:02:24 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-09-17 14:02:24 +0200 |
| commit | a65e8a0587d3e5c971bef3062dd0d8a3b5cb53b7 (patch) | |
| tree | 82c606411fd814cb5003633cfa592393abcbe057 /internal/plan | |
| parent | b44222fc2b061382dc601014cde287cc41b857ca (diff) | |
| download | krino-a65e8a0587d3e5c971bef3062dd0d8a3b5cb53b7.tar.gz krino-a65e8a0587d3e5c971bef3062dd0d8a3b5cb53b7.zip | |
a symlink in the sorted directory no longer redirects a step
Placeholders were already stopped from sending a file out of the
directory a rule named. A symlink is a name too, and the directory
krino sorts is by the threat model's own premise a place the internet
writes into: a link named after a rule's destination sent moves and
copies anywhere, and under (on-conflict overwrite) trashed a file
OUTSIDE the sorted directory - while the plan showed the in-tree text
and the run reported success.
A step whose destination passes through a symlink at or below the
directory being sorted now fails. A destination the configuration names
outside it - ~/docs on another disk - is the user's own arrangement and
is followed as before; both cases have a test.
End to end, the review's scenario (Out -> ~/secret, overwrite):
before: 1 applied, the user's file replaced and trashed
after: 0 applied 1 failed, the file untouched, nothing trashed
Two bookkeeping bugs in MkdirAllTracked went with it: a dangling
symlink read as a missing directory and was then recorded as one krino
had created - undo would have unlinked a link krino never made - and a
directory created by someone else between the check and the mkdir was
recorded the same way.
Diffstat (limited to 'internal/plan')
| -rw-r--r-- | internal/plan/chain.go | 2 | ||||
| -rw-r--r-- | internal/plan/step.go | 11 |
2 files changed, 10 insertions, 3 deletions
diff --git a/internal/plan/chain.go b/internal/plan/chain.go index 7c95d9b..f24bbfe 100644 --- a/internal/plan/chain.go +++ b/internal/plan/chain.go @@ -92,7 +92,7 @@ func Build(root string, in []Input, now time.Time, d Disk, claims *Claims) []Cha // buildOne builds the chain for a single file. claim is shared with every // other file processed by the same Build call. func buildOne(root string, in Input, now time.Time, d Disk, claim claimed) Chain { - c := Chain{File: in.File} + c := Chain{File: in.File, Root: root} cur := in.File.Path var deletedBy string diff --git a/internal/plan/step.go b/internal/plan/step.go index c613ce5..0b554d3 100644 --- a/internal/plan/step.go +++ b/internal/plan/step.go @@ -52,8 +52,15 @@ type Step struct { // Chain is one file's steps, in order. type Chain struct { - File scan.File - Steps []Step + File scan.File + Steps []Step + + // Root is the directory being sorted. Apply uses it to tell a + // destination inside that directory - where anything at all may have + // been written, by a download or an unpacked archive - from one the + // configuration named itself, which is the user's own arrangement. + Root string + Warnings []string } |
