@@ -159,6 +159,46 @@ describe("evaluateFilePolicy — denyPaths always wins", () => {
|
159 | 159 | expect(r.ok ? "" : r.reason).toMatch(/deny/); |
160 | 160 | }); |
161 | 161 | |
| 162 | +it("treats globstar slash as zero or more directories in denyPaths", () => { |
| 163 | +withConfig({ |
| 164 | +n1: { |
| 165 | +allowReadPaths: ["~/Downloads/**"], |
| 166 | +denyPaths: ["~/Downloads/**/*.pem"], |
| 167 | +}, |
| 168 | +}); |
| 169 | +const r = evaluateFilePolicy({ |
| 170 | +nodeId: "n1", |
| 171 | +kind: "read", |
| 172 | +path: path.join(os.homedir(), "Downloads", "key.pem"), |
| 173 | +}); |
| 174 | +expectResultFields(r, { ok: false, code: "POLICY_DENIED", askable: false }); |
| 175 | +}); |
| 176 | + |
| 177 | +it("preserves minimatch brace semantics in denyPaths", () => { |
| 178 | +withConfig({ |
| 179 | +n1: { |
| 180 | +allowReadPaths: ["~/Downloads/**"], |
| 181 | +denyPaths: ["~/Downloads/**/*.{pem,key}", "**/.{ssh,aws}/**"], |
| 182 | +}, |
| 183 | +}); |
| 184 | +expectResultFields( |
| 185 | +evaluateFilePolicy({ |
| 186 | +nodeId: "n1", |
| 187 | +kind: "read", |
| 188 | +path: path.join(os.homedir(), "Downloads", "api.key"), |
| 189 | +}), |
| 190 | +{ ok: false, code: "POLICY_DENIED", askable: false }, |
| 191 | +); |
| 192 | +expectResultFields( |
| 193 | +evaluateFilePolicy({ |
| 194 | +nodeId: "n1", |
| 195 | +kind: "read", |
| 196 | +path: path.join(os.homedir(), "Downloads", ".aws", "credentials"), |
| 197 | +}), |
| 198 | +{ ok: false, code: "POLICY_DENIED", askable: false }, |
| 199 | +); |
| 200 | +}); |
| 201 | + |
162 | 202 | it("denies even with ask=always (denyPaths is hard)", () => { |
163 | 203 | withConfig({ |
164 | 204 | n1: { |
|