feat: deny-by-default filesystem isolation
Flip the sandbox from allow-by-default reads (--ro-bind / /) to deny-by-default (--tmpfs / with selective mounts). This makes the sandbox safer by default — only system paths, CWD, and explicitly allowed paths are accessible. - Config: DefaultDenyRead is now *bool (nil = true, deny-by-default) with IsDefaultDenyRead() helper; opt out via "defaultDenyRead": false - Linux: new buildDenyByDefaultMounts() using --tmpfs / + selective --ro-bind for system paths, --symlink for merged-usr distros (Arch), --bind for CWD, and --ro-bind for user tooling/shell configs/caches - macOS: generateReadRules() adds CWD subpath, ancestor traversal, home shell configs/caches; generateWriteRules() auto-allows CWD - Landlock: deny-by-default mode allows only specific user tooling paths instead of blanket home directory read access - Sensitive .env files masked within CWD via empty-file overlay on Linux and deny rules on macOS - Learning templates now include allowRead and .env deny patterns
This commit is contained in:
@@ -410,7 +410,7 @@ func TestMerge(t *testing.T) {
|
||||
t.Run("merge defaultDenyRead and allowRead", func(t *testing.T) {
|
||||
base := &Config{
|
||||
Filesystem: FilesystemConfig{
|
||||
DefaultDenyRead: true,
|
||||
DefaultDenyRead: boolPtr(true),
|
||||
AllowRead: []string{"/home/user/project"},
|
||||
},
|
||||
}
|
||||
@@ -421,13 +421,40 @@ func TestMerge(t *testing.T) {
|
||||
}
|
||||
result := Merge(base, override)
|
||||
|
||||
if !result.Filesystem.DefaultDenyRead {
|
||||
t.Error("expected DefaultDenyRead to be true (from base)")
|
||||
if !result.Filesystem.IsDefaultDenyRead() {
|
||||
t.Error("expected IsDefaultDenyRead() to be true (from base)")
|
||||
}
|
||||
if len(result.Filesystem.AllowRead) != 2 {
|
||||
t.Errorf("expected 2 allowRead paths, got %d: %v", len(result.Filesystem.AllowRead), result.Filesystem.AllowRead)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("defaultDenyRead nil defaults to true", func(t *testing.T) {
|
||||
base := &Config{
|
||||
Filesystem: FilesystemConfig{},
|
||||
}
|
||||
result := Merge(base, nil)
|
||||
if !result.Filesystem.IsDefaultDenyRead() {
|
||||
t.Error("expected IsDefaultDenyRead() to be true when nil (deny-by-default)")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("defaultDenyRead explicit false overrides", func(t *testing.T) {
|
||||
base := &Config{
|
||||
Filesystem: FilesystemConfig{
|
||||
DefaultDenyRead: boolPtr(true),
|
||||
},
|
||||
}
|
||||
override := &Config{
|
||||
Filesystem: FilesystemConfig{
|
||||
DefaultDenyRead: boolPtr(false),
|
||||
},
|
||||
}
|
||||
result := Merge(base, override)
|
||||
if result.Filesystem.IsDefaultDenyRead() {
|
||||
t.Error("expected IsDefaultDenyRead() to be false (override explicit false)")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func boolPtr(b bool) *bool {
|
||||
|
||||
Reference in New Issue
Block a user