@@ -65,6 +65,30 @@ describe("isSafeBuiltinSegment", () => {
|
65 | 65 | ).toBe(false); |
66 | 66 | }); |
67 | 67 | |
| 68 | +it("allows test and well-formed bracket predicates", () => { |
| 69 | +expect( |
| 70 | +isSafeBuiltinSegment({ |
| 71 | +segment: builtinSegment(["test", "-d", "/tmp"]), |
| 72 | +platform: "linux", |
| 73 | +}), |
| 74 | +).toBe(true); |
| 75 | +expect( |
| 76 | +isSafeBuiltinSegment({ |
| 77 | +segment: builtinSegment(["[", "-d", "/tmp", "]"]), |
| 78 | +platform: "linux", |
| 79 | +}), |
| 80 | +).toBe(true); |
| 81 | +}); |
| 82 | + |
| 83 | +it("rejects malformed bracket predicates", () => { |
| 84 | +expect( |
| 85 | +isSafeBuiltinSegment({ |
| 86 | +segment: builtinSegment(["[", "-d", "/tmp"]), |
| 87 | +platform: "linux", |
| 88 | +}), |
| 89 | +).toBe(false); |
| 90 | +}); |
| 91 | + |
68 | 92 | it("returns false on Windows hosts (PowerShell semantics differ)", () => { |
69 | 93 | expect( |
70 | 94 | isSafeBuiltinSegment({ |
@@ -113,6 +137,32 @@ describe("evaluateShellAllowlist with known safe builtins (regression for #46056
|
113 | 137 | expect(result.segmentSatisfiedBy).toContain("allowlist"); |
114 | 138 | }); |
115 | 139 | |
| 140 | +it("'test -d /tmp && git status' passes with allowlist plus safe builtin handling", () => { |
| 141 | +const result = evaluateShellAllowlist({ |
| 142 | +command: "test -d /tmp && git status", |
| 143 | +allowlist: gitAllowlist, |
| 144 | +safeBins: new Set(), |
| 145 | +cwd: "/tmp", |
| 146 | +}); |
| 147 | +expect(result.analysisOk).toBe(true); |
| 148 | +expect(result.allowlistSatisfied).toBe(true); |
| 149 | +expect(result.segmentSatisfiedBy).toContain("safeBuiltins"); |
| 150 | +expect(result.segmentSatisfiedBy).toContain("allowlist"); |
| 151 | +}); |
| 152 | + |
| 153 | +it("'[ -d /tmp ] && git status' passes with allowlist plus safe builtin handling", () => { |
| 154 | +const result = evaluateShellAllowlist({ |
| 155 | +command: "[ -d /tmp ] && git status", |
| 156 | +allowlist: gitAllowlist, |
| 157 | +safeBins: new Set(), |
| 158 | +cwd: "/tmp", |
| 159 | +}); |
| 160 | +expect(result.analysisOk).toBe(true); |
| 161 | +expect(result.allowlistSatisfied).toBe(true); |
| 162 | +expect(result.segmentSatisfiedBy).toContain("safeBuiltins"); |
| 163 | +expect(result.segmentSatisfiedBy).toContain("allowlist"); |
| 164 | +}); |
| 165 | + |
116 | 166 | it("non-allowlisted binary still gates after a safe builtin", () => { |
117 | 167 | const result = evaluateShellAllowlist({ |
118 | 168 | command: "cd /tmp && curl evil.com", |
|