@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.
- package/LICENSE +77 -0
- package/README.md +120 -0
- package/bin/vibedefend.js +19 -0
- package/dist/auth/auth-store.js +170 -0
- package/dist/auth/auth-store.js.map +1 -0
- package/dist/auth/auth.js +125 -0
- package/dist/auth/auth.js.map +1 -0
- package/dist/auth/callback-server.js +216 -0
- package/dist/auth/callback-server.js.map +1 -0
- package/dist/auth/pkce.js +31 -0
- package/dist/auth/pkce.js.map +1 -0
- package/dist/auth/token-exchange.js +83 -0
- package/dist/auth/token-exchange.js.map +1 -0
- package/dist/clients/claude-code.js +170 -0
- package/dist/clients/claude-code.js.map +1 -0
- package/dist/clients/codex.js +378 -0
- package/dist/clients/codex.js.map +1 -0
- package/dist/clients/cursor-guards-rules.js +94 -0
- package/dist/clients/cursor-guards-rules.js.map +1 -0
- package/dist/clients/cursor.js +172 -0
- package/dist/clients/cursor.js.map +1 -0
- package/dist/clients/detect.js +86 -0
- package/dist/clients/detect.js.map +1 -0
- package/dist/clients/registry.js +41 -0
- package/dist/clients/registry.js.map +1 -0
- package/dist/clients/types.js +2 -0
- package/dist/clients/types.js.map +1 -0
- package/dist/clients/vscode.js +187 -0
- package/dist/clients/vscode.js.map +1 -0
- package/dist/clients/windsurf.js +151 -0
- package/dist/clients/windsurf.js.map +1 -0
- package/dist/config.js +32 -0
- package/dist/config.js.map +1 -0
- package/dist/custom-regions.js +112 -0
- package/dist/custom-regions.js.map +1 -0
- package/dist/diagnostics.js +122 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/doctor.js +125 -0
- package/dist/doctor.js.map +1 -0
- package/dist/guards-evaluator/bucketing.js +83 -0
- package/dist/guards-evaluator/bucketing.js.map +1 -0
- package/dist/guards-evaluator/evaluate.js +272 -0
- package/dist/guards-evaluator/evaluate.js.map +1 -0
- package/dist/guards-evaluator/glob.js +148 -0
- package/dist/guards-evaluator/glob.js.map +1 -0
- package/dist/guards-evaluator/index.js +9 -0
- package/dist/guards-evaluator/index.js.map +1 -0
- package/dist/guards-evaluator/preprocess.js +174 -0
- package/dist/guards-evaluator/preprocess.js.map +1 -0
- package/dist/guards-evaluator/redact.js +111 -0
- package/dist/guards-evaluator/redact.js.map +1 -0
- package/dist/guards-evaluator/regex.js +125 -0
- package/dist/guards-evaluator/regex.js.map +1 -0
- package/dist/guards-evaluator/types.js +2 -0
- package/dist/guards-evaluator/types.js.map +1 -0
- package/dist/guards-evaluator/validation.js +115 -0
- package/dist/guards-evaluator/validation.js.map +1 -0
- package/dist/hook-runner.js +6680 -0
- package/dist/hooks/install.js +169 -0
- package/dist/hooks/install.js.map +1 -0
- package/dist/hooks/runtime/api.js +167 -0
- package/dist/hooks/runtime/api.js.map +1 -0
- package/dist/hooks/runtime/config.js +60 -0
- package/dist/hooks/runtime/config.js.map +1 -0
- package/dist/hooks/runtime/emit.js +45 -0
- package/dist/hooks/runtime/emit.js.map +1 -0
- package/dist/hooks/runtime/fetch-rules.js +154 -0
- package/dist/hooks/runtime/fetch-rules.js.map +1 -0
- package/dist/hooks/runtime/guard-rules-cache.js +217 -0
- package/dist/hooks/runtime/guard-rules-cache.js.map +1 -0
- package/dist/hooks/runtime/guard-violations-buffer.js +105 -0
- package/dist/hooks/runtime/guard-violations-buffer.js.map +1 -0
- package/dist/hooks/runtime/pre-compact.js +41 -0
- package/dist/hooks/runtime/pre-compact.js.map +1 -0
- package/dist/hooks/runtime/resolve.js +206 -0
- package/dist/hooks/runtime/resolve.js.map +1 -0
- package/dist/hooks/runtime/session-review.js +198 -0
- package/dist/hooks/runtime/session-review.js.map +1 -0
- package/dist/hooks/runtime/session-start.js +101 -0
- package/dist/hooks/runtime/session-start.js.map +1 -0
- package/dist/hooks/runtime/sniff.js +112 -0
- package/dist/hooks/runtime/sniff.js.map +1 -0
- package/dist/hooks/runtime/types.js +22 -0
- package/dist/hooks/runtime/types.js.map +1 -0
- package/dist/hooks/runtime/user-prompt-submit.js +154 -0
- package/dist/hooks/runtime/user-prompt-submit.js.map +1 -0
- package/dist/index.js +129 -0
- package/dist/index.js.map +1 -0
- package/dist/install.js +183 -0
- package/dist/install.js.map +1 -0
- package/dist/login.js +335 -0
- package/dist/login.js.map +1 -0
- package/dist/prompts.js +134 -0
- package/dist/prompts.js.map +1 -0
- package/dist/self-update.js +177 -0
- package/dist/self-update.js.map +1 -0
- package/dist/status.js +58 -0
- package/dist/status.js.map +1 -0
- package/dist/utils.js +84 -0
- package/dist/utils.js.map +1 -0
- package/dist/version.js +23 -0
- package/dist/version.js.map +1 -0
- package/package.json +73 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core evaluator — pure function evaluate(rules, request) → Decision.
|
|
3
|
+
*
|
|
4
|
+
* Algorithm:
|
|
5
|
+
* 1. Filter rules with action === 'off'.
|
|
6
|
+
* 2. Bucket the request's target type.
|
|
7
|
+
* 3. Walk rules in that bucket; for each: check toolMatch, then per-target matchers.
|
|
8
|
+
* 4. Collect matched rules; sort by severity descending.
|
|
9
|
+
* 5. If any matched rule has action=deny → verdict=deny, message from highest-severity deny.
|
|
10
|
+
* 6. Else if any has action=warn → verdict=warn, message from highest-severity warn.
|
|
11
|
+
* 7. Else → verdict=allow.
|
|
12
|
+
*/
|
|
13
|
+
import { matchAnyGlob, matchAllGlobExcludes, matchGlob } from './glob.js';
|
|
14
|
+
import { compileRegex } from './regex.js';
|
|
15
|
+
import { bucketRules, targetTypeBucket } from './bucketing.js';
|
|
16
|
+
import { stripDataArgs } from './preprocess.js';
|
|
17
|
+
// -----------------------------------------------------------------------
|
|
18
|
+
// Severity ordering
|
|
19
|
+
// -----------------------------------------------------------------------
|
|
20
|
+
const SEVERITY_ORDER = {
|
|
21
|
+
critical: 4,
|
|
22
|
+
high: 3,
|
|
23
|
+
medium: 2,
|
|
24
|
+
low: 1,
|
|
25
|
+
};
|
|
26
|
+
function compareSeverityDesc(a, b) {
|
|
27
|
+
return SEVERITY_ORDER[b.severity] - SEVERITY_ORDER[a.severity];
|
|
28
|
+
}
|
|
29
|
+
// -----------------------------------------------------------------------
|
|
30
|
+
// Message formatter
|
|
31
|
+
// -----------------------------------------------------------------------
|
|
32
|
+
/**
|
|
33
|
+
* Format a message template substituting {target} and {rule_name}.
|
|
34
|
+
*
|
|
35
|
+
* {target} → human-readable description of the target
|
|
36
|
+
* {rule_name} → rule.name if set, else rule.id
|
|
37
|
+
*/
|
|
38
|
+
export function formatMessage(template, target, rule) {
|
|
39
|
+
let targetStr;
|
|
40
|
+
switch (target.type) {
|
|
41
|
+
case 'file':
|
|
42
|
+
targetStr = target.path;
|
|
43
|
+
break;
|
|
44
|
+
case 'command':
|
|
45
|
+
targetStr = target.command;
|
|
46
|
+
break;
|
|
47
|
+
case 'env':
|
|
48
|
+
targetStr = target.name;
|
|
49
|
+
break;
|
|
50
|
+
case 'http':
|
|
51
|
+
targetStr = target.url;
|
|
52
|
+
break;
|
|
53
|
+
case 'git':
|
|
54
|
+
targetStr = `git ${target.subcommand}`;
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
const ruleName = rule.name ?? rule.id;
|
|
58
|
+
return template
|
|
59
|
+
.replace(/\{target\}/g, targetStr)
|
|
60
|
+
.replace(/\{rule_name\}/g, ruleName);
|
|
61
|
+
}
|
|
62
|
+
// -----------------------------------------------------------------------
|
|
63
|
+
// Per-target matchers
|
|
64
|
+
// -----------------------------------------------------------------------
|
|
65
|
+
function matchesFile(rule, target, homeDir) {
|
|
66
|
+
const opts = { homeDir };
|
|
67
|
+
const globsSet = rule.filePathGlobs && rule.filePathGlobs.length > 0;
|
|
68
|
+
if (globsSet) {
|
|
69
|
+
if (!matchAnyGlob(rule.filePathGlobs, target.path, opts))
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
if (!matchAllGlobExcludes(rule.filePathExcludes, target.path, opts))
|
|
73
|
+
return false;
|
|
74
|
+
// If no globs at all (only excludes or nothing), treat as "any" only if at
|
|
75
|
+
// least one matcher is set.
|
|
76
|
+
if (!globsSet)
|
|
77
|
+
return false;
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
function matchesCommand(rule, target, homeDir) {
|
|
81
|
+
const opts = { homeDir };
|
|
82
|
+
const hasRegex = !!rule.commandRegex;
|
|
83
|
+
const hasArgGlobs = rule.commandArgGlobs && rule.commandArgGlobs.length > 0;
|
|
84
|
+
if (!hasRegex && !hasArgGlobs)
|
|
85
|
+
return false;
|
|
86
|
+
// Reconstruct full command string for regex matching (command + args joined).
|
|
87
|
+
// Then strip data-bearing arg values (e.g. `git commit -m "..."`, `gh pr
|
|
88
|
+
// --body "..."`) so the regex doesn't false-positive on user-provided text
|
|
89
|
+
// that happens to mention a dangerous keyword. See preprocess.ts header for
|
|
90
|
+
// the full rationale.
|
|
91
|
+
//
|
|
92
|
+
// CRITICAL: pass the argv-tuple to stripDataArgs directly (not the joined
|
|
93
|
+
// string). Naively joining `[cmd, ...argv].join(' ')` LOSES quote boundaries
|
|
94
|
+
// — a message arg "fix: drop table users" becomes 4 separate tokens, and
|
|
95
|
+
// the preprocessor only strips the first one. Passing the already-tokenized
|
|
96
|
+
// argv preserves each argument as one indivisible token regardless of
|
|
97
|
+
// whether it contains spaces.
|
|
98
|
+
const fullCommand = stripDataArgs([target.command, ...target.argv]);
|
|
99
|
+
if (hasRegex) {
|
|
100
|
+
// A single malformed rule (e.g. an unsupported `(?i)` inline flag rejected
|
|
101
|
+
// by native RegExp when re2-wasm isn't available) MUST NOT poison the
|
|
102
|
+
// evaluation of every other rule in the bucket. Swallow per-rule compile
|
|
103
|
+
// failures: log to stderr once so operators see the culprit, treat the
|
|
104
|
+
// rule as non-matching, and continue. The other rules still enforce.
|
|
105
|
+
try {
|
|
106
|
+
const re = compileRegex(rule.commandRegex);
|
|
107
|
+
if (!re.test(fullCommand))
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
catch (e) {
|
|
111
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
112
|
+
// eslint-disable-next-line no-console
|
|
113
|
+
console.error(`[guards-evaluator] Skipping rule ${rule.id} — invalid commandRegex: ${msg}`);
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (hasArgGlobs) {
|
|
118
|
+
// Every glob in commandArgGlobs must match at least one entry of argv
|
|
119
|
+
for (const glob of rule.commandArgGlobs) {
|
|
120
|
+
const matchedAny = target.argv.some((arg) => matchGlob(glob, arg, opts));
|
|
121
|
+
if (!matchedAny)
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
function matchesEnv(rule, target, homeDir) {
|
|
128
|
+
return matchAnyGlob(rule.envNameGlobs, target.name, { homeDir });
|
|
129
|
+
}
|
|
130
|
+
function matchesHttp(rule, target, homeDir) {
|
|
131
|
+
const opts = { homeDir };
|
|
132
|
+
// Parse hostname and path from URL
|
|
133
|
+
let hostname;
|
|
134
|
+
let pathname;
|
|
135
|
+
try {
|
|
136
|
+
const u = new URL(target.url);
|
|
137
|
+
hostname = u.hostname;
|
|
138
|
+
pathname = u.pathname;
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
// Fallback: treat entire url as hostname
|
|
142
|
+
hostname = target.url;
|
|
143
|
+
pathname = '';
|
|
144
|
+
}
|
|
145
|
+
// httpHostGlobs — at least one must match
|
|
146
|
+
const hostGlobsSet = rule.httpHostGlobs && rule.httpHostGlobs.length > 0;
|
|
147
|
+
if (hostGlobsSet) {
|
|
148
|
+
if (!matchAnyGlob(rule.httpHostGlobs, hostname, opts))
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
// httpHostExcludes — none must match
|
|
152
|
+
if (!matchAllGlobExcludes(rule.httpHostExcludes, hostname, opts))
|
|
153
|
+
return false;
|
|
154
|
+
// httpMethod — if set, method must be in the list
|
|
155
|
+
if (rule.httpMethod && rule.httpMethod.length > 0) {
|
|
156
|
+
if (!rule.httpMethod.includes(target.method.toUpperCase()))
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
// httpPathGlobs — if set, at least one must match the path
|
|
160
|
+
if (rule.httpPathGlobs && rule.httpPathGlobs.length > 0) {
|
|
161
|
+
if (!matchAnyGlob(rule.httpPathGlobs, pathname, opts))
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
// Must have at least one positive matcher
|
|
165
|
+
if (!hostGlobsSet)
|
|
166
|
+
return false;
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
function matchesGit(rule, target, homeDir) {
|
|
170
|
+
const opts = { homeDir };
|
|
171
|
+
// gitSubcommand — if set, must include target.subcommand
|
|
172
|
+
if (rule.gitSubcommand && rule.gitSubcommand.length > 0) {
|
|
173
|
+
if (!rule.gitSubcommand.includes(target.subcommand))
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
// gitRemoteGlobs — if set, target.remote must match at least one
|
|
177
|
+
if (rule.gitRemoteGlobs && rule.gitRemoteGlobs.length > 0) {
|
|
178
|
+
if (!target.remote)
|
|
179
|
+
return false;
|
|
180
|
+
if (!matchAnyGlob(rule.gitRemoteGlobs, target.remote, opts))
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
// gitBranchGlobs — if set, target.branch must match at least one
|
|
184
|
+
if (rule.gitBranchGlobs && rule.gitBranchGlobs.length > 0) {
|
|
185
|
+
if (!target.branch)
|
|
186
|
+
return false;
|
|
187
|
+
if (!matchAnyGlob(rule.gitBranchGlobs, target.branch, opts))
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
// Must have at least one matcher to be useful
|
|
191
|
+
const hasAny = (rule.gitSubcommand && rule.gitSubcommand.length > 0) ||
|
|
192
|
+
(rule.gitRemoteGlobs && rule.gitRemoteGlobs.length > 0) ||
|
|
193
|
+
(rule.gitBranchGlobs && rule.gitBranchGlobs.length > 0);
|
|
194
|
+
if (!hasAny)
|
|
195
|
+
return false;
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
function ruleMatches(rule, req) {
|
|
199
|
+
// toolMatch filter
|
|
200
|
+
if (rule.toolMatch && rule.toolMatch.length > 0) {
|
|
201
|
+
if (!rule.toolMatch.includes(req.tool))
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
const { target, homeDir } = req;
|
|
205
|
+
switch (target.type) {
|
|
206
|
+
case 'file': return matchesFile(rule, target, homeDir);
|
|
207
|
+
case 'command': return matchesCommand(rule, target, homeDir);
|
|
208
|
+
case 'env': return matchesEnv(rule, target, homeDir);
|
|
209
|
+
case 'http': return matchesHttp(rule, target, homeDir);
|
|
210
|
+
case 'git': return matchesGit(rule, target, homeDir);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
// -----------------------------------------------------------------------
|
|
214
|
+
// Public evaluator
|
|
215
|
+
// -----------------------------------------------------------------------
|
|
216
|
+
/**
|
|
217
|
+
* Evaluate a list of effective rules against a guard request.
|
|
218
|
+
*
|
|
219
|
+
* Rules with `action === 'off'` are silently ignored.
|
|
220
|
+
* Matching rules are sorted by severity descending; deny always beats warn.
|
|
221
|
+
*/
|
|
222
|
+
export function evaluate(rules, req) {
|
|
223
|
+
try {
|
|
224
|
+
// 1. Filter off rules
|
|
225
|
+
const active = rules.filter((r) => r.action !== 'off');
|
|
226
|
+
// 2. Bucket by target type
|
|
227
|
+
const bucketed = bucketRules(active);
|
|
228
|
+
const bucket = targetTypeBucket(req.target);
|
|
229
|
+
const candidates = bucketed[bucket];
|
|
230
|
+
// 3. Match each candidate
|
|
231
|
+
const matched = [];
|
|
232
|
+
for (const rule of candidates) {
|
|
233
|
+
if (ruleMatches(rule, req)) {
|
|
234
|
+
matched.push(rule);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
if (matched.length === 0) {
|
|
238
|
+
return { verdict: 'allow', matchedRuleIds: [], message: undefined, maxSeverity: null };
|
|
239
|
+
}
|
|
240
|
+
// 4. Sort by severity descending
|
|
241
|
+
matched.sort(compareSeverityDesc);
|
|
242
|
+
const matchedRuleIds = matched.map((r) => r.id);
|
|
243
|
+
const maxSeverity = matched[0].severity;
|
|
244
|
+
// 5. Determine verdict
|
|
245
|
+
const denyRules = matched.filter((r) => r.action === 'deny');
|
|
246
|
+
if (denyRules.length > 0) {
|
|
247
|
+
const topDeny = denyRules[0]; // already sorted
|
|
248
|
+
const template = topDeny.denyMessage ?? 'Action denied by rule {rule_name} on {target}.';
|
|
249
|
+
const message = formatMessage(template, req.target, topDeny);
|
|
250
|
+
return { verdict: 'deny', matchedRuleIds, message, maxSeverity };
|
|
251
|
+
}
|
|
252
|
+
const warnRules = matched.filter((r) => r.action === 'warn');
|
|
253
|
+
if (warnRules.length > 0) {
|
|
254
|
+
const topWarn = warnRules[0];
|
|
255
|
+
const template = topWarn.warnMessage ?? 'Action warned by rule {rule_name} on {target}.';
|
|
256
|
+
const message = formatMessage(template, req.target, topWarn);
|
|
257
|
+
return { verdict: 'warn', matchedRuleIds, message, maxSeverity };
|
|
258
|
+
}
|
|
259
|
+
// All matched rules are 'off' (shouldn't happen after filtering, but be safe)
|
|
260
|
+
return { verdict: 'allow', matchedRuleIds: [], message: undefined, maxSeverity: null };
|
|
261
|
+
}
|
|
262
|
+
catch (e) {
|
|
263
|
+
const message = e instanceof Error ? e.message : 'unknown evaluator error';
|
|
264
|
+
return {
|
|
265
|
+
verdict: 'deny',
|
|
266
|
+
matchedRuleIds: [],
|
|
267
|
+
message: `Guard evaluator failed: ${message}. Failing closed — refuse the action.`,
|
|
268
|
+
maxSeverity: 'critical',
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
//# sourceMappingURL=evaluate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluate.js","sourceRoot":"","sources":["../../src/guards-evaluator/evaluate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Glob matching implementation for VibeDefend Action Guards.
|
|
3
|
+
*
|
|
4
|
+
* Supports: * (no path sep), ** (any chars including /), ? (single char),
|
|
5
|
+
* [abc] character classes, ~ expansion (home dir only), path separator
|
|
6
|
+
* normalisation.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Expand ~ at the start of a pattern to opts.homeDir.
|
|
10
|
+
*/
|
|
11
|
+
function expandHome(pattern, homeDir) {
|
|
12
|
+
if (pattern === '~')
|
|
13
|
+
return homeDir;
|
|
14
|
+
if (pattern.startsWith('~/'))
|
|
15
|
+
return homeDir + pattern.slice(1);
|
|
16
|
+
return pattern;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Normalise path separators (Windows backslashes → forward slashes).
|
|
20
|
+
*/
|
|
21
|
+
function normaliseSep(s) {
|
|
22
|
+
return s.replace(/\\/g, '/');
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Escape a literal string for inclusion in a regex.
|
|
26
|
+
*/
|
|
27
|
+
function escapeRegex(s) {
|
|
28
|
+
return s.replace(/[.+^${}()|[\]\\]/g, '\\$&');
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Convert a glob pattern (after ~ expansion + sep normalisation) to a RegExp.
|
|
32
|
+
*
|
|
33
|
+
* Rules:
|
|
34
|
+
* ** → matches any sequence of characters including '/' (greedy)
|
|
35
|
+
* * → matches any sequence of characters except '/'
|
|
36
|
+
* ? → matches any single character except '/'
|
|
37
|
+
* [abc] → character class (passed through as-is)
|
|
38
|
+
*/
|
|
39
|
+
function globToRegex(pattern) {
|
|
40
|
+
let src = '';
|
|
41
|
+
let i = 0;
|
|
42
|
+
while (i < pattern.length) {
|
|
43
|
+
const c = pattern[i];
|
|
44
|
+
if (c === '*') {
|
|
45
|
+
if (pattern[i + 1] === '*') {
|
|
46
|
+
// ** — matches everything including slashes
|
|
47
|
+
// consume any surrounding slashes in pattern to avoid double-//
|
|
48
|
+
const before = src.endsWith('/') ? src.slice(0, -1) : src;
|
|
49
|
+
let j = i + 2;
|
|
50
|
+
while (j < pattern.length && pattern[j] === '/')
|
|
51
|
+
j++;
|
|
52
|
+
if (i === 0 && j === pattern.length) {
|
|
53
|
+
// just ** alone — matches anything
|
|
54
|
+
src = before + '.*';
|
|
55
|
+
}
|
|
56
|
+
else if (i === 0) {
|
|
57
|
+
// **/ at start
|
|
58
|
+
src = before + '(?:.*\\/)?';
|
|
59
|
+
}
|
|
60
|
+
else if (j >= pattern.length) {
|
|
61
|
+
// /** at end
|
|
62
|
+
src = before + '(?:\\/.*)?';
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
// /**/ in the middle
|
|
66
|
+
src = before + '(?:\\/.*\\/|\\/|\\/)';
|
|
67
|
+
// Actually: /**/foo should match /foo and /a/b/foo
|
|
68
|
+
// We handle this more carefully:
|
|
69
|
+
src = before + '(?:\\/|(?:\\/.+\\/))';
|
|
70
|
+
}
|
|
71
|
+
i = j;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// single * — no path separator
|
|
76
|
+
src += '[^/]*';
|
|
77
|
+
i++;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else if (c === '?') {
|
|
82
|
+
src += '[^/]';
|
|
83
|
+
i++;
|
|
84
|
+
}
|
|
85
|
+
else if (c === '[') {
|
|
86
|
+
// pass character class through
|
|
87
|
+
let j = i + 1;
|
|
88
|
+
let cls = '[';
|
|
89
|
+
if (j < pattern.length && pattern[j] === '!') {
|
|
90
|
+
cls += '^';
|
|
91
|
+
j++;
|
|
92
|
+
}
|
|
93
|
+
if (j < pattern.length && pattern[j] === ']') {
|
|
94
|
+
cls += '\\]';
|
|
95
|
+
j++;
|
|
96
|
+
}
|
|
97
|
+
while (j < pattern.length && pattern[j] !== ']') {
|
|
98
|
+
cls += escapeRegex(pattern[j]);
|
|
99
|
+
j++;
|
|
100
|
+
}
|
|
101
|
+
cls += ']';
|
|
102
|
+
src += cls;
|
|
103
|
+
i = j + 1;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
src += escapeRegex(c);
|
|
107
|
+
i++;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return new RegExp('^' + src + '$');
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Match a single glob pattern against a value.
|
|
114
|
+
*
|
|
115
|
+
* @param pattern Glob pattern (may start with ~)
|
|
116
|
+
* @param value The string to test (file path, host, etc.)
|
|
117
|
+
* @param opts Must include homeDir for ~ expansion
|
|
118
|
+
*/
|
|
119
|
+
export function matchGlob(pattern, value, opts) {
|
|
120
|
+
const expanded = expandHome(normaliseSep(pattern), normaliseSep(opts.homeDir));
|
|
121
|
+
const normValue = normaliseSep(value);
|
|
122
|
+
// A pattern without any glob characters — exact match
|
|
123
|
+
const hasGlob = /[*?[\]]/.test(expanded);
|
|
124
|
+
if (!hasGlob) {
|
|
125
|
+
return expanded === normValue;
|
|
126
|
+
}
|
|
127
|
+
const re = globToRegex(expanded);
|
|
128
|
+
return re.test(normValue);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Returns true if `value` matches ANY of the `patterns`.
|
|
132
|
+
* Returns false if patterns is undefined or empty.
|
|
133
|
+
*/
|
|
134
|
+
export function matchAnyGlob(patterns, value, opts) {
|
|
135
|
+
if (!patterns || patterns.length === 0)
|
|
136
|
+
return false;
|
|
137
|
+
return patterns.some((p) => matchGlob(p, value, opts));
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Returns true if `value` does NOT match any of the `excludes`.
|
|
141
|
+
* If excludes is undefined or empty, always returns true (nothing is excluded).
|
|
142
|
+
*/
|
|
143
|
+
export function matchAllGlobExcludes(excludes, value, opts) {
|
|
144
|
+
if (!excludes || excludes.length === 0)
|
|
145
|
+
return true;
|
|
146
|
+
return !excludes.some((p) => matchGlob(p, value, opts));
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=glob.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glob.js","sourceRoot":"","sources":["../../src/guards-evaluator/glob.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export { evaluate, formatMessage } from './evaluate.js';
|
|
3
|
+
export { validateRule } from './validation.js';
|
|
4
|
+
export { redactTarget, hashTarget } from './redact.js';
|
|
5
|
+
export { matchGlob, matchAnyGlob, matchAllGlobExcludes } from './glob.js';
|
|
6
|
+
export { compileRegex, isRegexSafe, isRe2Available, waitForRe2 } from './regex.js';
|
|
7
|
+
export { targetTypeBucket, ruleBuckets, bucketRules } from './bucketing.js';
|
|
8
|
+
export { stripDataArgs } from './preprocess.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/guards-evaluator/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACnF,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quote-aware preprocessing of shell command strings.
|
|
3
|
+
*
|
|
4
|
+
* Problem: the rule-evaluation regexes scan the full command string for
|
|
5
|
+
* dangerous patterns. They have no awareness of shell semantics, so they
|
|
6
|
+
* cannot tell that the literal text inside a `git commit -m "..."` argument
|
|
7
|
+
* is DATA (a commit message) rather than CODE. This produces false positives
|
|
8
|
+
* — a perfectly safe commit message saying "fix: close .env bypass" trips
|
|
9
|
+
* the secret-read rule because the regex sees `.env` as a substring.
|
|
10
|
+
*
|
|
11
|
+
* Fix: before running the rule regex, tokenize the command with `shell-quote`
|
|
12
|
+
* (a pure-JS bash-grammar tokenizer that respects single/double quotes,
|
|
13
|
+
* escapes, and shell operators). For known data-bearing flags — `-m`/`-F`/
|
|
14
|
+
* `--message`/`--file`/`--body` on `git commit|tag|notes|stash` and `gh
|
|
15
|
+
* pr|issue create` — replace the value token with an opaque placeholder
|
|
16
|
+
* so the regex never sees the user-provided text.
|
|
17
|
+
*
|
|
18
|
+
* Scope is INTENTIONALLY narrow:
|
|
19
|
+
* - Only flags that take freeform USER TEXT (commit messages, PR bodies)
|
|
20
|
+
* get their values stripped. `bash -c "..."` does NOT get stripped —
|
|
21
|
+
* that arg IS code, not data.
|
|
22
|
+
* - Only the subcommands that genuinely accept message text. `git push
|
|
23
|
+
* -m` (not a real flag) keeps its argument so we don't lose detection
|
|
24
|
+
* on hypothetical future variants.
|
|
25
|
+
* - Stripping resets at every shell operator (`;`, `&&`, `||`, `|`).
|
|
26
|
+
* So `git commit -m "msg"; cat .env` strips the message but keeps
|
|
27
|
+
* `cat .env` for evaluation.
|
|
28
|
+
*
|
|
29
|
+
* No I/O, no system access — pure string in, pure string out. Parse failures
|
|
30
|
+
* (unclosed quotes, invalid escapes) fall back to the original input so
|
|
31
|
+
* the scanner keeps running.
|
|
32
|
+
*/
|
|
33
|
+
import { parse as shellParse } from 'shell-quote';
|
|
34
|
+
/** Opaque placeholder substituted for stripped data arguments. */
|
|
35
|
+
const PLACEHOLDER = '<DATA>';
|
|
36
|
+
/**
|
|
37
|
+
* Subcommands that accept user-provided message TEXT as a `-m` / `-F` /
|
|
38
|
+
* `--message` / `--file` value. Other subcommands of the same tool either
|
|
39
|
+
* don't accept these flags or use them differently (e.g. `git push` has
|
|
40
|
+
* no `-m`, `git diff` doesn't either).
|
|
41
|
+
*
|
|
42
|
+
* Keyed by top-level command. Empty set means "always treat as data" (used
|
|
43
|
+
* for commands where every -m/-F is a message regardless of subcommand,
|
|
44
|
+
* e.g. `gh`).
|
|
45
|
+
*/
|
|
46
|
+
const DATA_BEARING_CONTEXTS = {
|
|
47
|
+
git: new Set(['commit', 'tag', 'notes', 'stash', 'merge', 'cherry-pick', 'revert']),
|
|
48
|
+
gh: null, // gh pr/issue create/edit all accept --body
|
|
49
|
+
hg: new Set(['commit', 'tag']), // mercurial
|
|
50
|
+
};
|
|
51
|
+
/** Flags whose VALUE is data (skip the next token). */
|
|
52
|
+
const DATA_FLAGS_VALUE = new Set([
|
|
53
|
+
'-m', '-F',
|
|
54
|
+
'--message', '--file',
|
|
55
|
+
'--body', '--body-file',
|
|
56
|
+
]);
|
|
57
|
+
/** Flags in `--flag=value` form whose value is data. */
|
|
58
|
+
const DATA_FLAGS_EQUAL = ['--message=', '--file=', '--body=', '--body-file='];
|
|
59
|
+
/**
|
|
60
|
+
* Strip data-argument values from a shell command.
|
|
61
|
+
*
|
|
62
|
+
* Accepts either a raw command STRING (legacy callers; will be tokenized
|
|
63
|
+
* with shell-quote, which may lose quote boundaries on free-form input) or
|
|
64
|
+
* a pre-tokenized ARGV ARRAY (preferred; quote boundaries already
|
|
65
|
+
* established by the caller's own tokenizer). The argv path is what the
|
|
66
|
+
* production evaluator uses — each argv element is treated as one
|
|
67
|
+
* indivisible token, so a message arg with spaces stays one token and gets
|
|
68
|
+
* cleanly replaced by `<DATA>`.
|
|
69
|
+
*
|
|
70
|
+
* Returns the (possibly modified) command as a single string. The caller's
|
|
71
|
+
* regex then sees the rest of the command unchanged — operators, other
|
|
72
|
+
* args, subsequent commands — so genuine code patterns still match.
|
|
73
|
+
*
|
|
74
|
+
* Never throws. Parse failures return the original input so the scanner
|
|
75
|
+
* still runs (fail-open at this layer; the per-rule regex is the gate).
|
|
76
|
+
*/
|
|
77
|
+
export function stripDataArgs(command) {
|
|
78
|
+
if (!command || (Array.isArray(command) && command.length === 0)) {
|
|
79
|
+
return Array.isArray(command) ? '' : command;
|
|
80
|
+
}
|
|
81
|
+
let tokens;
|
|
82
|
+
if (Array.isArray(command)) {
|
|
83
|
+
// Caller already tokenized — each element is one indivisible token.
|
|
84
|
+
// Skip shell-quote so we don't accidentally re-split a message arg
|
|
85
|
+
// that contains spaces. Operators in argv (rare; the caller's tokenizer
|
|
86
|
+
// would normally absorb them into the command string) are passed through
|
|
87
|
+
// as bare strings — they won't match our data-flag detection anyway.
|
|
88
|
+
tokens = command.slice();
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
try {
|
|
92
|
+
// CRITICAL: pass an env function that preserves `$VAR` references as
|
|
93
|
+
// their literal form. shell-quote's default behavior is to substitute
|
|
94
|
+
// variable references with empty strings, which would DROP `$HOME`,
|
|
95
|
+
// `$SECRET_KEY`, etc. from the command — breaking every rule that
|
|
96
|
+
// matches on those literals (e.g. shell.env.echo_secret looks for
|
|
97
|
+
// `echo $SECRET_KEY`, fs.delete.root_or_home matches `rm -rf $HOME`).
|
|
98
|
+
// Returning `$<name>` keeps the regex's view of the command identical
|
|
99
|
+
// to what the user typed.
|
|
100
|
+
tokens = shellParse(command, (key) => '$' + key);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return command;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Walk tokens, tracking the current segment's top-level command and
|
|
107
|
+
// subcommand so we know whether a `-m` is a data flag here.
|
|
108
|
+
const out = [];
|
|
109
|
+
let segmentTopCmd = null;
|
|
110
|
+
let segmentSubCmd = null;
|
|
111
|
+
let positionInSegment = 0;
|
|
112
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
113
|
+
const tok = tokens[i];
|
|
114
|
+
if (typeof tok === 'object' && 'op' in tok) {
|
|
115
|
+
// Shell operator (`;`, `&&`, `||`, `|`, `>`, `<`, etc.) — segment boundary.
|
|
116
|
+
out.push(tok.op);
|
|
117
|
+
segmentTopCmd = null;
|
|
118
|
+
segmentSubCmd = null;
|
|
119
|
+
positionInSegment = 0;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (typeof tok !== 'string') {
|
|
123
|
+
// Patterns / comments / other object tokens — preserve literal form.
|
|
124
|
+
out.push(JSON.stringify(tok));
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
// First non-operator token in a segment is the command name.
|
|
128
|
+
if (positionInSegment === 0) {
|
|
129
|
+
segmentTopCmd = tok;
|
|
130
|
+
out.push(tok);
|
|
131
|
+
positionInSegment++;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
// Second token might be the subcommand.
|
|
135
|
+
if (positionInSegment === 1) {
|
|
136
|
+
segmentSubCmd = tok;
|
|
137
|
+
}
|
|
138
|
+
const contextSubcommands = segmentTopCmd
|
|
139
|
+
? DATA_BEARING_CONTEXTS[segmentTopCmd]
|
|
140
|
+
: undefined;
|
|
141
|
+
const inDataBearingContext = contextSubcommands === null ||
|
|
142
|
+
(contextSubcommands !== undefined &&
|
|
143
|
+
segmentSubCmd !== null &&
|
|
144
|
+
contextSubcommands.has(segmentSubCmd));
|
|
145
|
+
if (inDataBearingContext) {
|
|
146
|
+
// -m "msg" / -F file / --message msg / --file path
|
|
147
|
+
if (DATA_FLAGS_VALUE.has(tok)) {
|
|
148
|
+
out.push(tok);
|
|
149
|
+
if (i + 1 < tokens.length) {
|
|
150
|
+
const next = tokens[i + 1];
|
|
151
|
+
if (typeof next === 'string') {
|
|
152
|
+
out.push(PLACEHOLDER);
|
|
153
|
+
i++;
|
|
154
|
+
positionInSegment++;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
positionInSegment++;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
// --message=msg / --file=path / --body=...
|
|
162
|
+
const equalPrefix = DATA_FLAGS_EQUAL.find((p) => tok.startsWith(p));
|
|
163
|
+
if (equalPrefix) {
|
|
164
|
+
out.push(equalPrefix + PLACEHOLDER);
|
|
165
|
+
positionInSegment++;
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
out.push(tok);
|
|
170
|
+
positionInSegment++;
|
|
171
|
+
}
|
|
172
|
+
return out.join(' ');
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=preprocess.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preprocess.js","sourceRoot":"","sources":["../../src/guards-evaluator/preprocess.ts"],"names":[],"mappings":"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"}
|