Scan reports special files (not regular, directory or symlink) in Result.Special, so the startup check refuses with a message naming them; Watch removes them through an os.Root after re-checking the type, and reports any it cannot remove (never as removed). Fixes #179. Adversarial review: BLOCKED, BLOCKED, PASS. Flake on main tracked in #193. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Mathias <mthbqv@gmail.com>
77 lines
2.5 KiB
Go
77 lines
2.5 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"syscall"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// hyperguild#157: the server refuses to start while a symlink exists in the
|
|
// brain dir, or while any part of it cannot be scanned (which could hide
|
|
// one); a missing brain dir is the only thing it lets pass.
|
|
func TestStartupSymlinkCheckRefusesABrainWithASymlink(t *testing.T) {
|
|
brain := t.TempDir()
|
|
require.NoError(t, os.Symlink(t.TempDir(), filepath.Join(brain, "planted")))
|
|
err := startupSymlinkCheck(brain)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "planted")
|
|
}
|
|
|
|
func TestStartupSymlinkCheckRefusesABrainWithAnUnreadableDir(t *testing.T) {
|
|
if os.Geteuid() == 0 {
|
|
t.Skip("root reads mode-000 directories")
|
|
}
|
|
brain := t.TempDir()
|
|
locked := filepath.Join(brain, "aaa")
|
|
require.NoError(t, os.MkdirAll(locked, 0o755))
|
|
require.NoError(t, os.Chmod(locked, 0o000))
|
|
t.Cleanup(func() { _ = os.Chmod(locked, 0o755) })
|
|
err := startupSymlinkCheck(brain)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "aaa")
|
|
}
|
|
|
|
func TestStartupSymlinkCheckPassesACleanOrMissingBrain(t *testing.T) {
|
|
brain := t.TempDir()
|
|
require.NoError(t, os.WriteFile(filepath.Join(brain, "n.md"), []byte("x"), 0o644))
|
|
assert.NoError(t, startupSymlinkCheck(brain))
|
|
assert.NoError(t, startupSymlinkCheck(filepath.Join(brain, "missing")))
|
|
}
|
|
|
|
func TestSymlinkScanIntervalFallsBackOnNonPositive(t *testing.T) {
|
|
for _, v := range []string{"0", "-5", "", "junk"} {
|
|
got := symlinkScanInterval(func(string) string { return v })
|
|
assert.Positive(t, got, "env %q", v)
|
|
}
|
|
}
|
|
|
|
func TestAlertingWarningsNamesTheSymlinkTripwire(t *testing.T) {
|
|
w := strings.Join(alertingWarnings(func(string) string { return "" }), " ")
|
|
assert.Contains(t, w, "symlink tripwire")
|
|
}
|
|
|
|
func TestStartupSymlinkCheckRefusesAnUnlistableBrainRoot(t *testing.T) {
|
|
if os.Geteuid() == 0 {
|
|
t.Skip("root lists mode-0100 directories")
|
|
}
|
|
brain := t.TempDir()
|
|
require.NoError(t, os.Chmod(brain, 0o100))
|
|
t.Cleanup(func() { _ = os.Chmod(brain, 0o755) })
|
|
assert.Error(t, startupSymlinkCheck(brain))
|
|
}
|
|
|
|
// hyperguild#179: a FIFO in the brain is refused at startup with a clear
|
|
// message, instead of hanging or exiting later in a reader.
|
|
func TestStartupSymlinkCheckRefusesABrainWithAFIFO(t *testing.T) {
|
|
brain := t.TempDir()
|
|
require.NoError(t, syscall.Mkfifo(filepath.Join(brain, "classification.yaml"), 0o644))
|
|
err := startupSymlinkCheck(brain)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "classification.yaml")
|
|
}
|