package sandbox import ( "os" "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestOverrideSuggestionSkipsGlobRuleTarget(t *testing.T) { assert.Nil(t, overrideSuggestion(Violation{ Kind: ViolationKindFSRead, Target: "**/.env", })) } func TestOverrideSuggestionUsesConcretePath(t *testing.T) { o := overrideSuggestion(Violation{ Kind: ViolationKindFSRead, Target: "./.env", }) require.NotNil(t, o) assert.Equal(t, ViolationKindFSRead, o.Kind) assert.Equal(t, "./.env", o.Target) } func TestOverrideSuggestionPreservesRawTargetCharacters(t *testing.T) { // Shell escaping is the presentation layer's job — the domain layer // returns the raw target verbatim, special characters included. o := overrideSuggestion(Violation{ Kind: ViolationKindFSRead, Target: "/tmp/My Dir/it's.env", }) require.NotNil(t, o) assert.Equal(t, "/tmp/My Dir/it's.env", o.Target) } func TestOverrideSuggestionSkipsControlCharacters(t *testing.T) { assert.Nil(t, overrideSuggestion(Violation{ Kind: ViolationKindFSRead, Target: "/tmp/bad\npath", })) } func TestOverrideSuggestionMapsAllSupportedKinds(t *testing.T) { tests := []struct { kind ViolationKind want bool }{ {ViolationKindFSRead, true}, {ViolationKindFSWrite, true}, {ViolationKindFSDeleteOrRename, true}, {ViolationKindExec, true}, {ViolationKindGenericDeny, false}, } for _, tt := range tests { t.Run(string(tt.kind), func(t *testing.T) { o := overrideSuggestion(Violation{Kind: tt.kind, Target: "/tmp/x"}) if tt.want { require.NotNil(t, o) assert.Equal(t, tt.kind, o.Kind) } else { assert.Nil(t, o) } }) } } func TestPrimaryViolationPrefersConcreteProjectPathOverDefaultNoise(t *testing.T) { cwd, err := os.Getwd() require.NoError(t, err) report := &ViolationReport{ SandboxName: DriverSeatbelt, Violations: []Violation{ { Kind: ViolationKindGenericDeny, RawKind: "default", Target: "/dev/dtracehelper", RuleLabel: "sandbox denied access to /dev/dtracehelper", }, { Kind: ViolationKindFSRead, RawKind: "file-read", Target: filepath.Join(cwd, ".env"), RuleTarget: "**/.env", RuleLabel: "read access denied: " + filepath.Join(cwd, ".env"), }, }, } primary := primaryViolation(report) require.NotNil(t, primary) assert.Equal(t, ViolationKindFSRead, primary.Kind) assert.Equal(t, filepath.Join(cwd, ".env"), primary.Target) } // Regression: a network-bind denial (e.g. httptest listeners under go test) // must outrank incidental fs noise like /dev/dtracehelper so the violations // list and failure hint name the network denial, not the noise. func TestPrimaryViolationPrefersNetworkDenialOverNoise(t *testing.T) { report := &ViolationReport{ SandboxName: DriverSeatbelt, Violations: []Violation{ { Kind: ViolationKindFSWrite, RawKind: "file-write", Target: "/dev/dtracehelper", RuleLabel: "write access denied: /dev/dtracehelper", }, { Kind: ViolationKindNetworkBind, RawKind: "default", Target: "local:*:0", RuleLabel: "network bind denied: local:*:0", }, }, } primary := primaryViolation(report) require.NotNil(t, primary) assert.Equal(t, ViolationKindNetworkBind, primary.Kind) assert.Equal(t, "local:*:0", primary.Target) } func TestPrimaryViolationPrefersLaterViolationOnScoreTie(t *testing.T) { report := &ViolationReport{ SandboxName: DriverSeatbelt, Violations: []Violation{ { Kind: ViolationKindExec, Target: "/tmp/first-bin", RuleLabel: "exec denied: /tmp/first-bin", }, { Kind: ViolationKindExec, Target: "/tmp/second-bin", RuleLabel: "exec denied: /tmp/second-bin", }, }, } primary := primaryViolation(report) require.NotNil(t, primary) assert.Equal(t, "/tmp/second-bin", primary.Target) } func TestIsProjectPathRejectsParentRelativeTargets(t *testing.T) { cwd, err := os.Getwd() require.NoError(t, err) tests := []struct { name string target string want bool }{ {name: "dot", target: ".", want: true}, {name: "dot slash", target: "./.env", want: true}, {name: "dotfile", target: ".env", want: true}, {name: "parent", target: "..", want: false}, {name: "parent slash", target: "../.env", want: false}, {name: "nested parent", target: "../../etc/passwd", want: false}, {name: "dot slash parent", target: "./../../etc/passwd", want: false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { assert.Equal(t, tt.want, isProjectPath(tt.target, cwd)) }) } } func TestIsSensitiveProjectFileRejectsParentRelativeTargets(t *testing.T) { assert.False(t, isSensitiveProjectFile("../.env")) assert.False(t, isSensitiveProjectFile("../../.ssh/config")) assert.True(t, isSensitiveProjectFile("./.env")) assert.True(t, isSensitiveProjectFile("./.ssh/config")) } func TestBuildExplanationStructuredOutput(t *testing.T) { exp := BuildExplanation(&ViolationReport{ SandboxName: "seatbelt", PolicyName: "npm-restrictive", CorrelationID: "run-1", Violations: []Violation{ { Kind: ViolationKindFSRead, Target: "./.env", RuleLabel: "read access denied: ./.env", }, { Kind: ViolationKindFSWrite, Target: "./out.log", RuleLabel: "write access denied: ./out.log", }, }, }) require.NotNil(t, exp.Primary) assert.Equal(t, ViolationKindFSRead, exp.Primary.Kind) require.NotNil(t, exp.Override) assert.Equal(t, ViolationKindFSRead, exp.Override.Kind) assert.Equal(t, "./.env", exp.Override.Target) assert.Equal(t, 1, exp.AdditionalDenials) } func TestBuildExplanationEmptyReport(t *testing.T) { exp := BuildExplanation(&ViolationReport{}) assert.Nil(t, exp.Primary) assert.Nil(t, exp.Override) assert.Equal(t, 0, exp.AdditionalDenials) } func TestIsSensitiveProjectTargetExported(t *testing.T) { assert.True(t, IsSensitiveProjectTarget("./.env")) assert.True(t, IsSensitiveProjectTarget(filepath.Join("/repo", ".npmrc"))) assert.False(t, IsSensitiveProjectTarget(filepath.Join("/repo", ".astro"))) assert.False(t, IsSensitiveProjectTarget("../.env")) } func TestIsSensitiveProjectTargetGNUPGFiles(t *testing.T) { assert.True(t, IsSensitiveProjectTarget("/home/user/.gnupg/pubring.kbx")) assert.True(t, IsSensitiveProjectTarget("/home/user/.gnupg/private-keys-v1.d/abc.key")) }