@node9/proxy 1.14.0 → 1.14.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.js CHANGED
@@ -3674,14 +3674,46 @@ var init_native = __esm({
3674
3674
  });
3675
3675
 
3676
3676
  // src/auth/cloud.ts
3677
- function auditLocalAllow(toolName, args, checkedBy, creds, meta) {
3678
- return fetch(`${creds.apiUrl}/audit`, {
3677
+ function validateApiUrl(raw) {
3678
+ let u;
3679
+ try {
3680
+ u = new URL(raw);
3681
+ } catch {
3682
+ return null;
3683
+ }
3684
+ if (u.username || u.password) return null;
3685
+ if (u.protocol === "https:") return u;
3686
+ if (u.protocol === "http:") {
3687
+ const h = u.hostname;
3688
+ if (h === "127.0.0.1" || h === "localhost" || h === "::1" || h === "[::1]") return u;
3689
+ }
3690
+ return null;
3691
+ }
3692
+ function auditLocalAllow(toolName, args, checkedBy, creds, meta, dlpInfo, containsSensitiveArgs = false) {
3693
+ const validated = validateApiUrl(creds.apiUrl);
3694
+ if (!validated) {
3695
+ try {
3696
+ import_fs10.default.appendFileSync(
3697
+ HOOK_DEBUG_LOG,
3698
+ `[audit] refused to send: invalid apiUrl scheme/host (got "${String(creds.apiUrl).slice(0, 200)}")
3699
+ `
3700
+ );
3701
+ } catch {
3702
+ }
3703
+ return Promise.resolve();
3704
+ }
3705
+ const safeArgs = containsSensitiveArgs ? { tool: toolName, redacted: true } : args;
3706
+ const dlpSample = dlpInfo && typeof dlpInfo.redactedSample === "string" ? dlpInfo.redactedSample.slice(0, DLP_SAMPLE_MAX_LEN) : void 0;
3707
+ const dlpPattern = dlpInfo && typeof dlpInfo.pattern === "string" ? dlpInfo.pattern.slice(0, DLP_PATTERN_MAX_LEN) : void 0;
3708
+ const safeCheckedBy = KNOWN_CHECKED_BY.has(checkedBy) ? checkedBy : "unknown";
3709
+ return fetch(`${validated.toString().replace(/\/$/, "")}/audit`, {
3679
3710
  method: "POST",
3680
3711
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${creds.apiKey}` },
3681
3712
  body: JSON.stringify({
3682
3713
  toolName,
3683
- args,
3684
- checkedBy,
3714
+ args: safeArgs,
3715
+ checkedBy: safeCheckedBy,
3716
+ ...dlpInfo && { dlpPattern, dlpSample },
3685
3717
  context: {
3686
3718
  agent: meta?.agent,
3687
3719
  mcpServer: meta?.mcpServer,
@@ -3815,7 +3847,7 @@ async function resolveNode9SaaS(requestId, creds, approved, decidedBy) {
3815
3847
  );
3816
3848
  }
3817
3849
  }
3818
- var import_fs10, import_os9, import_path13;
3850
+ var import_fs10, import_os9, import_path13, DLP_SAMPLE_MAX_LEN, DLP_PATTERN_MAX_LEN, KNOWN_CHECKED_BY;
3819
3851
  var init_cloud = __esm({
3820
3852
  "src/auth/cloud.ts"() {
3821
3853
  "use strict";
@@ -3823,6 +3855,21 @@ var init_cloud = __esm({
3823
3855
  import_os9 = __toESM(require("os"));
3824
3856
  import_path13 = __toESM(require("path"));
3825
3857
  init_audit();
3858
+ DLP_SAMPLE_MAX_LEN = 200;
3859
+ DLP_PATTERN_MAX_LEN = 100;
3860
+ KNOWN_CHECKED_BY = /* @__PURE__ */ new Set([
3861
+ "dlp-block",
3862
+ "observe-mode-dlp-would-block",
3863
+ "dlp-review-flagged",
3864
+ "loop-detected",
3865
+ "audit-mode",
3866
+ "local-policy",
3867
+ "smart-rule-block",
3868
+ "persistent",
3869
+ "trust",
3870
+ "observe-mode",
3871
+ "observe-mode-would-block"
3872
+ ]);
3826
3873
  }
3827
3874
  });
3828
3875
 
@@ -4010,6 +4057,16 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
4010
4057
  meta,
4011
4058
  true
4012
4059
  );
4060
+ if (approvers.cloud && creds?.apiKey)
4061
+ auditLocalAllow(
4062
+ toolName,
4063
+ args,
4064
+ isObserveMode ? "observe-mode-dlp-would-block" : "dlp-block",
4065
+ creds,
4066
+ meta,
4067
+ { pattern: dlpMatch.patternName, redactedSample: dlpMatch.redactedSample },
4068
+ true
4069
+ );
4013
4070
  if (isWriteTool(toolName) && filePath) {
4014
4071
  await notifyTaint(filePath, `DLP:${dlpMatch.patternName}`);
4015
4072
  }
@@ -4078,6 +4135,8 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
4078
4135
  const reason = `It looks like you've called "${toolName}" ${loopResult.count} times with identical arguments in the last ${ld.windowSeconds}s. Are you stuck? Step back and reconsider your approach \u2014 what are you actually trying to accomplish, and is there a different way to get there?`;
4079
4136
  if (!isManual)
4080
4137
  appendLocalAudit(toolName, args, "deny", "loop-detected", meta, hashAuditArgs);
4138
+ if (approvers.cloud && creds?.apiKey)
4139
+ auditLocalAllow(toolName, args, "loop-detected", creds, meta, void 0, true);
4081
4140
  return {
4082
4141
  approved: false,
4083
4142
  reason,
package/dist/cli.mjs CHANGED
@@ -3655,14 +3655,46 @@ var init_native = __esm({
3655
3655
  import fs10 from "fs";
3656
3656
  import os9 from "os";
3657
3657
  import path13 from "path";
3658
- function auditLocalAllow(toolName, args, checkedBy, creds, meta) {
3659
- return fetch(`${creds.apiUrl}/audit`, {
3658
+ function validateApiUrl(raw) {
3659
+ let u;
3660
+ try {
3661
+ u = new URL(raw);
3662
+ } catch {
3663
+ return null;
3664
+ }
3665
+ if (u.username || u.password) return null;
3666
+ if (u.protocol === "https:") return u;
3667
+ if (u.protocol === "http:") {
3668
+ const h = u.hostname;
3669
+ if (h === "127.0.0.1" || h === "localhost" || h === "::1" || h === "[::1]") return u;
3670
+ }
3671
+ return null;
3672
+ }
3673
+ function auditLocalAllow(toolName, args, checkedBy, creds, meta, dlpInfo, containsSensitiveArgs = false) {
3674
+ const validated = validateApiUrl(creds.apiUrl);
3675
+ if (!validated) {
3676
+ try {
3677
+ fs10.appendFileSync(
3678
+ HOOK_DEBUG_LOG,
3679
+ `[audit] refused to send: invalid apiUrl scheme/host (got "${String(creds.apiUrl).slice(0, 200)}")
3680
+ `
3681
+ );
3682
+ } catch {
3683
+ }
3684
+ return Promise.resolve();
3685
+ }
3686
+ const safeArgs = containsSensitiveArgs ? { tool: toolName, redacted: true } : args;
3687
+ const dlpSample = dlpInfo && typeof dlpInfo.redactedSample === "string" ? dlpInfo.redactedSample.slice(0, DLP_SAMPLE_MAX_LEN) : void 0;
3688
+ const dlpPattern = dlpInfo && typeof dlpInfo.pattern === "string" ? dlpInfo.pattern.slice(0, DLP_PATTERN_MAX_LEN) : void 0;
3689
+ const safeCheckedBy = KNOWN_CHECKED_BY.has(checkedBy) ? checkedBy : "unknown";
3690
+ return fetch(`${validated.toString().replace(/\/$/, "")}/audit`, {
3660
3691
  method: "POST",
3661
3692
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${creds.apiKey}` },
3662
3693
  body: JSON.stringify({
3663
3694
  toolName,
3664
- args,
3665
- checkedBy,
3695
+ args: safeArgs,
3696
+ checkedBy: safeCheckedBy,
3697
+ ...dlpInfo && { dlpPattern, dlpSample },
3666
3698
  context: {
3667
3699
  agent: meta?.agent,
3668
3700
  mcpServer: meta?.mcpServer,
@@ -3796,10 +3828,26 @@ async function resolveNode9SaaS(requestId, creds, approved, decidedBy) {
3796
3828
  );
3797
3829
  }
3798
3830
  }
3831
+ var DLP_SAMPLE_MAX_LEN, DLP_PATTERN_MAX_LEN, KNOWN_CHECKED_BY;
3799
3832
  var init_cloud = __esm({
3800
3833
  "src/auth/cloud.ts"() {
3801
3834
  "use strict";
3802
3835
  init_audit();
3836
+ DLP_SAMPLE_MAX_LEN = 200;
3837
+ DLP_PATTERN_MAX_LEN = 100;
3838
+ KNOWN_CHECKED_BY = /* @__PURE__ */ new Set([
3839
+ "dlp-block",
3840
+ "observe-mode-dlp-would-block",
3841
+ "dlp-review-flagged",
3842
+ "loop-detected",
3843
+ "audit-mode",
3844
+ "local-policy",
3845
+ "smart-rule-block",
3846
+ "persistent",
3847
+ "trust",
3848
+ "observe-mode",
3849
+ "observe-mode-would-block"
3850
+ ]);
3803
3851
  }
3804
3852
  });
3805
3853
 
@@ -3988,6 +4036,16 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
3988
4036
  meta,
3989
4037
  true
3990
4038
  );
4039
+ if (approvers.cloud && creds?.apiKey)
4040
+ auditLocalAllow(
4041
+ toolName,
4042
+ args,
4043
+ isObserveMode ? "observe-mode-dlp-would-block" : "dlp-block",
4044
+ creds,
4045
+ meta,
4046
+ { pattern: dlpMatch.patternName, redactedSample: dlpMatch.redactedSample },
4047
+ true
4048
+ );
3991
4049
  if (isWriteTool(toolName) && filePath) {
3992
4050
  await notifyTaint(filePath, `DLP:${dlpMatch.patternName}`);
3993
4051
  }
@@ -4056,6 +4114,8 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
4056
4114
  const reason = `It looks like you've called "${toolName}" ${loopResult.count} times with identical arguments in the last ${ld.windowSeconds}s. Are you stuck? Step back and reconsider your approach \u2014 what are you actually trying to accomplish, and is there a different way to get there?`;
4057
4115
  if (!isManual)
4058
4116
  appendLocalAudit(toolName, args, "deny", "loop-detected", meta, hashAuditArgs);
4117
+ if (approvers.cloud && creds?.apiKey)
4118
+ auditLocalAllow(toolName, args, "loop-detected", creds, meta, void 0, true);
4059
4119
  return {
4060
4120
  approved: false,
4061
4121
  reason,
package/dist/index.js CHANGED
@@ -3102,14 +3102,61 @@ var import_fs9 = __toESM(require("fs"));
3102
3102
  var import_os8 = __toESM(require("os"));
3103
3103
  var import_path13 = __toESM(require("path"));
3104
3104
  init_audit();
3105
- function auditLocalAllow(toolName, args, checkedBy, creds, meta) {
3106
- return fetch(`${creds.apiUrl}/audit`, {
3105
+ var DLP_SAMPLE_MAX_LEN = 200;
3106
+ var DLP_PATTERN_MAX_LEN = 100;
3107
+ var KNOWN_CHECKED_BY = /* @__PURE__ */ new Set([
3108
+ "dlp-block",
3109
+ "observe-mode-dlp-would-block",
3110
+ "dlp-review-flagged",
3111
+ "loop-detected",
3112
+ "audit-mode",
3113
+ "local-policy",
3114
+ "smart-rule-block",
3115
+ "persistent",
3116
+ "trust",
3117
+ "observe-mode",
3118
+ "observe-mode-would-block"
3119
+ ]);
3120
+ function validateApiUrl(raw) {
3121
+ let u;
3122
+ try {
3123
+ u = new URL(raw);
3124
+ } catch {
3125
+ return null;
3126
+ }
3127
+ if (u.username || u.password) return null;
3128
+ if (u.protocol === "https:") return u;
3129
+ if (u.protocol === "http:") {
3130
+ const h = u.hostname;
3131
+ if (h === "127.0.0.1" || h === "localhost" || h === "::1" || h === "[::1]") return u;
3132
+ }
3133
+ return null;
3134
+ }
3135
+ function auditLocalAllow(toolName, args, checkedBy, creds, meta, dlpInfo, containsSensitiveArgs = false) {
3136
+ const validated = validateApiUrl(creds.apiUrl);
3137
+ if (!validated) {
3138
+ try {
3139
+ import_fs9.default.appendFileSync(
3140
+ HOOK_DEBUG_LOG,
3141
+ `[audit] refused to send: invalid apiUrl scheme/host (got "${String(creds.apiUrl).slice(0, 200)}")
3142
+ `
3143
+ );
3144
+ } catch {
3145
+ }
3146
+ return Promise.resolve();
3147
+ }
3148
+ const safeArgs = containsSensitiveArgs ? { tool: toolName, redacted: true } : args;
3149
+ const dlpSample = dlpInfo && typeof dlpInfo.redactedSample === "string" ? dlpInfo.redactedSample.slice(0, DLP_SAMPLE_MAX_LEN) : void 0;
3150
+ const dlpPattern = dlpInfo && typeof dlpInfo.pattern === "string" ? dlpInfo.pattern.slice(0, DLP_PATTERN_MAX_LEN) : void 0;
3151
+ const safeCheckedBy = KNOWN_CHECKED_BY.has(checkedBy) ? checkedBy : "unknown";
3152
+ return fetch(`${validated.toString().replace(/\/$/, "")}/audit`, {
3107
3153
  method: "POST",
3108
3154
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${creds.apiKey}` },
3109
3155
  body: JSON.stringify({
3110
3156
  toolName,
3111
- args,
3112
- checkedBy,
3157
+ args: safeArgs,
3158
+ checkedBy: safeCheckedBy,
3159
+ ...dlpInfo && { dlpPattern, dlpSample },
3113
3160
  context: {
3114
3161
  agent: meta?.agent,
3115
3162
  mcpServer: meta?.mcpServer,
@@ -3433,6 +3480,16 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
3433
3480
  meta,
3434
3481
  true
3435
3482
  );
3483
+ if (approvers.cloud && creds?.apiKey)
3484
+ auditLocalAllow(
3485
+ toolName,
3486
+ args,
3487
+ isObserveMode ? "observe-mode-dlp-would-block" : "dlp-block",
3488
+ creds,
3489
+ meta,
3490
+ { pattern: dlpMatch.patternName, redactedSample: dlpMatch.redactedSample },
3491
+ true
3492
+ );
3436
3493
  if (isWriteTool(toolName) && filePath) {
3437
3494
  await notifyTaint(filePath, `DLP:${dlpMatch.patternName}`);
3438
3495
  }
@@ -3501,6 +3558,8 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
3501
3558
  const reason = `It looks like you've called "${toolName}" ${loopResult.count} times with identical arguments in the last ${ld.windowSeconds}s. Are you stuck? Step back and reconsider your approach \u2014 what are you actually trying to accomplish, and is there a different way to get there?`;
3502
3559
  if (!isManual)
3503
3560
  appendLocalAudit(toolName, args, "deny", "loop-detected", meta, hashAuditArgs);
3561
+ if (approvers.cloud && creds?.apiKey)
3562
+ auditLocalAllow(toolName, args, "loop-detected", creds, meta, void 0, true);
3504
3563
  return {
3505
3564
  approved: false,
3506
3565
  reason,
package/dist/index.mjs CHANGED
@@ -3072,14 +3072,61 @@ init_audit();
3072
3072
  import fs9 from "fs";
3073
3073
  import os8 from "os";
3074
3074
  import path13 from "path";
3075
- function auditLocalAllow(toolName, args, checkedBy, creds, meta) {
3076
- return fetch(`${creds.apiUrl}/audit`, {
3075
+ var DLP_SAMPLE_MAX_LEN = 200;
3076
+ var DLP_PATTERN_MAX_LEN = 100;
3077
+ var KNOWN_CHECKED_BY = /* @__PURE__ */ new Set([
3078
+ "dlp-block",
3079
+ "observe-mode-dlp-would-block",
3080
+ "dlp-review-flagged",
3081
+ "loop-detected",
3082
+ "audit-mode",
3083
+ "local-policy",
3084
+ "smart-rule-block",
3085
+ "persistent",
3086
+ "trust",
3087
+ "observe-mode",
3088
+ "observe-mode-would-block"
3089
+ ]);
3090
+ function validateApiUrl(raw) {
3091
+ let u;
3092
+ try {
3093
+ u = new URL(raw);
3094
+ } catch {
3095
+ return null;
3096
+ }
3097
+ if (u.username || u.password) return null;
3098
+ if (u.protocol === "https:") return u;
3099
+ if (u.protocol === "http:") {
3100
+ const h = u.hostname;
3101
+ if (h === "127.0.0.1" || h === "localhost" || h === "::1" || h === "[::1]") return u;
3102
+ }
3103
+ return null;
3104
+ }
3105
+ function auditLocalAllow(toolName, args, checkedBy, creds, meta, dlpInfo, containsSensitiveArgs = false) {
3106
+ const validated = validateApiUrl(creds.apiUrl);
3107
+ if (!validated) {
3108
+ try {
3109
+ fs9.appendFileSync(
3110
+ HOOK_DEBUG_LOG,
3111
+ `[audit] refused to send: invalid apiUrl scheme/host (got "${String(creds.apiUrl).slice(0, 200)}")
3112
+ `
3113
+ );
3114
+ } catch {
3115
+ }
3116
+ return Promise.resolve();
3117
+ }
3118
+ const safeArgs = containsSensitiveArgs ? { tool: toolName, redacted: true } : args;
3119
+ const dlpSample = dlpInfo && typeof dlpInfo.redactedSample === "string" ? dlpInfo.redactedSample.slice(0, DLP_SAMPLE_MAX_LEN) : void 0;
3120
+ const dlpPattern = dlpInfo && typeof dlpInfo.pattern === "string" ? dlpInfo.pattern.slice(0, DLP_PATTERN_MAX_LEN) : void 0;
3121
+ const safeCheckedBy = KNOWN_CHECKED_BY.has(checkedBy) ? checkedBy : "unknown";
3122
+ return fetch(`${validated.toString().replace(/\/$/, "")}/audit`, {
3077
3123
  method: "POST",
3078
3124
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${creds.apiKey}` },
3079
3125
  body: JSON.stringify({
3080
3126
  toolName,
3081
- args,
3082
- checkedBy,
3127
+ args: safeArgs,
3128
+ checkedBy: safeCheckedBy,
3129
+ ...dlpInfo && { dlpPattern, dlpSample },
3083
3130
  context: {
3084
3131
  agent: meta?.agent,
3085
3132
  mcpServer: meta?.mcpServer,
@@ -3403,6 +3450,16 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
3403
3450
  meta,
3404
3451
  true
3405
3452
  );
3453
+ if (approvers.cloud && creds?.apiKey)
3454
+ auditLocalAllow(
3455
+ toolName,
3456
+ args,
3457
+ isObserveMode ? "observe-mode-dlp-would-block" : "dlp-block",
3458
+ creds,
3459
+ meta,
3460
+ { pattern: dlpMatch.patternName, redactedSample: dlpMatch.redactedSample },
3461
+ true
3462
+ );
3406
3463
  if (isWriteTool(toolName) && filePath) {
3407
3464
  await notifyTaint(filePath, `DLP:${dlpMatch.patternName}`);
3408
3465
  }
@@ -3471,6 +3528,8 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
3471
3528
  const reason = `It looks like you've called "${toolName}" ${loopResult.count} times with identical arguments in the last ${ld.windowSeconds}s. Are you stuck? Step back and reconsider your approach \u2014 what are you actually trying to accomplish, and is there a different way to get there?`;
3472
3529
  if (!isManual)
3473
3530
  appendLocalAudit(toolName, args, "deny", "loop-detected", meta, hashAuditArgs);
3531
+ if (approvers.cloud && creds?.apiKey)
3532
+ auditLocalAllow(toolName, args, "loop-detected", creds, meta, void 0, true);
3474
3533
  return {
3475
3534
  approved: false,
3476
3535
  reason,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node9/proxy",
3
- "version": "1.14.0",
3
+ "version": "1.14.1",
4
4
  "description": "The Sudo Command for AI Agents. Execution Security for Claude Code & MCP.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",