@cybedefend/vibedefend 1.1.1

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.
Files changed (103) hide show
  1. package/LICENSE +77 -0
  2. package/README.md +120 -0
  3. package/bin/vibedefend.js +19 -0
  4. package/dist/auth/auth-store.js +170 -0
  5. package/dist/auth/auth-store.js.map +1 -0
  6. package/dist/auth/auth.js +125 -0
  7. package/dist/auth/auth.js.map +1 -0
  8. package/dist/auth/callback-server.js +216 -0
  9. package/dist/auth/callback-server.js.map +1 -0
  10. package/dist/auth/pkce.js +31 -0
  11. package/dist/auth/pkce.js.map +1 -0
  12. package/dist/auth/token-exchange.js +83 -0
  13. package/dist/auth/token-exchange.js.map +1 -0
  14. package/dist/clients/claude-code.js +170 -0
  15. package/dist/clients/claude-code.js.map +1 -0
  16. package/dist/clients/codex.js +378 -0
  17. package/dist/clients/codex.js.map +1 -0
  18. package/dist/clients/cursor-guards-rules.js +94 -0
  19. package/dist/clients/cursor-guards-rules.js.map +1 -0
  20. package/dist/clients/cursor.js +172 -0
  21. package/dist/clients/cursor.js.map +1 -0
  22. package/dist/clients/detect.js +86 -0
  23. package/dist/clients/detect.js.map +1 -0
  24. package/dist/clients/registry.js +41 -0
  25. package/dist/clients/registry.js.map +1 -0
  26. package/dist/clients/types.js +2 -0
  27. package/dist/clients/types.js.map +1 -0
  28. package/dist/clients/vscode.js +187 -0
  29. package/dist/clients/vscode.js.map +1 -0
  30. package/dist/clients/windsurf.js +151 -0
  31. package/dist/clients/windsurf.js.map +1 -0
  32. package/dist/config.js +32 -0
  33. package/dist/config.js.map +1 -0
  34. package/dist/custom-regions.js +112 -0
  35. package/dist/custom-regions.js.map +1 -0
  36. package/dist/diagnostics.js +122 -0
  37. package/dist/diagnostics.js.map +1 -0
  38. package/dist/doctor.js +125 -0
  39. package/dist/doctor.js.map +1 -0
  40. package/dist/guards-evaluator/bucketing.js +83 -0
  41. package/dist/guards-evaluator/bucketing.js.map +1 -0
  42. package/dist/guards-evaluator/evaluate.js +272 -0
  43. package/dist/guards-evaluator/evaluate.js.map +1 -0
  44. package/dist/guards-evaluator/glob.js +148 -0
  45. package/dist/guards-evaluator/glob.js.map +1 -0
  46. package/dist/guards-evaluator/index.js +9 -0
  47. package/dist/guards-evaluator/index.js.map +1 -0
  48. package/dist/guards-evaluator/preprocess.js +174 -0
  49. package/dist/guards-evaluator/preprocess.js.map +1 -0
  50. package/dist/guards-evaluator/redact.js +111 -0
  51. package/dist/guards-evaluator/redact.js.map +1 -0
  52. package/dist/guards-evaluator/regex.js +125 -0
  53. package/dist/guards-evaluator/regex.js.map +1 -0
  54. package/dist/guards-evaluator/types.js +2 -0
  55. package/dist/guards-evaluator/types.js.map +1 -0
  56. package/dist/guards-evaluator/validation.js +115 -0
  57. package/dist/guards-evaluator/validation.js.map +1 -0
  58. package/dist/hook-runner.js +6680 -0
  59. package/dist/hooks/install.js +169 -0
  60. package/dist/hooks/install.js.map +1 -0
  61. package/dist/hooks/runtime/api.js +167 -0
  62. package/dist/hooks/runtime/api.js.map +1 -0
  63. package/dist/hooks/runtime/config.js +60 -0
  64. package/dist/hooks/runtime/config.js.map +1 -0
  65. package/dist/hooks/runtime/emit.js +45 -0
  66. package/dist/hooks/runtime/emit.js.map +1 -0
  67. package/dist/hooks/runtime/fetch-rules.js +154 -0
  68. package/dist/hooks/runtime/fetch-rules.js.map +1 -0
  69. package/dist/hooks/runtime/guard-rules-cache.js +217 -0
  70. package/dist/hooks/runtime/guard-rules-cache.js.map +1 -0
  71. package/dist/hooks/runtime/guard-violations-buffer.js +105 -0
  72. package/dist/hooks/runtime/guard-violations-buffer.js.map +1 -0
  73. package/dist/hooks/runtime/pre-compact.js +41 -0
  74. package/dist/hooks/runtime/pre-compact.js.map +1 -0
  75. package/dist/hooks/runtime/resolve.js +206 -0
  76. package/dist/hooks/runtime/resolve.js.map +1 -0
  77. package/dist/hooks/runtime/session-review.js +198 -0
  78. package/dist/hooks/runtime/session-review.js.map +1 -0
  79. package/dist/hooks/runtime/session-start.js +101 -0
  80. package/dist/hooks/runtime/session-start.js.map +1 -0
  81. package/dist/hooks/runtime/sniff.js +112 -0
  82. package/dist/hooks/runtime/sniff.js.map +1 -0
  83. package/dist/hooks/runtime/types.js +22 -0
  84. package/dist/hooks/runtime/types.js.map +1 -0
  85. package/dist/hooks/runtime/user-prompt-submit.js +154 -0
  86. package/dist/hooks/runtime/user-prompt-submit.js.map +1 -0
  87. package/dist/index.js +129 -0
  88. package/dist/index.js.map +1 -0
  89. package/dist/install.js +183 -0
  90. package/dist/install.js.map +1 -0
  91. package/dist/login.js +335 -0
  92. package/dist/login.js.map +1 -0
  93. package/dist/prompts.js +134 -0
  94. package/dist/prompts.js.map +1 -0
  95. package/dist/self-update.js +177 -0
  96. package/dist/self-update.js.map +1 -0
  97. package/dist/status.js +58 -0
  98. package/dist/status.js.map +1 -0
  99. package/dist/utils.js +84 -0
  100. package/dist/utils.js.map +1 -0
  101. package/dist/version.js +23 -0
  102. package/dist/version.js.map +1 -0
  103. package/package.json +73 -0
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Secret-pattern redaction and hashing — mirrors Python redact.py.
3
+ *
4
+ * redactTarget(text, maxLen?) — strip known secret patterns (replacing each
5
+ * match with [REDACTED]) then truncate to maxLen. Redaction happens BEFORE
6
+ * truncation so secrets near the end of long strings are caught.
7
+ *
8
+ * hashTarget(text) — SHA-256 hex of text (UTF-8). Used to de-duplicate
9
+ * guard_violations rows without storing raw target strings.
10
+ *
11
+ * Patterns (most-specific first, matching Python order):
12
+ * 1. JWTs: eyJ... three base64url segments
13
+ * 2. GitHub PATs: ghp_ + 36 alphanumeric
14
+ * 3. Stripe secret keys: sk_(live|test)_...
15
+ * 4. AWS access key IDs: AKIA + 16 uppercase/digit
16
+ * 5. Bearer tokens: "Bearer <token>" — the token portion only is replaced
17
+ * 6. Generic hex tokens >= 32 chars (word-boundary guarded)
18
+ * 7. Generic base64-ish tokens >= 32 chars with ≥1 uppercase AND ≥1 digit
19
+ * (high-entropy gate — file paths almost never have uppercase mid-path)
20
+ */
21
+ import { createHash } from 'node:crypto';
22
+ const REDACTED = '[REDACTED]';
23
+ const PATTERNS = [
24
+ // 1. JWT — three base64url segments separated by dots
25
+ {
26
+ re: /eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g,
27
+ captureIndex: null,
28
+ },
29
+ // 2. GitHub PAT
30
+ {
31
+ re: /ghp_[a-zA-Z0-9]{36}/g,
32
+ captureIndex: null,
33
+ },
34
+ // 3. Stripe secret key (live or test)
35
+ {
36
+ re: /sk_(?:live|test)_[0-9a-zA-Z]{24,}/g,
37
+ captureIndex: null,
38
+ },
39
+ // 4. AWS access key ID
40
+ {
41
+ re: /AKIA[0-9A-Z]{16}/g,
42
+ captureIndex: null,
43
+ },
44
+ // 5. Bearer token — preserve the "Bearer " keyword, replace only the token.
45
+ // Group 1 = the prefix ("Bearer "), group 2 = the token value.
46
+ {
47
+ re: /((?:bearer\s))([^\s]{10,})/gi,
48
+ captureIndex: 2,
49
+ },
50
+ // 6. Generic hex token >= 32 chars (word boundary so short IDs are skipped)
51
+ {
52
+ re: /\b[0-9a-f]{32,}\b/g,
53
+ captureIndex: null,
54
+ },
55
+ // 7. Generic base64-ish >= 32 chars: must contain ≥1 uppercase AND ≥1 digit
56
+ // to skip plain file paths. Negative lookbehind prevents matching runs of
57
+ // path chars. JS lookbehind support is >= V8 6.3 (Node 10+), well within
58
+ // our Node >=18.17 requirement.
59
+ {
60
+ re: /(?<![/\w])(?=[A-Za-z0-9+/]{32,}={0,2}(?![A-Za-z0-9+/]))(?=[A-Za-z0-9+/]*[A-Z])(?=[A-Za-z0-9+/]*[0-9])[A-Za-z0-9+/]{32,}={0,2}/gm,
61
+ captureIndex: null,
62
+ },
63
+ ];
64
+ /**
65
+ * Apply all redaction patterns to `text`, then truncate to `maxLen` chars.
66
+ */
67
+ export function redactTarget(text, maxLen = 256) {
68
+ if (!text)
69
+ return text;
70
+ let result = text;
71
+ for (const { re, captureIndex } of PATTERNS) {
72
+ re.lastIndex = 0;
73
+ if (captureIndex === null) {
74
+ result = result.replace(re, REDACTED);
75
+ }
76
+ else {
77
+ // Replace only the captured group, preserving surrounding match content.
78
+ result = result.replace(re, (...args) => {
79
+ // args: [fullMatch, g1, g2, ..., offset, input, groups?]
80
+ const fullMatch = args[0];
81
+ const groups = args.slice(1, -2);
82
+ // Rebuild the full match with the target capture replaced
83
+ let rebuilt = '';
84
+ let pos = 0;
85
+ for (let gi = 0; gi < groups.length; gi++) {
86
+ const groupVal = groups[gi] ?? '';
87
+ const groupStart = fullMatch.indexOf(groupVal, pos);
88
+ if (groupStart >= 0) {
89
+ rebuilt += fullMatch.slice(pos, groupStart);
90
+ rebuilt += gi + 1 === captureIndex ? REDACTED : groupVal;
91
+ pos = groupStart + groupVal.length;
92
+ }
93
+ }
94
+ rebuilt += fullMatch.slice(pos);
95
+ return rebuilt;
96
+ });
97
+ }
98
+ re.lastIndex = 0;
99
+ }
100
+ if (result.length > maxLen) {
101
+ result = result.slice(0, maxLen);
102
+ }
103
+ return result;
104
+ }
105
+ /**
106
+ * Return the hex SHA-256 digest of `text` encoded as UTF-8.
107
+ */
108
+ export function hashTarget(text) {
109
+ return createHash('sha256').update(text, 'utf8').digest('hex');
110
+ }
111
+ //# sourceMappingURL=redact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.js","sourceRoot":"","sources":["../../src/guards-evaluator/redact.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * RE2-backed regex compilation with fallback to native RegExp.
3
+ *
4
+ * re2-wasm (Google's RE2 library compiled to WASM) guarantees linear-time
5
+ * matching, providing ReDoS protection for the vast majority of patterns.
6
+ * RE2 does not support lookaheads ((?!...)/(?=...)) or back-references —
7
+ * patterns using these constructs automatically fall back to native RegExp
8
+ * with a per-pattern warning. The overall engine preference order is:
9
+ *
10
+ * 1. RE2 (linear-time, ReDoS-safe) — most patterns
11
+ * 2. native RegExp (fallback for lookaheads) — small set of patterns
12
+ *
13
+ * Note: re2-wasm requires the 'u' (unicode) flag; it is added automatically.
14
+ */
15
+ // Cache of compiled regexes to avoid recompilation on repeated calls.
16
+ const _cache = new Map();
17
+ let _Re2 = null;
18
+ let _re2Available = false;
19
+ let _initDone = false;
20
+ let _initPromise = null;
21
+ async function _initRe2() {
22
+ try {
23
+ // Dynamic import — succeeds when re2-wasm is installed.
24
+ const mod = await import('re2-wasm');
25
+ _Re2 = mod.default.RE2;
26
+ // Smoke test
27
+ const r = new _Re2('hello', 'u');
28
+ r.test('hello');
29
+ _re2Available = true;
30
+ }
31
+ catch {
32
+ console.warn('[guards-evaluator] re2-wasm unavailable — falling back to native RegExp for all patterns. ' +
33
+ 'ReDoS protection is NOT active. Consider installing re2-wasm.');
34
+ _re2Available = false;
35
+ }
36
+ finally {
37
+ _initDone = true;
38
+ }
39
+ }
40
+ // Kick off initialisation immediately so the engine is ready by first use.
41
+ _initPromise = _initRe2();
42
+ /**
43
+ * Returns whether re2-wasm has been successfully loaded.
44
+ * Exposed for tests.
45
+ */
46
+ export function isRe2Available() {
47
+ return _re2Available;
48
+ }
49
+ /**
50
+ * Wait for the re2 initialisation to complete.
51
+ * Call this in async contexts (e.g. test setup) to ensure the engine is ready.
52
+ */
53
+ export async function waitForRe2() {
54
+ if (!_initDone && _initPromise)
55
+ await _initPromise;
56
+ }
57
+ /**
58
+ * Compile a regex pattern and return an object with a `test` method.
59
+ *
60
+ * Uses RE2 (linear-time) when available and the pattern is compatible.
61
+ * Automatically falls back to native RegExp for patterns that use
62
+ * lookaheads, lookbehinds, or other RE2-unsupported constructs.
63
+ * Results are cached by pattern string.
64
+ *
65
+ * @throws {SyntaxError} if the pattern is syntactically invalid in both engines.
66
+ */
67
+ export function compileRegex(pattern) {
68
+ const cached = _cache.get(pattern);
69
+ if (cached)
70
+ return cached;
71
+ let compiled;
72
+ if (_re2Available && _Re2) {
73
+ try {
74
+ // RE2 requires the 'u' flag (Unicode mode).
75
+ const re2Instance = new _Re2(pattern, 'u');
76
+ compiled = { test: (text) => re2Instance.test(text) };
77
+ }
78
+ catch {
79
+ // RE2 rejected the pattern — likely a lookahead/lookbehind/back-ref.
80
+ // Fall back to native RegExp for this specific pattern.
81
+ try {
82
+ const native = new RegExp(pattern);
83
+ compiled = { test: (text) => native.test(text) };
84
+ }
85
+ catch (nativeErr) {
86
+ throw new SyntaxError(`Invalid regex pattern "${pattern}": ${String(nativeErr)}`);
87
+ }
88
+ }
89
+ }
90
+ else {
91
+ try {
92
+ const native = new RegExp(pattern);
93
+ compiled = { test: (text) => native.test(text) };
94
+ }
95
+ catch (err) {
96
+ throw new SyntaxError(`Invalid regex pattern "${pattern}": ${String(err)}`);
97
+ }
98
+ }
99
+ _cache.set(pattern, compiled);
100
+ return compiled;
101
+ }
102
+ /**
103
+ * Returns true if the pattern can be compiled without error.
104
+ *
105
+ * Used at validation time to reject user-supplied patterns before they
106
+ * are stored. With RE2, patterns using lookaheads silently fall through to
107
+ * native RegExp — both engines must accept the pattern for this to return true.
108
+ */
109
+ export function isRegexSafe(pattern) {
110
+ try {
111
+ compileRegex(pattern);
112
+ return true;
113
+ }
114
+ catch {
115
+ return false;
116
+ }
117
+ }
118
+ /**
119
+ * Clear the internal regex cache.
120
+ * Exposed for testing.
121
+ */
122
+ export function clearRegexCache() {
123
+ _cache.clear();
124
+ }
125
+ //# sourceMappingURL=regex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regex.js","sourceRoot":"","sources":["../../src/guards-evaluator/regex.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,sEAAsE;AACtE,MAAM,MAAM,GAAG,IAAI,GAAG,EAAyB,CAAC;AAIhD,IAAI,IAAI,GAA0B,IAAI,CAAC;AACvC,IAAI,aAAa,GAAG,KAAK,CAAC;AAC1B,IAAI,SAAS,GAAG,KAAK,CAAC;AACtB,IAAI,YAAY,GAAyB,IAAI,CAAC;AAE9C,KAAK,UAAU,QAAQ;IACrB,IAAI,CAAC;QACH,wDAAwD;QACxD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,UAAU,CAAyC,CAAC;QAC7E,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC;QACvB,aAAa;QACb,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACjC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAChB,aAAa,GAAG,IAAI,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,IAAI,CACV,4FAA4F;YAC5F,+DAA+D,CAChE,CAAC;QACF,aAAa,GAAG,KAAK,CAAC;IACxB,CAAC;YAAS,CAAC;QACT,SAAS,GAAG,IAAI,CAAC;IACnB,CAAC;AACH,CAAC;AAED,2EAA2E;AAC3E,YAAY,GAAG,QAAQ,EAAE,CAAC;AAE1B;;;GAGG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,aAAa,CAAC;AACvB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,IAAI,CAAC,SAAS,IAAI,YAAY;QAAE,MAAM,YAAY,CAAC;AACrD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,IAAI,QAAuB,CAAC;IAE5B,IAAI,aAAa,IAAI,IAAI,EAAE,CAAC;QAC1B,IAAI,CAAC;YACH,4CAA4C;YAC5C,MAAM,WAAW,GAAG,IAAI,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YAC3C,QAAQ,GAAG,EAAE,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAChE,CAAC;QAAC,MAAM,CAAC;YACP,qEAAqE;YACrE,wDAAwD;YACxD,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC;gBACnC,QAAQ,GAAG,EAAE,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3D,CAAC;YAAC,OAAO,SAAS,EAAE,CAAC;gBACnB,MAAM,IAAI,WAAW,CAAC,0BAA0B,OAAO,MAAM,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YACpF,CAAC;QACH,CAAC;IACH,CAAC;SAAM,CAAC;QACN,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC;YACnC,QAAQ,GAAG,EAAE,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,WAAW,CAAC,0BAA0B,OAAO,MAAM,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC9E,CAAC;IACH,CAAC;IAED,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC9B,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,IAAI,CAAC;QACH,YAAY,CAAC,OAAO,CAAC,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,CAAC,KAAK,EAAE,CAAC;AACjB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/guards-evaluator/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Rule validation — mirrors the Python matcher_validation.py constraints.
3
+ *
4
+ * validateRule(rule) → { ok, errors }
5
+ *
6
+ * Checks:
7
+ * - Required fields: id, category, subcategory, action, severity
8
+ * - At least one matcher field is non-empty
9
+ * - commandRegex (if set) is valid (via isRegexSafe)
10
+ * - Each glob in glob-list fields: non-empty, <=512 chars, no ** /** sequence
11
+ */
12
+ import { isRegexSafe } from './regex.js';
13
+ const VALID_ACTIONS = ['deny', 'warn', 'off'];
14
+ const VALID_SEVERITIES = ['critical', 'high', 'medium', 'low'];
15
+ const VALID_CATEGORIES = ['filesystem', 'shell', 'network', 'git', 'process'];
16
+ const VALID_SUBCATEGORIES = [
17
+ 'read', 'write', 'delete', 'list',
18
+ 'privilege', 'install', 'env', 'exec', 'destructive', 'network',
19
+ 'http', 'git', 'process',
20
+ ];
21
+ const MAX_GLOB_LEN = 512;
22
+ const REDUNDANT_DOUBLE_STAR = /\*\*\/\*\*/;
23
+ const GLOB_FIELDS = [
24
+ 'filePathGlobs',
25
+ 'filePathExcludes',
26
+ 'envNameGlobs',
27
+ 'httpHostGlobs',
28
+ 'httpHostExcludes',
29
+ 'httpPathGlobs',
30
+ 'gitRemoteGlobs',
31
+ 'gitBranchGlobs',
32
+ ];
33
+ function validateGlob(pattern, field) {
34
+ if (!pattern || pattern.length === 0) {
35
+ return `${field}: glob pattern must not be empty`;
36
+ }
37
+ if (pattern.length > MAX_GLOB_LEN) {
38
+ return `${field}: glob pattern must not exceed ${MAX_GLOB_LEN} chars (got ${pattern.length})`;
39
+ }
40
+ if (REDUNDANT_DOUBLE_STAR.test(pattern)) {
41
+ return `${field}: glob pattern contains redundant '**/**' sequence; use '**' alone`;
42
+ }
43
+ return null;
44
+ }
45
+ /**
46
+ * Validate a (possibly partial) rule object.
47
+ *
48
+ * Returns `{ ok: true, errors: [] }` on success or
49
+ * `{ ok: false, errors: string[] }` with reasons on failure.
50
+ */
51
+ export function validateRule(rule) {
52
+ const errors = [];
53
+ // Required scalar fields
54
+ if (!rule.id || typeof rule.id !== 'string' || rule.id.trim() === '') {
55
+ errors.push('id: required non-empty string');
56
+ }
57
+ if (!rule.category || !VALID_CATEGORIES.includes(rule.category)) {
58
+ errors.push(`category: must be one of ${VALID_CATEGORIES.join(', ')}`);
59
+ }
60
+ if (!rule.subcategory || !VALID_SUBCATEGORIES.includes(rule.subcategory)) {
61
+ errors.push(`subcategory: must be one of ${VALID_SUBCATEGORIES.join(', ')}`);
62
+ }
63
+ if (!rule.action || !VALID_ACTIONS.includes(rule.action)) {
64
+ errors.push(`action: must be one of ${VALID_ACTIONS.join(', ')}`);
65
+ }
66
+ if (!rule.severity || !VALID_SEVERITIES.includes(rule.severity)) {
67
+ errors.push(`severity: must be one of ${VALID_SEVERITIES.join(', ')}`);
68
+ }
69
+ // At least one matcher field must be non-empty
70
+ const hasFile = (rule.filePathGlobs?.length ?? 0) > 0;
71
+ const hasCmd = !!rule.commandRegex || (rule.commandArgGlobs?.length ?? 0) > 0;
72
+ const hasEnv = (rule.envNameGlobs?.length ?? 0) > 0;
73
+ const hasHttp = (rule.httpHostGlobs?.length ?? 0) > 0 ||
74
+ (rule.httpMethod?.length ?? 0) > 0 ||
75
+ (rule.httpPathGlobs?.length ?? 0) > 0;
76
+ const hasGit = (rule.gitRemoteGlobs?.length ?? 0) > 0 ||
77
+ (rule.gitBranchGlobs?.length ?? 0) > 0 ||
78
+ (rule.gitSubcommand?.length ?? 0) > 0;
79
+ if (!hasFile && !hasCmd && !hasEnv && !hasHttp && !hasGit) {
80
+ errors.push('at least one matcher field (filePathGlobs, commandRegex, envNameGlobs, httpHostGlobs, gitSubcommand, …) must be non-empty');
81
+ }
82
+ // HTTP completeness: httpMethod / httpPathGlobs / httpHostExcludes require httpHostGlobs
83
+ const hasHttpHostGlobs = (rule.httpHostGlobs?.length ?? 0) > 0;
84
+ const hasHttpMethodOrPath = (rule.httpMethod?.length ?? 0) > 0 ||
85
+ (rule.httpPathGlobs?.length ?? 0) > 0 ||
86
+ (rule.httpHostExcludes?.length ?? 0) > 0;
87
+ if (hasHttpMethodOrPath && !hasHttpHostGlobs) {
88
+ errors.push('httpHostGlobs is required when httpMethod, httpPathGlobs, or httpHostExcludes is set');
89
+ }
90
+ // File completeness: filePathExcludes requires filePathGlobs
91
+ const hasFilePathGlobs = (rule.filePathGlobs?.length ?? 0) > 0;
92
+ const hasFilePathExcludes = (rule.filePathExcludes?.length ?? 0) > 0;
93
+ if (hasFilePathExcludes && !hasFilePathGlobs) {
94
+ errors.push('filePathGlobs is required when filePathExcludes is set');
95
+ }
96
+ // commandRegex validation
97
+ if (rule.commandRegex) {
98
+ if (!isRegexSafe(rule.commandRegex)) {
99
+ errors.push(`commandRegex: invalid or unsafe pattern "${rule.commandRegex}"`);
100
+ }
101
+ }
102
+ // Glob field validation
103
+ for (const field of GLOB_FIELDS) {
104
+ const globs = rule[field];
105
+ if (globs && Array.isArray(globs)) {
106
+ for (const glob of globs) {
107
+ const err = validateGlob(glob, String(field));
108
+ if (err)
109
+ errors.push(err);
110
+ }
111
+ }
112
+ }
113
+ return errors.length === 0 ? { ok: true, errors: [] } : { ok: false, errors };
114
+ }
115
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/guards-evaluator/validation.ts"],"names":[],"mappings":"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"}