opencode-landstrip 0.16.8 → 0.16.10
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/index.ts +25 -18
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -164,10 +164,6 @@ function matchDepth(filePath: string, patterns: string[], baseDirectory: string)
|
|
|
164
164
|
return depth;
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
function matchesPattern(filePath: string, patterns: string[], baseDirectory: string): boolean {
|
|
168
|
-
return matchDepth(filePath, patterns, baseDirectory) >= 0;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
167
|
function resolveFilesystemPatterns(patterns: string[], baseDirectory: string): string[] {
|
|
172
168
|
return patterns.map((pattern) =>
|
|
173
169
|
pattern.includes('*')
|
|
@@ -188,10 +184,6 @@ function resolveFilesystemConfig(
|
|
|
188
184
|
};
|
|
189
185
|
}
|
|
190
186
|
|
|
191
|
-
function shouldPromptForWrite(path: string, allowWrite: string[], baseDirectory: string): boolean {
|
|
192
|
-
return allowWrite.length === 0 || !matchesPattern(path, allowWrite, baseDirectory);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
187
|
function domainMatchesPattern(domain: string, pattern: string): boolean {
|
|
196
188
|
const normalizedDomain = domain.toLowerCase();
|
|
197
189
|
const normalizedPattern = pattern.toLowerCase();
|
|
@@ -321,17 +313,19 @@ function evaluateWritePermission(
|
|
|
321
313
|
effectiveAllowWrite: string[],
|
|
322
314
|
): SandboxPermissionDecision {
|
|
323
315
|
const filePath = canonicalizePath(path, baseDirectory);
|
|
316
|
+
const allowDepth = matchDepth(filePath, effectiveAllowWrite, baseDirectory);
|
|
317
|
+
const denyDepth = matchDepth(filePath, config.filesystem.denyWrite, baseDirectory);
|
|
324
318
|
|
|
325
|
-
if (
|
|
319
|
+
if (denyDepth > allowDepth) {
|
|
326
320
|
return {
|
|
327
321
|
status: 'deny',
|
|
328
322
|
kind: 'write',
|
|
329
323
|
resource: filePath,
|
|
330
|
-
message: `Sandbox: write access denied for "${filePath}" (
|
|
324
|
+
message: `Sandbox: write access denied for "${filePath}" (denyWrite overrides allowWrite).`,
|
|
331
325
|
};
|
|
332
326
|
}
|
|
333
327
|
|
|
334
|
-
if (
|
|
328
|
+
if (allowDepth >= 0) {
|
|
335
329
|
return { status: 'allow', kind: 'write', resource: filePath, message: '' };
|
|
336
330
|
}
|
|
337
331
|
|
|
@@ -665,12 +659,17 @@ function buildWrappedCommand(
|
|
|
665
659
|
if (trapPort === null) return plain;
|
|
666
660
|
|
|
667
661
|
// Connect fd 3 to the TUI's query-response socket BEFORE landstrip applies the
|
|
668
|
-
// sandbox, so a denied
|
|
669
|
-
//
|
|
670
|
-
//
|
|
671
|
-
//
|
|
662
|
+
// sandbox, so a denied filesystem access can be approved live instead of
|
|
663
|
+
// forcing a re-run.
|
|
664
|
+
//
|
|
665
|
+
// /dev/tcp is a bash/ksh built-in — it does not work in zsh, dash, or fish.
|
|
666
|
+
// We try the native redirect first (fast path when the host shell supports it)
|
|
667
|
+
// and fall back to an explicit bash invocation that always speaks /dev/tcp.
|
|
668
|
+
// If both fail (no bash, dead port, set -e in the outer shell) landstrip runs
|
|
669
|
+
// without --trap-fd so the toast-notify path still works.
|
|
672
670
|
const trapped = [landstripBinaryPath(), '--trap-fd', '3', ...baseArgs].map(shellQuote).join(' ');
|
|
673
|
-
|
|
671
|
+
const bashTrap = `bash -c ${shellQuote(`exec 3<>/dev/tcp/127.0.0.1/${trapPort} && exec "$@"`)} bash ${trapped}`;
|
|
672
|
+
return `{ exec 3<>/dev/tcp/127.0.0.1/${trapPort} ; } 2>/dev/null && ${trapped} || ${bashTrap} 2>/dev/null || ${plain}`;
|
|
674
673
|
}
|
|
675
674
|
|
|
676
675
|
function isGeneratedWrappedCommand(command: string): boolean {
|
|
@@ -696,11 +695,19 @@ function splitShellQuotedArgs(command: string): string[] {
|
|
|
696
695
|
if (command[i] === "'") {
|
|
697
696
|
i++;
|
|
698
697
|
let arg = '';
|
|
699
|
-
while (i < command.length
|
|
698
|
+
while (i < command.length) {
|
|
699
|
+
if (command[i] === "'") {
|
|
700
|
+
if (command[i + 1] === '\\' && command[i + 2] === "'" && command[i + 3] === "'") {
|
|
701
|
+
arg += "'";
|
|
702
|
+
i += 4;
|
|
703
|
+
continue;
|
|
704
|
+
}
|
|
705
|
+
i++;
|
|
706
|
+
break;
|
|
707
|
+
}
|
|
700
708
|
arg += command[i];
|
|
701
709
|
i++;
|
|
702
710
|
}
|
|
703
|
-
if (i < command.length) i++;
|
|
704
711
|
args.push(arg);
|
|
705
712
|
} else {
|
|
706
713
|
let arg = '';
|