@bike4mind/cli 0.2.29-feat-cli-sandbox.18842 → 0.2.29-feat-session-permission.18841
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/{chunk-JJL2EFHA.js → chunk-LBTTUQJM.js} +3 -62
- package/dist/commands/mcpCommand.js +1 -2
- package/dist/index.js +51 -201
- package/package.json +6 -6
- package/dist/BubblewrapRuntime-EJM4QF7U.js +0 -68
- package/dist/SandboxOrchestrator-AEOHC2BL.js +0 -101
- package/dist/SandboxRuntimeAdapter-SRX3IM2Q.js +0 -13
- package/dist/SeatbeltRuntime-DZMEIRPM.js +0 -92
- package/dist/chunk-PRJKJWD6.js +0 -44
- package/dist/chunk-XPSG72HV.js +0 -26
- package/dist/types-2T7ALTCA.js +0 -7
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
DEFAULT_SANDBOX_CONFIG
|
|
4
|
-
} from "./chunk-XPSG72HV.js";
|
|
5
2
|
|
|
6
3
|
// src/utils/Logger.ts
|
|
7
4
|
import fs from "fs/promises";
|
|
@@ -265,39 +262,6 @@ import path2 from "path";
|
|
|
265
262
|
import { homedir } from "os";
|
|
266
263
|
import { v4 as uuidv4 } from "uuid";
|
|
267
264
|
import { z } from "zod";
|
|
268
|
-
var SandboxFilesystemSchema = z.object({
|
|
269
|
-
allowedReadPaths: z.array(z.string()).default(DEFAULT_SANDBOX_CONFIG.filesystem.allowedReadPaths),
|
|
270
|
-
deniedPaths: z.array(z.string()).default(DEFAULT_SANDBOX_CONFIG.filesystem.deniedPaths),
|
|
271
|
-
writeOnlyToWorkingDir: z.boolean().default(true)
|
|
272
|
-
});
|
|
273
|
-
var SandboxPlatformSchema = z.object({
|
|
274
|
-
linux: z.object({
|
|
275
|
-
runtime: z.literal("bubblewrap").default("bubblewrap"),
|
|
276
|
-
seccompProfile: z.string().optional()
|
|
277
|
-
}).default({ runtime: "bubblewrap" }),
|
|
278
|
-
macos: z.object({
|
|
279
|
-
runtime: z.literal("seatbelt").default("seatbelt"),
|
|
280
|
-
profileTemplate: z.string().default("default")
|
|
281
|
-
}).default({ runtime: "seatbelt", profileTemplate: "default" })
|
|
282
|
-
});
|
|
283
|
-
var SandboxConfigSchema = z.object({
|
|
284
|
-
enabled: z.boolean().default(false),
|
|
285
|
-
mode: z.enum(["disabled", "auto-allow", "permissions"]).default("disabled"),
|
|
286
|
-
filesystem: SandboxFilesystemSchema.default(DEFAULT_SANDBOX_CONFIG.filesystem),
|
|
287
|
-
excludedCommands: z.array(z.string()).default(DEFAULT_SANDBOX_CONFIG.excludedCommands),
|
|
288
|
-
platform: SandboxPlatformSchema.default(DEFAULT_SANDBOX_CONFIG.platform)
|
|
289
|
-
});
|
|
290
|
-
var PartialSandboxConfigSchema = z.object({
|
|
291
|
-
enabled: z.boolean().optional(),
|
|
292
|
-
mode: z.enum(["disabled", "auto-allow", "permissions"]).optional(),
|
|
293
|
-
filesystem: z.object({
|
|
294
|
-
allowedReadPaths: z.array(z.string()).optional(),
|
|
295
|
-
deniedPaths: z.array(z.string()).optional(),
|
|
296
|
-
writeOnlyToWorkingDir: z.boolean().optional()
|
|
297
|
-
}).optional(),
|
|
298
|
-
excludedCommands: z.array(z.string()).optional(),
|
|
299
|
-
platform: SandboxPlatformSchema.optional()
|
|
300
|
-
}).optional();
|
|
301
265
|
var AuthTokensSchema = z.object({
|
|
302
266
|
accessToken: z.string(),
|
|
303
267
|
refreshToken: z.string(),
|
|
@@ -372,8 +336,7 @@ var CliConfigSchema = z.object({
|
|
|
372
336
|
disabled: z.array(z.string()),
|
|
373
337
|
config: z.record(z.any())
|
|
374
338
|
}),
|
|
375
|
-
trustedTools: z.array(z.string()).optional().default([])
|
|
376
|
-
sandbox: SandboxConfigSchema.optional()
|
|
339
|
+
trustedTools: z.array(z.string()).optional().default([])
|
|
377
340
|
});
|
|
378
341
|
var ProjectConfigSchema = z.object({
|
|
379
342
|
tools: z.object({
|
|
@@ -391,8 +354,7 @@ var ProjectConfigSchema = z.object({
|
|
|
391
354
|
theme: z.enum(["light", "dark"]).optional(),
|
|
392
355
|
exportFormat: z.enum(["markdown", "json"]).optional(),
|
|
393
356
|
enableSkillTool: z.boolean().optional()
|
|
394
|
-
}).optional()
|
|
395
|
-
sandbox: PartialSandboxConfigSchema
|
|
357
|
+
}).optional()
|
|
396
358
|
});
|
|
397
359
|
var ProjectLocalConfigSchema = z.object({
|
|
398
360
|
trustedTools: z.array(z.string()).optional(),
|
|
@@ -409,8 +371,7 @@ var ProjectLocalConfigSchema = z.object({
|
|
|
409
371
|
exportFormat: z.enum(["markdown", "json"]).optional(),
|
|
410
372
|
enableSkillTool: z.boolean().optional()
|
|
411
373
|
}).optional(),
|
|
412
|
-
mcpServers: McpServersSchema.optional()
|
|
413
|
-
sandbox: PartialSandboxConfigSchema
|
|
374
|
+
mcpServers: McpServersSchema.optional()
|
|
414
375
|
});
|
|
415
376
|
var DEFAULT_CONFIG = {
|
|
416
377
|
version: "0.1.0",
|
|
@@ -535,20 +496,6 @@ function mergeMcpServers(...serverArrays) {
|
|
|
535
496
|
}
|
|
536
497
|
return Array.from(serverMap.values());
|
|
537
498
|
}
|
|
538
|
-
function mergeSandboxConfig(base, override) {
|
|
539
|
-
const resolved = base ?? DEFAULT_SANDBOX_CONFIG;
|
|
540
|
-
if (!override) return resolved;
|
|
541
|
-
return {
|
|
542
|
-
enabled: override.enabled ?? resolved.enabled,
|
|
543
|
-
mode: override.mode ?? resolved.mode,
|
|
544
|
-
filesystem: {
|
|
545
|
-
...resolved.filesystem,
|
|
546
|
-
...override.filesystem ?? {}
|
|
547
|
-
},
|
|
548
|
-
excludedCommands: override.excludedCommands ?? resolved.excludedCommands,
|
|
549
|
-
platform: override.platform ?? resolved.platform
|
|
550
|
-
};
|
|
551
|
-
}
|
|
552
499
|
function mergeConfigs(global, project, local) {
|
|
553
500
|
const merged = { ...global };
|
|
554
501
|
if (project) {
|
|
@@ -575,9 +522,6 @@ function mergeConfigs(global, project, local) {
|
|
|
575
522
|
if (project.mcpServers) {
|
|
576
523
|
merged.mcpServers = mergeMcpServers(merged.mcpServers, project.mcpServers);
|
|
577
524
|
}
|
|
578
|
-
if (project.sandbox) {
|
|
579
|
-
merged.sandbox = mergeSandboxConfig(merged.sandbox, project.sandbox);
|
|
580
|
-
}
|
|
581
525
|
}
|
|
582
526
|
if (local) {
|
|
583
527
|
if (local.trustedTools) {
|
|
@@ -599,9 +543,6 @@ function mergeConfigs(global, project, local) {
|
|
|
599
543
|
if (local.mcpServers) {
|
|
600
544
|
merged.mcpServers = mergeMcpServers(merged.mcpServers, local.mcpServers);
|
|
601
545
|
}
|
|
602
|
-
if (local.sandbox) {
|
|
603
|
-
merged.sandbox = mergeSandboxConfig(merged.sandbox, local.sandbox);
|
|
604
|
-
}
|
|
605
546
|
}
|
|
606
547
|
return merged;
|
|
607
548
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "./chunk-ELTTBWAQ.js";
|
|
3
2
|
import "./chunk-BPFEGDC7.js";
|
|
4
3
|
import "./chunk-BDQBOLYG.js";
|
|
5
4
|
import {
|
|
@@ -10,13 +9,13 @@ import {
|
|
|
10
9
|
import {
|
|
11
10
|
ConfigStore,
|
|
12
11
|
logger
|
|
13
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-LBTTUQJM.js";
|
|
14
13
|
import {
|
|
15
14
|
selectActiveBackgroundAgents,
|
|
16
15
|
useCliStore
|
|
17
16
|
} from "./chunk-TVW4ZESU.js";
|
|
18
|
-
import "./chunk-XPSG72HV.js";
|
|
19
17
|
import "./chunk-PKKJ44C5.js";
|
|
18
|
+
import "./chunk-ELTTBWAQ.js";
|
|
20
19
|
import {
|
|
21
20
|
BFLImageService,
|
|
22
21
|
BaseStorage,
|
|
@@ -646,24 +645,6 @@ var COMMANDS = [
|
|
|
646
645
|
name: "compact",
|
|
647
646
|
description: "Compact conversation into new session",
|
|
648
647
|
args: "[instructions]"
|
|
649
|
-
},
|
|
650
|
-
// Sandbox commands
|
|
651
|
-
{
|
|
652
|
-
name: "sandbox",
|
|
653
|
-
description: "Show sandbox status and configuration"
|
|
654
|
-
},
|
|
655
|
-
{
|
|
656
|
-
name: "sandbox:enable",
|
|
657
|
-
description: "Enable OS-level sandbox for bash commands"
|
|
658
|
-
},
|
|
659
|
-
{
|
|
660
|
-
name: "sandbox:disable",
|
|
661
|
-
description: "Disable sandbox mode"
|
|
662
|
-
},
|
|
663
|
-
{
|
|
664
|
-
name: "sandbox:mode",
|
|
665
|
-
description: "Set sandbox mode (auto-allow or permissions)",
|
|
666
|
-
args: "<auto-allow|permissions>"
|
|
667
648
|
}
|
|
668
649
|
];
|
|
669
650
|
function getAllCommandNames() {
|
|
@@ -1279,10 +1260,12 @@ function PermissionPrompt({
|
|
|
1279
1260
|
}) {
|
|
1280
1261
|
const items = canBeTrusted ? [
|
|
1281
1262
|
{ label: "\u2713 Allow once", value: "allow-once" },
|
|
1263
|
+
{ label: "\u2713 Allow for this session", value: "allow-session" },
|
|
1282
1264
|
{ label: "\u2713 Always allow (trust this tool)", value: "allow-always" },
|
|
1283
1265
|
{ label: "\u2717 Deny", value: "deny" }
|
|
1284
1266
|
] : [
|
|
1285
1267
|
{ label: "\u2713 Allow once", value: "allow-once" },
|
|
1268
|
+
{ label: "\u2713 Allow for this session", value: "allow-session" },
|
|
1286
1269
|
{ label: "\u2717 Deny", value: "deny" }
|
|
1287
1270
|
];
|
|
1288
1271
|
const [selectedIndex, setSelectedIndex] = useState3(0);
|
|
@@ -3711,9 +3694,6 @@ EXAMPLES:
|
|
|
3711
3694
|
Remember: Use context from previous messages to understand follow-up questions.${contextSection}`;
|
|
3712
3695
|
}
|
|
3713
3696
|
|
|
3714
|
-
// src/utils/toolsAdapter.ts
|
|
3715
|
-
import { rmSync } from "fs";
|
|
3716
|
-
|
|
3717
3697
|
// ../../b4m-core/packages/services/dist/src/referService/generateCodes.js
|
|
3718
3698
|
import { randomBytes } from "crypto";
|
|
3719
3699
|
import range from "lodash/range.js";
|
|
@@ -11732,42 +11712,20 @@ var CliLogger = class extends Logger {
|
|
|
11732
11712
|
log(...args) {
|
|
11733
11713
|
}
|
|
11734
11714
|
};
|
|
11735
|
-
function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore, apiClient
|
|
11715
|
+
function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore, apiClient) {
|
|
11736
11716
|
const originalFn = tool.toolFn;
|
|
11737
11717
|
const toolName = tool.toolSchema.name;
|
|
11738
11718
|
return {
|
|
11739
11719
|
...tool,
|
|
11740
11720
|
toolFn: async (args) => {
|
|
11741
|
-
|
|
11742
|
-
|
|
11743
|
-
if (toolName === "bash_execute" && args?.command && sandboxOrchestrator) {
|
|
11744
|
-
const pathMod = await import("path");
|
|
11745
|
-
const cwd = args.cwd ? pathMod.resolve(process.cwd(), args.cwd) : process.cwd();
|
|
11746
|
-
const decision = sandboxOrchestrator.shouldSandbox(args.command, cwd);
|
|
11747
|
-
if (decision.type === "blocked") {
|
|
11748
|
-
return `Command blocked by sandbox: ${decision.reason}`;
|
|
11749
|
-
}
|
|
11750
|
-
if (decision.type === "sandbox") {
|
|
11751
|
-
isSandboxed = true;
|
|
11752
|
-
sandboxedArgs = {
|
|
11753
|
-
...args,
|
|
11754
|
-
command: decision.wrappedCommand.commandString,
|
|
11755
|
-
// Store cleanup paths for post-execution cleanup
|
|
11756
|
-
_sandboxCleanup: decision.wrappedCommand.cleanupPaths
|
|
11757
|
-
};
|
|
11758
|
-
}
|
|
11759
|
-
}
|
|
11760
|
-
const effectiveArgs = isSandboxed ? sandboxedArgs : args;
|
|
11761
|
-
if (!permissionManager.needsPermission(toolName, { isSandboxed })) {
|
|
11762
|
-
const result2 = await executeTool(toolName, effectiveArgs, apiClient, originalFn);
|
|
11763
|
-
cleanupSandboxFiles(effectiveArgs?._sandboxCleanup);
|
|
11721
|
+
if (!permissionManager.needsPermission(toolName)) {
|
|
11722
|
+
const result2 = await executeTool(toolName, args, apiClient, originalFn);
|
|
11764
11723
|
agentContext.observationQueue.push({ toolName, result: result2 });
|
|
11765
11724
|
return result2;
|
|
11766
11725
|
}
|
|
11767
11726
|
const { useCliStore: useCliStore2 } = await import("./store-FU6NDC2W.js");
|
|
11768
11727
|
if (useCliStore2.getState().autoAcceptEdits) {
|
|
11769
|
-
const result2 = await executeTool(toolName,
|
|
11770
|
-
cleanupSandboxFiles(effectiveArgs?._sandboxCleanup);
|
|
11728
|
+
const result2 = await executeTool(toolName, args, apiClient, originalFn);
|
|
11771
11729
|
agentContext.observationQueue.push({ toolName, result: result2 });
|
|
11772
11730
|
return result2;
|
|
11773
11731
|
}
|
|
@@ -11802,13 +11760,15 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
|
|
|
11802
11760
|
} else if (toolName === "bash_execute" && args?.command) {
|
|
11803
11761
|
const cwd = args.cwd ? ` (in ${args.cwd})` : "";
|
|
11804
11762
|
const timeout = args.timeout ? ` [timeout: ${args.timeout}ms]` : "";
|
|
11805
|
-
|
|
11806
|
-
preview = `$ ${args.command}${cwd}${timeout}${sandboxLabel}`;
|
|
11763
|
+
preview = `$ ${args.command}${cwd}${timeout}`;
|
|
11807
11764
|
}
|
|
11808
|
-
const response = await showPermissionPrompt(toolName,
|
|
11765
|
+
const response = await showPermissionPrompt(toolName, args, preview);
|
|
11809
11766
|
if (response.action === "deny") {
|
|
11810
11767
|
throw new PermissionDeniedError(toolName, args);
|
|
11811
11768
|
}
|
|
11769
|
+
if (response.action === "allow-session") {
|
|
11770
|
+
permissionManager.trustToolForSession(toolName);
|
|
11771
|
+
}
|
|
11812
11772
|
if (response.action === "allow-always") {
|
|
11813
11773
|
const canTrust = permissionManager.trustTool(toolName);
|
|
11814
11774
|
if (canTrust) {
|
|
@@ -11830,22 +11790,12 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
|
|
|
11830
11790
|
}
|
|
11831
11791
|
}
|
|
11832
11792
|
}
|
|
11833
|
-
const result = await executeTool(toolName,
|
|
11834
|
-
cleanupSandboxFiles(effectiveArgs?._sandboxCleanup);
|
|
11793
|
+
const result = await executeTool(toolName, args, apiClient, originalFn);
|
|
11835
11794
|
agentContext.observationQueue.push({ toolName, result });
|
|
11836
11795
|
return result;
|
|
11837
11796
|
}
|
|
11838
11797
|
};
|
|
11839
11798
|
}
|
|
11840
|
-
function cleanupSandboxFiles(paths) {
|
|
11841
|
-
if (!paths || paths.length === 0) return;
|
|
11842
|
-
for (const p of paths) {
|
|
11843
|
-
try {
|
|
11844
|
-
rmSync(p, { recursive: true, force: true });
|
|
11845
|
-
} catch {
|
|
11846
|
-
}
|
|
11847
|
-
}
|
|
11848
|
-
}
|
|
11849
11799
|
function wrapToolWithHooks(tool, hooks, hookContext) {
|
|
11850
11800
|
const hasToolHooks = hooks?.PreToolUse || hooks?.PostToolUse || hooks?.PostToolUseFailure;
|
|
11851
11801
|
if (!hasToolHooks) {
|
|
@@ -11939,7 +11889,7 @@ function normalizeToolName(toolName) {
|
|
|
11939
11889
|
}
|
|
11940
11890
|
return TOOL_NAME_MAPPING[toolName] || toolName;
|
|
11941
11891
|
}
|
|
11942
|
-
function generateCliTools(userId, llm, model, permissionManager, showPermissionPrompt, agentContext, configStore, apiClient, toolFilter
|
|
11892
|
+
function generateCliTools(userId, llm, model, permissionManager, showPermissionPrompt, agentContext, configStore, apiClient, toolFilter) {
|
|
11943
11893
|
const logger2 = new CliLogger();
|
|
11944
11894
|
const storage = new NoOpStorage();
|
|
11945
11895
|
const user = {
|
|
@@ -11999,15 +11949,7 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
|
|
|
11999
11949
|
tools_to_generate
|
|
12000
11950
|
);
|
|
12001
11951
|
let tools = Object.entries(toolsMap).map(
|
|
12002
|
-
([_, tool]) => wrapToolWithPermission(
|
|
12003
|
-
tool,
|
|
12004
|
-
permissionManager,
|
|
12005
|
-
showPermissionPrompt,
|
|
12006
|
-
agentContext,
|
|
12007
|
-
configStore,
|
|
12008
|
-
apiClient,
|
|
12009
|
-
sandboxOrchestrator
|
|
12010
|
-
)
|
|
11952
|
+
([_, tool]) => wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore, apiClient)
|
|
12011
11953
|
);
|
|
12012
11954
|
if (toolFilter) {
|
|
12013
11955
|
const { allowedTools, deniedTools } = toolFilter;
|
|
@@ -12031,22 +11973,12 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
|
|
|
12031
11973
|
var PermissionManager = class {
|
|
12032
11974
|
constructor(trustedTools = [], customCategories, deniedTools) {
|
|
12033
11975
|
this.trustedTools = /* @__PURE__ */ new Set();
|
|
11976
|
+
this.sessionTrustedTools = /* @__PURE__ */ new Set();
|
|
12034
11977
|
this.deniedTools = /* @__PURE__ */ new Set();
|
|
12035
|
-
this._sandboxMode = "disabled";
|
|
12036
|
-
this._sandboxActive = false;
|
|
12037
11978
|
this.trustedTools = new Set(trustedTools);
|
|
12038
11979
|
this.customCategories = new Map(Object.entries(customCategories || {}));
|
|
12039
11980
|
this.deniedTools = new Set(deniedTools || []);
|
|
12040
11981
|
}
|
|
12041
|
-
/** Update sandbox state from the orchestrator */
|
|
12042
|
-
setSandboxState(mode, active) {
|
|
12043
|
-
this._sandboxMode = mode;
|
|
12044
|
-
this._sandboxActive = active;
|
|
12045
|
-
}
|
|
12046
|
-
/** Check if sandbox auto-allow is active */
|
|
12047
|
-
isSandboxAutoAllow() {
|
|
12048
|
-
return this._sandboxMode === "auto-allow" && this._sandboxActive;
|
|
12049
|
-
}
|
|
12050
11982
|
/**
|
|
12051
11983
|
* Check if a tool needs permission before execution
|
|
12052
11984
|
*
|
|
@@ -12057,13 +11989,8 @@ var PermissionManager = class {
|
|
|
12057
11989
|
*
|
|
12058
11990
|
* Note: prompt_always tools CANNOT be trusted, so they always need permission
|
|
12059
11991
|
* Note: denied tools from project config ALWAYS need permission (cannot be overridden locally)
|
|
12060
|
-
*
|
|
12061
|
-
* @param toolName - The tool being checked
|
|
12062
|
-
* @param options.isSandboxed - If true, the command will run inside the OS-level sandbox.
|
|
12063
|
-
* In auto-allow mode, sandboxed bash_execute commands skip the permission prompt
|
|
12064
|
-
* because the sandbox provides the security boundary.
|
|
12065
11992
|
*/
|
|
12066
|
-
needsPermission(toolName
|
|
11993
|
+
needsPermission(toolName) {
|
|
12067
11994
|
const categoryMap = Object.fromEntries(this.customCategories);
|
|
12068
11995
|
const category = getToolCategory(toolName, categoryMap);
|
|
12069
11996
|
if (this.deniedTools.has(toolName)) {
|
|
@@ -12072,7 +11999,7 @@ var PermissionManager = class {
|
|
|
12072
11999
|
if (category === "auto_approve") {
|
|
12073
12000
|
return false;
|
|
12074
12001
|
}
|
|
12075
|
-
if (
|
|
12002
|
+
if (this.sessionTrustedTools.has(toolName)) {
|
|
12076
12003
|
return false;
|
|
12077
12004
|
}
|
|
12078
12005
|
if (category === "prompt_always") {
|
|
@@ -12142,6 +12069,29 @@ var PermissionManager = class {
|
|
|
12142
12069
|
getDeniedTools() {
|
|
12143
12070
|
return Array.from(this.deniedTools).sort();
|
|
12144
12071
|
}
|
|
12072
|
+
/**
|
|
12073
|
+
* Trust a tool for the current session only (in-memory, no persistence)
|
|
12074
|
+
* Works for all tool categories including prompt_always, but NOT project-denied tools
|
|
12075
|
+
*/
|
|
12076
|
+
trustToolForSession(toolName) {
|
|
12077
|
+
if (this.deniedTools.has(toolName)) {
|
|
12078
|
+
return false;
|
|
12079
|
+
}
|
|
12080
|
+
this.sessionTrustedTools.add(toolName);
|
|
12081
|
+
return true;
|
|
12082
|
+
}
|
|
12083
|
+
/**
|
|
12084
|
+
* Check if a tool is trusted for the current session
|
|
12085
|
+
*/
|
|
12086
|
+
isSessionTrusted(toolName) {
|
|
12087
|
+
return this.sessionTrustedTools.has(toolName);
|
|
12088
|
+
}
|
|
12089
|
+
/**
|
|
12090
|
+
* Clear all session-scoped trust (called on exit or session reset)
|
|
12091
|
+
*/
|
|
12092
|
+
clearSessionTrust() {
|
|
12093
|
+
this.sessionTrustedTools.clear();
|
|
12094
|
+
}
|
|
12145
12095
|
/**
|
|
12146
12096
|
* Clear all trusted tools
|
|
12147
12097
|
*/
|
|
@@ -13643,7 +13593,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
|
|
|
13643
13593
|
// package.json
|
|
13644
13594
|
var package_default = {
|
|
13645
13595
|
name: "@bike4mind/cli",
|
|
13646
|
-
version: "0.2.29-feat-
|
|
13596
|
+
version: "0.2.29-feat-session-permission.18841+6d9c4deb5",
|
|
13647
13597
|
type: "module",
|
|
13648
13598
|
description: "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
13649
13599
|
license: "UNLICENSED",
|
|
@@ -13753,10 +13703,10 @@ var package_default = {
|
|
|
13753
13703
|
},
|
|
13754
13704
|
devDependencies: {
|
|
13755
13705
|
"@bike4mind/agents": "0.1.0",
|
|
13756
|
-
"@bike4mind/common": "2.50.1-feat-
|
|
13757
|
-
"@bike4mind/mcp": "1.29.1-feat-
|
|
13758
|
-
"@bike4mind/services": "2.48.1-feat-
|
|
13759
|
-
"@bike4mind/utils": "2.5.1-feat-
|
|
13706
|
+
"@bike4mind/common": "2.50.1-feat-session-permission.18841+6d9c4deb5",
|
|
13707
|
+
"@bike4mind/mcp": "1.29.1-feat-session-permission.18841+6d9c4deb5",
|
|
13708
|
+
"@bike4mind/services": "2.48.1-feat-session-permission.18841+6d9c4deb5",
|
|
13709
|
+
"@bike4mind/utils": "2.5.1-feat-session-permission.18841+6d9c4deb5",
|
|
13760
13710
|
"@types/better-sqlite3": "^7.6.13",
|
|
13761
13711
|
"@types/diff": "^5.0.9",
|
|
13762
13712
|
"@types/jsonwebtoken": "^9.0.4",
|
|
@@ -13773,7 +13723,7 @@ var package_default = {
|
|
|
13773
13723
|
optionalDependencies: {
|
|
13774
13724
|
"@vscode/ripgrep": "^1.17.0"
|
|
13775
13725
|
},
|
|
13776
|
-
gitHead: "
|
|
13726
|
+
gitHead: "6d9c4deb5a83cfc1087043d22f407d3444a91cca"
|
|
13777
13727
|
};
|
|
13778
13728
|
|
|
13779
13729
|
// src/config/constants.ts
|
|
@@ -15581,8 +15531,7 @@ function CliApp() {
|
|
|
15581
15531
|
agentStore: null,
|
|
15582
15532
|
abortController: null,
|
|
15583
15533
|
contextContent: "",
|
|
15584
|
-
backgroundManager: null
|
|
15585
|
-
sandboxOrchestrator: null
|
|
15534
|
+
backgroundManager: null
|
|
15586
15535
|
});
|
|
15587
15536
|
const [isInitialized, setIsInitialized] = useState9(false);
|
|
15588
15537
|
const [initError, setInitError] = useState9(null);
|
|
@@ -15779,20 +15728,6 @@ function CliApp() {
|
|
|
15779
15728
|
config.tools.disabled || []
|
|
15780
15729
|
// denied tools from project config
|
|
15781
15730
|
);
|
|
15782
|
-
const { createSandboxRuntime } = await import("./SandboxRuntimeAdapter-SRX3IM2Q.js");
|
|
15783
|
-
const { SandboxOrchestrator } = await import("./SandboxOrchestrator-AEOHC2BL.js");
|
|
15784
|
-
const { DEFAULT_SANDBOX_CONFIG } = await import("./types-2T7ALTCA.js");
|
|
15785
|
-
const sandboxRuntime = await createSandboxRuntime();
|
|
15786
|
-
const sandboxConfig = config.sandbox ?? DEFAULT_SANDBOX_CONFIG;
|
|
15787
|
-
const sandboxOrchestrator = new SandboxOrchestrator(sandboxConfig, sandboxRuntime);
|
|
15788
|
-
permissionManager.setSandboxState(sandboxConfig.mode, sandboxOrchestrator.isActive());
|
|
15789
|
-
if (sandboxConfig.enabled && sandboxConfig.mode !== "disabled") {
|
|
15790
|
-
if (sandboxRuntime) {
|
|
15791
|
-
console.log(`\u{1F512} Sandbox: ${sandboxConfig.mode} (${sandboxRuntime.name})`);
|
|
15792
|
-
} else {
|
|
15793
|
-
console.log("\u26A0\uFE0F Sandbox: enabled but runtime not available on this platform");
|
|
15794
|
-
}
|
|
15795
|
-
}
|
|
15796
15731
|
let permissionPromptCounter = 0;
|
|
15797
15732
|
const promptFn = (toolName, args, preview) => {
|
|
15798
15733
|
return new Promise((resolve3) => {
|
|
@@ -15818,10 +15753,7 @@ function CliApp() {
|
|
|
15818
15753
|
promptFn,
|
|
15819
15754
|
agentContext,
|
|
15820
15755
|
state.configStore,
|
|
15821
|
-
apiClient
|
|
15822
|
-
void 0,
|
|
15823
|
-
// toolFilter
|
|
15824
|
-
sandboxOrchestrator
|
|
15756
|
+
apiClient
|
|
15825
15757
|
);
|
|
15826
15758
|
startupLog.push(`\u{1F6E0}\uFE0F Loaded ${b4mTools2.length} B4M tool(s)`);
|
|
15827
15759
|
const mcpManager = new McpManager(config);
|
|
@@ -15979,10 +15911,8 @@ ${contextResult.mergedContent}` : "";
|
|
|
15979
15911
|
// Store agent store for agent management commands
|
|
15980
15912
|
contextContent: contextResult.mergedContent,
|
|
15981
15913
|
// Store raw context for compact instructions
|
|
15982
|
-
backgroundManager
|
|
15914
|
+
backgroundManager
|
|
15983
15915
|
// Store for grouped notification turn tracking
|
|
15984
|
-
sandboxOrchestrator
|
|
15985
|
-
// Store sandbox orchestrator for /sandbox commands
|
|
15986
15916
|
}));
|
|
15987
15917
|
setStoreSession(newSession);
|
|
15988
15918
|
const bannerLines = [
|
|
@@ -17451,86 +17381,6 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
17451
17381
|
}
|
|
17452
17382
|
break;
|
|
17453
17383
|
}
|
|
17454
|
-
// --- Sandbox commands ---
|
|
17455
|
-
case "sandbox": {
|
|
17456
|
-
if (!state.sandboxOrchestrator) {
|
|
17457
|
-
console.log("\nSandbox: Not initialized");
|
|
17458
|
-
break;
|
|
17459
|
-
}
|
|
17460
|
-
const status = state.sandboxOrchestrator.getStatus();
|
|
17461
|
-
console.log("\nSandbox Status:");
|
|
17462
|
-
console.log(` Enabled: ${status.enabled ? "Yes" : "No"}`);
|
|
17463
|
-
console.log(` Mode: ${status.mode}`);
|
|
17464
|
-
console.log(` Platform: ${status.platform ?? "N/A"}`);
|
|
17465
|
-
console.log(` Runtime: ${status.runtimeName ?? "N/A"}`);
|
|
17466
|
-
console.log(` Available: ${status.runtimeAvailable ? "Yes" : "No"}`);
|
|
17467
|
-
console.log("");
|
|
17468
|
-
console.log("Filesystem Config:");
|
|
17469
|
-
console.log(` Write only to CWD: ${status.config.filesystem.writeOnlyToWorkingDir}`);
|
|
17470
|
-
console.log(` Allowed reads: ${status.config.filesystem.allowedReadPaths.join(", ") || "(none)"}`);
|
|
17471
|
-
console.log(` Denied paths: ${status.config.filesystem.deniedPaths.join(", ") || "(none)"}`);
|
|
17472
|
-
console.log(` Excluded cmds: ${status.config.excludedCommands.join(", ") || "(none)"}`);
|
|
17473
|
-
console.log("");
|
|
17474
|
-
break;
|
|
17475
|
-
}
|
|
17476
|
-
case "sandbox:enable": {
|
|
17477
|
-
if (!state.sandboxOrchestrator) {
|
|
17478
|
-
console.log("Sandbox not initialized");
|
|
17479
|
-
break;
|
|
17480
|
-
}
|
|
17481
|
-
if (!state.sandboxOrchestrator.isAvailable()) {
|
|
17482
|
-
console.log("Sandbox runtime not available on this platform");
|
|
17483
|
-
break;
|
|
17484
|
-
}
|
|
17485
|
-
state.sandboxOrchestrator.setMode("auto-allow");
|
|
17486
|
-
state.permissionManager?.setSandboxState("auto-allow", true);
|
|
17487
|
-
const config = await state.configStore.get();
|
|
17488
|
-
await state.configStore.save({
|
|
17489
|
-
...config,
|
|
17490
|
-
sandbox: { ...state.sandboxOrchestrator.getConfig() }
|
|
17491
|
-
});
|
|
17492
|
-
console.log("Sandbox enabled (auto-allow mode)");
|
|
17493
|
-
break;
|
|
17494
|
-
}
|
|
17495
|
-
case "sandbox:disable": {
|
|
17496
|
-
if (!state.sandboxOrchestrator) {
|
|
17497
|
-
console.log("Sandbox not initialized");
|
|
17498
|
-
break;
|
|
17499
|
-
}
|
|
17500
|
-
state.sandboxOrchestrator.setMode("disabled");
|
|
17501
|
-
state.permissionManager?.setSandboxState("disabled", false);
|
|
17502
|
-
const disableConfig = await state.configStore.get();
|
|
17503
|
-
await state.configStore.save({
|
|
17504
|
-
...disableConfig,
|
|
17505
|
-
sandbox: { ...state.sandboxOrchestrator.getConfig() }
|
|
17506
|
-
});
|
|
17507
|
-
console.log("Sandbox disabled");
|
|
17508
|
-
break;
|
|
17509
|
-
}
|
|
17510
|
-
case "sandbox:mode": {
|
|
17511
|
-
if (!state.sandboxOrchestrator) {
|
|
17512
|
-
console.log("Sandbox not initialized");
|
|
17513
|
-
break;
|
|
17514
|
-
}
|
|
17515
|
-
const modeArg = args[0];
|
|
17516
|
-
if (modeArg !== "auto-allow" && modeArg !== "permissions") {
|
|
17517
|
-
console.log("Usage: /sandbox:mode <auto-allow|permissions>");
|
|
17518
|
-
break;
|
|
17519
|
-
}
|
|
17520
|
-
if (!state.sandboxOrchestrator.isAvailable()) {
|
|
17521
|
-
console.log("Sandbox runtime not available on this platform");
|
|
17522
|
-
break;
|
|
17523
|
-
}
|
|
17524
|
-
state.sandboxOrchestrator.setMode(modeArg);
|
|
17525
|
-
state.permissionManager?.setSandboxState(modeArg, state.sandboxOrchestrator.isActive());
|
|
17526
|
-
const modeConfig = await state.configStore.get();
|
|
17527
|
-
await state.configStore.save({
|
|
17528
|
-
...modeConfig,
|
|
17529
|
-
sandbox: { ...state.sandboxOrchestrator.getConfig() }
|
|
17530
|
-
});
|
|
17531
|
-
console.log(`Sandbox mode set to: ${modeArg}`);
|
|
17532
|
-
break;
|
|
17533
|
-
}
|
|
17534
17384
|
default:
|
|
17535
17385
|
console.log(`Unknown command: /${command}`);
|
|
17536
17386
|
console.log("Type /help for available commands");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bike4mind/cli",
|
|
3
|
-
"version": "0.2.29-feat-
|
|
3
|
+
"version": "0.2.29-feat-session-permission.18841+6d9c4deb5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -110,10 +110,10 @@
|
|
|
110
110
|
},
|
|
111
111
|
"devDependencies": {
|
|
112
112
|
"@bike4mind/agents": "0.1.0",
|
|
113
|
-
"@bike4mind/common": "2.50.1-feat-
|
|
114
|
-
"@bike4mind/mcp": "1.29.1-feat-
|
|
115
|
-
"@bike4mind/services": "2.48.1-feat-
|
|
116
|
-
"@bike4mind/utils": "2.5.1-feat-
|
|
113
|
+
"@bike4mind/common": "2.50.1-feat-session-permission.18841+6d9c4deb5",
|
|
114
|
+
"@bike4mind/mcp": "1.29.1-feat-session-permission.18841+6d9c4deb5",
|
|
115
|
+
"@bike4mind/services": "2.48.1-feat-session-permission.18841+6d9c4deb5",
|
|
116
|
+
"@bike4mind/utils": "2.5.1-feat-session-permission.18841+6d9c4deb5",
|
|
117
117
|
"@types/better-sqlite3": "^7.6.13",
|
|
118
118
|
"@types/diff": "^5.0.9",
|
|
119
119
|
"@types/jsonwebtoken": "^9.0.4",
|
|
@@ -130,5 +130,5 @@
|
|
|
130
130
|
"optionalDependencies": {
|
|
131
131
|
"@vscode/ripgrep": "^1.17.0"
|
|
132
132
|
},
|
|
133
|
-
"gitHead": "
|
|
133
|
+
"gitHead": "6d9c4deb5a83cfc1087043d22f407d3444a91cca"
|
|
134
134
|
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
expandPath,
|
|
4
|
-
isBinaryAvailable
|
|
5
|
-
} from "./chunk-PRJKJWD6.js";
|
|
6
|
-
|
|
7
|
-
// src/sandbox/runtime/BubblewrapRuntime.ts
|
|
8
|
-
import os from "os";
|
|
9
|
-
import { existsSync } from "fs";
|
|
10
|
-
var SYSTEM_RO_BINDS = ["/usr", "/bin", "/lib", "/lib64", "/sbin", "/etc"];
|
|
11
|
-
var SPECIAL_MOUNTS = {
|
|
12
|
-
dev: "/dev",
|
|
13
|
-
proc: "/proc",
|
|
14
|
-
tmp: "/tmp"
|
|
15
|
-
};
|
|
16
|
-
var BubblewrapRuntime = class {
|
|
17
|
-
constructor() {
|
|
18
|
-
this.platform = "linux";
|
|
19
|
-
this.name = "bubblewrap";
|
|
20
|
-
}
|
|
21
|
-
isAvailable() {
|
|
22
|
-
return isBinaryAvailable("bwrap");
|
|
23
|
-
}
|
|
24
|
-
wrapCommand(options) {
|
|
25
|
-
const { command, cwd, filesystemConfig, env } = options;
|
|
26
|
-
const expandedDenied = filesystemConfig.deniedPaths.map(expandPath);
|
|
27
|
-
const expandedAllowed = filesystemConfig.allowedReadPaths.map(expandPath);
|
|
28
|
-
const args = [];
|
|
29
|
-
for (const sysPath of SYSTEM_RO_BINDS) {
|
|
30
|
-
if (existsSync(sysPath)) {
|
|
31
|
-
args.push("--ro-bind", sysPath, sysPath);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
args.push("--dev", SPECIAL_MOUNTS.dev);
|
|
35
|
-
args.push("--proc", SPECIAL_MOUNTS.proc);
|
|
36
|
-
args.push("--tmpfs", SPECIAL_MOUNTS.tmp);
|
|
37
|
-
args.push("--bind", cwd, cwd);
|
|
38
|
-
const homeDir = os.homedir();
|
|
39
|
-
args.push("--ro-bind", homeDir, homeDir);
|
|
40
|
-
for (const allowedPath of expandedAllowed) {
|
|
41
|
-
if (!allowedPath.startsWith(homeDir) && existsSync(allowedPath)) {
|
|
42
|
-
args.push("--ro-bind-try", allowedPath, allowedPath);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
for (const deniedPath of expandedDenied) {
|
|
46
|
-
args.push("--tmpfs", deniedPath);
|
|
47
|
-
}
|
|
48
|
-
args.push("--unshare-all");
|
|
49
|
-
args.push("--share-net");
|
|
50
|
-
args.push("--die-with-parent");
|
|
51
|
-
args.push("--chdir", cwd);
|
|
52
|
-
args.push("bash", "-c", command);
|
|
53
|
-
const commandString = ["bwrap", ...args.map(shellEscape)].join(" ");
|
|
54
|
-
return {
|
|
55
|
-
executable: "bwrap",
|
|
56
|
-
args,
|
|
57
|
-
env: env ?? {},
|
|
58
|
-
commandString
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
function shellEscape(str) {
|
|
63
|
-
if (/^[a-zA-Z0-9._/=:-]+$/.test(str)) return str;
|
|
64
|
-
return `'${str.replace(/'/g, "'\\''")}'`;
|
|
65
|
-
}
|
|
66
|
-
export {
|
|
67
|
-
BubblewrapRuntime
|
|
68
|
-
};
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
DEFAULT_SANDBOX_CONFIG
|
|
4
|
-
} from "./chunk-XPSG72HV.js";
|
|
5
|
-
|
|
6
|
-
// src/sandbox/SandboxOrchestrator.ts
|
|
7
|
-
var SandboxOrchestrator = class {
|
|
8
|
-
constructor(config, runtime) {
|
|
9
|
-
this.config = config ?? DEFAULT_SANDBOX_CONFIG;
|
|
10
|
-
this.runtime = runtime ?? null;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Determine whether a command should be sandboxed.
|
|
14
|
-
*
|
|
15
|
-
* Decision logic:
|
|
16
|
-
* 1. If sandbox is disabled → unsandboxed (no permission change)
|
|
17
|
-
* 2. If command matches an excluded command → unsandboxed (requires permission)
|
|
18
|
-
* 3. If runtime is not available → unsandboxed with warning
|
|
19
|
-
* 4. Otherwise → sandbox the command
|
|
20
|
-
*/
|
|
21
|
-
shouldSandbox(command, cwd) {
|
|
22
|
-
if (!this.config.enabled || this.config.mode === "disabled") {
|
|
23
|
-
return { type: "unsandboxed", requiresPermission: true };
|
|
24
|
-
}
|
|
25
|
-
const baseCommand = this.getBaseCommand(command);
|
|
26
|
-
if (this.isExcludedCommand(baseCommand)) {
|
|
27
|
-
return {
|
|
28
|
-
type: "unsandboxed",
|
|
29
|
-
requiresPermission: true,
|
|
30
|
-
reason: `Command '${baseCommand}' is excluded from sandboxing`
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
if (!this.runtime) {
|
|
34
|
-
return {
|
|
35
|
-
type: "unsandboxed",
|
|
36
|
-
requiresPermission: true,
|
|
37
|
-
reason: "Sandbox runtime not available on this platform"
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
const wrappedCommand = this.runtime.wrapCommand({
|
|
41
|
-
command,
|
|
42
|
-
cwd,
|
|
43
|
-
filesystemConfig: this.config.filesystem
|
|
44
|
-
});
|
|
45
|
-
return { type: "sandbox", wrappedCommand };
|
|
46
|
-
}
|
|
47
|
-
/** Get the current sandbox mode */
|
|
48
|
-
getMode() {
|
|
49
|
-
return this.config.mode;
|
|
50
|
-
}
|
|
51
|
-
/** Set the sandbox mode (does not persist — caller must save config) */
|
|
52
|
-
setMode(mode) {
|
|
53
|
-
this.config.mode = mode;
|
|
54
|
-
this.config.enabled = mode !== "disabled";
|
|
55
|
-
}
|
|
56
|
-
/** Check if sandbox is enabled and runtime is available */
|
|
57
|
-
isAvailable() {
|
|
58
|
-
return this.runtime !== null && this.runtime.isAvailable();
|
|
59
|
-
}
|
|
60
|
-
/** Check if sandbox is currently active (enabled + available) */
|
|
61
|
-
isActive() {
|
|
62
|
-
return this.config.enabled && this.config.mode !== "disabled" && this.isAvailable();
|
|
63
|
-
}
|
|
64
|
-
/** Get the current sandbox configuration */
|
|
65
|
-
getConfig() {
|
|
66
|
-
return this.config;
|
|
67
|
-
}
|
|
68
|
-
/** Update config (does not persist — caller must save) */
|
|
69
|
-
updateConfig(config) {
|
|
70
|
-
this.config = config;
|
|
71
|
-
}
|
|
72
|
-
/** Get full status information for display */
|
|
73
|
-
getStatus() {
|
|
74
|
-
return {
|
|
75
|
-
mode: this.config.mode,
|
|
76
|
-
enabled: this.config.enabled,
|
|
77
|
-
platform: this.runtime?.platform ?? null,
|
|
78
|
-
runtimeAvailable: this.runtime?.isAvailable() ?? false,
|
|
79
|
-
runtimeName: this.runtime?.name ?? null,
|
|
80
|
-
config: this.config
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Extract the base command name from a full command string.
|
|
85
|
-
* e.g., "docker compose up -d" → "docker"
|
|
86
|
-
*/
|
|
87
|
-
getBaseCommand(command) {
|
|
88
|
-
const trimmed = command.trim();
|
|
89
|
-
const withoutEnv = trimmed.replace(/^(\w+=\S+\s+)*/, "");
|
|
90
|
-
const parts = withoutEnv.split(/\s+/);
|
|
91
|
-
const first = parts[0] || "";
|
|
92
|
-
return first.split("/").pop() || first;
|
|
93
|
-
}
|
|
94
|
-
/** Check if a command is in the excluded list */
|
|
95
|
-
isExcludedCommand(baseCommand) {
|
|
96
|
-
return this.config.excludedCommands.some((excluded) => baseCommand === excluded);
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
export {
|
|
100
|
-
SandboxOrchestrator
|
|
101
|
-
};
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
expandPath,
|
|
4
|
-
isBinaryAvailable
|
|
5
|
-
} from "./chunk-PRJKJWD6.js";
|
|
6
|
-
|
|
7
|
-
// src/sandbox/runtime/SeatbeltRuntime.ts
|
|
8
|
-
import { writeFileSync, mkdtempSync } from "fs";
|
|
9
|
-
import path from "path";
|
|
10
|
-
import os from "os";
|
|
11
|
-
function escapeSeatbeltPath(p) {
|
|
12
|
-
return p.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
13
|
-
}
|
|
14
|
-
var SeatbeltRuntime = class {
|
|
15
|
-
constructor() {
|
|
16
|
-
this.platform = "darwin";
|
|
17
|
-
this.name = "seatbelt";
|
|
18
|
-
}
|
|
19
|
-
isAvailable() {
|
|
20
|
-
return isBinaryAvailable("sandbox-exec");
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Generate a Seatbelt profile string from the filesystem config.
|
|
24
|
-
*
|
|
25
|
-
* Strategy:
|
|
26
|
-
* - Start with (allow default) to permit most operations
|
|
27
|
-
* - Deny all file writes globally
|
|
28
|
-
* - Allow file writes only to the working directory
|
|
29
|
-
* - Deny all access to explicitly denied paths
|
|
30
|
-
* - Allow read access to explicitly allowed paths
|
|
31
|
-
*/
|
|
32
|
-
generateProfile(options) {
|
|
33
|
-
const { cwd, filesystemConfig } = options;
|
|
34
|
-
const expandedDenied = filesystemConfig.deniedPaths.map(expandPath);
|
|
35
|
-
const expandedAllowed = filesystemConfig.allowedReadPaths.map(expandPath);
|
|
36
|
-
const lines = [
|
|
37
|
-
"(version 1)",
|
|
38
|
-
"",
|
|
39
|
-
"; Start with permissive defaults (process exec, network, sysctl, etc.)",
|
|
40
|
-
"(allow default)",
|
|
41
|
-
""
|
|
42
|
-
];
|
|
43
|
-
if (filesystemConfig.writeOnlyToWorkingDir) {
|
|
44
|
-
lines.push("; Deny all file writes globally");
|
|
45
|
-
lines.push("(deny file-write*)");
|
|
46
|
-
lines.push("");
|
|
47
|
-
lines.push("; Allow writes to working directory");
|
|
48
|
-
lines.push(`(allow file-write* (subpath "${escapeSeatbeltPath(cwd)}"))`);
|
|
49
|
-
lines.push("");
|
|
50
|
-
lines.push("; Allow writes to temp directories");
|
|
51
|
-
lines.push(`(allow file-write* (subpath "/tmp"))`);
|
|
52
|
-
lines.push(`(allow file-write* (subpath "/private/tmp"))`);
|
|
53
|
-
lines.push(`(allow file-write* (subpath "${escapeSeatbeltPath(os.tmpdir())}"))`);
|
|
54
|
-
lines.push("");
|
|
55
|
-
}
|
|
56
|
-
if (expandedDenied.length > 0) {
|
|
57
|
-
lines.push("; Deny access to sensitive paths");
|
|
58
|
-
for (const deniedPath of expandedDenied) {
|
|
59
|
-
lines.push(`(deny file-read* file-write* (subpath "${escapeSeatbeltPath(deniedPath)}"))`);
|
|
60
|
-
}
|
|
61
|
-
lines.push("");
|
|
62
|
-
}
|
|
63
|
-
if (expandedAllowed.length > 0) {
|
|
64
|
-
lines.push("; Explicitly allowed read paths");
|
|
65
|
-
for (const allowedPath of expandedAllowed) {
|
|
66
|
-
lines.push(`(allow file-read* (subpath "${escapeSeatbeltPath(allowedPath)}"))`);
|
|
67
|
-
}
|
|
68
|
-
lines.push("");
|
|
69
|
-
}
|
|
70
|
-
return lines.join("\n");
|
|
71
|
-
}
|
|
72
|
-
wrapCommand(options) {
|
|
73
|
-
const profile = this.generateProfile(options);
|
|
74
|
-
const tmpDir = mkdtempSync(path.join(os.tmpdir(), "b4m-sandbox-"));
|
|
75
|
-
const profilePath = path.join(tmpDir, "sandbox.sb");
|
|
76
|
-
writeFileSync(profilePath, profile, "utf-8");
|
|
77
|
-
const args = ["-f", profilePath, "bash", "-c", options.command];
|
|
78
|
-
return {
|
|
79
|
-
executable: "sandbox-exec",
|
|
80
|
-
args,
|
|
81
|
-
env: options.env ?? {},
|
|
82
|
-
commandString: `sandbox-exec -f ${profilePath} bash -c ${shellEscape(options.command)}`,
|
|
83
|
-
cleanupPaths: [profilePath, tmpDir]
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
function shellEscape(str) {
|
|
88
|
-
return `'${str.replace(/'/g, "'\\''")}'`;
|
|
89
|
-
}
|
|
90
|
-
export {
|
|
91
|
-
SeatbeltRuntime
|
|
92
|
-
};
|
package/dist/chunk-PRJKJWD6.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// src/sandbox/runtime/SandboxRuntimeAdapter.ts
|
|
4
|
-
import os from "os";
|
|
5
|
-
import { execSync } from "child_process";
|
|
6
|
-
function detectPlatform() {
|
|
7
|
-
const platform = os.platform();
|
|
8
|
-
if (platform === "darwin") return "darwin";
|
|
9
|
-
if (platform === "linux") return "linux";
|
|
10
|
-
return null;
|
|
11
|
-
}
|
|
12
|
-
function isBinaryAvailable(binary) {
|
|
13
|
-
try {
|
|
14
|
-
execSync(`which ${binary}`, { stdio: "ignore" });
|
|
15
|
-
return true;
|
|
16
|
-
} catch {
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
function expandPath(pathStr) {
|
|
21
|
-
return pathStr.replace(/\$HOME/g, os.homedir()).replace(/\$USER/g, os.userInfo().username).replace(/~\//g, `${os.homedir()}/`);
|
|
22
|
-
}
|
|
23
|
-
async function createSandboxRuntime() {
|
|
24
|
-
const platform = detectPlatform();
|
|
25
|
-
if (!platform) return null;
|
|
26
|
-
if (platform === "darwin") {
|
|
27
|
-
const { SeatbeltRuntime } = await import("./SeatbeltRuntime-DZMEIRPM.js");
|
|
28
|
-
const runtime = new SeatbeltRuntime();
|
|
29
|
-
return runtime.isAvailable() ? runtime : null;
|
|
30
|
-
}
|
|
31
|
-
if (platform === "linux") {
|
|
32
|
-
const { BubblewrapRuntime } = await import("./BubblewrapRuntime-EJM4QF7U.js");
|
|
33
|
-
const runtime = new BubblewrapRuntime();
|
|
34
|
-
return runtime.isAvailable() ? runtime : null;
|
|
35
|
-
}
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export {
|
|
40
|
-
detectPlatform,
|
|
41
|
-
isBinaryAvailable,
|
|
42
|
-
expandPath,
|
|
43
|
-
createSandboxRuntime
|
|
44
|
-
};
|
package/dist/chunk-XPSG72HV.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// src/sandbox/types.ts
|
|
4
|
-
var DEFAULT_SANDBOX_CONFIG = {
|
|
5
|
-
enabled: false,
|
|
6
|
-
mode: "disabled",
|
|
7
|
-
filesystem: {
|
|
8
|
-
writeOnlyToWorkingDir: true,
|
|
9
|
-
allowedReadPaths: ["$HOME/.gitconfig", "$HOME/.npmrc", "$HOME/.node_modules"],
|
|
10
|
-
deniedPaths: ["$HOME/.ssh", "$HOME/.aws", "$HOME/.gnupg", "$HOME/.env", "/etc/shadow", "/etc/passwd"]
|
|
11
|
-
},
|
|
12
|
-
excludedCommands: ["docker", "watchman", "podman"],
|
|
13
|
-
platform: {
|
|
14
|
-
linux: {
|
|
15
|
-
runtime: "bubblewrap"
|
|
16
|
-
},
|
|
17
|
-
macos: {
|
|
18
|
-
runtime: "seatbelt",
|
|
19
|
-
profileTemplate: "default"
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export {
|
|
25
|
-
DEFAULT_SANDBOX_CONFIG
|
|
26
|
-
};
|