Writers that created or rewrote brain files by path followed symlinks: - promote/reject: os.MkdirAll + os.WriteFile of the destination, then os.Remove of the raw source. Now PutRegular + brainfs.Remove; the source is kept when the write is refused. - StampProvenanceFile (brain_edit's re-stamp): provenance.ApplyFile read and rewrote by path. Now ReadRegular + WriteRegular; ApplyFile, now unused, is removed. - BuildWingIndex (_index.md) and wiki.RebuildIndex (wiki/index.md): now PutRegular. - wiki.AppendLog (log.md) and AutoTunnel's fuzzy-candidate log (raw/tunnel-candidates-*.md): now AppendRegular; tunnel's fileExists, now unused, is removed. - New brainfs.Remove: clean path, real parent, removes a final symlink itself, never its target. brain_edit's own atomic rename was already refused behind a symlinked directory by #187's read check; a guard test pins it. Pipeline writes, BackfillRefs, the watcher's raw/ markers and the session archive in cmd/server follow in a separate PR (#158). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -63,8 +62,10 @@ func BuildWingIndex(brainDir, wing string) error {
|
||||
fmt.Fprintf(&b, "| %s | [%s](%s/%s.md) | %s |\n", e.Hall, e.Title, e.Hall, e.Slug, e.Created)
|
||||
}
|
||||
|
||||
dest := filepath.Join(wingDir, "_index.md")
|
||||
return os.WriteFile(dest, []byte(b.String()), 0o644)
|
||||
// Written through the brain root, never through a symlinked _index.md
|
||||
// (hyperguild#158).
|
||||
_ = wingDir
|
||||
return bfs.PutRegular("wiki/"+w+"/_index.md", []byte(b.String()))
|
||||
}
|
||||
|
||||
// BuildAllWingIndexes regenerates _index.md for every wing under brain/wiki/.
|
||||
|
||||
Reference in New Issue
Block a user