pi-landstrip 0.16.20 → 0.16.22

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.
Files changed (2) hide show
  1. package/index.ts +43 -84
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -443,6 +443,11 @@ function extractNativeWriteDeniedPath(output: string, cwd: string): string | nul
443
443
  );
444
444
  if (match) return normalizePathMatch(match[1], cwd);
445
445
 
446
+ match = output.match(
447
+ /^[a-zA-Z0-9_-]+: couldn't open temporary file (\/[^:\n]+): (?:Operation not permitted|Permission denied)$/m,
448
+ );
449
+ if (match) return normalizePathMatch(match[1], cwd);
450
+
446
451
  return null;
447
452
  }
448
453
 
@@ -782,88 +787,40 @@ function landstripAvailable(): boolean {
782
787
  }
783
788
  }
784
789
 
785
- // Essential environment variables to forward to the sandboxed process.
786
- // Only these names (plus their lowercase variants) are passed through.
787
- // Filtering prevents E2BIG (Argument list too long) when pi's own
788
- // process environment grows large over a long-running session.
789
- const FORWARD_ENV_NAMES = new Set([
790
- 'PATH',
791
- 'HOME',
792
- 'USER',
793
- 'LOGNAME',
794
- 'SHELL',
795
- 'LANG',
796
- 'LC_ALL',
797
- 'LC_CTYPE',
798
- 'TERM',
799
- 'COLORTERM',
800
- 'TMPDIR',
801
- 'TMP',
802
- 'TEMP',
803
- 'DISPLAY',
804
- 'WAYLAND_DISPLAY',
805
- 'SSH_AUTH_SOCK',
806
- 'SSH_AGENT_PID',
807
- 'XDG_CACHE_HOME',
808
- 'XDG_CONFIG_HOME',
809
- 'XDG_DATA_HOME',
810
- 'XDG_STATE_HOME',
811
- 'XDG_RUNTIME_DIR',
812
- 'DBUS_SESSION_BUS_ADDRESS',
813
- 'NVM_DIR',
814
- 'NVM_INC',
815
- 'NVM_CD_FLAGS',
816
- 'GIT_ASKPASS',
817
- 'GIT_TERMINAL_PROMPT',
818
- 'EDITOR',
819
- 'VISUAL',
820
- 'PAGER',
821
- 'BROWSER',
822
- 'MANPATH',
823
- 'INFOPATH',
824
- 'PKG_CONFIG_PATH',
825
- 'LD_LIBRARY_PATH',
826
- 'JAVA_HOME',
827
- 'GOPATH',
828
- 'GOROOT',
829
- 'CARGO_HOME',
830
- 'RUSTUP_HOME',
831
- 'PYTHONPATH',
832
- 'VIRTUAL_ENV',
833
- 'CONDA_PREFIX',
834
- 'NODE_PATH',
835
- 'npm_config_cache',
836
- 'npm_config_userconfig',
837
- 'DENO_DIR',
838
- 'BUN_INSTALL',
839
- ]);
840
-
841
- function forwardEnv(baseEnv: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
842
- const filtered: NodeJS.ProcessEnv = {};
843
- for (const name of Object.keys(baseEnv)) {
844
- if (FORWARD_ENV_NAMES.has(name) || FORWARD_ENV_NAMES.has(name.toUpperCase())) {
845
- const value = baseEnv[name];
846
- if (value !== undefined) filtered[name] = value;
790
+ // Write the full environment to a temporary shell file.
791
+ //
792
+ // Sandboxed process reaches environment through the filesystem instead of the
793
+ // execve() argument buffer, which has a ~128 KiB cap.
794
+ export function writeEnvFile(
795
+ env: NodeJS.ProcessEnv,
796
+ proxyPort: number | null,
797
+ ): { dir: string; path: string } {
798
+ const lines: string[] = [];
799
+ for (const [key, value] of Object.entries(env)) {
800
+ if (value === undefined) continue;
801
+ // Escape single quotes: ' -> '\''
802
+ const escaped = value.replace(/'/g, "'\\''");
803
+ lines.push(`export ${key}='${escaped}'`);
804
+ }
805
+ if (proxyPort !== null) {
806
+ const url = `http://127.0.0.1:${proxyPort}`;
807
+ for (const v of [
808
+ 'HTTP_PROXY',
809
+ 'HTTPS_PROXY',
810
+ 'ALL_PROXY',
811
+ 'http_proxy',
812
+ 'https_proxy',
813
+ 'all_proxy',
814
+ ]) {
815
+ lines.push(`export ${v}='${url}'`);
847
816
  }
817
+ lines.push("export NO_PROXY=''");
818
+ lines.push("export no_proxy=''");
848
819
  }
849
- return filtered;
850
- }
851
-
852
- function proxyEnv(env: NodeJS.ProcessEnv | undefined, port: number): NodeJS.ProcessEnv {
853
- const url = `http://127.0.0.1:${port}`;
854
-
855
- return {
856
- ...forwardEnv(process.env),
857
- ...env,
858
- HTTP_PROXY: url,
859
- HTTPS_PROXY: url,
860
- ALL_PROXY: url,
861
- http_proxy: url,
862
- https_proxy: url,
863
- all_proxy: url,
864
- NO_PROXY: '',
865
- no_proxy: '',
866
- };
820
+ const dir = mkdtempSync(join(tmpdir(), 'pi-landstrip-env-'));
821
+ const path = join(dir, 'env.sh');
822
+ writeFileSync(path, lines.join('\n'), 'utf-8');
823
+ return { dir, path };
867
824
  }
868
825
 
869
826
  function parseProxyPort(value: string | undefined, defaultPort: number): number | null {
@@ -1234,7 +1191,9 @@ export function createLandstripIntegration(
1234
1191
  const allowNetwork = config.network.allowNetwork;
1235
1192
  const proxy = allowNetwork ? null : await startProxy(cwd);
1236
1193
  const policy = writePolicyFile(cwd, proxy?.port ?? null);
1237
- const landstripArgs = ['--trap-fd', '3', '-p', policy.path, shell, ...args, command];
1194
+ const envFile = writeEnvFile({ ...process.env, ...env }, proxy?.port ?? null);
1195
+ const wrappedCommand = `source '${envFile.path}' && ${command}`;
1196
+ const landstripArgs = ['--trap-fd', '3', '-p', policy.path, shell, ...args, wrappedCommand];
1238
1197
 
1239
1198
  return new Promise((resolvePromise, reject) => {
1240
1199
  (async () => {
@@ -1252,13 +1211,12 @@ export function createLandstripIntegration(
1252
1211
  void proxy?.stop();
1253
1212
  trapSocket.destroy();
1254
1213
  rmSync(policy.dir, { recursive: true, force: true });
1214
+ rmSync(envFile.dir, { recursive: true, force: true });
1255
1215
  };
1256
1216
 
1257
1217
  const child = spawn(binaryPath(), landstripArgs, {
1258
1218
  cwd,
1259
- env: allowNetwork
1260
- ? { ...forwardEnv(process.env), ...env }
1261
- : proxyEnv(env, proxy!.port),
1219
+ env: { PATH: process.env.PATH, HOME: process.env.HOME },
1262
1220
  detached: true,
1263
1221
  stdio: ['ignore', 'pipe', 'pipe', childEnd],
1264
1222
  });
@@ -1464,6 +1422,7 @@ export function createLandstripIntegration(
1464
1422
  onStderr: (data) => {
1465
1423
  stderrOutput += data.toString('utf8');
1466
1424
  },
1425
+ promptOnBlock: true,
1467
1426
  }),
1468
1427
  shellPath: SettingsManager.create(ctx.cwd).getShellPath(),
1469
1428
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-landstrip",
3
- "version": "0.16.20",
3
+ "version": "0.16.22",
4
4
  "description": "Landlock-based sandboxing for pi with interactive permission prompts",
5
5
  "keywords": [
6
6
  "landstrip",