MCPcopy Create free account
hub / github.com/codehamr/codehamr / TestBootstrapRefusesSymlinkedDir

Function TestBootstrapRefusesSymlinkedDir

internal/config/config_test.go:606–624  ·  view source on GitHub ↗

TestBootstrapRefusesSymlinkedDir: a co-tenant could plant .codehamr → an attacker-controlled dir before first run. Bootstrap must Lstat (not Stat) and refuse any symlink: even with a 0o600 config.yaml, the attacker owns the parent and can swap or read what codehamr writes. Same defence for a planted

(t *testing.T)

Source from the content-addressed store, hash-verified

604// parent and can swap or read what codehamr writes. Same defence for a planted
605// config.yaml symlink.
606func TestBootstrapRefusesSymlinkedDir(t *testing.T) {
607 root := t.TempDir()
608 target := t.TempDir()
609 link := filepath.Join(root, DirName)
610 if err := os.Symlink(target, link); err != nil {
611 t.Skipf("symlink unsupported: %v", err)
612 }
613 _, _, err := Bootstrap(root)
614 if err == nil {
615 t.Fatal("Bootstrap accepted a symlinked .codehamr - config-injection vector left open")
616 }
617 if !strings.Contains(err.Error(), "symlink") {
618 t.Fatalf("error should name the symlink defence: %v", err)
619 }
620 // Target must stay untouched, nothing dropped into the attacker-controlled dir.
621 if _, err := os.Stat(filepath.Join(target, "config.yaml")); err == nil {
622 t.Fatal("Bootstrap wrote into the symlink target despite the rejection")
623 }
624}
625
626func TestBootstrapRefusesSymlinkedConfigYAML(t *testing.T) {
627 root := t.TempDir()

Callers

nothing calls this directly

Calls 2

BootstrapFunction · 0.85
ErrorMethod · 0.80

Tested by

no test coverage detected