@node9/proxy 2.5.0 → 2.6.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/index.js CHANGED
@@ -4027,6 +4027,10 @@ var COMMAND_CHECK_KEYS = [
4027
4027
  "evalDynamic",
4028
4028
  "pipeChainHigh"
4029
4029
  ];
4030
+ var CLASS_B_COMMAND_CHECKS = /* @__PURE__ */ new Set([
4031
+ "evalDynamic",
4032
+ "pipeChainHigh"
4033
+ ]);
4030
4034
  function applyManagedCommandChecks(local, managed, locked) {
4031
4035
  const next = { ...local };
4032
4036
  for (const key of COMMAND_CHECK_KEYS) {
@@ -4036,7 +4040,7 @@ function applyManagedCommandChecks(local, managed, locked) {
4036
4040
  const resolved = floorValue(COMMAND_CHECK_ORDER, local[key], m, {
4037
4041
  locked: locked.includes(lockKey)
4038
4042
  });
4039
- if ((key === "evalDynamic" || key === "pipeChainHigh") && resolved === "off") continue;
4043
+ if (CLASS_B_COMMAND_CHECKS.has(key) && resolved === "off") continue;
4040
4044
  next[key] = resolved;
4041
4045
  }
4042
4046
  return next;
@@ -4177,6 +4181,7 @@ var DANGEROUS_WORDS = [
4177
4181
  ];
4178
4182
  var DEFAULT_CONFIG = {
4179
4183
  version: "1.0",
4184
+ policySource: "local",
4180
4185
  settings: {
4181
4186
  mode: "standard",
4182
4187
  autoStartDaemon: true,
@@ -4440,13 +4445,15 @@ function getCredentials() {
4440
4445
  if (profile?.apiKey) {
4441
4446
  return {
4442
4447
  apiKey: profile.apiKey,
4443
- apiUrl: profile.apiUrl || DEFAULT_API_URL
4448
+ apiUrl: profile.apiUrl || DEFAULT_API_URL,
4449
+ localOnly: profile.localOnly === true || profileName !== "default"
4444
4450
  };
4445
4451
  }
4446
4452
  if (creds.apiKey) {
4447
4453
  return {
4448
4454
  apiKey: creds.apiKey,
4449
- apiUrl: creds.apiUrl || DEFAULT_API_URL
4455
+ apiUrl: creds.apiUrl || DEFAULT_API_URL,
4456
+ localOnly: creds.localOnly === true
4450
4457
  };
4451
4458
  }
4452
4459
  }
@@ -4558,22 +4565,16 @@ function getConfig(cwd) {
4558
4565
  const i = COMMAND_CHECK_ORDER.indexOf(v ?? "");
4559
4566
  return i === -1 ? 1 : i;
4560
4567
  };
4561
- const applyLayer = (source, isProject = false) => {
4568
+ const pr2Creds = getCredentials();
4569
+ const keyed = !!pr2Creds?.apiKey && pr2Creds.localOnly !== true;
4570
+ const applyLayer = (source, isProject = false, isCloud = false) => {
4562
4571
  if (!source) return;
4563
4572
  const s = source.settings || {};
4564
4573
  const p = source.policy || {};
4565
- if (s.mode !== void 0) mergedSettings.mode = s.mode;
4566
4574
  if (s.autoStartDaemon !== void 0) mergedSettings.autoStartDaemon = s.autoStartDaemon;
4567
4575
  if (s.enableHookLogDebug !== void 0)
4568
4576
  mergedSettings.enableHookLogDebug = s.enableHookLogDebug;
4569
- if (s.approvers) mergedSettings.approvers = { ...mergedSettings.approvers, ...s.approvers };
4570
4577
  if (s.shipper) mergedSettings.shipper = { ...mergedSettings.shipper, ...s.shipper };
4571
- if (s.approvalTimeoutMs !== void 0) mergedSettings.approvalTimeoutMs = s.approvalTimeoutMs;
4572
- if (s.approvalTimeoutSeconds !== void 0 && s.approvalTimeoutMs === void 0)
4573
- mergedSettings.approvalTimeoutMs = s.approvalTimeoutSeconds * 1e3;
4574
- if (s.environment !== void 0) mergedSettings.environment = s.environment;
4575
- if (s.reviewChannel !== void 0) mergedSettings.reviewChannel = s.reviewChannel;
4576
- if (s.mcpAllowWeakening !== void 0) mergedSettings.mcpAllowWeakening = s.mcpAllowWeakening;
4577
4578
  if (s.cloudSyncIntervalHours !== void 0)
4578
4579
  mergedSettings.cloudSyncIntervalHours = s.cloudSyncIntervalHours;
4579
4580
  if (s.mcpAutoWrap !== void 0) mergedSettings.mcpAutoWrap = s.mcpAutoWrap === true;
@@ -4581,6 +4582,15 @@ function getConfig(cwd) {
4581
4582
  mergedSettings.mcpReconcileIntervalMinutes = s.mcpReconcileIntervalMinutes;
4582
4583
  if (s.mcpStaleAfterDays !== void 0) mergedSettings.mcpStaleAfterDays = s.mcpStaleAfterDays;
4583
4584
  if (s.hud !== void 0) mergedSettings.hud = { ...mergedSettings.hud, ...s.hud };
4585
+ if (keyed && !isCloud) return;
4586
+ if (s.mode !== void 0) mergedSettings.mode = s.mode;
4587
+ if (s.approvers) mergedSettings.approvers = { ...mergedSettings.approvers, ...s.approvers };
4588
+ if (s.approvalTimeoutMs !== void 0) mergedSettings.approvalTimeoutMs = s.approvalTimeoutMs;
4589
+ if (s.approvalTimeoutSeconds !== void 0 && s.approvalTimeoutMs === void 0)
4590
+ mergedSettings.approvalTimeoutMs = s.approvalTimeoutSeconds * 1e3;
4591
+ if (s.environment !== void 0) mergedSettings.environment = s.environment;
4592
+ if (s.reviewChannel !== void 0) mergedSettings.reviewChannel = s.reviewChannel;
4593
+ if (s.mcpAllowWeakening !== void 0) mergedSettings.mcpAllowWeakening = s.mcpAllowWeakening;
4584
4594
  if (p.sandboxPaths) mergedPolicy.sandboxPaths.push(...p.sandboxPaths);
4585
4595
  if (p.ignoredTools) mergedPolicy.ignoredTools.push(...p.ignoredTools);
4586
4596
  if (p.dangerousWords) mergedPolicy.dangerousWords = [...p.dangerousWords];
@@ -4688,6 +4698,9 @@ function getConfig(cwd) {
4688
4698
  /* isProject */
4689
4699
  true
4690
4700
  );
4701
+ if (keyed) {
4702
+ mergedSettings.approvers = { ...mergedSettings.approvers, cloud: true };
4703
+ }
4691
4704
  let cloudManagedShields = [];
4692
4705
  const managedCommandCheckKeys = /* @__PURE__ */ new Set();
4693
4706
  const lockedCommandCheckKeys = /* @__PURE__ */ new Set();
@@ -4700,7 +4713,12 @@ function getConfig(cwd) {
4700
4713
  try {
4701
4714
  const raw = readRulesCacheResilient(cacheFile);
4702
4715
  if (Array.isArray(raw.rules) && raw.rules.length > 0) {
4703
- applyLayer({ policy: { smartRules: raw.rules } });
4716
+ applyLayer(
4717
+ { policy: { smartRules: raw.rules } },
4718
+ false,
4719
+ /* isCloud */
4720
+ true
4721
+ );
4704
4722
  }
4705
4723
  if (Array.isArray(raw.shields)) {
4706
4724
  cloudManagedShields = raw.shields.filter((s) => typeof s === "string");
@@ -4709,47 +4727,85 @@ function getConfig(cwd) {
4709
4727
  const mc = raw.managedConfig;
4710
4728
  const locked = Array.isArray(mc.locked) ? mc.locked.filter((f) => typeof f === "string") : [];
4711
4729
  if (typeof mc.mode === "string") {
4712
- mergedSettings.mode = resolveManagedMode(
4713
- mergedSettings.mode,
4714
- mc.mode,
4715
- locked.includes("mode")
4716
- );
4730
+ if (keyed) {
4731
+ if (["observe", "audit", "standard", "strict"].includes(mc.mode)) {
4732
+ mergedSettings.mode = mc.mode;
4733
+ }
4734
+ } else {
4735
+ mergedSettings.mode = resolveManagedMode(
4736
+ mergedSettings.mode,
4737
+ mc.mode,
4738
+ locked.includes("mode")
4739
+ );
4740
+ }
4717
4741
  }
4718
4742
  if (typeof mc.mode === "string" || locked.includes("mode")) {
4719
4743
  modeCloudControlled = true;
4720
4744
  }
4721
4745
  if (mc.egress && typeof mc.egress === "object") {
4722
4746
  const hosts = (v) => Array.isArray(v) ? v.filter((h) => typeof h === "string") : void 0;
4723
- mergedPolicy.egress = applyManagedEgress(
4724
- mergedPolicy.egress,
4725
- {
4726
- enabled: typeof mc.egress.enabled === "boolean" ? mc.egress.enabled : void 0,
4727
- mode: typeof mc.egress.mode === "string" ? mc.egress.mode : void 0,
4728
- allow: hosts(mc.egress.allow),
4729
- deny: hosts(mc.egress.deny),
4730
- allowPrivate: typeof mc.egress.allowPrivate === "boolean" ? mc.egress.allowPrivate : void 0
4731
- },
4732
- locked,
4733
- egressModeUserSet
4734
- );
4747
+ if (keyed) {
4748
+ const e = mc.egress;
4749
+ if (typeof e.enabled === "boolean") mergedPolicy.egress.enabled = e.enabled;
4750
+ if (e.mode === "off" || e.mode === "review" || e.mode === "block")
4751
+ mergedPolicy.egress.mode = e.mode;
4752
+ const allow = hosts(e.allow);
4753
+ if (allow) mergedPolicy.egress.allow = allow;
4754
+ const deny = hosts(e.deny);
4755
+ if (deny) mergedPolicy.egress.deny = deny;
4756
+ if (typeof e.allowPrivate === "boolean")
4757
+ mergedPolicy.egress.allowPrivate = e.allowPrivate;
4758
+ } else {
4759
+ mergedPolicy.egress = applyManagedEgress(
4760
+ mergedPolicy.egress,
4761
+ {
4762
+ enabled: typeof mc.egress.enabled === "boolean" ? mc.egress.enabled : void 0,
4763
+ mode: typeof mc.egress.mode === "string" ? mc.egress.mode : void 0,
4764
+ allow: hosts(mc.egress.allow),
4765
+ deny: hosts(mc.egress.deny),
4766
+ allowPrivate: typeof mc.egress.allowPrivate === "boolean" ? mc.egress.allowPrivate : void 0
4767
+ },
4768
+ locked,
4769
+ egressModeUserSet
4770
+ );
4771
+ }
4735
4772
  }
4736
4773
  if (mc.dlp && typeof mc.dlp === "object") {
4737
- mergedPolicy.dlp = applyManagedDlp(
4738
- mergedPolicy.dlp,
4739
- {
4740
- enabled: typeof mc.dlp.enabled === "boolean" ? mc.dlp.enabled : void 0,
4741
- pii: typeof mc.dlp.pii === "string" ? mc.dlp.pii : void 0,
4742
- reviewAction: mc.dlp.reviewAction === "review" || mc.dlp.reviewAction === "block" ? mc.dlp.reviewAction : void 0
4743
- },
4744
- locked
4745
- );
4774
+ if (keyed) {
4775
+ if (typeof mc.dlp.enabled === "boolean") mergedPolicy.dlp.enabled = mc.dlp.enabled;
4776
+ if (mc.dlp.pii === "off" || mc.dlp.pii === "block") mergedPolicy.dlp.pii = mc.dlp.pii;
4777
+ if (mc.dlp.reviewAction === "review" || mc.dlp.reviewAction === "block")
4778
+ mergedPolicy.dlp.reviewAction = mc.dlp.reviewAction;
4779
+ } else {
4780
+ mergedPolicy.dlp = applyManagedDlp(
4781
+ mergedPolicy.dlp,
4782
+ {
4783
+ enabled: typeof mc.dlp.enabled === "boolean" ? mc.dlp.enabled : void 0,
4784
+ pii: typeof mc.dlp.pii === "string" ? mc.dlp.pii : void 0,
4785
+ reviewAction: mc.dlp.reviewAction === "review" || mc.dlp.reviewAction === "block" ? mc.dlp.reviewAction : void 0
4786
+ },
4787
+ locked
4788
+ );
4789
+ }
4746
4790
  }
4747
4791
  if (mc.commandChecks && typeof mc.commandChecks === "object") {
4748
- mergedPolicy.commandChecks = applyManagedCommandChecks(
4749
- mergedPolicy.commandChecks ?? {},
4750
- mc.commandChecks,
4751
- locked
4752
- );
4792
+ if (keyed) {
4793
+ const src = mc.commandChecks;
4794
+ const next = { ...mergedPolicy.commandChecks ?? {} };
4795
+ for (const key of COMMAND_CHECK_KEYS) {
4796
+ const val = src[key];
4797
+ if (val !== "off" && val !== "review" && val !== "block") continue;
4798
+ if (val === "off" && CLASS_B_COMMAND_CHECKS.has(key)) continue;
4799
+ next[key] = val;
4800
+ }
4801
+ mergedPolicy.commandChecks = next;
4802
+ } else {
4803
+ mergedPolicy.commandChecks = applyManagedCommandChecks(
4804
+ mergedPolicy.commandChecks ?? {},
4805
+ mc.commandChecks,
4806
+ locked
4807
+ );
4808
+ }
4753
4809
  for (const [key, val] of Object.entries(mc.commandChecks)) {
4754
4810
  if (typeof val !== "string") continue;
4755
4811
  managedCommandCheckKeys.add(key);
@@ -4846,7 +4902,8 @@ function getConfig(cwd) {
4846
4902
  }
4847
4903
  }
4848
4904
  const shieldOverrides = readShieldOverrides();
4849
- const activeShieldNames = [.../* @__PURE__ */ new Set([...readActiveShields(), ...cloudManagedShields])];
4905
+ if (keyed) mergedPolicy.trustedHostsManaged = true;
4906
+ const activeShieldNames = keyed ? [...new Set(cloudManagedShields)] : [.../* @__PURE__ */ new Set([...readActiveShields(), ...cloudManagedShields])];
4850
4907
  const appliedShields = [];
4851
4908
  const cloudManagedSet = new Set(cloudManagedShields);
4852
4909
  for (const shieldName of activeShieldNames) {
@@ -4910,7 +4967,9 @@ function getConfig(cwd) {
4910
4967
  mergedPolicy.smartRules.push(injected);
4911
4968
  }
4912
4969
  const envMode = process.env.NODE9_MODE;
4913
- if (envMode && !modeCloudControlled && ["observe", "audit", "standard", "strict"].includes(envMode)) {
4970
+ if (envMode && !modeCloudControlled && // PR-2: one listening point includes the env var — a keyed machine's
4971
+ // mode comes from the workspace (or the shipped default), never the shell.
4972
+ !keyed && ["observe", "audit", "standard", "strict"].includes(envMode)) {
4914
4973
  mergedSettings.mode = envMode;
4915
4974
  }
4916
4975
  if ((cloudManagedShields.length > 0 || cloudMandatesEnforcement) && !modeCloudControlled && !modeCloudStaged && (mergedSettings.mode === "observe" || mergedSettings.mode === "audit")) {
@@ -4937,7 +4996,11 @@ function getConfig(cwd) {
4937
4996
  const result = {
4938
4997
  settings: mergedSettings,
4939
4998
  policy: mergedPolicy,
4940
- environments: mergedEnvironments
4999
+ environments: mergedEnvironments,
5000
+ // PR-2 — the one truth introspection reads: which of the two working
5001
+ // modes this machine is in. 'workspace' = keyed, policy from the cloud;
5002
+ // 'local' = the local stack (incl. --local / named-profile keys).
5003
+ policySource: keyed ? "workspace" : "local"
4941
5004
  };
4942
5005
  if (!cwd) cachedConfig = result;
4943
5006
  return result;
@@ -6483,7 +6546,7 @@ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
6483
6546
  } else if (!taintWarning && !appPermReview) {
6484
6547
  const toolLower = toolName.toLowerCase();
6485
6548
  const isFileTool = toolLower === "read" || toolLower === "grep" || toolLower === "glob" || toolLower === "read_file" || toolLower === "grep_search" || toolLower === "list_files";
6486
- const activeShields = isFileTool ? readActiveShields() : [];
6549
+ const activeShields = isFileTool ? config.policy.appliedShields ?? readActiveShields() : [];
6487
6550
  const managedJail = isFileTool ? config.policy.managedJailPaths ?? [] : [];
6488
6551
  if (isFileTool && (activeShields.includes("project-jail") || activeShields.includes(USER_JAIL_SHIELD) || managedJail.length > 0)) {
6489
6552
  const argsObj = args && typeof args === "object" && !Array.isArray(args) ? args : {};
package/dist/index.mjs CHANGED
@@ -3997,6 +3997,10 @@ var COMMAND_CHECK_KEYS = [
3997
3997
  "evalDynamic",
3998
3998
  "pipeChainHigh"
3999
3999
  ];
4000
+ var CLASS_B_COMMAND_CHECKS = /* @__PURE__ */ new Set([
4001
+ "evalDynamic",
4002
+ "pipeChainHigh"
4003
+ ]);
4000
4004
  function applyManagedCommandChecks(local, managed, locked) {
4001
4005
  const next = { ...local };
4002
4006
  for (const key of COMMAND_CHECK_KEYS) {
@@ -4006,7 +4010,7 @@ function applyManagedCommandChecks(local, managed, locked) {
4006
4010
  const resolved = floorValue(COMMAND_CHECK_ORDER, local[key], m, {
4007
4011
  locked: locked.includes(lockKey)
4008
4012
  });
4009
- if ((key === "evalDynamic" || key === "pipeChainHigh") && resolved === "off") continue;
4013
+ if (CLASS_B_COMMAND_CHECKS.has(key) && resolved === "off") continue;
4010
4014
  next[key] = resolved;
4011
4015
  }
4012
4016
  return next;
@@ -4147,6 +4151,7 @@ var DANGEROUS_WORDS = [
4147
4151
  ];
4148
4152
  var DEFAULT_CONFIG = {
4149
4153
  version: "1.0",
4154
+ policySource: "local",
4150
4155
  settings: {
4151
4156
  mode: "standard",
4152
4157
  autoStartDaemon: true,
@@ -4410,13 +4415,15 @@ function getCredentials() {
4410
4415
  if (profile?.apiKey) {
4411
4416
  return {
4412
4417
  apiKey: profile.apiKey,
4413
- apiUrl: profile.apiUrl || DEFAULT_API_URL
4418
+ apiUrl: profile.apiUrl || DEFAULT_API_URL,
4419
+ localOnly: profile.localOnly === true || profileName !== "default"
4414
4420
  };
4415
4421
  }
4416
4422
  if (creds.apiKey) {
4417
4423
  return {
4418
4424
  apiKey: creds.apiKey,
4419
- apiUrl: creds.apiUrl || DEFAULT_API_URL
4425
+ apiUrl: creds.apiUrl || DEFAULT_API_URL,
4426
+ localOnly: creds.localOnly === true
4420
4427
  };
4421
4428
  }
4422
4429
  }
@@ -4528,22 +4535,16 @@ function getConfig(cwd) {
4528
4535
  const i = COMMAND_CHECK_ORDER.indexOf(v ?? "");
4529
4536
  return i === -1 ? 1 : i;
4530
4537
  };
4531
- const applyLayer = (source, isProject = false) => {
4538
+ const pr2Creds = getCredentials();
4539
+ const keyed = !!pr2Creds?.apiKey && pr2Creds.localOnly !== true;
4540
+ const applyLayer = (source, isProject = false, isCloud = false) => {
4532
4541
  if (!source) return;
4533
4542
  const s = source.settings || {};
4534
4543
  const p = source.policy || {};
4535
- if (s.mode !== void 0) mergedSettings.mode = s.mode;
4536
4544
  if (s.autoStartDaemon !== void 0) mergedSettings.autoStartDaemon = s.autoStartDaemon;
4537
4545
  if (s.enableHookLogDebug !== void 0)
4538
4546
  mergedSettings.enableHookLogDebug = s.enableHookLogDebug;
4539
- if (s.approvers) mergedSettings.approvers = { ...mergedSettings.approvers, ...s.approvers };
4540
4547
  if (s.shipper) mergedSettings.shipper = { ...mergedSettings.shipper, ...s.shipper };
4541
- if (s.approvalTimeoutMs !== void 0) mergedSettings.approvalTimeoutMs = s.approvalTimeoutMs;
4542
- if (s.approvalTimeoutSeconds !== void 0 && s.approvalTimeoutMs === void 0)
4543
- mergedSettings.approvalTimeoutMs = s.approvalTimeoutSeconds * 1e3;
4544
- if (s.environment !== void 0) mergedSettings.environment = s.environment;
4545
- if (s.reviewChannel !== void 0) mergedSettings.reviewChannel = s.reviewChannel;
4546
- if (s.mcpAllowWeakening !== void 0) mergedSettings.mcpAllowWeakening = s.mcpAllowWeakening;
4547
4548
  if (s.cloudSyncIntervalHours !== void 0)
4548
4549
  mergedSettings.cloudSyncIntervalHours = s.cloudSyncIntervalHours;
4549
4550
  if (s.mcpAutoWrap !== void 0) mergedSettings.mcpAutoWrap = s.mcpAutoWrap === true;
@@ -4551,6 +4552,15 @@ function getConfig(cwd) {
4551
4552
  mergedSettings.mcpReconcileIntervalMinutes = s.mcpReconcileIntervalMinutes;
4552
4553
  if (s.mcpStaleAfterDays !== void 0) mergedSettings.mcpStaleAfterDays = s.mcpStaleAfterDays;
4553
4554
  if (s.hud !== void 0) mergedSettings.hud = { ...mergedSettings.hud, ...s.hud };
4555
+ if (keyed && !isCloud) return;
4556
+ if (s.mode !== void 0) mergedSettings.mode = s.mode;
4557
+ if (s.approvers) mergedSettings.approvers = { ...mergedSettings.approvers, ...s.approvers };
4558
+ if (s.approvalTimeoutMs !== void 0) mergedSettings.approvalTimeoutMs = s.approvalTimeoutMs;
4559
+ if (s.approvalTimeoutSeconds !== void 0 && s.approvalTimeoutMs === void 0)
4560
+ mergedSettings.approvalTimeoutMs = s.approvalTimeoutSeconds * 1e3;
4561
+ if (s.environment !== void 0) mergedSettings.environment = s.environment;
4562
+ if (s.reviewChannel !== void 0) mergedSettings.reviewChannel = s.reviewChannel;
4563
+ if (s.mcpAllowWeakening !== void 0) mergedSettings.mcpAllowWeakening = s.mcpAllowWeakening;
4554
4564
  if (p.sandboxPaths) mergedPolicy.sandboxPaths.push(...p.sandboxPaths);
4555
4565
  if (p.ignoredTools) mergedPolicy.ignoredTools.push(...p.ignoredTools);
4556
4566
  if (p.dangerousWords) mergedPolicy.dangerousWords = [...p.dangerousWords];
@@ -4658,6 +4668,9 @@ function getConfig(cwd) {
4658
4668
  /* isProject */
4659
4669
  true
4660
4670
  );
4671
+ if (keyed) {
4672
+ mergedSettings.approvers = { ...mergedSettings.approvers, cloud: true };
4673
+ }
4661
4674
  let cloudManagedShields = [];
4662
4675
  const managedCommandCheckKeys = /* @__PURE__ */ new Set();
4663
4676
  const lockedCommandCheckKeys = /* @__PURE__ */ new Set();
@@ -4670,7 +4683,12 @@ function getConfig(cwd) {
4670
4683
  try {
4671
4684
  const raw = readRulesCacheResilient(cacheFile);
4672
4685
  if (Array.isArray(raw.rules) && raw.rules.length > 0) {
4673
- applyLayer({ policy: { smartRules: raw.rules } });
4686
+ applyLayer(
4687
+ { policy: { smartRules: raw.rules } },
4688
+ false,
4689
+ /* isCloud */
4690
+ true
4691
+ );
4674
4692
  }
4675
4693
  if (Array.isArray(raw.shields)) {
4676
4694
  cloudManagedShields = raw.shields.filter((s) => typeof s === "string");
@@ -4679,47 +4697,85 @@ function getConfig(cwd) {
4679
4697
  const mc = raw.managedConfig;
4680
4698
  const locked = Array.isArray(mc.locked) ? mc.locked.filter((f) => typeof f === "string") : [];
4681
4699
  if (typeof mc.mode === "string") {
4682
- mergedSettings.mode = resolveManagedMode(
4683
- mergedSettings.mode,
4684
- mc.mode,
4685
- locked.includes("mode")
4686
- );
4700
+ if (keyed) {
4701
+ if (["observe", "audit", "standard", "strict"].includes(mc.mode)) {
4702
+ mergedSettings.mode = mc.mode;
4703
+ }
4704
+ } else {
4705
+ mergedSettings.mode = resolveManagedMode(
4706
+ mergedSettings.mode,
4707
+ mc.mode,
4708
+ locked.includes("mode")
4709
+ );
4710
+ }
4687
4711
  }
4688
4712
  if (typeof mc.mode === "string" || locked.includes("mode")) {
4689
4713
  modeCloudControlled = true;
4690
4714
  }
4691
4715
  if (mc.egress && typeof mc.egress === "object") {
4692
4716
  const hosts = (v) => Array.isArray(v) ? v.filter((h) => typeof h === "string") : void 0;
4693
- mergedPolicy.egress = applyManagedEgress(
4694
- mergedPolicy.egress,
4695
- {
4696
- enabled: typeof mc.egress.enabled === "boolean" ? mc.egress.enabled : void 0,
4697
- mode: typeof mc.egress.mode === "string" ? mc.egress.mode : void 0,
4698
- allow: hosts(mc.egress.allow),
4699
- deny: hosts(mc.egress.deny),
4700
- allowPrivate: typeof mc.egress.allowPrivate === "boolean" ? mc.egress.allowPrivate : void 0
4701
- },
4702
- locked,
4703
- egressModeUserSet
4704
- );
4717
+ if (keyed) {
4718
+ const e = mc.egress;
4719
+ if (typeof e.enabled === "boolean") mergedPolicy.egress.enabled = e.enabled;
4720
+ if (e.mode === "off" || e.mode === "review" || e.mode === "block")
4721
+ mergedPolicy.egress.mode = e.mode;
4722
+ const allow = hosts(e.allow);
4723
+ if (allow) mergedPolicy.egress.allow = allow;
4724
+ const deny = hosts(e.deny);
4725
+ if (deny) mergedPolicy.egress.deny = deny;
4726
+ if (typeof e.allowPrivate === "boolean")
4727
+ mergedPolicy.egress.allowPrivate = e.allowPrivate;
4728
+ } else {
4729
+ mergedPolicy.egress = applyManagedEgress(
4730
+ mergedPolicy.egress,
4731
+ {
4732
+ enabled: typeof mc.egress.enabled === "boolean" ? mc.egress.enabled : void 0,
4733
+ mode: typeof mc.egress.mode === "string" ? mc.egress.mode : void 0,
4734
+ allow: hosts(mc.egress.allow),
4735
+ deny: hosts(mc.egress.deny),
4736
+ allowPrivate: typeof mc.egress.allowPrivate === "boolean" ? mc.egress.allowPrivate : void 0
4737
+ },
4738
+ locked,
4739
+ egressModeUserSet
4740
+ );
4741
+ }
4705
4742
  }
4706
4743
  if (mc.dlp && typeof mc.dlp === "object") {
4707
- mergedPolicy.dlp = applyManagedDlp(
4708
- mergedPolicy.dlp,
4709
- {
4710
- enabled: typeof mc.dlp.enabled === "boolean" ? mc.dlp.enabled : void 0,
4711
- pii: typeof mc.dlp.pii === "string" ? mc.dlp.pii : void 0,
4712
- reviewAction: mc.dlp.reviewAction === "review" || mc.dlp.reviewAction === "block" ? mc.dlp.reviewAction : void 0
4713
- },
4714
- locked
4715
- );
4744
+ if (keyed) {
4745
+ if (typeof mc.dlp.enabled === "boolean") mergedPolicy.dlp.enabled = mc.dlp.enabled;
4746
+ if (mc.dlp.pii === "off" || mc.dlp.pii === "block") mergedPolicy.dlp.pii = mc.dlp.pii;
4747
+ if (mc.dlp.reviewAction === "review" || mc.dlp.reviewAction === "block")
4748
+ mergedPolicy.dlp.reviewAction = mc.dlp.reviewAction;
4749
+ } else {
4750
+ mergedPolicy.dlp = applyManagedDlp(
4751
+ mergedPolicy.dlp,
4752
+ {
4753
+ enabled: typeof mc.dlp.enabled === "boolean" ? mc.dlp.enabled : void 0,
4754
+ pii: typeof mc.dlp.pii === "string" ? mc.dlp.pii : void 0,
4755
+ reviewAction: mc.dlp.reviewAction === "review" || mc.dlp.reviewAction === "block" ? mc.dlp.reviewAction : void 0
4756
+ },
4757
+ locked
4758
+ );
4759
+ }
4716
4760
  }
4717
4761
  if (mc.commandChecks && typeof mc.commandChecks === "object") {
4718
- mergedPolicy.commandChecks = applyManagedCommandChecks(
4719
- mergedPolicy.commandChecks ?? {},
4720
- mc.commandChecks,
4721
- locked
4722
- );
4762
+ if (keyed) {
4763
+ const src = mc.commandChecks;
4764
+ const next = { ...mergedPolicy.commandChecks ?? {} };
4765
+ for (const key of COMMAND_CHECK_KEYS) {
4766
+ const val = src[key];
4767
+ if (val !== "off" && val !== "review" && val !== "block") continue;
4768
+ if (val === "off" && CLASS_B_COMMAND_CHECKS.has(key)) continue;
4769
+ next[key] = val;
4770
+ }
4771
+ mergedPolicy.commandChecks = next;
4772
+ } else {
4773
+ mergedPolicy.commandChecks = applyManagedCommandChecks(
4774
+ mergedPolicy.commandChecks ?? {},
4775
+ mc.commandChecks,
4776
+ locked
4777
+ );
4778
+ }
4723
4779
  for (const [key, val] of Object.entries(mc.commandChecks)) {
4724
4780
  if (typeof val !== "string") continue;
4725
4781
  managedCommandCheckKeys.add(key);
@@ -4816,7 +4872,8 @@ function getConfig(cwd) {
4816
4872
  }
4817
4873
  }
4818
4874
  const shieldOverrides = readShieldOverrides();
4819
- const activeShieldNames = [.../* @__PURE__ */ new Set([...readActiveShields(), ...cloudManagedShields])];
4875
+ if (keyed) mergedPolicy.trustedHostsManaged = true;
4876
+ const activeShieldNames = keyed ? [...new Set(cloudManagedShields)] : [.../* @__PURE__ */ new Set([...readActiveShields(), ...cloudManagedShields])];
4820
4877
  const appliedShields = [];
4821
4878
  const cloudManagedSet = new Set(cloudManagedShields);
4822
4879
  for (const shieldName of activeShieldNames) {
@@ -4880,7 +4937,9 @@ function getConfig(cwd) {
4880
4937
  mergedPolicy.smartRules.push(injected);
4881
4938
  }
4882
4939
  const envMode = process.env.NODE9_MODE;
4883
- if (envMode && !modeCloudControlled && ["observe", "audit", "standard", "strict"].includes(envMode)) {
4940
+ if (envMode && !modeCloudControlled && // PR-2: one listening point includes the env var — a keyed machine's
4941
+ // mode comes from the workspace (or the shipped default), never the shell.
4942
+ !keyed && ["observe", "audit", "standard", "strict"].includes(envMode)) {
4884
4943
  mergedSettings.mode = envMode;
4885
4944
  }
4886
4945
  if ((cloudManagedShields.length > 0 || cloudMandatesEnforcement) && !modeCloudControlled && !modeCloudStaged && (mergedSettings.mode === "observe" || mergedSettings.mode === "audit")) {
@@ -4907,7 +4966,11 @@ function getConfig(cwd) {
4907
4966
  const result = {
4908
4967
  settings: mergedSettings,
4909
4968
  policy: mergedPolicy,
4910
- environments: mergedEnvironments
4969
+ environments: mergedEnvironments,
4970
+ // PR-2 — the one truth introspection reads: which of the two working
4971
+ // modes this machine is in. 'workspace' = keyed, policy from the cloud;
4972
+ // 'local' = the local stack (incl. --local / named-profile keys).
4973
+ policySource: keyed ? "workspace" : "local"
4911
4974
  };
4912
4975
  if (!cwd) cachedConfig = result;
4913
4976
  return result;
@@ -6453,7 +6516,7 @@ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
6453
6516
  } else if (!taintWarning && !appPermReview) {
6454
6517
  const toolLower = toolName.toLowerCase();
6455
6518
  const isFileTool = toolLower === "read" || toolLower === "grep" || toolLower === "glob" || toolLower === "read_file" || toolLower === "grep_search" || toolLower === "list_files";
6456
- const activeShields = isFileTool ? readActiveShields() : [];
6519
+ const activeShields = isFileTool ? config.policy.appliedShields ?? readActiveShields() : [];
6457
6520
  const managedJail = isFileTool ? config.policy.managedJailPaths ?? [] : [];
6458
6521
  if (isFileTool && (activeShields.includes("project-jail") || activeShields.includes(USER_JAIL_SHIELD) || managedJail.length > 0)) {
6459
6522
  const argsObj = args && typeof args === "object" && !Array.isArray(args) ? args : {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node9/proxy",
3
- "version": "2.5.0",
3
+ "version": "2.6.1",
4
4
  "description": "The Sudo Command for AI Agents. Execution Security for Claude Code, Codex, Gemini, Cursor, Opencode, Pi, and any MCP server.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -70,7 +70,9 @@
70
70
  "bump-extractor-version": "node scripts/check-extractor-version.mjs --bump",
71
71
  "fix": "npm run format && npm run lint:fix",
72
72
  "validate": "npm run format && npm run lint && npm run typecheck && npm run test && npm run test:e2e && npm run build",
73
+ "pretest:e2e": "npm run build",
73
74
  "test:e2e": "cross-env NODE9_TESTING=1 bash scripts/e2e.sh",
75
+ "pretest": "npm run build",
74
76
  "test": "cross-env NODE9_TESTING=1 vitest --run",
75
77
  "test:coverage": "cross-env NODE9_TESTING=1 vitest --run --coverage",
76
78
  "test:watch": "cross-env NODE9_TESTING=1 vitest",