opencode-landstrip 0.14.2 → 0.15.0
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 +40 -41
- package/package.json +2 -2
package/index.ts
CHANGED
|
@@ -33,11 +33,11 @@ interface LandstripPolicy {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
type LandstripTrap =
|
|
36
|
-
| { kind: '
|
|
37
|
-
| { kind: '
|
|
38
|
-
| { kind: '
|
|
39
|
-
| { kind: '
|
|
40
|
-
| { kind: '
|
|
36
|
+
| { kind: 'filesystem'; operation: 'read' | 'write'; path: string; mechanism: string }
|
|
37
|
+
| { kind: 'network'; operation: string; target: string; mechanism: string }
|
|
38
|
+
| { kind: 'launch'; program: string; message: string }
|
|
39
|
+
| { kind: 'usage'; message: string }
|
|
40
|
+
| { kind: 'internal'; detail: Record<string, string> };
|
|
41
41
|
|
|
42
42
|
interface BashSandboxState {
|
|
43
43
|
originalCommand: string;
|
|
@@ -58,7 +58,7 @@ interface SandboxPermissionDecision {
|
|
|
58
58
|
|
|
59
59
|
type ToastVariant = 'info' | 'success' | 'warning' | 'error';
|
|
60
60
|
|
|
61
|
-
const LANDSTRIP_VERSION = [0,
|
|
61
|
+
const LANDSTRIP_VERSION = [0, 15, 1] as const;
|
|
62
62
|
const REQUIRED_LANDSTRIP_VERSION = LANDSTRIP_VERSION.join('.');
|
|
63
63
|
const LANDSTRIP_OPERATIONS = new Set<'read' | 'write'>(['read', 'write']);
|
|
64
64
|
const SUPPORTED_PLATFORMS = new Set<NodeJS.Platform>(['linux', 'darwin', 'win32']);
|
|
@@ -247,9 +247,9 @@ function extractBlockedPath(
|
|
|
247
247
|
// Landstrip structured trap format carrying a denied path
|
|
248
248
|
const landstripErrors = parseLandstripErrors(output);
|
|
249
249
|
for (const trap of landstripErrors) {
|
|
250
|
-
if (trap.kind === '
|
|
251
|
-
if (trap.kind === '
|
|
252
|
-
return normalizeBlockedPath(trap.
|
|
250
|
+
if (trap.kind === 'filesystem') return normalizeBlockedPath(trap.path, baseDirectory);
|
|
251
|
+
if (trap.kind === 'internal' && trap.detail.file) {
|
|
252
|
+
return normalizeBlockedPath(trap.detail.file, baseDirectory);
|
|
253
253
|
}
|
|
254
254
|
}
|
|
255
255
|
|
|
@@ -407,40 +407,39 @@ function hasMinimumVersion(version: string, minimum: readonly [number, number, n
|
|
|
407
407
|
|
|
408
408
|
function decodeLandstripTrap(value: unknown): LandstripTrap | null {
|
|
409
409
|
if (typeof value !== 'object' || value === null || Array.isArray(value)) return null;
|
|
410
|
-
const
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
if (!Array.isArray(payload)) return null;
|
|
417
|
-
const [operation, path, mechanism] = payload;
|
|
410
|
+
const record = value as Record<string, unknown>;
|
|
411
|
+
const mechanism = typeof record.mechanism === 'string' ? record.mechanism : '';
|
|
412
|
+
|
|
413
|
+
switch (record.kind) {
|
|
414
|
+
case 'filesystem': {
|
|
415
|
+
const { operation, path } = record;
|
|
418
416
|
if (!isLandstripOperation(operation) || typeof path !== 'string') return null;
|
|
419
|
-
return { kind, operation, path, mechanism
|
|
417
|
+
return { kind: 'filesystem', operation, path, mechanism };
|
|
420
418
|
}
|
|
421
|
-
case '
|
|
422
|
-
|
|
423
|
-
const [operation, target, mechanism] = payload;
|
|
419
|
+
case 'network': {
|
|
420
|
+
const { operation, target } = record;
|
|
424
421
|
if (typeof operation !== 'string' || typeof target !== 'string') return null;
|
|
425
|
-
return { kind, operation, target, mechanism
|
|
422
|
+
return { kind: 'network', operation, target, mechanism };
|
|
426
423
|
}
|
|
427
|
-
case '
|
|
428
|
-
|
|
429
|
-
const [program, message] = payload;
|
|
424
|
+
case 'launch': {
|
|
425
|
+
const { program, message } = record;
|
|
430
426
|
if (typeof program !== 'string') return null;
|
|
431
|
-
return { kind, program, message: typeof message === 'string' ? message : '' };
|
|
427
|
+
return { kind: 'launch', program, message: typeof message === 'string' ? message : '' };
|
|
432
428
|
}
|
|
433
|
-
case '
|
|
434
|
-
|
|
435
|
-
|
|
429
|
+
case 'usage': {
|
|
430
|
+
const { message } = record;
|
|
431
|
+
if (typeof message !== 'string') return null;
|
|
432
|
+
return { kind: 'usage', message };
|
|
436
433
|
}
|
|
437
|
-
case '
|
|
438
|
-
|
|
439
|
-
const
|
|
440
|
-
|
|
441
|
-
|
|
434
|
+
case 'internal': {
|
|
435
|
+
const detail: Record<string, string> = {};
|
|
436
|
+
const payload = record.detail;
|
|
437
|
+
if (typeof payload === 'object' && payload !== null && !Array.isArray(payload)) {
|
|
438
|
+
for (const [key, val] of Object.entries(payload as Record<string, unknown>)) {
|
|
439
|
+
detail[key] = typeof val === 'string' ? val : JSON.stringify(val);
|
|
440
|
+
}
|
|
442
441
|
}
|
|
443
|
-
return { kind,
|
|
442
|
+
return { kind: 'internal', detail };
|
|
444
443
|
}
|
|
445
444
|
default:
|
|
446
445
|
return null;
|
|
@@ -470,20 +469,20 @@ function parseLandstripErrors(output: string): LandstripTrap[] {
|
|
|
470
469
|
|
|
471
470
|
function formatLandstripTrap(trap: LandstripTrap): string {
|
|
472
471
|
switch (trap.kind) {
|
|
473
|
-
case '
|
|
472
|
+
case 'filesystem':
|
|
474
473
|
return `landstrip: filesystem ${trap.operation} denied (${trap.path})${
|
|
475
474
|
trap.mechanism ? ` [${trap.mechanism}]` : ''
|
|
476
475
|
}`;
|
|
477
|
-
case '
|
|
476
|
+
case 'network':
|
|
478
477
|
return `landstrip: network ${trap.operation} denied (${trap.target})${
|
|
479
478
|
trap.mechanism ? ` [${trap.mechanism}]` : ''
|
|
480
479
|
}`;
|
|
481
|
-
case '
|
|
480
|
+
case 'launch':
|
|
482
481
|
return `landstrip: launch failed (${trap.program})${trap.message ? `: ${trap.message}` : ''}`;
|
|
483
|
-
case '
|
|
482
|
+
case 'usage':
|
|
484
483
|
return `landstrip: usage error: ${trap.message}`;
|
|
485
|
-
case '
|
|
486
|
-
const detail = Object.entries(trap.
|
|
484
|
+
case 'internal': {
|
|
485
|
+
const detail = Object.entries(trap.detail)
|
|
487
486
|
.map(([key, val]) => `${key}: ${val}`)
|
|
488
487
|
.join(', ');
|
|
489
488
|
return `landstrip: internal error${detail ? ` (${detail})` : ''}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-landstrip",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "Landlock-based sandboxing for opencode with landstrip",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"landlock",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"ci:test": "npm test"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@landstrip/landstrip": "^0.
|
|
52
|
+
"@landstrip/landstrip": "^0.15.1"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@opencode-ai/plugin": "^1.17.7",
|