sync: update from private repo (8ed98ab)
CI / build-and-test (push) Has been cancelled

This commit is contained in:
oss-sync
2026-06-09 00:46:41 +00:00
parent ef44e1a5d9
commit d6d8e83867
20 changed files with 452 additions and 12 deletions
+3 -2
View File
@@ -291,7 +291,7 @@ export async function runPiece(
spawnSubTask?: (params: { title: string; instruction: string; piece?: string }) => Promise<{ jobId: string; subtaskIndex: number; workspacePath: string }>;
cancelCheck?: () => boolean;
abortController?: AbortController;
safetyConfig?: { maxIterations?: number; maxRevisits?: number; bashUnrestricted?: boolean; bashSandbox?: 'auto' | 'always' | 'off' };
safetyConfig?: { maxIterations?: number; maxRevisits?: number; bashUnrestricted?: boolean; bashSandbox?: 'auto' | 'always' | 'off'; bashAllowNetwork?: boolean };
searchFilter?: SearchFilterConfig;
customPiecesDir?: string | string[];
contextManager?: ContextManager;
@@ -690,7 +690,7 @@ function prepareMovementContext(
/** Role for the job owner. */
notesUserRole?: 'admin' | 'user';
/** Safety config — threaded so prepareMovementContext can propagate bashUnrestricted. */
safetyConfig?: { bashUnrestricted?: boolean; bashSandbox?: 'auto' | 'always' | 'off' };
safetyConfig?: { bashUnrestricted?: boolean; bashSandbox?: 'auto' | 'always' | 'off'; bashAllowNetwork?: boolean };
skillCatalog?: import('./skills.js').SkillCatalog;
/** Per-task option: when true, MCP tools are not loaded/dispatched. */
mcpDisabled?: boolean;
@@ -716,6 +716,7 @@ function prepareMovementContext(
allowedCommands: movementDef.allowed_commands,
bashUnrestricted: options?.safetyConfig?.bashUnrestricted,
bashSandbox: options?.safetyConfig?.bashSandbox,
bashAllowNetwork: options?.safetyConfig?.bashAllowNetwork,
skillCatalog: options?.skillCatalog,
allowedSshConnections: movementDef.allowed_ssh_connections,
pieceName: piece.name,
+2
View File
@@ -62,6 +62,7 @@ export interface ToolContext {
allowedCommands?: string[]; // Bash ツールで許可するコマンド名一覧 (省略時は DEFAULT_ALLOWED_COMMANDS)
bashUnrestricted?: boolean; // true: skip the command whitelist (bwrap/exec is chosen by bashSandbox, not this)
bashSandbox?: 'auto' | 'always' | 'off'; // サンドボックス機構の選択 (config.safety.bashSandbox 由来)
bashAllowNetwork?: boolean; // true: bwrap サンドボックスで host network を許可 (--unshare-net を外す。config.safety.bashAllowNetwork 由来)
skillCatalog?: import('../skills.js').SkillCatalog;
toolsConfig?: ToolsConfig;
searchFilter?: SearchFilterConfig; // AppConfig.searchFilter (トップレベル)
@@ -1007,6 +1008,7 @@ async function executeBash(input: Record<string, unknown>, ctx: ToolContext): Pr
}
const result: SandboxedBashResult = await executeSandboxedBash(
command, ctx.workspacePath, timeoutSec, BASH_MAX_BUFFER_BYTES, ctx.abortSignal, skillBinds,
ctx.bashAllowNetwork === true,
);
const out = result.isError ? result.output : capOutput(result.output, 'stdout');
logBashHistory(ctx.workspacePath, command, result.isError, Date.now() - startedAt, {
+21
View File
@@ -245,6 +245,27 @@ describe('buildBwrapArgs sandboxing', () => {
expect(i).toBeGreaterThan(-1);
expect(args).toContain('HOME');
});
it('unshares network by default (allowNetwork omitted)', () => {
const args = buildBwrapArgs('echo hi', '/work/ws');
expect(args).toContain('--unshare-net');
});
it('keeps host network when allowNetwork=true (drops only --unshare-net)', () => {
const args = buildBwrapArgs('echo hi', '/work/ws', undefined, process.env, true);
expect(args).not.toContain('--unshare-net');
// all other isolations remain
expect(args).toContain('--unshare-user');
expect(args).toContain('--unshare-ipc');
expect(args).toContain('--unshare-pid');
expect(args).toContain('--unshare-uts');
expect(args).toContain('--unshare-cgroup');
});
it('unshares network when allowNetwork=false (explicit)', () => {
const args = buildBwrapArgs('echo hi', '/work/ws', undefined, process.env, false);
expect(args).toContain('--unshare-net');
});
});
describe('checkBwrapAvailable', () => {
+10 -2
View File
@@ -36,6 +36,7 @@ export function buildBwrapArgs(
workspacePath: string,
extraReadOnlyBinds?: ExtraReadOnlyBind[],
parentEnv: NodeJS.ProcessEnv = process.env,
allowNetwork: boolean = false,
): string[] {
const args: string[] = [];
@@ -70,7 +71,13 @@ export function buildBwrapArgs(
args.push('--chdir', workspacePath);
args.push('--die-with-parent');
args.push('--unshare-user', '--unshare-ipc', '--unshare-pid', '--unshare-uts', '--unshare-cgroup', '--unshare-net');
// Network isolation is the one --unshare-* that's optional. When
// allowNetwork is true (config.safety.bashAllowNetwork) the sandbox keeps host
// network so pip/npm/curl work; all other namespaces stay unshared.
args.push('--unshare-user', '--unshare-ipc', '--unshare-pid', '--unshare-uts', '--unshare-cgroup');
if (!allowNetwork) {
args.push('--unshare-net');
}
args.push('--clearenv');
const sandboxEnv = buildSandboxEnv(parentEnv, workspacePath);
@@ -124,8 +131,9 @@ export async function executeSandboxedBash(
maxBuffer: number,
abortSignal?: AbortSignal,
extraReadOnlyBinds?: ExtraReadOnlyBind[],
allowNetwork: boolean = false,
): Promise<SandboxedBashResult> {
const args = buildBwrapArgs(command, workspacePath, extraReadOnlyBinds);
const args = buildBwrapArgs(command, workspacePath, extraReadOnlyBinds, process.env, allowNetwork);
if (abortSignal?.aborted) {
return { output: 'Cancelled before sandbox bash launch', isError: true };