@solongate/proxy 0.49.1 → 0.51.0

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/hooks/guard.mjs CHANGED
@@ -31,7 +31,7 @@ import { createHash } from 'node:crypto';
31
31
  // the installed hook self-updates when the cloud version is higher (see
32
32
  // maybeSelfUpdate). This is what makes guard fixes propagate without a manual
33
33
  // reinstall — the same trust model as the OPA WASM this hook already runs.
34
- const HOOK_VERSION = 17;
34
+ const HOOK_VERSION = 18;
35
35
 
36
36
  // Safe file read with size limit (1MB max) to prevent DoS via large files
37
37
  const MAX_FILE_READ = 1024 * 1024; // 1MB
@@ -1419,6 +1419,7 @@ process.stdin.on('end', async () => {
1419
1419
  reason: 'ghost path (hidden from agent)',
1420
1420
  permission: guessPermission(toolName),
1421
1421
  source: `${AGENT_TYPE}-guard`, agent_id: AGENT_TYPE, agent_name: AGENT_NAME,
1422
+ session_id: data.session_id || '',
1422
1423
  evaluation_time_ms: Date.now() - _evalStart,
1423
1424
  }),
1424
1425
  signal: AbortSignal.timeout(3000),
@@ -1497,6 +1498,7 @@ process.stdin.on('end', async () => {
1497
1498
  permission: guessPermission(toolName),
1498
1499
  source: `${AGENT_TYPE}-guard`,
1499
1500
  agent_id: AGENT_TYPE, agent_name: AGENT_NAME,
1501
+ session_id: data.session_id || '',
1500
1502
  evaluation_time_ms: Date.now() - _evalStart,
1501
1503
  };
1502
1504
  // PI hook layer removed — piResult fields no longer attached.
package/hooks/stop.mjs CHANGED
@@ -1,75 +1,75 @@
1
- #!/usr/bin/env node
2
- /**
3
- * SolonGate Stop Hook (Stop event)
4
- * Logs a single ALLOW when Claude responds WITHOUT any tool calls.
5
- * If tool calls were made, audit.mjs already logged them — this hook skips.
6
- * Auto-installed by: npx @solongate/proxy init
7
- */
8
- import { readFileSync, existsSync, unlinkSync, writeFileSync } from 'node:fs';
9
- import { resolve, join } from 'node:path';
10
-
11
- function loadEnvKey(dir) {
12
- try {
13
- const envPath = resolve(dir, '.env');
14
- if (!existsSync(envPath)) return {};
15
- const lines = readFileSync(envPath, 'utf-8').split('\n');
16
- const env = {};
17
- for (const line of lines) {
18
- const m = line.match(/^([A-Z_]+)=(.*)$/);
19
- if (m) env[m[1]] = m[2].replace(/^["']|["']$/g, '').trim();
20
- }
21
- return env;
22
- } catch { return {}; }
23
- }
24
-
25
- const dotenv = loadEnvKey(process.cwd());
26
- const API_KEY = process.env.SOLONGATE_API_KEY || dotenv.SOLONGATE_API_KEY || '';
27
- const API_URL = process.env.SOLONGATE_API_URL || dotenv.SOLONGATE_API_URL || 'https://api.solongate.com';
28
-
29
- // Agent identity from CLI args: node stop.mjs <agent_id> <agent_name>
30
- const AGENT_ID = process.argv[2] || 'claude-code';
31
- const AGENT_NAME = process.argv[3] || 'Claude Code';
32
-
33
- if (!API_KEY || !API_KEY.startsWith('sg_live_')) process.exit(0);
34
-
35
- // Flag file: audit.mjs writes this when a tool call was logged in this turn.
36
- // If the flag exists, tool calls were made → skip (already logged).
37
- // If the flag doesn't exist, no tool calls → log 1 ALLOW for the text response.
38
- const flagDir = resolve('.solongate');
39
- const flagFile = join(flagDir, '.last-tool-call');
40
-
41
- let input = '';
42
- process.stdin.on('data', c => input += c);
43
- process.stdin.on('end', async () => {
44
- try {
45
- // Check if tool calls were made in this turn
46
- if (existsSync(flagFile)) {
47
- // Tool calls happened → audit.mjs already logged them. Clean up flag.
48
- try { unlinkSync(flagFile); } catch {}
49
- process.exit(0);
50
- }
51
-
52
- // No tool calls → log 1 ALLOW for the text-only response (fire-and-forget)
53
- fetch(`${API_URL}/api/v1/audit-logs`, {
54
- method: 'POST',
55
- headers: {
56
- 'Authorization': `Bearer ${API_KEY}`,
57
- 'Content-Type': 'application/json',
58
- },
59
- body: JSON.stringify({
60
- tool: '_response',
61
- arguments: {},
62
- decision: 'ALLOW',
63
- reason: 'text response (no tool calls)',
64
- source: `${AGENT_ID}-hook`,
65
- evaluationTimeMs: 0,
66
- agent_id: AGENT_ID,
67
- agent_name: AGENT_NAME,
68
- }),
69
- signal: AbortSignal.timeout(5000),
70
- }).catch(() => {}).finally(() => process.exit(0));
71
- setTimeout(() => process.exit(0), 3000);
72
- } catch {
73
- process.exit(0);
74
- }
75
- });
1
+ #!/usr/bin/env node
2
+ /**
3
+ * SolonGate Stop Hook (Stop event)
4
+ * Logs a single ALLOW when Claude responds WITHOUT any tool calls.
5
+ * If tool calls were made, audit.mjs already logged them — this hook skips.
6
+ * Auto-installed by: npx @solongate/proxy login
7
+ */
8
+ import { readFileSync, existsSync, unlinkSync, writeFileSync } from 'node:fs';
9
+ import { resolve, join } from 'node:path';
10
+
11
+ function loadEnvKey(dir) {
12
+ try {
13
+ const envPath = resolve(dir, '.env');
14
+ if (!existsSync(envPath)) return {};
15
+ const lines = readFileSync(envPath, 'utf-8').split('\n');
16
+ const env = {};
17
+ for (const line of lines) {
18
+ const m = line.match(/^([A-Z_]+)=(.*)$/);
19
+ if (m) env[m[1]] = m[2].replace(/^["']|["']$/g, '').trim();
20
+ }
21
+ return env;
22
+ } catch { return {}; }
23
+ }
24
+
25
+ const dotenv = loadEnvKey(process.cwd());
26
+ const API_KEY = process.env.SOLONGATE_API_KEY || dotenv.SOLONGATE_API_KEY || '';
27
+ const API_URL = process.env.SOLONGATE_API_URL || dotenv.SOLONGATE_API_URL || 'https://api.solongate.com';
28
+
29
+ // Agent identity from CLI args: node stop.mjs <agent_id> <agent_name>
30
+ const AGENT_ID = process.argv[2] || 'claude-code';
31
+ const AGENT_NAME = process.argv[3] || 'Claude Code';
32
+
33
+ if (!API_KEY || !API_KEY.startsWith('sg_live_')) process.exit(0);
34
+
35
+ // Flag file: audit.mjs writes this when a tool call was logged in this turn.
36
+ // If the flag exists, tool calls were made → skip (already logged).
37
+ // If the flag doesn't exist, no tool calls → log 1 ALLOW for the text response.
38
+ const flagDir = resolve('.solongate');
39
+ const flagFile = join(flagDir, '.last-tool-call');
40
+
41
+ let input = '';
42
+ process.stdin.on('data', c => input += c);
43
+ process.stdin.on('end', async () => {
44
+ try {
45
+ // Check if tool calls were made in this turn
46
+ if (existsSync(flagFile)) {
47
+ // Tool calls happened → audit.mjs already logged them. Clean up flag.
48
+ try { unlinkSync(flagFile); } catch {}
49
+ process.exit(0);
50
+ }
51
+
52
+ // No tool calls → log 1 ALLOW for the text-only response (fire-and-forget)
53
+ fetch(`${API_URL}/api/v1/audit-logs`, {
54
+ method: 'POST',
55
+ headers: {
56
+ 'Authorization': `Bearer ${API_KEY}`,
57
+ 'Content-Type': 'application/json',
58
+ },
59
+ body: JSON.stringify({
60
+ tool: '_response',
61
+ arguments: {},
62
+ decision: 'ALLOW',
63
+ reason: 'text response (no tool calls)',
64
+ source: `${AGENT_ID}-hook`,
65
+ evaluationTimeMs: 0,
66
+ agent_id: AGENT_ID,
67
+ agent_name: AGENT_NAME,
68
+ }),
69
+ signal: AbortSignal.timeout(5000),
70
+ }).catch(() => {}).finally(() => process.exit(0));
71
+ setTimeout(() => process.exit(0), 3000);
72
+ } catch {
73
+ process.exit(0);
74
+ }
75
+ });
package/package.json CHANGED
@@ -1,77 +1,76 @@
1
- {
2
- "name": "@solongate/proxy",
3
- "version": "0.49.1",
4
- "description": "AI tool security proxy — protect any AI tool server with customizable policies, path/command constraints, rate limiting, and audit logging. Zero code changes required.",
5
- "type": "module",
6
- "bin": {
7
- "solongate": "./dist/index.js",
8
- "solongate-proxy": "./dist/index.js",
9
- "solongate-init": "./dist/init.js",
10
- "solongate-audit": "./dist/audit/index.js",
11
- "proxy": "./dist/index.js"
12
- },
13
- "main": "./dist/lib.js",
14
- "types": "./dist/lib.d.ts",
15
- "exports": {
16
- ".": {
17
- "types": "./dist/lib.d.ts",
18
- "import": "./dist/lib.js"
19
- },
20
- "./cli": {
21
- "types": "./dist/index.d.ts",
22
- "import": "./dist/index.js"
23
- }
24
- },
25
- "files": [
26
- "dist",
27
- "hooks",
28
- "README.md"
29
- ],
30
- "scripts": {
31
- "build": "tsup && pnpm build:types && pnpm build:hooks",
32
- "build:types": "node scripts/build-types.mjs",
33
- "build:hooks": "node scripts/bundle-hooks.mjs",
34
- "dev": "tsx src/index.ts",
35
- "typecheck": "tsc --noEmit",
36
- "clean": "rm -rf dist .turbo"
37
- },
38
- "keywords": [
39
- "ai-tool-security",
40
- "ai-tool-proxy",
41
- "security",
42
- "proxy",
43
- "gateway",
44
- "firewall",
45
- "ai-security",
46
- "tool-security",
47
- "claude",
48
- "openclaw",
49
- "solongate",
50
- "prompt-injection",
51
- "path-traversal",
52
- "rate-limiting"
53
- ],
54
- "author": "SolonGate <hello@solongate.com>",
55
- "license": "MIT",
56
- "homepage": "https://solongate.com",
57
- "repository": {
58
- "type": "git",
59
- "url": "https://github.com/solongate/solongate"
60
- },
61
- "engines": {
62
- "node": ">=18.0.0"
63
- },
64
- "dependencies": {
65
- "@modelcontextprotocol/sdk": "^1.26.0",
66
- "zod": "^3.25.0"
67
- },
68
- "devDependencies": {
69
- "@open-policy-agent/opa-wasm": "^1.10.0",
70
- "chalk": "^5.3.0",
71
- "@solongate/tsconfig": "workspace:*",
72
- "esbuild": "^0.19.12",
73
- "tsup": "^8.3.0",
74
- "tsx": "^4.19.0",
75
- "typescript": "^5.7.0"
76
- }
77
- }
1
+ {
2
+ "name": "@solongate/proxy",
3
+ "version": "0.51.0",
4
+ "description": "AI tool security proxy — protect any AI tool server with customizable policies, path/command constraints, rate limiting, and audit logging. Zero code changes required.",
5
+ "type": "module",
6
+ "bin": {
7
+ "solongate": "./dist/index.js",
8
+ "solongate-proxy": "./dist/index.js",
9
+ "solongate-audit": "./dist/audit/index.js",
10
+ "proxy": "./dist/index.js"
11
+ },
12
+ "main": "./dist/lib.js",
13
+ "types": "./dist/lib.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/lib.d.ts",
17
+ "import": "./dist/lib.js"
18
+ },
19
+ "./cli": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js"
22
+ }
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "hooks",
27
+ "README.md"
28
+ ],
29
+ "scripts": {
30
+ "build": "tsup && pnpm build:types && pnpm build:hooks",
31
+ "build:types": "node scripts/build-types.mjs",
32
+ "build:hooks": "node scripts/bundle-hooks.mjs",
33
+ "dev": "tsx src/index.ts",
34
+ "typecheck": "tsc --noEmit",
35
+ "clean": "rm -rf dist .turbo"
36
+ },
37
+ "keywords": [
38
+ "ai-tool-security",
39
+ "ai-tool-proxy",
40
+ "security",
41
+ "proxy",
42
+ "gateway",
43
+ "firewall",
44
+ "ai-security",
45
+ "tool-security",
46
+ "claude",
47
+ "openclaw",
48
+ "solongate",
49
+ "prompt-injection",
50
+ "path-traversal",
51
+ "rate-limiting"
52
+ ],
53
+ "author": "SolonGate <hello@solongate.com>",
54
+ "license": "MIT",
55
+ "homepage": "https://solongate.com",
56
+ "repository": {
57
+ "type": "git",
58
+ "url": "https://github.com/solongate/solongate"
59
+ },
60
+ "engines": {
61
+ "node": ">=18.0.0"
62
+ },
63
+ "dependencies": {
64
+ "@modelcontextprotocol/sdk": "^1.26.0",
65
+ "zod": "^3.25.0"
66
+ },
67
+ "devDependencies": {
68
+ "@open-policy-agent/opa-wasm": "^1.10.0",
69
+ "chalk": "^5.3.0",
70
+ "@solongate/tsconfig": "workspace:*",
71
+ "esbuild": "^0.19.12",
72
+ "tsup": "^8.3.0",
73
+ "tsx": "^4.19.0",
74
+ "typescript": "^5.7.0"
75
+ }
76
+ }
package/dist/init.d.ts DELETED
@@ -1,18 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * solongate init — Automatically wrap MCP servers with SolonGate protection.
4
- *
5
- * Reads your existing MCP configuration, wraps each server with the
6
- * SolonGate proxy, and writes the protected configuration back.
7
- *
8
- * Usage:
9
- * solongate-init [options]
10
- *
11
- * Options:
12
- * --config <path> Path to MCP config file (default: auto-detect)
13
- * --policy <file> Custom policy JSON file (auto-detects policy.json)
14
- * --all Protect all servers without prompting
15
- * --dry-run Show what would change without writing
16
- * --restore Restore original config from backup
17
- */
18
- export {};