@solongate/proxy 0.15.2 → 0.15.4

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 (2) hide show
  1. package/hooks/guard.mjs +71 -2
  2. package/package.json +1 -1
package/hooks/guard.mjs CHANGED
@@ -290,9 +290,57 @@ process.stdin.on('end', async () => {
290
290
  const args = data.tool_input || {};
291
291
 
292
292
  // ── Self-protection: block access to hook files and settings ──
293
- const allStrings = scanStrings(args).map(s => s.replace(/\\/g, '/').toLowerCase());
294
- const protectedPaths = ['.solongate', '.claude', '.cursor', 'policy.json', '.mcp.json'];
293
+ // Hardcoded, no bypass possible runs before policy/PI config
294
+ const protectedPaths = [
295
+ '.solongate', '.claude', '.cursor', '.gemini', '.antigravity', '.openclaw', '.perplexity',
296
+ 'policy.json', '.mcp.json',
297
+ ];
298
+
299
+ // Strip shell quotes/escapes: .sol'on'gate → .solongate, .sol"on"gate → .solongate
300
+ function stripShellQuotes(s) {
301
+ return s.replace(/\\(.)/g, '$1').replace(/'/g, '').replace(/"/g, '');
302
+ }
303
+
304
+ // Check if a glob/wildcard pattern could match any protected path
305
+ // e.g. ".antig*" matches ".antigravity", "/path/.sol*" matches ".solongate"
306
+ function globMatchesProtected(s) {
307
+ if (!s.includes('*') && !s.includes('?')) return null;
308
+ // Extract all path segments and the full string to test
309
+ const segments = s.split('/').filter(Boolean);
310
+ const candidates = [s, ...segments];
311
+ for (const candidate of candidates) {
312
+ if (!candidate.includes('*') && !candidate.includes('?')) continue;
313
+ for (const p of protectedPaths) {
314
+ // Build regex from glob: * → .*, ? → .
315
+ const escaped = candidate.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\\\*/g, '.*').replace(/\\\?/g, '.');
316
+ try {
317
+ if (new RegExp('^' + escaped + '$', 'i').test(p)) return p;
318
+ } catch { /* invalid regex, skip */ }
319
+ }
320
+ }
321
+ return null;
322
+ }
323
+
324
+ // Normalize: lowercase, forward slashes, strip shell quotes
325
+ const rawStrings = scanStrings(args).map(s => s.replace(/\\/g, '/').toLowerCase());
326
+ const allStrings = [];
327
+ for (const s of rawStrings) {
328
+ allStrings.push(s);
329
+ // Also add quote-stripped version
330
+ const stripped = stripShellQuotes(s);
331
+ if (stripped !== s) allStrings.push(stripped);
332
+ // Split by spaces (for commands like "rm -rf .sol'on'gate .cl*")
333
+ for (const tok of s.split(/\s+/)) {
334
+ if (tok !== s) {
335
+ allStrings.push(tok);
336
+ const strippedTok = stripShellQuotes(tok);
337
+ if (strippedTok !== tok) allStrings.push(strippedTok);
338
+ }
339
+ }
340
+ }
341
+
295
342
  for (const s of allStrings) {
343
+ // Direct match
296
344
  for (const p of protectedPaths) {
297
345
  if (s.includes(p)) {
298
346
  const msg = 'SOLONGATE: Access to protected file "' + p + '" is blocked';
@@ -314,6 +362,27 @@ process.stdin.on('end', async () => {
314
362
  process.exit(2);
315
363
  }
316
364
  }
365
+ // Wildcard/glob match
366
+ const globHit = globMatchesProtected(s);
367
+ if (globHit) {
368
+ const msg = 'SOLONGATE: Wildcard pattern "' + s + '" matches protected path "' + globHit + '" — blocked';
369
+ if (API_KEY && API_KEY.startsWith('sg_live_')) {
370
+ try {
371
+ await fetch(API_URL + '/api/v1/audit-logs', {
372
+ method: 'POST',
373
+ headers: { 'Authorization': 'Bearer ' + API_KEY, 'Content-Type': 'application/json' },
374
+ body: JSON.stringify({
375
+ tool: data.tool_name || '', arguments: args,
376
+ decision: 'DENY', reason: msg,
377
+ source: 'claude-code-guard',
378
+ }),
379
+ signal: AbortSignal.timeout(3000),
380
+ });
381
+ } catch {}
382
+ }
383
+ process.stderr.write(msg);
384
+ process.exit(2);
385
+ }
317
386
  }
318
387
 
319
388
  // ── Fetch PI config from Cloud ──
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solongate/proxy",
3
- "version": "0.15.2",
3
+ "version": "0.15.4",
4
4
  "description": "MCP security proxy — protect any MCP server with customizable policies, path/command constraints, rate limiting, and audit logging. Zero code changes required.",
5
5
  "type": "module",
6
6
  "bin": {