Skip to content

Commit b4524fe

Browse files
Test: Improve recursion depth limit tests for JSON utils
* 🎯 **What:** Improved `tests/unit/json_utils_security.test.ts` to strictly verify the recursion depth limit (1000) in `generateMergePatch` and `applyMergePatch`. * 📊 **Coverage:** Added boundary tests for depth 1000 (allowed) and depth 1001 (disallowed) using a deterministic `createDeepObject` helper. * ✨ **Result:** Verified that the safety mechanism correctly enforces the limit without off-by-one errors. Confirmed behavior by temporarily lowering the limit. Co-authored-by: zknpr <96851588+zknpr@users.noreply.github.com>
1 parent 2a3de52 commit b4524fe

1 file changed

Lines changed: 42 additions & 20 deletions

File tree

tests/unit/json_utils_security.test.ts

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,34 @@ import { describe, it } from 'node:test';
33
import assert from 'node:assert';
44
import { generateMergePatch, applyMergePatch } from '../../src/core/json-utils';
55

6+
function createDeepObject(depth: number, leafValue: any = 1) {
7+
let obj: any = { leaf: leafValue };
8+
for (let i = 0; i < depth; i++) {
9+
obj = { next: obj };
10+
}
11+
return obj;
12+
}
13+
614
describe('JSON Merge Patch Security', () => {
7-
it('generateMergePatch should throw on deep recursion', () => {
8-
const depth = 1100; // > 1000
9-
let original: any = { a: 1 };
10-
let modified: any = { a: 2 };
11-
12-
for (let i = 0; i < depth; i++) {
13-
original = { next: original };
14-
modified = { next: modified };
15-
}
15+
// MAX_DEPTH is 1000.
16+
// Nesting level N creates depth N+1 (recursion for leaf comparison/application).
17+
// So Nesting 999 -> Depth 1000 (Allowed).
18+
// Nesting 1000 -> Depth 1001 (Throw).
19+
20+
it('generateMergePatch should allow max depth (1000)', () => {
21+
const nesting = 999;
22+
const original = createDeepObject(nesting, 1);
23+
const modified = createDeepObject(nesting, 2);
24+
25+
// Should not throw
26+
const patch = generateMergePatch(original, modified);
27+
assert.notStrictEqual(patch, undefined);
28+
});
29+
30+
it('generateMergePatch should throw on max depth + 1 (1001)', () => {
31+
const nesting = 1000;
32+
const original = createDeepObject(nesting, 1);
33+
const modified = createDeepObject(nesting, 2);
1634

1735
try {
1836
generateMergePatch(original, modified);
@@ -22,21 +40,25 @@ describe('JSON Merge Patch Security', () => {
2240
}
2341
});
2442

25-
it('applyMergePatch should throw on deep recursion', () => {
26-
const depth = 1100; // > 1000
27-
let target: any = { a: 1 };
28-
let patch: any = { a: 2 };
43+
it('applyMergePatch should allow max depth (1000)', () => {
44+
const nesting = 999;
45+
const target = {};
46+
const patch = createDeepObject(nesting, 1);
2947

30-
for (let i = 0; i < depth; i++) {
31-
target = { next: target };
32-
patch = { next: patch };
33-
}
48+
// Should not throw
49+
applyMergePatch(target, patch);
50+
});
51+
52+
it('applyMergePatch should throw on max depth + 1 (1001)', () => {
53+
const nesting = 1000;
54+
const target = {};
55+
const patch = createDeepObject(nesting, 1);
3456

3557
try {
36-
applyMergePatch(target, patch);
37-
assert.fail('Should have thrown depth limit error');
58+
applyMergePatch(target, patch);
59+
assert.fail('Should have thrown depth limit error');
3860
} catch (e: any) {
39-
assert.match(e.message, /JSON apply merge patch depth limit exceeded/);
61+
assert.match(e.message, /JSON apply merge patch depth limit exceeded/);
4062
}
4163
});
4264

0 commit comments

Comments
 (0)