@solongate/proxy 0.47.7 → 0.48.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/dist/cli-utils.d.ts +27 -0
- package/dist/config.d.ts +105 -0
- package/dist/core/capability-token.d.ts +46 -0
- package/dist/core/constants.d.ts +47 -0
- package/dist/core/context-boundary.d.ts +19 -0
- package/dist/core/context.d.ts +24 -0
- package/dist/core/errors.d.ts +51 -0
- package/dist/core/execution.d.ts +35 -0
- package/dist/core/index.d.ts +14 -0
- package/dist/core/input-guard.d.ts +66 -0
- package/dist/core/mcp-types.d.ts +35 -0
- package/dist/core/permissions.d.ts +27 -0
- package/dist/core/policy.d.ts +399 -0
- package/dist/core/response-scanner.d.ts +27 -0
- package/dist/core/schema-validator.d.ts +33 -0
- package/dist/core/tool.d.ts +23 -0
- package/dist/core/trust.d.ts +28 -0
- package/dist/create.d.ts +13 -0
- package/dist/global-install.d.ts +17 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +211 -158
- package/dist/init.d.ts +18 -0
- package/dist/init.js +0 -0
- package/dist/inject.d.ts +19 -0
- package/dist/lib.d.ts +18 -0
- package/dist/lib.js +103 -48
- package/dist/login.d.ts +2 -0
- package/dist/policy-engine/command-matcher.d.ts +34 -0
- package/dist/policy-engine/defaults.d.ts +23 -0
- package/dist/policy-engine/engine.d.ts +30 -0
- package/dist/policy-engine/evaluator.d.ts +13 -0
- package/dist/policy-engine/filename-matcher.d.ts +20 -0
- package/dist/policy-engine/index.d.ts +12 -0
- package/dist/policy-engine/matcher.d.ts +18 -0
- package/dist/policy-engine/opa/index.d.ts +4 -0
- package/dist/policy-engine/opa/json-to-rego.d.ts +2 -0
- package/dist/policy-engine/opa/opa-evaluator.d.ts +10 -0
- package/dist/policy-engine/opa/rego-compiler.d.ts +2 -0
- package/dist/policy-engine/opa/request-adapter.d.ts +17 -0
- package/dist/policy-engine/path-matcher.d.ts +41 -0
- package/dist/policy-engine/policy-store.d.ts +66 -0
- package/dist/policy-engine/url-matcher.d.ts +29 -0
- package/dist/policy-engine/validator.d.ts +7 -0
- package/dist/policy-engine/warnings.d.ts +10 -0
- package/dist/proxy.d.ts +89 -0
- package/dist/pull-push.d.ts +17 -0
- package/dist/sdk/config.d.ts +26 -0
- package/dist/sdk/expiring-set.d.ts +18 -0
- package/dist/sdk/index.d.ts +10 -0
- package/dist/sdk/interceptor.d.ts +45 -0
- package/dist/sdk/logger.d.ts +16 -0
- package/dist/sdk/rate-limiter.d.ts +59 -0
- package/dist/sdk/secure-server.d.ts +68 -0
- package/dist/sdk/server-verifier.d.ts +53 -0
- package/dist/sdk/solongate.d.ts +105 -0
- package/dist/sdk/token-issuer.d.ts +37 -0
- package/dist/sync.d.ts +82 -0
- package/hooks/audit.mjs +3 -1
- package/hooks/guard.bundled.mjs +63 -7
- package/hooks/guard.mjs +75 -14
- package/package.json +15 -13
package/dist/init.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
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 {};
|
package/dist/init.js
CHANGED
|
File without changes
|
package/dist/inject.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* solongate inject — Auto-inject SolonGate SDK into an existing MCP server.
|
|
4
|
+
*
|
|
5
|
+
* Detects a TypeScript MCP server project, installs the SDK, and makes minimal
|
|
6
|
+
* source code changes to add SolonGate protection. Creates a backup so
|
|
7
|
+
* changes can be reverted with --restore.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* solongate-proxy inject [options]
|
|
11
|
+
*
|
|
12
|
+
* Options:
|
|
13
|
+
* --file <path> Entry file to modify (default: auto-detect)
|
|
14
|
+
* --dry-run Preview changes without writing
|
|
15
|
+
* --restore Restore from backup
|
|
16
|
+
* --skip-install Don't install SDK package
|
|
17
|
+
* -h, --help Show help
|
|
18
|
+
*/
|
|
19
|
+
export {};
|
package/dist/lib.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @solongate/proxy — Library exports.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports SDK classes (SolonGate, SecureMcpServer, RateLimiter, etc.)
|
|
5
|
+
* so that external consumers can import from '@solongate/proxy' without
|
|
6
|
+
* needing a separate @solongate/sdk package.
|
|
7
|
+
*/
|
|
8
|
+
export { SolonGate, LicenseError } from './sdk/solongate.js';
|
|
9
|
+
export { SecureMcpServer, type SecureMcpServerOptions } from './sdk/secure-server.js';
|
|
10
|
+
export { interceptToolCall, ExfiltrationChainTracker, type InterceptorOptions } from './sdk/interceptor.js';
|
|
11
|
+
export { resolveConfig, DEFAULT_CONFIG, type SolonGateConfig } from './sdk/config.js';
|
|
12
|
+
export { SecurityLogger } from './sdk/logger.js';
|
|
13
|
+
export { TokenIssuer } from './sdk/token-issuer.js';
|
|
14
|
+
export { ServerVerifier, type SignedMcpRequest, type SignatureValidationResult } from './sdk/server-verifier.js';
|
|
15
|
+
export { RateLimiter, type RateLimitResult } from './sdk/rate-limiter.js';
|
|
16
|
+
export { TrustLevel, Permission, PolicyEffect, type PolicyRule, type PolicySet, type PolicyDecision, type SecurityContext, type ExecutionRequest, type ExecutionResult, type ToolCapability, type McpCallToolParams, type McpCallToolResult, type CapabilityToken, type TokenConfig, type InputGuardConfig, type ThreatType, type DetectedThreat, type SanitizationResult, SolonGateError, PolicyDeniedError, SchemaValidationError, RateLimitError as CoreRateLimitError, InputGuardError, NetworkError, createSecurityContext, createDeniedToolResult, validateToolInput, sanitizeInput, detectPathTraversal, detectShellInjection, detectWildcardAbuse, detectSSRF, detectSQLInjection, detectExfiltration, detectBoundaryEscape, checkLengthLimits, checkEntropyLimits, scanResponse, RESPONSE_WARNING_MARKER, BOUNDARY_PREFIX, BOUNDARY_SUFFIX, tagUserInput, stripBoundaryTags, type ResponseScanConfig, type ResponseThreatType, type ResponseThreat, type ResponseScanResult, type TaggedArguments, } from './core/index.js';
|
|
17
|
+
export { PolicyEngine, PolicyStore, type PolicyVersion, type PolicyDiff, createDefaultDenyPolicySet, createPermissivePolicySet, createReadOnlyPolicySet, } from './policy-engine/index.js';
|
|
18
|
+
export { SolonGateProxy } from './proxy.js';
|
package/dist/lib.js
CHANGED
|
@@ -6150,8 +6150,7 @@ var init_src = __esm({
|
|
|
6150
6150
|
}
|
|
6151
6151
|
});
|
|
6152
6152
|
|
|
6153
|
-
//
|
|
6154
|
-
import { z } from "zod";
|
|
6153
|
+
// src/core/errors.ts
|
|
6155
6154
|
var SolonGateError = class extends Error {
|
|
6156
6155
|
code;
|
|
6157
6156
|
timestamp;
|
|
@@ -6228,11 +6227,16 @@ var NetworkError = class extends SolonGateError {
|
|
|
6228
6227
|
this.name = "NetworkError";
|
|
6229
6228
|
}
|
|
6230
6229
|
};
|
|
6230
|
+
|
|
6231
|
+
// src/core/trust.ts
|
|
6231
6232
|
var TrustLevel = {
|
|
6232
6233
|
UNTRUSTED: "UNTRUSTED",
|
|
6233
6234
|
VERIFIED: "VERIFIED",
|
|
6234
6235
|
TRUSTED: "TRUSTED"
|
|
6235
6236
|
};
|
|
6237
|
+
|
|
6238
|
+
// src/core/permissions.ts
|
|
6239
|
+
import { z } from "zod";
|
|
6236
6240
|
var Permission = {
|
|
6237
6241
|
READ: "READ",
|
|
6238
6242
|
WRITE: "WRITE",
|
|
@@ -6259,50 +6263,55 @@ var NO_PERMISSIONS = Object.freeze(
|
|
|
6259
6263
|
var READ_ONLY = Object.freeze(
|
|
6260
6264
|
/* @__PURE__ */ new Set([Permission.READ])
|
|
6261
6265
|
);
|
|
6266
|
+
|
|
6267
|
+
// src/core/policy.ts
|
|
6268
|
+
import { z as z2 } from "zod";
|
|
6262
6269
|
var PolicyEffect = {
|
|
6263
6270
|
ALLOW: "ALLOW",
|
|
6264
6271
|
DENY: "DENY"
|
|
6265
6272
|
};
|
|
6266
|
-
var PolicyRuleSchema =
|
|
6267
|
-
id:
|
|
6268
|
-
description:
|
|
6269
|
-
effect:
|
|
6270
|
-
priority:
|
|
6271
|
-
toolPattern:
|
|
6272
|
-
permission:
|
|
6273
|
-
minimumTrustLevel:
|
|
6274
|
-
argumentConstraints:
|
|
6275
|
-
pathConstraints:
|
|
6276
|
-
allowed:
|
|
6277
|
-
denied:
|
|
6278
|
-
rootDirectory:
|
|
6279
|
-
allowSymlinks:
|
|
6273
|
+
var PolicyRuleSchema = z2.object({
|
|
6274
|
+
id: z2.string().min(1).max(256),
|
|
6275
|
+
description: z2.string().max(1024),
|
|
6276
|
+
effect: z2.enum(["ALLOW", "DENY"]),
|
|
6277
|
+
priority: z2.number().int().min(0).max(1e4).default(1e3),
|
|
6278
|
+
toolPattern: z2.string().min(1).max(512),
|
|
6279
|
+
permission: z2.enum(["READ", "WRITE", "EXECUTE", "NETWORK"]).optional(),
|
|
6280
|
+
minimumTrustLevel: z2.enum(["UNTRUSTED", "VERIFIED", "TRUSTED"]),
|
|
6281
|
+
argumentConstraints: z2.record(z2.unknown()).optional(),
|
|
6282
|
+
pathConstraints: z2.object({
|
|
6283
|
+
allowed: z2.array(z2.string()).optional(),
|
|
6284
|
+
denied: z2.array(z2.string()).optional(),
|
|
6285
|
+
rootDirectory: z2.string().optional(),
|
|
6286
|
+
allowSymlinks: z2.boolean().optional()
|
|
6280
6287
|
}).optional(),
|
|
6281
|
-
commandConstraints:
|
|
6282
|
-
allowed:
|
|
6283
|
-
denied:
|
|
6288
|
+
commandConstraints: z2.object({
|
|
6289
|
+
allowed: z2.array(z2.string()).optional(),
|
|
6290
|
+
denied: z2.array(z2.string()).optional()
|
|
6284
6291
|
}).optional(),
|
|
6285
|
-
filenameConstraints:
|
|
6286
|
-
allowed:
|
|
6287
|
-
denied:
|
|
6292
|
+
filenameConstraints: z2.object({
|
|
6293
|
+
allowed: z2.array(z2.string()).optional(),
|
|
6294
|
+
denied: z2.array(z2.string()).optional()
|
|
6288
6295
|
}).optional(),
|
|
6289
|
-
urlConstraints:
|
|
6290
|
-
allowed:
|
|
6291
|
-
denied:
|
|
6296
|
+
urlConstraints: z2.object({
|
|
6297
|
+
allowed: z2.array(z2.string()).optional(),
|
|
6298
|
+
denied: z2.array(z2.string()).optional()
|
|
6292
6299
|
}).optional(),
|
|
6293
|
-
enabled:
|
|
6294
|
-
createdAt:
|
|
6295
|
-
updatedAt:
|
|
6300
|
+
enabled: z2.boolean().default(true),
|
|
6301
|
+
createdAt: z2.string().datetime(),
|
|
6302
|
+
updatedAt: z2.string().datetime()
|
|
6296
6303
|
});
|
|
6297
|
-
var PolicySetSchema =
|
|
6298
|
-
id:
|
|
6299
|
-
name:
|
|
6300
|
-
description:
|
|
6301
|
-
version:
|
|
6302
|
-
rules:
|
|
6303
|
-
createdAt:
|
|
6304
|
-
updatedAt:
|
|
6304
|
+
var PolicySetSchema = z2.object({
|
|
6305
|
+
id: z2.string().min(1).max(256),
|
|
6306
|
+
name: z2.string().min(1).max(256),
|
|
6307
|
+
description: z2.string().max(2048),
|
|
6308
|
+
version: z2.number().int().min(0),
|
|
6309
|
+
rules: z2.array(PolicyRuleSchema),
|
|
6310
|
+
createdAt: z2.string().datetime(),
|
|
6311
|
+
updatedAt: z2.string().datetime()
|
|
6305
6312
|
});
|
|
6313
|
+
|
|
6314
|
+
// src/core/context.ts
|
|
6306
6315
|
function createSecurityContext(params) {
|
|
6307
6316
|
return {
|
|
6308
6317
|
trustLevel: "UNTRUSTED",
|
|
@@ -6313,6 +6322,8 @@ function createSecurityContext(params) {
|
|
|
6313
6322
|
...params
|
|
6314
6323
|
};
|
|
6315
6324
|
}
|
|
6325
|
+
|
|
6326
|
+
// src/core/constants.ts
|
|
6316
6327
|
var DEFAULT_POLICY_EFFECT = "DENY";
|
|
6317
6328
|
var MAX_RULES_PER_POLICY_SET = 1e3;
|
|
6318
6329
|
var MAX_ARGUMENT_DEPTH = 10;
|
|
@@ -6333,6 +6344,8 @@ var UNSAFE_CONFIGURATION_WARNINGS = {
|
|
|
6333
6344
|
RATE_LIMIT_ZERO: "A rate limit of 0 means unlimited calls. This removes protection against runaway loops.",
|
|
6334
6345
|
DISABLED_VALIDATION: "Disabling schema validation removes input sanitization protections."
|
|
6335
6346
|
};
|
|
6347
|
+
|
|
6348
|
+
// src/core/mcp-types.ts
|
|
6336
6349
|
function createDeniedToolResult(reason) {
|
|
6337
6350
|
return {
|
|
6338
6351
|
content: [
|
|
@@ -6348,6 +6361,9 @@ function createDeniedToolResult(reason) {
|
|
|
6348
6361
|
isError: true
|
|
6349
6362
|
};
|
|
6350
6363
|
}
|
|
6364
|
+
|
|
6365
|
+
// src/core/schema-validator.ts
|
|
6366
|
+
import { z as z3 } from "zod";
|
|
6351
6367
|
var DEFAULT_OPTIONS = {
|
|
6352
6368
|
maxDepth: MAX_ARGUMENT_DEPTH,
|
|
6353
6369
|
maxSizeBytes: MAX_ARGUMENTS_SIZE_BYTES,
|
|
@@ -6423,6 +6439,8 @@ function measureDepth(value, currentDepth) {
|
|
|
6423
6439
|
}
|
|
6424
6440
|
return maxChildDepth;
|
|
6425
6441
|
}
|
|
6442
|
+
|
|
6443
|
+
// src/core/input-guard.ts
|
|
6426
6444
|
var DEFAULT_INPUT_GUARD_CONFIG = Object.freeze({
|
|
6427
6445
|
pathTraversal: true,
|
|
6428
6446
|
shellInjection: true,
|
|
@@ -6797,6 +6815,8 @@ function sanitizeObject(basePath, obj, config) {
|
|
|
6797
6815
|
function truncate(str, maxLen) {
|
|
6798
6816
|
return str.length > maxLen ? str.slice(0, maxLen) + "..." : str;
|
|
6799
6817
|
}
|
|
6818
|
+
|
|
6819
|
+
// src/core/response-scanner.ts
|
|
6800
6820
|
var DEFAULT_RESPONSE_SCAN_CONFIG = Object.freeze({
|
|
6801
6821
|
injectedInstruction: true,
|
|
6802
6822
|
hiddenDirective: true,
|
|
@@ -6906,6 +6926,8 @@ var RESPONSE_WARNING_MARKER = "[SOLONGATE WARNING: response may contain injected
|
|
|
6906
6926
|
function truncate2(str, maxLen) {
|
|
6907
6927
|
return str.length > maxLen ? str.slice(0, maxLen) + "..." : str;
|
|
6908
6928
|
}
|
|
6929
|
+
|
|
6930
|
+
// src/core/context-boundary.ts
|
|
6909
6931
|
function tagUserInput(args) {
|
|
6910
6932
|
return tagObject(args);
|
|
6911
6933
|
}
|
|
@@ -6931,13 +6953,13 @@ function tagObject(obj) {
|
|
|
6931
6953
|
function stripBoundaryTags(text) {
|
|
6932
6954
|
return text.replaceAll(BOUNDARY_PREFIX, "").replaceAll(BOUNDARY_SUFFIX, "");
|
|
6933
6955
|
}
|
|
6956
|
+
|
|
6957
|
+
// src/core/capability-token.ts
|
|
6934
6958
|
var DEFAULT_TOKEN_TTL_SECONDS = 30;
|
|
6935
6959
|
var TOKEN_ALGORITHM = "HS256";
|
|
6936
6960
|
var MIN_SECRET_LENGTH = 32;
|
|
6937
6961
|
|
|
6938
|
-
//
|
|
6939
|
-
import { gunzipSync } from "zlib";
|
|
6940
|
-
import { createHash, randomUUID } from "crypto";
|
|
6962
|
+
// src/policy-engine/validator.ts
|
|
6941
6963
|
function validatePolicySet(input) {
|
|
6942
6964
|
const errors = [];
|
|
6943
6965
|
const warnings = [];
|
|
@@ -6987,6 +7009,8 @@ function validatePolicySet(input) {
|
|
|
6987
7009
|
warnings
|
|
6988
7010
|
};
|
|
6989
7011
|
}
|
|
7012
|
+
|
|
7013
|
+
// src/policy-engine/warnings.ts
|
|
6990
7014
|
function analyzeSecurityWarnings(policySet) {
|
|
6991
7015
|
const warnings = [];
|
|
6992
7016
|
for (const rule of policySet.rules) {
|
|
@@ -7028,6 +7052,8 @@ function analyzeRuleWarnings(rule) {
|
|
|
7028
7052
|
}
|
|
7029
7053
|
return warnings;
|
|
7030
7054
|
}
|
|
7055
|
+
|
|
7056
|
+
// src/policy-engine/defaults.ts
|
|
7031
7057
|
function createDefaultDenyPolicySet() {
|
|
7032
7058
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7033
7059
|
return {
|
|
@@ -7151,6 +7177,11 @@ function createReadOnlyPolicySet(toolPattern) {
|
|
|
7151
7177
|
updatedAt: now
|
|
7152
7178
|
};
|
|
7153
7179
|
}
|
|
7180
|
+
|
|
7181
|
+
// src/policy-engine/opa/opa-evaluator.ts
|
|
7182
|
+
import { gunzipSync } from "zlib";
|
|
7183
|
+
|
|
7184
|
+
// src/policy-engine/path-matcher.ts
|
|
7154
7185
|
var PATH_FIELDS = /* @__PURE__ */ new Set([
|
|
7155
7186
|
"path",
|
|
7156
7187
|
"file",
|
|
@@ -7197,6 +7228,8 @@ function extractPathArguments(args) {
|
|
|
7197
7228
|
}
|
|
7198
7229
|
return paths;
|
|
7199
7230
|
}
|
|
7231
|
+
|
|
7232
|
+
// src/policy-engine/command-matcher.ts
|
|
7200
7233
|
var COMMAND_FIELDS = /* @__PURE__ */ new Set([
|
|
7201
7234
|
"command",
|
|
7202
7235
|
"cmd",
|
|
@@ -7318,6 +7351,8 @@ function extractCommandArguments(args) {
|
|
|
7318
7351
|
commands.push(...expanded);
|
|
7319
7352
|
return commands;
|
|
7320
7353
|
}
|
|
7354
|
+
|
|
7355
|
+
// src/policy-engine/url-matcher.ts
|
|
7321
7356
|
var URL_FIELDS = /* @__PURE__ */ new Set([
|
|
7322
7357
|
"url",
|
|
7323
7358
|
"href",
|
|
@@ -7372,6 +7407,8 @@ function extractUrlArguments(args) {
|
|
|
7372
7407
|
}
|
|
7373
7408
|
return urls;
|
|
7374
7409
|
}
|
|
7410
|
+
|
|
7411
|
+
// src/policy-engine/filename-matcher.ts
|
|
7375
7412
|
var SENSITIVE_FILENAMES = [
|
|
7376
7413
|
".env",
|
|
7377
7414
|
".env.local",
|
|
@@ -7559,6 +7596,8 @@ function looksLikeFilename(s) {
|
|
|
7559
7596
|
if (KNOWN_EXTENSIONLESS_FILES.has(s.toLowerCase())) return true;
|
|
7560
7597
|
return false;
|
|
7561
7598
|
}
|
|
7599
|
+
|
|
7600
|
+
// src/policy-engine/opa/request-adapter.ts
|
|
7562
7601
|
function toOpaInput(request) {
|
|
7563
7602
|
const args = request.arguments ?? {};
|
|
7564
7603
|
return {
|
|
@@ -7572,6 +7611,8 @@ function toOpaInput(request) {
|
|
|
7572
7611
|
filenames: extractFilenames(args)
|
|
7573
7612
|
};
|
|
7574
7613
|
}
|
|
7614
|
+
|
|
7615
|
+
// src/policy-engine/opa/opa-evaluator.ts
|
|
7575
7616
|
var loadPolicyFn = null;
|
|
7576
7617
|
async function getLoadPolicy() {
|
|
7577
7618
|
if (!loadPolicyFn) {
|
|
@@ -7674,6 +7715,8 @@ var OpaEvaluator = class {
|
|
|
7674
7715
|
this.policy.setData(data);
|
|
7675
7716
|
}
|
|
7676
7717
|
};
|
|
7718
|
+
|
|
7719
|
+
// src/policy-engine/engine.ts
|
|
7677
7720
|
var PolicyEngine = class {
|
|
7678
7721
|
policySet;
|
|
7679
7722
|
timeoutMs;
|
|
@@ -7776,11 +7819,16 @@ var PolicyEngine = class {
|
|
|
7776
7819
|
this.policySet = createDefaultDenyPolicySet();
|
|
7777
7820
|
}
|
|
7778
7821
|
};
|
|
7822
|
+
|
|
7823
|
+
// src/policy-engine/matcher.ts
|
|
7779
7824
|
var TRUST_LEVEL_ORDER = {
|
|
7780
7825
|
[TrustLevel.UNTRUSTED]: 0,
|
|
7781
7826
|
[TrustLevel.VERIFIED]: 1,
|
|
7782
7827
|
[TrustLevel.TRUSTED]: 2
|
|
7783
7828
|
};
|
|
7829
|
+
|
|
7830
|
+
// src/policy-engine/policy-store.ts
|
|
7831
|
+
import { createHash } from "crypto";
|
|
7784
7832
|
function stableStringify(val) {
|
|
7785
7833
|
return JSON.stringify(
|
|
7786
7834
|
val,
|
|
@@ -7882,6 +7930,13 @@ var PolicyStore = class {
|
|
|
7882
7930
|
}
|
|
7883
7931
|
};
|
|
7884
7932
|
|
|
7933
|
+
// src/policy-engine/opa/rego-compiler.ts
|
|
7934
|
+
import { execFileSync } from "child_process";
|
|
7935
|
+
import { writeFileSync, readFileSync, mkdirSync, rmSync } from "fs";
|
|
7936
|
+
import { join } from "path";
|
|
7937
|
+
import { tmpdir } from "os";
|
|
7938
|
+
import { randomUUID } from "crypto";
|
|
7939
|
+
|
|
7885
7940
|
// src/sdk/config.ts
|
|
7886
7941
|
var DEFAULT_CONFIG = Object.freeze({
|
|
7887
7942
|
validateSchemas: true,
|
|
@@ -8935,13 +8990,13 @@ import {
|
|
|
8935
8990
|
ListResourceTemplatesRequestSchema
|
|
8936
8991
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
8937
8992
|
import { createServer as createHttpServer } from "http";
|
|
8938
|
-
import { resolve as resolve2, join as
|
|
8939
|
-
import { mkdirSync as
|
|
8993
|
+
import { resolve as resolve2, join as join3 } from "path";
|
|
8994
|
+
import { mkdirSync as mkdirSync3, appendFileSync } from "fs";
|
|
8940
8995
|
|
|
8941
8996
|
// src/config.ts
|
|
8942
|
-
import { readFileSync, existsSync } from "fs";
|
|
8997
|
+
import { readFileSync as readFileSync2, existsSync } from "fs";
|
|
8943
8998
|
import { appendFile } from "fs/promises";
|
|
8944
|
-
import { resolve, join } from "path";
|
|
8999
|
+
import { resolve, join as join2 } from "path";
|
|
8945
9000
|
import { homedir } from "os";
|
|
8946
9001
|
var DEFAULT_API_URL = "https://api.solongate.com";
|
|
8947
9002
|
async function fetchCloudPolicy(apiKey, apiUrl, policyId) {
|
|
@@ -9041,7 +9096,7 @@ async function sendAuditLog(apiKey, apiUrl, entry) {
|
|
|
9041
9096
|
}
|
|
9042
9097
|
|
|
9043
9098
|
// src/sync.ts
|
|
9044
|
-
import { readFileSync as
|
|
9099
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, watch, existsSync as existsSync2 } from "fs";
|
|
9045
9100
|
var log = (...args) => process.stderr.write(`[SolonGate Sync] ${args.map(String).join(" ")}
|
|
9046
9101
|
`);
|
|
9047
9102
|
var PolicySyncManager = class {
|
|
@@ -9130,7 +9185,7 @@ var PolicySyncManager = class {
|
|
|
9130
9185
|
log("Policy file deleted \u2014 keeping current policy");
|
|
9131
9186
|
return;
|
|
9132
9187
|
}
|
|
9133
|
-
const content =
|
|
9188
|
+
const content = readFileSync3(filePath, "utf-8");
|
|
9134
9189
|
const newPolicy = JSON.parse(content);
|
|
9135
9190
|
if (newPolicy.version <= this.localVersion) {
|
|
9136
9191
|
newPolicy.version = Math.max(this.localVersion, this.cloudVersion) + 1;
|
|
@@ -9239,7 +9294,7 @@ var PolicySyncManager = class {
|
|
|
9239
9294
|
try {
|
|
9240
9295
|
const { id: _id, ...rest } = policy;
|
|
9241
9296
|
const json = JSON.stringify(rest, null, 2) + "\n";
|
|
9242
|
-
|
|
9297
|
+
writeFileSync2(this.localPath, json, "utf-8");
|
|
9243
9298
|
} catch (err) {
|
|
9244
9299
|
log(`File write error: ${err instanceof Error ? err.message : String(err)}`);
|
|
9245
9300
|
}
|
|
@@ -9516,8 +9571,8 @@ var SolonGateProxy = class {
|
|
|
9516
9571
|
pid: process.pid
|
|
9517
9572
|
};
|
|
9518
9573
|
const debugDir = resolve2(".solongate");
|
|
9519
|
-
|
|
9520
|
-
appendFileSync(
|
|
9574
|
+
mkdirSync3(debugDir, { recursive: true });
|
|
9575
|
+
appendFileSync(join3(debugDir, ".debug-proxy"), JSON.stringify(debugInfo) + "\n");
|
|
9521
9576
|
} catch {
|
|
9522
9577
|
}
|
|
9523
9578
|
if (clientVersion?.name && !this.config.agentName) {
|
package/dist/login.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { PolicyRule } from '../core/index.js';
|
|
2
|
+
type CommandConstraints = NonNullable<PolicyRule['commandConstraints']>;
|
|
3
|
+
/**
|
|
4
|
+
* Extracts inner commands from subshell wrappers (bash -c, eval, etc.)
|
|
5
|
+
* Returns the original command plus any extracted inner commands.
|
|
6
|
+
*/
|
|
7
|
+
export declare function extractInnerCommands(command: string, depth?: number): string[];
|
|
8
|
+
/**
|
|
9
|
+
* Extracts command-like arguments from tool call arguments.
|
|
10
|
+
* Uses known field names plus heuristic detection for command-like strings
|
|
11
|
+
* in any field, and recurses into nested objects/arrays.
|
|
12
|
+
*/
|
|
13
|
+
export declare function extractCommandArguments(args: Readonly<Record<string, unknown>>): string[];
|
|
14
|
+
/**
|
|
15
|
+
* Glob-style command pattern matching.
|
|
16
|
+
* Matches against the command string (first word) or full command line.
|
|
17
|
+
*
|
|
18
|
+
* Patterns:
|
|
19
|
+
* 'ls' → exact match on command name
|
|
20
|
+
* 'git*' → command starts with 'git'
|
|
21
|
+
* '*sql*' → command contains 'sql'
|
|
22
|
+
* 'rm -rf *' → full command line starts with 'rm -rf '
|
|
23
|
+
*/
|
|
24
|
+
export declare function matchCommandPattern(command: string, pattern: string): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Checks if a command is allowed by the given constraints.
|
|
27
|
+
*
|
|
28
|
+
* Evaluation order:
|
|
29
|
+
* 1. If denied list exists, command must NOT match any denied pattern
|
|
30
|
+
* 2. If allowed list exists, command must match at least one allowed pattern
|
|
31
|
+
* 3. If neither list exists, command is allowed (constraints are optional)
|
|
32
|
+
*/
|
|
33
|
+
export declare function isCommandAllowed(command: string, constraints: CommandConstraints): boolean;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { PolicySet } from '../core/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Creates the default "deny all" policy set.
|
|
4
|
+
* This is the starting policy for any new SolonGate deployment.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createDefaultDenyPolicySet(): PolicySet;
|
|
7
|
+
/**
|
|
8
|
+
* Creates a permissive "allow all" policy set.
|
|
9
|
+
* Allows all tool executions — useful for development or when
|
|
10
|
+
* using SolonGate only for monitoring and audit logging.
|
|
11
|
+
*/
|
|
12
|
+
export declare function createPermissivePolicySet(): PolicySet;
|
|
13
|
+
/**
|
|
14
|
+
* Creates a read-only policy set for a specific tool pattern.
|
|
15
|
+
* Allows reads for VERIFIED requests only.
|
|
16
|
+
*/
|
|
17
|
+
export declare function createReadOnlyPolicySet(toolPattern: string): PolicySet;
|
|
18
|
+
/**
|
|
19
|
+
* Creates a sandboxed policy set for a given root directory.
|
|
20
|
+
* Allows file operations within rootDir, blocks dangerous commands,
|
|
21
|
+
* denies access to sensitive files.
|
|
22
|
+
*/
|
|
23
|
+
export declare function createSandboxedPolicySet(rootDir: string): PolicySet;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { PolicySet, PolicyDecision, ExecutionRequest } from '../core/index.js';
|
|
2
|
+
import { type ValidationResult } from './validator.js';
|
|
3
|
+
import { type SecurityWarning } from './warnings.js';
|
|
4
|
+
import { PolicyStore, type PolicyVersion } from './policy-store.js';
|
|
5
|
+
export declare class PolicyEngine {
|
|
6
|
+
private policySet;
|
|
7
|
+
private readonly timeoutMs;
|
|
8
|
+
private readonly store;
|
|
9
|
+
private opaEvaluator;
|
|
10
|
+
constructor(options?: {
|
|
11
|
+
policySet?: PolicySet;
|
|
12
|
+
timeoutMs?: number;
|
|
13
|
+
store?: PolicyStore;
|
|
14
|
+
wasmBundle?: BufferSource;
|
|
15
|
+
});
|
|
16
|
+
private _pendingWasm;
|
|
17
|
+
initOpa(): Promise<void>;
|
|
18
|
+
loadWasmBundle(wasmBundle: BufferSource): Promise<void>;
|
|
19
|
+
evaluate(request: ExecutionRequest): PolicyDecision;
|
|
20
|
+
getEvaluatorMode(): 'opa' | 'opa-unloaded';
|
|
21
|
+
loadPolicySet(policySet: PolicySet, options?: {
|
|
22
|
+
reason?: string;
|
|
23
|
+
createdBy?: string;
|
|
24
|
+
}): ValidationResult;
|
|
25
|
+
rollback(version: number): PolicyVersion;
|
|
26
|
+
getPolicySet(): Readonly<PolicySet>;
|
|
27
|
+
getSecurityWarnings(): readonly SecurityWarning[];
|
|
28
|
+
getStore(): PolicyStore | null;
|
|
29
|
+
reset(): void;
|
|
30
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PolicySet, PolicyDecision, ExecutionRequest } from '../core/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Evaluates a policy set against an execution request.
|
|
4
|
+
*
|
|
5
|
+
* Pure function: no side effects, no I/O, fully deterministic.
|
|
6
|
+
*
|
|
7
|
+
* Algorithm:
|
|
8
|
+
* 1. Sort rules by priority (ascending - lower number = higher priority)
|
|
9
|
+
* 2. Find the first matching rule
|
|
10
|
+
* 3. If a rule matches, return its effect
|
|
11
|
+
* 4. If no rule matches, return DENY (default-deny)
|
|
12
|
+
*/
|
|
13
|
+
export declare function evaluatePolicy(policySet: PolicySet, request: ExecutionRequest): PolicyDecision;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { PolicyRule } from '../core/index.js';
|
|
2
|
+
type FilenameConstraints = NonNullable<PolicyRule['filenameConstraints']>;
|
|
3
|
+
/**
|
|
4
|
+
* Extracts filenames from ALL string arguments using shell-agnostic scanning.
|
|
5
|
+
*
|
|
6
|
+
* Architecture: OS-permission style enforcement.
|
|
7
|
+
* Instead of trying to parse every shell trick, we strip ALL shell syntax
|
|
8
|
+
* and scan the raw text. If a protected filename appears in ANY form,
|
|
9
|
+
* it gets extracted and checked against policy constraints.
|
|
10
|
+
*/
|
|
11
|
+
export declare function extractFilenames(args: Readonly<Record<string, unknown>>): string[];
|
|
12
|
+
/**
|
|
13
|
+
* Glob-style filename pattern matching (case-insensitive).
|
|
14
|
+
*/
|
|
15
|
+
export declare function matchFilenamePattern(filename: string, pattern: string): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Checks if a filename is allowed by the given constraints.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isFilenameAllowed(filename: string, constraints: FilenameConstraints): boolean;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { PolicyEngine } from './engine.js';
|
|
2
|
+
export { evaluatePolicy } from './evaluator.js';
|
|
3
|
+
export { ruleMatchesRequest, toolPatternMatches, trustLevelMeetsMinimum } from './matcher.js';
|
|
4
|
+
export { validatePolicyRule, validatePolicySet, type ValidationResult } from './validator.js';
|
|
5
|
+
export { analyzeSecurityWarnings, type SecurityWarning } from './warnings.js';
|
|
6
|
+
export { createDefaultDenyPolicySet, createPermissivePolicySet, createReadOnlyPolicySet, createSandboxedPolicySet } from './defaults.js';
|
|
7
|
+
export { isPathAllowed, isWithinRoot, matchPathPattern, normalizePath, extractPathArguments, } from './path-matcher.js';
|
|
8
|
+
export { isCommandAllowed, matchCommandPattern, extractCommandArguments, } from './command-matcher.js';
|
|
9
|
+
export { isFilenameAllowed, matchFilenamePattern, extractFilenames, } from './filename-matcher.js';
|
|
10
|
+
export { isUrlAllowed, matchUrlPattern, extractUrlArguments, } from './url-matcher.js';
|
|
11
|
+
export { PolicyStore, type PolicyVersion, type PolicyDiff } from './policy-store.js';
|
|
12
|
+
export { OpaEvaluator, convertPolicySetToRego, compileRegoToWasm, isOpaAvailable, toOpaInput, type OpaInput, type OpaDecision } from './opa/index.js';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { PolicyRule, ExecutionRequest } from '../core/index.js';
|
|
2
|
+
import { TrustLevel } from '../core/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Pure function: determines if a policy rule matches an execution request.
|
|
5
|
+
* No side effects. No I/O. Fully deterministic.
|
|
6
|
+
*/
|
|
7
|
+
export declare function ruleMatchesRequest(rule: PolicyRule, request: ExecutionRequest): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Glob-style tool name pattern matching.
|
|
10
|
+
* Supports:
|
|
11
|
+
* '*' → match all
|
|
12
|
+
* 'prefix*' → starts with prefix
|
|
13
|
+
* '*suffix' → ends with suffix
|
|
14
|
+
* '*infix*' → contains infix
|
|
15
|
+
* Does NOT support regex (ReDoS prevention).
|
|
16
|
+
*/
|
|
17
|
+
export declare function toolPatternMatches(pattern: string, toolName: string): boolean;
|
|
18
|
+
export declare function trustLevelMeetsMinimum(actual: TrustLevel, minimum: TrustLevel): boolean;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PolicyDecision, ExecutionRequest } from '../../core/index.js';
|
|
2
|
+
export declare class OpaEvaluator {
|
|
3
|
+
private policy;
|
|
4
|
+
private initialized;
|
|
5
|
+
loadBundle(wasmBundle: BufferSource): Promise<void>;
|
|
6
|
+
loadWasm(wasmBytes: BufferSource): Promise<void>;
|
|
7
|
+
evaluate(request: ExecutionRequest): PolicyDecision;
|
|
8
|
+
isReady(): boolean;
|
|
9
|
+
setData(data: unknown): void;
|
|
10
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ExecutionRequest } from '../../core/index.js';
|
|
2
|
+
export interface OpaInput {
|
|
3
|
+
tool_name: string;
|
|
4
|
+
permission: string;
|
|
5
|
+
trust_level: string;
|
|
6
|
+
arguments: Record<string, unknown>;
|
|
7
|
+
paths: string[];
|
|
8
|
+
commands: string[];
|
|
9
|
+
urls: string[];
|
|
10
|
+
filenames: string[];
|
|
11
|
+
}
|
|
12
|
+
export interface OpaDecision {
|
|
13
|
+
effect: 'ALLOW' | 'DENY';
|
|
14
|
+
reason: string;
|
|
15
|
+
matched_rule: string | null;
|
|
16
|
+
}
|
|
17
|
+
export declare function toOpaInput(request: ExecutionRequest): OpaInput;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { PolicyRule } from '../core/index.js';
|
|
2
|
+
type PathConstraints = NonNullable<PolicyRule['pathConstraints']>;
|
|
3
|
+
/**
|
|
4
|
+
* Normalizes a file path for consistent matching.
|
|
5
|
+
* Resolves . and .. segments, normalizes separators.
|
|
6
|
+
*/
|
|
7
|
+
export declare function normalizePath(path: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Checks if a path is within a root directory (sandbox boundary).
|
|
10
|
+
* Prevents escaping via .., symlinks, etc.
|
|
11
|
+
*/
|
|
12
|
+
export declare function isWithinRoot(path: string, root: string): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Glob-style path pattern matching.
|
|
15
|
+
* Supports:
|
|
16
|
+
* - * matches any single path segment (not /)
|
|
17
|
+
* - ** matches any number of path segments
|
|
18
|
+
* - Exact match
|
|
19
|
+
*
|
|
20
|
+
* Does NOT support regex (ReDoS prevention).
|
|
21
|
+
*/
|
|
22
|
+
export declare function matchPathPattern(path: string, pattern: string): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Checks if a path is allowed by the given constraints.
|
|
25
|
+
*
|
|
26
|
+
* Evaluation order:
|
|
27
|
+
* 1. If rootDirectory is set, path must be within it
|
|
28
|
+
* 2. If denied list exists, path must NOT match any denied pattern
|
|
29
|
+
* 3. If allowed list exists, path must match at least one allowed pattern
|
|
30
|
+
* 4. If neither list exists, path is allowed (constraints are optional)
|
|
31
|
+
*/
|
|
32
|
+
export declare function isPathAllowed(path: string, constraints: PathConstraints): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Extracts path-like arguments from tool call arguments.
|
|
35
|
+
* Uses multiple heuristics:
|
|
36
|
+
* 1. Known path field names — always extract
|
|
37
|
+
* 2. Strings containing / or \ (original heuristic)
|
|
38
|
+
* 3. Strings starting with . (.env, ./foo)
|
|
39
|
+
*/
|
|
40
|
+
export declare function extractPathArguments(args: Readonly<Record<string, unknown>>): string[];
|
|
41
|
+
export {};
|