test: pin the edit symlink refusal, AppendRegular's clean check and Remove (#188)
CI / Lint / Test / Vet (pull_request) Failing after 1m6s
CI / Mirror to GitHub (pull_request) Skipped

Review round 1 on PR #189 (three tests stayed green with their guard
removed):
- TestEditRefusesANoteBehindASymlinkedDirectory had no .git, so Edit
  refused "not the sync source" before any path check. It now has one,
  plus a positive control.
- AppendRegular's unclean-path case was refused by a final symlink, not
  cleanRel. New test where ".." after a symlinked dir resolves to a real
  file, for AppendRegular and PutRegular.
- brainfs.Remove had no test; new one (refuses behind a symlinked dir,
  removes a final link but never its target, positive control).

Also: promote/reject create with O_EXCL (new brainfs.CreateRegular), so a
note that appears after the collision check is never overwritten;
gofmt fixes in provenance.go and wiki/log.go; dead wingDir and
putBrainFile removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-05 22:57:26 +02:00
co-authored by Claude Opus 5.5
parent 138d6e2545
commit db18785bfc
7 changed files with 80 additions and 13 deletions
+19
View File
@@ -156,6 +156,25 @@ func (b *Brain) PutRegular(rel string, data []byte) error {
} else if !errors.Is(err, fs.ErrNotExist) {
return err
}
return b.createNew(rel, data)
}
// CreateRegular creates a new regular file at a brain-relative path, with
// PutRegular's parent rules, and fails with fs.ErrExist if anything is
// already there: for writers that must never overwrite (promote, reject).
func (b *Brain) CreateRegular(rel string, data []byte) error {
if err := cleanRel(rel); err != nil {
return err
}
if err := b.mkdirReal(path.Dir(rel)); err != nil {
return err
}
return b.createNew(rel, data)
}
// createNew creates rel with O_EXCL and writes data only after confirming
// the path is the regular file it created.
func (b *Brain) createNew(rel string, data []byte) error {
f, err := b.root.OpenFile(rel, os.O_WRONLY|os.O_CREATE|os.O_EXCL|syscall.O_NOFOLLOW|syscall.O_NONBLOCK, 0o644)
if err != nil {
return err