Files
zero/internal/sandbox/windows_command_runner_test.go
0207f2b269 fix(sandbox): keep Windows restricted-token SIDs narrow and fail closed on DenyRead (#1006)
* fix(sandbox): keep Windows restricted-token SIDs narrow and fail closed on DenyRead

* fix(sandbox): address CodeRabbit review feedback on PR 640

* refactor(sandbox): Address CodeRabbit nitpicks on PR 640.

Co-Authored-By: cairn-code <[email protected]>

* fix(sandbox): skip inherited ACEs and reject DenyRead upfront during setup

Skip inherited ACEs when preserving read deny entries, correct syntax in the command runner error message, and evaluate unsupported DenyRead profiles before the elevation check in Windows sandbox setup.

Refs #640

* Reject unsupported DenyRead profiles upfront during sandbox setup

Refs #640

* Migrate legacy Windows DenyWrite ACEs, randomize smoke probes, and clean dead descendant machinery.

Refs #640

* Use /d /c for denied-write probe command and verify ownership on cleanup.

Refs #640

* Honor NoInherit in legacy ACL migration and verify probe ownership.

Refs #639

* Preserve DenyRead bits when migrating combined legacy deny ACEs.

Refs #639

---------

Co-authored-by: euxaristia <[email protected]>
Co-authored-by: cairn-code <[email protected]>
2026-09-12 08:33:06 +08:00

64 lines
2.1 KiB
Go

package sandbox
import (
"strings"
"testing"
)
func TestWindowsDenyReadRestrictedTokenUnsupported(t *testing.T) {
// Both restricted-token runner levels reject DenyRead before launch/setup.
for _, level := range []WindowsSandboxLevel{
WindowsSandboxLevelRestrictedToken,
WindowsSandboxLevelUnelevated,
} {
err := windowsDenyReadRestrictedTokenUnsupported(WindowsSandboxCommandConfig{
SandboxLevel: level,
PermissionProfile: PermissionProfile{
FileSystem: FileSystemPolicy{
Kind: FileSystemRestricted,
DenyRead: []string{`C:\secret`, `D:\private`},
},
},
})
if err == nil {
t.Fatalf("expected unsupported error for %s DenyRead profile", level)
}
msg := err.Error()
for _, want := range []string{"DenyRead", "not supported", "restricted-token", "unelevated", "path count: 2"} {
if !strings.Contains(msg, want) {
t.Fatalf("%s error %q missing %q", level, msg, want)
}
}
// DenyRead often names credential or private-file paths; keep them out of stderr.
for _, secret := range []string{`C:\secret`, `D:\private`} {
if strings.Contains(msg, secret) {
t.Fatalf("%s error leaked DenyRead path %q: %q", level, secret, msg)
}
}
if strings.Contains(msg, "--sandbox forbid") {
t.Fatalf("%s error advertises unsupported --sandbox forbid recovery: %q", level, msg)
}
if strings.Contains(msg, "sandbox_permissions") || strings.Contains(msg, "require_escalated") {
t.Fatalf("%s error advertises unusable escalation recovery: %q", level, msg)
}
if !strings.Contains(msg, "Remove DenyRead") {
t.Fatalf("%s error should advise removing DenyRead: %q", level, msg)
}
}
// No DenyRead: allowed (WRITE_RESTRICTED path can launch system tools).
for _, level := range []WindowsSandboxLevel{
WindowsSandboxLevelRestrictedToken,
WindowsSandboxLevelUnelevated,
} {
if err := windowsDenyReadRestrictedTokenUnsupported(WindowsSandboxCommandConfig{
SandboxLevel: level,
PermissionProfile: PermissionProfile{
FileSystem: FileSystemPolicy{Kind: FileSystemRestricted},
},
}); err != nil {
t.Fatalf("unexpected error without DenyRead at %s: %v", level, err)
}
}
}