blockintel-gate-sdk 0.3.2 → 0.3.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # BlockIntel Gate SDK
2
2
 
3
- Production-grade TypeScript/Node.js SDK for [BlockIntel Gate](https://blockintel.ai) Hot Path API.
3
+ Production-grade TypeScript/Node.js SDK for [BlockIntel Gate](https://blockintelai.com) Hot Path API.
4
4
 
5
5
  ## Installation
6
6
 
@@ -102,6 +102,47 @@ const response = await gate.evaluate({
102
102
  });
103
103
  ```
104
104
 
105
+ ### Local Development with Gate Local
106
+
107
+ For local development and testing, use **Gate Local** - a Docker container that emulates the Gate Hot Path:
108
+
109
+ ```bash
110
+ # Start Gate Local
111
+ docker pull blockintelai/gate-local:latest
112
+ docker run -d --name gate-local -p 3000:3000 blockintelai/gate-local:latest
113
+ ```
114
+
115
+ Then configure your client for local mode:
116
+
117
+ ```typescript
118
+ import { GateClient } from '@blockintel/gate-sdk';
119
+
120
+ // Local development configuration
121
+ const gate = new GateClient({
122
+ baseUrl: 'http://localhost:3000', // Gate Local endpoint
123
+ tenantId: 'local-dev', // Any tenant ID (ignored in local mode)
124
+ local: true, // Enable local mode (disables auth/heartbeat)
125
+ auth: {
126
+ mode: 'apiKey',
127
+ apiKey: 'local-dev-key' // Any API key (ignored in local mode)
128
+ },
129
+ });
130
+
131
+ // Evaluate transactions locally
132
+ const response = await gate.evaluate({
133
+ txIntent: {
134
+ toAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
135
+ value: '1000000000000000000', // 1 ETH in wei
136
+ valueUsd: 2500.0,
137
+ chainId: 1,
138
+ },
139
+ });
140
+
141
+ console.log(`Decision: ${response.decision}`);
142
+ ```
143
+
144
+ **📚 Full Local Development Guide**: See [Gate Local Quick Start Guide](https://docs.blockintelai.com/gate/local-development) for complete setup instructions, trading bot integration examples, and troubleshooting.
145
+
105
146
  ### Step-Up Polling
106
147
 
107
148
  ```typescript
@@ -159,7 +200,7 @@ When step-up is disabled, the SDK treats `REQUIRE_STEP_UP` as `BLOCK` by default
159
200
 
160
201
  ```bash
161
202
  # Required
162
- GATE_BASE_URL=https://gate.blockintelai.net
203
+ GATE_BASE_URL=https://gate.blockintelai.com
163
204
  GATE_TENANT_ID=your-tenant-id
164
205
 
165
206
  # HMAC Authentication
@@ -353,12 +394,12 @@ The heartbeat manager is automatically configured based on your `GateClientConfi
353
394
 
354
395
  ```typescript
355
396
  const gate = new GateClient({
356
- baseUrl: 'https://gate.blockintelai.net', // Hot Path URL
397
+ baseUrl: 'https://gate.blockintelai.com', // Hot Path URL
357
398
  tenantId: 'your-tenant-id',
358
399
  auth: { mode: 'hmac', ... },
359
400
  // Heartbeat manager uses baseUrl to infer Control Plane URL
360
401
  // Or explicitly set controlPlaneUrl if different
361
- controlPlaneUrl: 'https://control-plane.blockintelai.net', // Optional
402
+ controlPlaneUrl: 'https://control-plane.blockintelai.com', // Optional
362
403
  signerId: 'my-signer-id', // Optional: signerId for heartbeat (if known upfront)
363
404
  heartbeatRefreshIntervalSeconds: 10, // Optional: heartbeat refresh interval (default: 10s)
364
405
  });
@@ -455,13 +496,22 @@ See [examples](./examples) directory for complete examples:
455
496
 
456
497
  See [PUBLISHING.md](./PUBLISHING.md) for detailed publishing instructions.
457
498
 
499
+ **Quick steps:**
500
+ 1. Update version in `package.json`
501
+ 2. Create GitHub release tag
502
+ 3. GitHub Actions publishes to NPM automatically
503
+
458
504
  ## License
459
505
 
460
506
  MIT License - see [LICENSE](./LICENSE) file.
461
507
 
462
508
  ## Support
463
509
 
464
- - **Documentation:** https://docs.blockintel.ai
510
+ - **Documentation:** https://docs.blockintelai.com
465
511
  - **Issues:** https://github.com/4KInc/blockintel-ai/issues
466
- - **Email:** support@blockintel.ai
512
+ - **Email:** support@blockintelai.com
513
+
514
+ ## Keywords
515
+
516
+ blockintel, gate, sdk, defense, crypto, security, transaction, evaluation
467
517
 
package/dist/index.cjs CHANGED
@@ -1250,6 +1250,250 @@ var HeartbeatManager = class {
1250
1250
  }
1251
1251
  };
1252
1252
 
1253
+ // src/security/IamPermissionRiskChecker.ts
1254
+ var IamPermissionRiskChecker = class {
1255
+ options;
1256
+ constructor(options) {
1257
+ this.options = options;
1258
+ }
1259
+ /**
1260
+ * Perform synchronous IAM permission risk check
1261
+ *
1262
+ * Performs quick checks (credentials, environment markers) synchronously.
1263
+ * In HARD mode, throws error if risk detected and override not set.
1264
+ *
1265
+ * Use this for blocking initialization checks.
1266
+ */
1267
+ checkSync() {
1268
+ const checks = [];
1269
+ const credentialsCheck = this.checkAwsCredentials();
1270
+ if (credentialsCheck.hasRisk) {
1271
+ checks.push(credentialsCheck);
1272
+ }
1273
+ const envCheck = this.checkEnvironmentMarkers();
1274
+ if (envCheck.hasRisk) {
1275
+ checks.push(envCheck);
1276
+ }
1277
+ const highestConfidence = this.getHighestConfidence(checks);
1278
+ const highestRisk = checks.find((c) => c.confidence === highestConfidence);
1279
+ if (!highestRisk || !highestRisk.hasRisk) {
1280
+ return {
1281
+ hasRisk: false,
1282
+ confidence: "LOW",
1283
+ details: "No IAM permission risk detected (synchronous check)"
1284
+ };
1285
+ }
1286
+ if (this.options.enforcementMode === "HARD" && !this.options.allowInsecureKmsSignPermission) {
1287
+ const errorMessage = this.buildErrorMessage(highestRisk);
1288
+ throw new Error(errorMessage);
1289
+ }
1290
+ this.logWarning(highestRisk);
1291
+ return highestRisk;
1292
+ }
1293
+ /**
1294
+ * Perform full IAM permission risk check (including async IAM simulation)
1295
+ *
1296
+ * Returns risk assessment with confidence level.
1297
+ * In HARD mode, throws error if risk detected and override not set.
1298
+ */
1299
+ async check() {
1300
+ const syncResult = this.checkSync();
1301
+ const simulationCheck = await this.checkIamSimulation();
1302
+ if (simulationCheck.hasRisk) {
1303
+ if (this.options.enforcementMode === "HARD" && !this.options.allowInsecureKmsSignPermission) {
1304
+ const errorMessage = this.buildErrorMessage(simulationCheck);
1305
+ throw new Error(errorMessage);
1306
+ }
1307
+ this.logWarning(simulationCheck);
1308
+ return simulationCheck;
1309
+ }
1310
+ return syncResult;
1311
+ }
1312
+ /**
1313
+ * Check if AWS credentials are present
1314
+ */
1315
+ checkAwsCredentials() {
1316
+ const hasEnvVars = !!(process.env.AWS_ACCESS_KEY_ID || process.env.AWS_SECRET_ACCESS_KEY || process.env.AWS_SESSION_TOKEN);
1317
+ const hasRoleCredentials = !!(process.env.AWS_ROLE_ARN || process.env.AWS_WEB_IDENTITY_TOKEN_FILE || process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI);
1318
+ if (hasEnvVars || hasRoleCredentials) {
1319
+ return {
1320
+ hasRisk: true,
1321
+ riskType: "AWS_CREDENTIALS_DETECTED",
1322
+ confidence: "MEDIUM",
1323
+ details: "AWS credentials detected in environment. Application may have direct KMS signing permissions.",
1324
+ remediation: "Remove kms:Sign permission from application role. See https://docs.blockintelai.com/gate/IAM_HARDENING"
1325
+ };
1326
+ }
1327
+ return {
1328
+ hasRisk: false,
1329
+ confidence: "LOW",
1330
+ details: "No AWS credentials detected in environment variables"
1331
+ };
1332
+ }
1333
+ /**
1334
+ * Check IAM permissions using simulation API (if available)
1335
+ */
1336
+ async checkIamSimulation() {
1337
+ try {
1338
+ const iamModule = await import('@aws-sdk/client-iam').catch(() => null);
1339
+ if (!iamModule || !iamModule.IAMClient || !iamModule.SimulatePrincipalPolicyCommand) {
1340
+ return {
1341
+ hasRisk: false,
1342
+ confidence: "LOW",
1343
+ details: "AWS SDK not available for IAM simulation"
1344
+ };
1345
+ }
1346
+ const { IAMClient, SimulatePrincipalPolicyCommand } = iamModule;
1347
+ const principalArn = await this.getCurrentPrincipalArn();
1348
+ if (!principalArn) {
1349
+ return {
1350
+ hasRisk: false,
1351
+ confidence: "LOW",
1352
+ details: "Could not determine current principal ARN for simulation"
1353
+ };
1354
+ }
1355
+ const client = new IAMClient({});
1356
+ const command = new SimulatePrincipalPolicyCommand({
1357
+ PolicySourceArn: principalArn,
1358
+ ActionNames: ["kms:Sign"],
1359
+ ResourceArns: this.options.kmsKeyIds?.map((id) => `arn:aws:kms:*:*:key/${id}`) || ["arn:aws:kms:*:*:key/*"]
1360
+ });
1361
+ const response = await client.send(command).catch(() => null);
1362
+ if (!response) {
1363
+ return {
1364
+ hasRisk: false,
1365
+ confidence: "LOW",
1366
+ details: "IAM simulation not available (may require additional permissions)"
1367
+ };
1368
+ }
1369
+ const allowsSign = response.EvaluationResults?.some(
1370
+ (result) => result.EvalDecision === "allowed" || result.EvalDecision === "explicitAllow"
1371
+ );
1372
+ if (allowsSign) {
1373
+ return {
1374
+ hasRisk: true,
1375
+ riskType: "DIRECT_KMS_SIGN_PERMISSION",
1376
+ confidence: "HIGH",
1377
+ details: `IAM simulation confirms principal ${principalArn} has kms:Sign permission. Direct KMS signing can bypass Gate.`,
1378
+ remediation: "Remove kms:Sign permission from application role. See https://docs.blockintelai.com/gate/IAM_HARDENING"
1379
+ };
1380
+ }
1381
+ return {
1382
+ hasRisk: false,
1383
+ confidence: "HIGH",
1384
+ details: "IAM simulation confirms no kms:Sign permission"
1385
+ };
1386
+ } catch (error) {
1387
+ return {
1388
+ hasRisk: false,
1389
+ confidence: "LOW",
1390
+ details: `IAM simulation failed: ${error instanceof Error ? error.message : "Unknown error"}`
1391
+ };
1392
+ }
1393
+ }
1394
+ /**
1395
+ * Check environment markers that suggest direct KMS usage
1396
+ */
1397
+ checkEnvironmentMarkers() {
1398
+ const markers = [
1399
+ "KMS_KEY_ID",
1400
+ "AWS_KMS_KEY_ID",
1401
+ "KMS_KEY_ARN",
1402
+ "AWS_KMS_KEY_ARN"
1403
+ ];
1404
+ const foundMarkers = markers.filter((marker) => process.env[marker]);
1405
+ if (foundMarkers.length > 0) {
1406
+ return {
1407
+ hasRisk: true,
1408
+ riskType: "ENVIRONMENT_MARKERS",
1409
+ confidence: "LOW",
1410
+ details: `Environment markers suggest direct KMS usage: ${foundMarkers.join(", ")}`,
1411
+ remediation: "Review environment variables and ensure KMS access is gated through Gate SDK"
1412
+ };
1413
+ }
1414
+ return {
1415
+ hasRisk: false,
1416
+ confidence: "LOW",
1417
+ details: "No environment markers suggesting direct KMS usage"
1418
+ };
1419
+ }
1420
+ /**
1421
+ * Get current principal ARN (best-effort)
1422
+ */
1423
+ async getCurrentPrincipalArn() {
1424
+ try {
1425
+ const stsModule = await import('@aws-sdk/client-sts').catch(() => null);
1426
+ if (!stsModule || !stsModule.STSClient || !stsModule.GetCallerIdentityCommand) {
1427
+ return null;
1428
+ }
1429
+ const { STSClient, GetCallerIdentityCommand } = stsModule;
1430
+ const client = new STSClient({});
1431
+ const command = new GetCallerIdentityCommand({});
1432
+ const response = await client.send(command).catch(() => null);
1433
+ if (response?.Arn) {
1434
+ return response.Arn;
1435
+ }
1436
+ } catch (error) {
1437
+ }
1438
+ return null;
1439
+ }
1440
+ /**
1441
+ * Get highest confidence level from checks
1442
+ */
1443
+ getHighestConfidence(checks) {
1444
+ if (checks.some((c) => c.confidence === "HIGH")) {
1445
+ return "HIGH";
1446
+ }
1447
+ if (checks.some((c) => c.confidence === "MEDIUM")) {
1448
+ return "MEDIUM";
1449
+ }
1450
+ return "LOW";
1451
+ }
1452
+ /**
1453
+ * Build error message for HARD mode
1454
+ */
1455
+ buildErrorMessage(result) {
1456
+ const parts = [
1457
+ "[GATE ERROR] Hard enforcement mode blocked initialization:",
1458
+ ` - IAM permission risk: ${result.details}`,
1459
+ ` - Risk type: ${result.riskType}`,
1460
+ ` - Confidence: ${result.confidence}`,
1461
+ ` - Tenant ID: ${this.options.tenantId}`
1462
+ ];
1463
+ if (this.options.signerId) {
1464
+ parts.push(` - Signer ID: ${this.options.signerId}`);
1465
+ }
1466
+ if (this.options.environment) {
1467
+ parts.push(` - Environment: ${this.options.environment}`);
1468
+ }
1469
+ if (result.remediation) {
1470
+ parts.push(` - Remediation: ${result.remediation}`);
1471
+ }
1472
+ parts.push(" - See: https://docs.blockintelai.com/gate/IAM_HARDENING");
1473
+ parts.push(` - Override: Set allowInsecureKmsSignPermission=true (not recommended for production)`);
1474
+ return parts.join("\n");
1475
+ }
1476
+ /**
1477
+ * Log warning (SOFT mode or override set)
1478
+ */
1479
+ logWarning(result) {
1480
+ const logData = {
1481
+ level: "WARN",
1482
+ message: "IAM permission risk detected",
1483
+ tenantId: this.options.tenantId,
1484
+ signerId: this.options.signerId,
1485
+ environment: this.options.environment,
1486
+ enforcementMode: this.options.enforcementMode,
1487
+ riskType: result.riskType,
1488
+ confidence: result.confidence,
1489
+ details: result.details,
1490
+ remediation: result.remediation,
1491
+ documentation: "https://docs.blockintelai.com/gate/IAM_HARDENING"
1492
+ };
1493
+ console.warn("[GATE WARNING]", JSON.stringify(logData, null, 2));
1494
+ }
1495
+ };
1496
+
1253
1497
  // src/client/GateClient.ts
1254
1498
  var GateClient = class {
1255
1499
  config;
@@ -1328,6 +1572,39 @@ var GateClient = class {
1328
1572
  });
1329
1573
  this.heartbeatManager.start();
1330
1574
  }
1575
+ if (!config.local) {
1576
+ const enforcementMode = config.enforcementMode || "SOFT";
1577
+ const allowInsecureKmsSignPermission = config.allowInsecureKmsSignPermission ?? enforcementMode === "SOFT";
1578
+ const riskChecker = new IamPermissionRiskChecker({
1579
+ tenantId: config.tenantId,
1580
+ signerId: config.signerId,
1581
+ environment: config.environment,
1582
+ enforcementMode,
1583
+ allowInsecureKmsSignPermission,
1584
+ kmsKeyIds: config.kmsKeyIds
1585
+ });
1586
+ riskChecker.checkSync();
1587
+ this.performIamRiskCheckAsync(riskChecker, enforcementMode).catch((error) => {
1588
+ if (enforcementMode === "SOFT" || allowInsecureKmsSignPermission) {
1589
+ console.warn("[GATE CLIENT] Async IAM risk check warning:", error instanceof Error ? error.message : String(error));
1590
+ } else {
1591
+ console.error("[GATE CLIENT] Async IAM risk check found risk after initialization:", error);
1592
+ }
1593
+ });
1594
+ }
1595
+ }
1596
+ /**
1597
+ * Perform async IAM permission risk check (non-blocking)
1598
+ *
1599
+ * Performs async IAM simulation check in background.
1600
+ * Logs warnings but doesn't block (initialization already completed).
1601
+ */
1602
+ async performIamRiskCheckAsync(riskChecker, enforcementMode) {
1603
+ try {
1604
+ await riskChecker.check();
1605
+ } catch (error) {
1606
+ console.warn("[GATE CLIENT] Async IAM risk check warning:", error instanceof Error ? error.message : String(error));
1607
+ }
1331
1608
  }
1332
1609
  /**
1333
1610
  * Evaluate a transaction defense request