observability-toolkit 1.8.2 → 1.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -0
- package/dist/backends/index.d.ts +43 -0
- package/dist/backends/index.d.ts.map +1 -1
- package/dist/backends/index.js +41 -0
- package/dist/backends/index.js.map +1 -1
- package/dist/backends/index.test.d.ts +5 -0
- package/dist/backends/index.test.d.ts.map +1 -0
- package/dist/backends/index.test.js +156 -0
- package/dist/backends/index.test.js.map +1 -0
- package/dist/backends/local-jsonl-boolean-search.test.js +15 -12
- package/dist/backends/local-jsonl-boolean-search.test.js.map +1 -1
- package/dist/backends/local-jsonl-cache.test.d.ts +2 -0
- package/dist/backends/local-jsonl-cache.test.d.ts.map +1 -0
- package/dist/backends/local-jsonl-cache.test.js +295 -0
- package/dist/backends/local-jsonl-cache.test.js.map +1 -0
- package/dist/backends/local-jsonl-circuit-breaker.test.d.ts +2 -0
- package/dist/backends/local-jsonl-circuit-breaker.test.d.ts.map +1 -0
- package/dist/backends/local-jsonl-circuit-breaker.test.js +180 -0
- package/dist/backends/local-jsonl-circuit-breaker.test.js.map +1 -0
- package/dist/backends/local-jsonl-export.test.d.ts +2 -0
- package/dist/backends/local-jsonl-export.test.d.ts.map +1 -0
- package/dist/backends/local-jsonl-export.test.js +704 -0
- package/dist/backends/local-jsonl-export.test.js.map +1 -0
- package/dist/backends/local-jsonl-index.test.d.ts +2 -0
- package/dist/backends/local-jsonl-index.test.d.ts.map +1 -0
- package/dist/backends/local-jsonl-index.test.js +554 -0
- package/dist/backends/local-jsonl-index.test.js.map +1 -0
- package/dist/backends/local-jsonl-logs.test.d.ts +2 -0
- package/dist/backends/local-jsonl-logs.test.d.ts.map +1 -0
- package/dist/backends/local-jsonl-logs.test.js +612 -0
- package/dist/backends/local-jsonl-logs.test.js.map +1 -0
- package/dist/backends/local-jsonl-metrics.test.d.ts +2 -0
- package/dist/backends/local-jsonl-metrics.test.d.ts.map +1 -0
- package/dist/backends/local-jsonl-metrics.test.js +876 -0
- package/dist/backends/local-jsonl-metrics.test.js.map +1 -0
- package/dist/backends/local-jsonl-traces.test.d.ts +2 -0
- package/dist/backends/local-jsonl-traces.test.d.ts.map +1 -0
- package/dist/backends/local-jsonl-traces.test.js +1729 -0
- package/dist/backends/local-jsonl-traces.test.js.map +1 -0
- package/dist/backends/local-jsonl.d.ts +9 -0
- package/dist/backends/local-jsonl.d.ts.map +1 -1
- package/dist/backends/local-jsonl.js +348 -227
- package/dist/backends/local-jsonl.js.map +1 -1
- package/dist/backends/local-jsonl.test.js +290 -21
- package/dist/backends/local-jsonl.test.js.map +1 -1
- package/dist/backends/signoz-api-circuit-breaker.test.d.ts +6 -0
- package/dist/backends/signoz-api-circuit-breaker.test.d.ts.map +1 -0
- package/dist/backends/signoz-api-circuit-breaker.test.js +548 -0
- package/dist/backends/signoz-api-circuit-breaker.test.js.map +1 -0
- package/dist/backends/signoz-api-rate-limiter.test.d.ts +6 -0
- package/dist/backends/signoz-api-rate-limiter.test.d.ts.map +1 -0
- package/dist/backends/signoz-api-rate-limiter.test.js +389 -0
- package/dist/backends/signoz-api-rate-limiter.test.js.map +1 -0
- package/dist/backends/signoz-api-ssrf.test.d.ts +6 -0
- package/dist/backends/signoz-api-ssrf.test.d.ts.map +1 -0
- package/dist/backends/signoz-api-ssrf.test.js +216 -0
- package/dist/backends/signoz-api-ssrf.test.js.map +1 -0
- package/dist/backends/signoz-api-test-helpers.d.ts +80 -0
- package/dist/backends/signoz-api-test-helpers.d.ts.map +1 -0
- package/dist/backends/signoz-api-test-helpers.js +79 -0
- package/dist/backends/signoz-api-test-helpers.js.map +1 -0
- package/dist/backends/signoz-api.d.ts +16 -0
- package/dist/backends/signoz-api.d.ts.map +1 -1
- package/dist/backends/signoz-api.js +71 -9
- package/dist/backends/signoz-api.js.map +1 -1
- package/dist/backends/signoz-api.test.d.ts +9 -0
- package/dist/backends/signoz-api.test.d.ts.map +1 -1
- package/dist/backends/signoz-api.test.js +14 -1027
- package/dist/backends/signoz-api.test.js.map +1 -1
- package/dist/lib/cache.d.ts +47 -1
- package/dist/lib/cache.d.ts.map +1 -1
- package/dist/lib/cache.js +40 -3
- package/dist/lib/cache.js.map +1 -1
- package/dist/lib/circuit-breaker.d.ts +83 -0
- package/dist/lib/circuit-breaker.d.ts.map +1 -0
- package/dist/lib/circuit-breaker.js +125 -0
- package/dist/lib/circuit-breaker.js.map +1 -0
- package/dist/lib/circuit-breaker.test.d.ts +2 -0
- package/dist/lib/circuit-breaker.test.d.ts.map +1 -0
- package/dist/lib/circuit-breaker.test.js +263 -0
- package/dist/lib/circuit-breaker.test.js.map +1 -0
- package/dist/lib/constants-symlink.test.d.ts +12 -0
- package/dist/lib/constants-symlink.test.d.ts.map +1 -0
- package/dist/lib/constants-symlink.test.js +357 -0
- package/dist/lib/constants-symlink.test.js.map +1 -0
- package/dist/lib/constants.d.ts +43 -0
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +154 -24
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/constants.test.js +156 -7
- package/dist/lib/constants.test.js.map +1 -1
- package/dist/lib/edge-cases.test.d.ts +11 -0
- package/dist/lib/edge-cases.test.d.ts.map +1 -0
- package/dist/lib/edge-cases.test.js +634 -0
- package/dist/lib/edge-cases.test.js.map +1 -0
- package/dist/lib/error-sanitizer.d.ts.map +1 -1
- package/dist/lib/error-sanitizer.js +62 -26
- package/dist/lib/error-sanitizer.js.map +1 -1
- package/dist/lib/error-sanitizer.test.js +186 -0
- package/dist/lib/error-sanitizer.test.js.map +1 -1
- package/dist/lib/error-types.d.ts +54 -0
- package/dist/lib/error-types.d.ts.map +1 -0
- package/dist/lib/error-types.js +154 -0
- package/dist/lib/error-types.js.map +1 -0
- package/dist/lib/error-types.test.d.ts +2 -0
- package/dist/lib/error-types.test.d.ts.map +1 -0
- package/dist/lib/error-types.test.js +196 -0
- package/dist/lib/error-types.test.js.map +1 -0
- package/dist/lib/file-utils.test.js +3 -3
- package/dist/lib/file-utils.test.js.map +1 -1
- package/dist/lib/indexer.test.js +157 -24
- package/dist/lib/indexer.test.js.map +1 -1
- package/dist/lib/input-validator.d.ts +17 -0
- package/dist/lib/input-validator.d.ts.map +1 -1
- package/dist/lib/input-validator.fuzz.test.d.ts +12 -0
- package/dist/lib/input-validator.fuzz.test.d.ts.map +1 -0
- package/dist/lib/input-validator.fuzz.test.js +290 -0
- package/dist/lib/input-validator.fuzz.test.js.map +1 -0
- package/dist/lib/input-validator.js +62 -3
- package/dist/lib/input-validator.js.map +1 -1
- package/dist/lib/input-validator.test.js +129 -1
- package/dist/lib/input-validator.test.js.map +1 -1
- package/dist/lib/logger.d.ts +46 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +81 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/logger.test.d.ts +2 -0
- package/dist/lib/logger.test.d.ts.map +1 -0
- package/dist/lib/logger.test.js +122 -0
- package/dist/lib/logger.test.js.map +1 -0
- package/dist/lib/query-sanitizer.d.ts +51 -3
- package/dist/lib/query-sanitizer.d.ts.map +1 -1
- package/dist/lib/query-sanitizer.js +105 -31
- package/dist/lib/query-sanitizer.js.map +1 -1
- package/dist/lib/query-sanitizer.test.js +102 -1
- package/dist/lib/query-sanitizer.test.js.map +1 -1
- package/dist/lib/server-utils.d.ts +88 -0
- package/dist/lib/server-utils.d.ts.map +1 -0
- package/dist/lib/server-utils.js +173 -0
- package/dist/lib/server-utils.js.map +1 -0
- package/dist/lib/shared-schemas.d.ts +81 -0
- package/dist/lib/shared-schemas.d.ts.map +1 -0
- package/dist/lib/shared-schemas.js +80 -0
- package/dist/lib/shared-schemas.js.map +1 -0
- package/dist/lib/shared-schemas.test.d.ts +5 -0
- package/dist/lib/shared-schemas.test.d.ts.map +1 -0
- package/dist/lib/shared-schemas.test.js +106 -0
- package/dist/lib/shared-schemas.test.js.map +1 -0
- package/dist/lib/toon-encoder.d.ts +26 -0
- package/dist/lib/toon-encoder.d.ts.map +1 -0
- package/dist/lib/toon-encoder.js +61 -0
- package/dist/lib/toon-encoder.js.map +1 -0
- package/dist/lib/toon-encoder.test.d.ts +5 -0
- package/dist/lib/toon-encoder.test.d.ts.map +1 -0
- package/dist/lib/toon-encoder.test.js +85 -0
- package/dist/lib/toon-encoder.test.js.map +1 -0
- package/dist/server.d.ts +1 -49
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +154 -162
- package/dist/server.js.map +1 -1
- package/dist/server.test.js +198 -7
- package/dist/server.test.js.map +1 -1
- package/dist/test-helpers/env-utils.d.ts +87 -0
- package/dist/test-helpers/env-utils.d.ts.map +1 -0
- package/dist/test-helpers/env-utils.js +132 -0
- package/dist/test-helpers/env-utils.js.map +1 -0
- package/dist/test-helpers/file-utils.d.ts +67 -0
- package/dist/test-helpers/file-utils.d.ts.map +1 -1
- package/dist/test-helpers/file-utils.js +165 -2
- package/dist/test-helpers/file-utils.js.map +1 -1
- package/dist/test-helpers/fuzz-generators.d.ts +58 -0
- package/dist/test-helpers/fuzz-generators.d.ts.map +1 -0
- package/dist/test-helpers/fuzz-generators.js +216 -0
- package/dist/test-helpers/fuzz-generators.js.map +1 -0
- package/dist/test-helpers/index.d.ts +11 -0
- package/dist/test-helpers/index.d.ts.map +1 -0
- package/dist/test-helpers/index.js +30 -0
- package/dist/test-helpers/index.js.map +1 -0
- package/dist/test-helpers/memfs-utils.d.ts +181 -0
- package/dist/test-helpers/memfs-utils.d.ts.map +1 -0
- package/dist/test-helpers/memfs-utils.js +292 -0
- package/dist/test-helpers/memfs-utils.js.map +1 -0
- package/dist/test-helpers/memfs-utils.test.d.ts +5 -0
- package/dist/test-helpers/memfs-utils.test.d.ts.map +1 -0
- package/dist/test-helpers/memfs-utils.test.js +338 -0
- package/dist/test-helpers/memfs-utils.test.js.map +1 -0
- package/dist/test-helpers/mock-backends.d.ts +113 -2
- package/dist/test-helpers/mock-backends.d.ts.map +1 -1
- package/dist/test-helpers/mock-backends.js +199 -3
- package/dist/test-helpers/mock-backends.js.map +1 -1
- package/dist/test-helpers/mock-backends.test.d.ts +5 -0
- package/dist/test-helpers/mock-backends.test.d.ts.map +1 -0
- package/dist/test-helpers/mock-backends.test.js +368 -0
- package/dist/test-helpers/mock-backends.test.js.map +1 -0
- package/dist/test-helpers/race-condition-helpers.d.ts +85 -0
- package/dist/test-helpers/race-condition-helpers.d.ts.map +1 -0
- package/dist/test-helpers/race-condition-helpers.js +279 -0
- package/dist/test-helpers/race-condition-helpers.js.map +1 -0
- package/dist/test-helpers/schema-validators.d.ts +32 -0
- package/dist/test-helpers/schema-validators.d.ts.map +1 -0
- package/dist/test-helpers/schema-validators.js +125 -0
- package/dist/test-helpers/schema-validators.js.map +1 -0
- package/dist/test-helpers/test-data-builders.d.ts +260 -0
- package/dist/test-helpers/test-data-builders.d.ts.map +1 -0
- package/dist/test-helpers/test-data-builders.js +337 -0
- package/dist/test-helpers/test-data-builders.js.map +1 -0
- package/dist/test-helpers/test-data-builders.test.d.ts +2 -0
- package/dist/test-helpers/test-data-builders.test.d.ts.map +1 -0
- package/dist/test-helpers/test-data-builders.test.js +306 -0
- package/dist/test-helpers/test-data-builders.test.js.map +1 -0
- package/dist/test-helpers/tool-validators.d.ts +28 -0
- package/dist/test-helpers/tool-validators.d.ts.map +1 -0
- package/dist/test-helpers/tool-validators.js +71 -0
- package/dist/test-helpers/tool-validators.js.map +1 -0
- package/dist/tools/context-stats.d.ts +1 -0
- package/dist/tools/context-stats.d.ts.map +1 -1
- package/dist/tools/context-stats.js +9 -5
- package/dist/tools/context-stats.js.map +1 -1
- package/dist/tools/context-stats.test.js +24 -10
- package/dist/tools/context-stats.test.js.map +1 -1
- package/dist/tools/get-trace-url.js +2 -2
- package/dist/tools/get-trace-url.js.map +1 -1
- package/dist/tools/health-check.js +2 -2
- package/dist/tools/health-check.js.map +1 -1
- package/dist/tools/query-evaluations.d.ts +21 -18
- package/dist/tools/query-evaluations.d.ts.map +1 -1
- package/dist/tools/query-evaluations.js +33 -19
- package/dist/tools/query-evaluations.js.map +1 -1
- package/dist/tools/query-evaluations.test.js +60 -63
- package/dist/tools/query-evaluations.test.js.map +1 -1
- package/dist/tools/query-llm-events.d.ts +19 -15
- package/dist/tools/query-llm-events.d.ts.map +1 -1
- package/dist/tools/query-llm-events.js +31 -15
- package/dist/tools/query-llm-events.js.map +1 -1
- package/dist/tools/query-llm-events.test.js +277 -12
- package/dist/tools/query-llm-events.test.js.map +1 -1
- package/dist/tools/query-logs.d.ts +22 -22
- package/dist/tools/query-logs.d.ts.map +1 -1
- package/dist/tools/query-logs.js +9 -9
- package/dist/tools/query-logs.js.map +1 -1
- package/dist/tools/query-logs.test.js +19 -72
- package/dist/tools/query-logs.test.js.map +1 -1
- package/dist/tools/query-metrics.d.ts +14 -14
- package/dist/tools/query-metrics.d.ts.map +1 -1
- package/dist/tools/query-metrics.js +9 -9
- package/dist/tools/query-metrics.js.map +1 -1
- package/dist/tools/query-metrics.test.js +12 -25
- package/dist/tools/query-metrics.test.js.map +1 -1
- package/dist/tools/query-traces.d.ts +28 -28
- package/dist/tools/query-traces.d.ts.map +1 -1
- package/dist/tools/query-traces.js +18 -18
- package/dist/tools/query-traces.js.map +1 -1
- package/dist/tools/query-traces.test.js +58 -54
- package/dist/tools/query-traces.test.js.map +1 -1
- package/dist/tools/setup-claudeignore.js +7 -7
- package/dist/tools/setup-claudeignore.js.map +1 -1
- package/dist/tools/setup-claudeignore.test.js +4 -25
- package/dist/tools/setup-claudeignore.test.js.map +1 -1
- package/package.json +4 -2
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test helpers for race condition and TOCTOU testing
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for simulating and testing race conditions in file system operations.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Options for race condition simulation
|
|
8
|
+
*/
|
|
9
|
+
export interface RaceConditionOptions {
|
|
10
|
+
/** Delay in milliseconds between operations */
|
|
11
|
+
delayMs?: number;
|
|
12
|
+
/** Number of iterations for the race */
|
|
13
|
+
iterations?: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Create a temporary directory structure for symlink testing
|
|
17
|
+
*/
|
|
18
|
+
export declare function createSymlinkTestDir(baseDir: string, name: string): {
|
|
19
|
+
symlinkPath: string;
|
|
20
|
+
targetPath: string;
|
|
21
|
+
cleanup: () => void;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Create a circular symlink chain for testing
|
|
25
|
+
*/
|
|
26
|
+
export declare function createCircularSymlinks(baseDir: string, prefix: string): {
|
|
27
|
+
paths: string[];
|
|
28
|
+
cleanup: () => void;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Create a broken symlink (pointing to non-existent target)
|
|
32
|
+
*/
|
|
33
|
+
export declare function createBrokenSymlink(baseDir: string, name: string): {
|
|
34
|
+
symlinkPath: string;
|
|
35
|
+
cleanup: () => void;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Create a symlink chain (symlink -> symlink -> directory)
|
|
39
|
+
*/
|
|
40
|
+
export declare function createSymlinkChain(baseDir: string, prefix: string, depth?: number): {
|
|
41
|
+
startPath: string;
|
|
42
|
+
endPath: string;
|
|
43
|
+
cleanup: () => void;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Create a symlink pointing outside allowed directories
|
|
47
|
+
*/
|
|
48
|
+
export declare function createEscapeSymlink(baseDir: string, name: string, escapePath?: string): {
|
|
49
|
+
symlinkPath: string;
|
|
50
|
+
cleanup: () => void;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Simulate a symlink swap attack (TOCTOU)
|
|
54
|
+
* Returns a function that swaps the symlink target when called
|
|
55
|
+
*/
|
|
56
|
+
export declare function createSymlinkSwapper(symlinkPath: string, target1: string, target2: string): {
|
|
57
|
+
swap: () => void;
|
|
58
|
+
getCurrentTarget: () => string;
|
|
59
|
+
cleanup: () => void;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Create a mock file system operation that can be intercepted
|
|
63
|
+
*/
|
|
64
|
+
export interface MockableFsOperation<T> {
|
|
65
|
+
original: T;
|
|
66
|
+
mock: T | null;
|
|
67
|
+
intercept: (mockFn: T) => void;
|
|
68
|
+
restore: () => void;
|
|
69
|
+
call: (...args: unknown[]) => unknown;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Simulate rapid file system changes for race condition testing
|
|
73
|
+
*/
|
|
74
|
+
export declare function simulateRapidChanges(createFn: () => void, deleteFn: () => void, iterations?: number, delayMs?: number): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Create a directory with a specific file for testing
|
|
77
|
+
*/
|
|
78
|
+
export declare function createTestDirectory(baseDir: string, name: string, files?: Array<{
|
|
79
|
+
name: string;
|
|
80
|
+
content: string;
|
|
81
|
+
}>): {
|
|
82
|
+
path: string;
|
|
83
|
+
cleanup: () => void;
|
|
84
|
+
};
|
|
85
|
+
//# sourceMappingURL=race-condition-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"race-condition-helpers.d.ts","sourceRoot":"","sources":["../../src/test-helpers/race-condition-helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,GACX;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,CAmClE;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,CA+B1C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,GACX;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,CAuB9C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,KAAK,GAAE,MAAU,GAChB;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,CA4C7D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,UAAU,GAAE,MAAe,GAC1B;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,CAqB9C;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd;IAAE,IAAI,EAAE,MAAM,IAAI,CAAC;IAAC,gBAAgB,EAAE,MAAM,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,CAgD3E;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB,CAAC,CAAC;IACpC,QAAQ,EAAE,CAAC,CAAC;IACZ,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACf,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,IAAI,CAAC;IAC/B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;CACvC;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,IAAI,EACpB,QAAQ,EAAE,MAAM,IAAI,EACpB,UAAU,GAAE,MAAW,EACvB,OAAO,GAAE,MAAU,GAClB,OAAO,CAAC,IAAI,CAAC,CAOf;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,GAC/C;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,CAgCvC"}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test helpers for race condition and TOCTOU testing
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for simulating and testing race conditions in file system operations.
|
|
5
|
+
*/
|
|
6
|
+
import { mkdirSync, rmdirSync, symlinkSync, unlinkSync, writeFileSync, existsSync } from 'fs';
|
|
7
|
+
import { join } from 'path';
|
|
8
|
+
/**
|
|
9
|
+
* Create a temporary directory structure for symlink testing
|
|
10
|
+
*/
|
|
11
|
+
export function createSymlinkTestDir(baseDir, name) {
|
|
12
|
+
const targetPath = join(baseDir, `${name}-target`);
|
|
13
|
+
const symlinkPath = join(baseDir, `${name}-link`);
|
|
14
|
+
// Create target directory
|
|
15
|
+
if (!existsSync(targetPath)) {
|
|
16
|
+
mkdirSync(targetPath, { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
// Create symlink
|
|
19
|
+
if (existsSync(symlinkPath)) {
|
|
20
|
+
try {
|
|
21
|
+
unlinkSync(symlinkPath);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// Ignore if already removed
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
symlinkSync(targetPath, symlinkPath);
|
|
28
|
+
return {
|
|
29
|
+
symlinkPath,
|
|
30
|
+
targetPath,
|
|
31
|
+
cleanup: () => {
|
|
32
|
+
try {
|
|
33
|
+
unlinkSync(symlinkPath);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// Ignore
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
rmdirSync(targetPath);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Ignore
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Create a circular symlink chain for testing
|
|
49
|
+
*/
|
|
50
|
+
export function createCircularSymlinks(baseDir, prefix) {
|
|
51
|
+
const link1 = join(baseDir, `${prefix}-circular-1`);
|
|
52
|
+
const link2 = join(baseDir, `${prefix}-circular-2`);
|
|
53
|
+
const link3 = join(baseDir, `${prefix}-circular-3`);
|
|
54
|
+
// Clean up any existing links
|
|
55
|
+
for (const p of [link1, link2, link3]) {
|
|
56
|
+
try {
|
|
57
|
+
unlinkSync(p);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// Ignore
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Create circular chain: link1 -> link2 -> link3 -> link1
|
|
64
|
+
symlinkSync(link2, link1);
|
|
65
|
+
symlinkSync(link3, link2);
|
|
66
|
+
symlinkSync(link1, link3);
|
|
67
|
+
return {
|
|
68
|
+
paths: [link1, link2, link3],
|
|
69
|
+
cleanup: () => {
|
|
70
|
+
for (const p of [link1, link2, link3]) {
|
|
71
|
+
try {
|
|
72
|
+
unlinkSync(p);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// Ignore
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Create a broken symlink (pointing to non-existent target)
|
|
83
|
+
*/
|
|
84
|
+
export function createBrokenSymlink(baseDir, name) {
|
|
85
|
+
const symlinkPath = join(baseDir, `${name}-broken`);
|
|
86
|
+
const nonExistentTarget = join(baseDir, 'nonexistent-target-' + Date.now());
|
|
87
|
+
// Clean up any existing link
|
|
88
|
+
try {
|
|
89
|
+
unlinkSync(symlinkPath);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// Ignore
|
|
93
|
+
}
|
|
94
|
+
symlinkSync(nonExistentTarget, symlinkPath);
|
|
95
|
+
return {
|
|
96
|
+
symlinkPath,
|
|
97
|
+
cleanup: () => {
|
|
98
|
+
try {
|
|
99
|
+
unlinkSync(symlinkPath);
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
// Ignore
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Create a symlink chain (symlink -> symlink -> directory)
|
|
109
|
+
*/
|
|
110
|
+
export function createSymlinkChain(baseDir, prefix, depth = 3) {
|
|
111
|
+
const paths = [];
|
|
112
|
+
const endPath = join(baseDir, `${prefix}-chain-target`);
|
|
113
|
+
// Create target directory
|
|
114
|
+
if (!existsSync(endPath)) {
|
|
115
|
+
mkdirSync(endPath, { recursive: true });
|
|
116
|
+
}
|
|
117
|
+
paths.push(endPath);
|
|
118
|
+
// Create symlink chain
|
|
119
|
+
let currentTarget = endPath;
|
|
120
|
+
for (let i = depth - 1; i >= 0; i--) {
|
|
121
|
+
const linkPath = join(baseDir, `${prefix}-chain-${i}`);
|
|
122
|
+
try {
|
|
123
|
+
unlinkSync(linkPath);
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
// Ignore
|
|
127
|
+
}
|
|
128
|
+
symlinkSync(currentTarget, linkPath);
|
|
129
|
+
paths.push(linkPath);
|
|
130
|
+
currentTarget = linkPath;
|
|
131
|
+
}
|
|
132
|
+
const startPath = currentTarget;
|
|
133
|
+
return {
|
|
134
|
+
startPath,
|
|
135
|
+
endPath,
|
|
136
|
+
cleanup: () => {
|
|
137
|
+
for (const p of paths) {
|
|
138
|
+
try {
|
|
139
|
+
unlinkSync(p);
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
// Ignore symlink errors
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
rmdirSync(p);
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
// Ignore directory errors
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Create a symlink pointing outside allowed directories
|
|
156
|
+
*/
|
|
157
|
+
export function createEscapeSymlink(baseDir, name, escapePath = '/tmp') {
|
|
158
|
+
const symlinkPath = join(baseDir, `${name}-escape`);
|
|
159
|
+
try {
|
|
160
|
+
unlinkSync(symlinkPath);
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
// Ignore
|
|
164
|
+
}
|
|
165
|
+
symlinkSync(escapePath, symlinkPath);
|
|
166
|
+
return {
|
|
167
|
+
symlinkPath,
|
|
168
|
+
cleanup: () => {
|
|
169
|
+
try {
|
|
170
|
+
unlinkSync(symlinkPath);
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
// Ignore
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Simulate a symlink swap attack (TOCTOU)
|
|
180
|
+
* Returns a function that swaps the symlink target when called
|
|
181
|
+
*/
|
|
182
|
+
export function createSymlinkSwapper(symlinkPath, target1, target2) {
|
|
183
|
+
let currentTarget = target1;
|
|
184
|
+
// Ensure targets exist
|
|
185
|
+
if (!existsSync(target1)) {
|
|
186
|
+
mkdirSync(target1, { recursive: true });
|
|
187
|
+
}
|
|
188
|
+
if (!existsSync(target2)) {
|
|
189
|
+
mkdirSync(target2, { recursive: true });
|
|
190
|
+
}
|
|
191
|
+
// Create initial symlink
|
|
192
|
+
try {
|
|
193
|
+
unlinkSync(symlinkPath);
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
// Ignore
|
|
197
|
+
}
|
|
198
|
+
symlinkSync(target1, symlinkPath);
|
|
199
|
+
return {
|
|
200
|
+
swap: () => {
|
|
201
|
+
currentTarget = currentTarget === target1 ? target2 : target1;
|
|
202
|
+
try {
|
|
203
|
+
unlinkSync(symlinkPath);
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
// Ignore
|
|
207
|
+
}
|
|
208
|
+
symlinkSync(currentTarget, symlinkPath);
|
|
209
|
+
},
|
|
210
|
+
getCurrentTarget: () => currentTarget,
|
|
211
|
+
cleanup: () => {
|
|
212
|
+
try {
|
|
213
|
+
unlinkSync(symlinkPath);
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
// Ignore
|
|
217
|
+
}
|
|
218
|
+
try {
|
|
219
|
+
rmdirSync(target1);
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
// Ignore
|
|
223
|
+
}
|
|
224
|
+
try {
|
|
225
|
+
rmdirSync(target2);
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
// Ignore
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Simulate rapid file system changes for race condition testing
|
|
235
|
+
*/
|
|
236
|
+
export async function simulateRapidChanges(createFn, deleteFn, iterations = 10, delayMs = 1) {
|
|
237
|
+
for (let i = 0; i < iterations; i++) {
|
|
238
|
+
createFn();
|
|
239
|
+
await new Promise(resolve => setTimeout(resolve, delayMs));
|
|
240
|
+
deleteFn();
|
|
241
|
+
await new Promise(resolve => setTimeout(resolve, delayMs));
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Create a directory with a specific file for testing
|
|
246
|
+
*/
|
|
247
|
+
export function createTestDirectory(baseDir, name, files) {
|
|
248
|
+
const dirPath = join(baseDir, name);
|
|
249
|
+
if (!existsSync(dirPath)) {
|
|
250
|
+
mkdirSync(dirPath, { recursive: true });
|
|
251
|
+
}
|
|
252
|
+
if (files) {
|
|
253
|
+
for (const file of files) {
|
|
254
|
+
writeFileSync(join(dirPath, file.name), file.content);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return {
|
|
258
|
+
path: dirPath,
|
|
259
|
+
cleanup: () => {
|
|
260
|
+
if (files) {
|
|
261
|
+
for (const file of files) {
|
|
262
|
+
try {
|
|
263
|
+
unlinkSync(join(dirPath, file.name));
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
// Ignore
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
try {
|
|
271
|
+
rmdirSync(dirPath);
|
|
272
|
+
}
|
|
273
|
+
catch {
|
|
274
|
+
// Ignore
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=race-condition-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"race-condition-helpers.js","sourceRoot":"","sources":["../../src/test-helpers/race-condition-helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared test utilities for validating Zod schemas
|
|
3
|
+
*/
|
|
4
|
+
import type { z } from 'zod';
|
|
5
|
+
/**
|
|
6
|
+
* Generate standard backend selection schema tests
|
|
7
|
+
* @param schema - Zod schema with backend field
|
|
8
|
+
* @param schemaName - Name for test descriptions
|
|
9
|
+
*/
|
|
10
|
+
export declare function validateBackendSchema(schema: z.ZodType<{
|
|
11
|
+
backend?: string;
|
|
12
|
+
}>, schemaName: string): void;
|
|
13
|
+
/**
|
|
14
|
+
* Generate standard limit parameter validation tests
|
|
15
|
+
* @param schema - Zod schema with limit field
|
|
16
|
+
* @param schemaName - Name for test descriptions
|
|
17
|
+
* @param defaultLimit - Expected default limit value
|
|
18
|
+
* @param maxLimit - Maximum allowed limit (optional, defaults to 1000)
|
|
19
|
+
*/
|
|
20
|
+
export declare function validateLimitSchema(schema: z.ZodType<{
|
|
21
|
+
limit?: number;
|
|
22
|
+
}>, schemaName: string, defaultLimit: number, maxLimit?: number): void;
|
|
23
|
+
/**
|
|
24
|
+
* Generate standard date range validation tests
|
|
25
|
+
* @param schema - Zod schema with startDate/endDate fields
|
|
26
|
+
* @param schemaName - Name for test descriptions
|
|
27
|
+
*/
|
|
28
|
+
export declare function validateDateRangeSchema(schema: z.ZodType<{
|
|
29
|
+
startDate?: string;
|
|
30
|
+
endDate?: string;
|
|
31
|
+
}>, schemaName: string): void;
|
|
32
|
+
//# sourceMappingURL=schema-validators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-validators.d.ts","sourceRoot":"","sources":["../../src/test-helpers/schema-validators.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,EACvC,UAAU,EAAE,MAAM,GACjB,IAAI,CAuCN;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,EACrC,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,QAAQ,SAAO,GACd,IAAI,CAwCN;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,EAC3D,UAAU,EAAE,MAAM,GACjB,IAAI,CA8BN"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared test utilities for validating Zod schemas
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it } from 'node:test';
|
|
5
|
+
import * as assert from 'node:assert';
|
|
6
|
+
/**
|
|
7
|
+
* Generate standard backend selection schema tests
|
|
8
|
+
* @param schema - Zod schema with backend field
|
|
9
|
+
* @param schemaName - Name for test descriptions
|
|
10
|
+
*/
|
|
11
|
+
export function validateBackendSchema(schema, schemaName) {
|
|
12
|
+
describe(`${schemaName} backend validation`, () => {
|
|
13
|
+
it('should validate input with backend=local', () => {
|
|
14
|
+
const result = schema.safeParse({ backend: 'local' });
|
|
15
|
+
assert.strictEqual(result.success, true);
|
|
16
|
+
if (result.success) {
|
|
17
|
+
assert.strictEqual(result.data.backend, 'local');
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
it('should validate input with backend=signoz', () => {
|
|
21
|
+
const result = schema.safeParse({ backend: 'signoz' });
|
|
22
|
+
assert.strictEqual(result.success, true);
|
|
23
|
+
if (result.success) {
|
|
24
|
+
assert.strictEqual(result.data.backend, 'signoz');
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
it('should validate input with backend=auto', () => {
|
|
28
|
+
const result = schema.safeParse({ backend: 'auto' });
|
|
29
|
+
assert.strictEqual(result.success, true);
|
|
30
|
+
if (result.success) {
|
|
31
|
+
assert.strictEqual(result.data.backend, 'auto');
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
it('should default backend to auto when not provided', () => {
|
|
35
|
+
const result = schema.safeParse({});
|
|
36
|
+
assert.strictEqual(result.success, true);
|
|
37
|
+
if (result.success) {
|
|
38
|
+
assert.strictEqual(result.data.backend, 'auto');
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
it('should reject invalid backend values', () => {
|
|
42
|
+
const result = schema.safeParse({ backend: 'invalid' });
|
|
43
|
+
assert.strictEqual(result.success, false);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Generate standard limit parameter validation tests
|
|
49
|
+
* @param schema - Zod schema with limit field
|
|
50
|
+
* @param schemaName - Name for test descriptions
|
|
51
|
+
* @param defaultLimit - Expected default limit value
|
|
52
|
+
* @param maxLimit - Maximum allowed limit (optional, defaults to 1000)
|
|
53
|
+
*/
|
|
54
|
+
export function validateLimitSchema(schema, schemaName, defaultLimit, maxLimit = 1000) {
|
|
55
|
+
describe(`${schemaName} limit validation`, () => {
|
|
56
|
+
it(`should use ${defaultLimit} as default limit`, () => {
|
|
57
|
+
const result = schema.safeParse({});
|
|
58
|
+
assert.strictEqual(result.success, true);
|
|
59
|
+
if (result.success) {
|
|
60
|
+
assert.strictEqual(result.data.limit, defaultLimit);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
it('should accept custom limit value', () => {
|
|
64
|
+
const customLimit = Math.floor(defaultLimit / 2) || 25;
|
|
65
|
+
const result = schema.safeParse({ limit: customLimit });
|
|
66
|
+
assert.strictEqual(result.success, true);
|
|
67
|
+
if (result.success) {
|
|
68
|
+
assert.strictEqual(result.data.limit, customLimit);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
it('should accept limit of 1', () => {
|
|
72
|
+
const result = schema.safeParse({ limit: 1 });
|
|
73
|
+
assert.strictEqual(result.success, true);
|
|
74
|
+
if (result.success) {
|
|
75
|
+
assert.strictEqual(result.data.limit, 1);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
it(`should accept max limit value of ${maxLimit}`, () => {
|
|
79
|
+
const result = schema.safeParse({ limit: maxLimit });
|
|
80
|
+
assert.strictEqual(result.success, true);
|
|
81
|
+
if (result.success) {
|
|
82
|
+
assert.strictEqual(result.data.limit, maxLimit);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
it('should reject non-numeric limit', () => {
|
|
86
|
+
const result = schema.safeParse({ limit: 'fifty' });
|
|
87
|
+
assert.strictEqual(result.success, false);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Generate standard date range validation tests
|
|
93
|
+
* @param schema - Zod schema with startDate/endDate fields
|
|
94
|
+
* @param schemaName - Name for test descriptions
|
|
95
|
+
*/
|
|
96
|
+
export function validateDateRangeSchema(schema, schemaName) {
|
|
97
|
+
describe(`${schemaName} date range validation`, () => {
|
|
98
|
+
it('should accept startDate only', () => {
|
|
99
|
+
const result = schema.safeParse({ startDate: '2026-01-01' });
|
|
100
|
+
assert.strictEqual(result.success, true);
|
|
101
|
+
if (result.success) {
|
|
102
|
+
assert.strictEqual(result.data.startDate, '2026-01-01');
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
it('should accept endDate only', () => {
|
|
106
|
+
const result = schema.safeParse({ endDate: '2026-01-31' });
|
|
107
|
+
assert.strictEqual(result.success, true);
|
|
108
|
+
if (result.success) {
|
|
109
|
+
assert.strictEqual(result.data.endDate, '2026-01-31');
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
it('should accept both startDate and endDate', () => {
|
|
113
|
+
const result = schema.safeParse({
|
|
114
|
+
startDate: '2026-01-01',
|
|
115
|
+
endDate: '2026-01-31',
|
|
116
|
+
});
|
|
117
|
+
assert.strictEqual(result.success, true);
|
|
118
|
+
if (result.success) {
|
|
119
|
+
assert.strictEqual(result.data.startDate, '2026-01-01');
|
|
120
|
+
assert.strictEqual(result.data.endDate, '2026-01-31');
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=schema-validators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-validators.js","sourceRoot":"","sources":["../../src/test-helpers/schema-validators.ts"],"names":[],"mappings":"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"}
|