diff --git a/src/container-runtime.ts b/src/container-runtime.ts index e488e9e..8b59882 100644 --- a/src/container-runtime.ts +++ b/src/container-runtime.ts @@ -54,8 +54,16 @@ export function writableMountArgs( return ['-v', `${hostPath}:${containerPath}`]; } -export function tmpfsMountArgs(containerPath: string): string[] { - return ['--tmpfs', containerPath]; +export function tmpfsMountArgs( + containerPath: string, + options?: string | string[], +): string[] { + if (!options || (Array.isArray(options) && options.length === 0)) { + return ['--tmpfs', containerPath]; + } + + const optionText = Array.isArray(options) ? options.join(',') : options; + return ['--tmpfs', `${containerPath}:${optionText}`]; } export function stopContainer(name: string): string { diff --git a/src/verification.test.ts b/src/verification.test.ts index d90ca68..c403bb1 100644 --- a/src/verification.test.ts +++ b/src/verification.test.ts @@ -5,12 +5,16 @@ import path from 'path'; import { describe, expect, it } from 'vitest'; import { + buildDockerRunArgs, buildVerificationCommand, computeVerificationSnapshot, isVerificationProfile, runVerificationRequest, } from './verification.js'; -import { hasInstalledNodeModules } from './workspace-package-manager.js'; +import { + ensureWorkspaceDependenciesInstalled, + hasInstalledNodeModules, +} from './workspace-package-manager.js'; describe('verification helpers', () => { it('recognizes only fixed verification profiles', () => { @@ -190,4 +194,38 @@ describe('verification helpers', () => { expect(result.ok).toBe(false); expect(result.error).toContain('Snapshot mismatch before verification'); }); + + it('runs verification commands via docker entrypoint override', () => { + const repoDir = fs.mkdtempSync( + path.join(os.tmpdir(), 'ejclaw-verification-docker-'), + ); + fs.mkdirSync(path.join(repoDir, 'node_modules', '.bin'), { + recursive: true, + }); + fs.writeFileSync( + path.join(repoDir, 'package.json'), + JSON.stringify({ + name: 'verification-docker', + packageManager: 'bun@1.3.11', + scripts: { + typecheck: 'tsc --noEmit', + }, + }), + ); + fs.writeFileSync(path.join(repoDir, 'bun.lock'), ''); + fs.writeFileSync(path.join(repoDir, 'node_modules', '.bin', 'tsc'), ''); + ensureWorkspaceDependenciesInstalled(repoDir); + + const command = buildVerificationCommand('typecheck', repoDir); + const args = buildDockerRunArgs('/tmp/verify-workspace', repoDir, command); + const imageIndex = args.findIndex((value) => value === 'ejclaw-reviewer:latest'); + + expect(args).toContain('--entrypoint'); + expect(args[args.indexOf('--entrypoint') + 1]).toBe(command.file); + expect(imageIndex).toBeGreaterThan(args.indexOf('--entrypoint')); + expect(args.slice(imageIndex + 1)).toEqual(command.args); + expect(args).toContain( + '/workspace/project/node_modules/.vite-temp:uid=1000,gid=1000,mode=1777', + ); + }); }); diff --git a/src/verification.ts b/src/verification.ts index 5cf7658..b37b466 100644 --- a/src/verification.ts +++ b/src/verification.ts @@ -152,9 +152,10 @@ function detectRuntimeVersion(): string { } } -function buildDockerRunArgs( +export function buildDockerRunArgs( scratchWorkspace: string, sourceRepoDir: string, + command: Pick, ): string[] { const args = [ 'run', @@ -162,6 +163,8 @@ function buildDockerRunArgs( '-i', '--workdir', PRIMARY_PROJECT_MOUNT, + '--entrypoint', + command.file, '-e', `TZ=${TIMEZONE}`, '-e', @@ -196,6 +199,12 @@ function buildDockerRunArgs( path.join(PRIMARY_PROJECT_MOUNT, 'node_modules'), ), ); + args.push( + ...tmpfsMountArgs( + path.join(PRIMARY_PROJECT_MOUNT, 'node_modules', '.vite-temp'), + ['uid=1000', 'gid=1000', 'mode=1777'], + ), + ); } const pnpmStore = detectPnpmStorePath(sourceRepoDir); @@ -204,6 +213,7 @@ function buildDockerRunArgs( } args.push(...tmpfsMountArgs('/tmp')); + args.push(REVIEWER_CONTAINER_IMAGE, ...command.args); return args; } @@ -346,8 +356,7 @@ export async function runVerificationRequest( }; } - const dockerArgs = buildDockerRunArgs(scratchWorkspace, repoDir); - dockerArgs.push(REVIEWER_CONTAINER_IMAGE, command.file, ...command.args); + const dockerArgs = buildDockerRunArgs(scratchWorkspace, repoDir, command); try { const { stdout, stderr } = await execFileCapture(