diff --git a/src/services/agent-volumes/agent-volumes.test-utils.ts b/src/services/agent-volumes/agent-volumes.test-utils.ts new file mode 100644 index 000000000..b6b5238be --- /dev/null +++ b/src/services/agent-volumes/agent-volumes.test-utils.ts @@ -0,0 +1,10 @@ +import type { WrapperConfig } from '../../types'; + +export function makeAgentVolumeConfig(overrides: Partial = {}): WrapperConfig { + return { + allowDomains: 'example.com', + agentCommand: 'echo test', + workDir: '/tmp/awf-test', + ...overrides, + } as WrapperConfig; +} diff --git a/src/services/agent-volumes/docker-host-staging.test.ts b/src/services/agent-volumes/docker-host-staging.test.ts index 1e2697c22..b5a0ce1dc 100644 --- a/src/services/agent-volumes/docker-host-staging.test.ts +++ b/src/services/agent-volumes/docker-host-staging.test.ts @@ -12,16 +12,7 @@ import { extractCommandBinaryName, getDockerHostStageRoot, } from './docker-host-staging'; -import { WrapperConfig } from '../../types'; - -function makeConfig(overrides: Partial = {}): WrapperConfig { - return { - allowDomains: 'example.com', - agentCommand: 'echo test', - workDir: '/tmp/awf-test', - ...overrides, - } as WrapperConfig; -} +import { makeAgentVolumeConfig } from './agent-volumes.test-utils'; let tmpDir: string; @@ -76,21 +67,21 @@ describe('shouldUseDockerHostStaging', () => { describe('getDockerHostStageRoot', () => { it('uses workDir as stageRoot when prefix is not a /tmp path', () => { - const config = makeConfig({ workDir: tmpDir, dockerHostPathPrefix: '/var/runner' }); + const config = makeAgentVolumeConfig({ workDir: tmpDir, dockerHostPathPrefix: '/var/runner' }); const stageRoot = getDockerHostStageRoot(config); expect(stageRoot).toContain(tmpDir); expect(fs.existsSync(stageRoot)).toBe(true); }); it('uses normalizedPrefix as stageRoot for /tmp-based prefixes', () => { - const config = makeConfig({ workDir: tmpDir, dockerHostPathPrefix: tmpDir }); + const config = makeAgentVolumeConfig({ workDir: tmpDir, dockerHostPathPrefix: tmpDir }); const stageRoot = getDockerHostStageRoot(config); expect(stageRoot).toContain(tmpDir); expect(fs.existsSync(stageRoot)).toBe(true); }); it('creates the stage root directory', () => { - const config = makeConfig({ workDir: tmpDir }); + const config = makeAgentVolumeConfig({ workDir: tmpDir }); const stageRoot = getDockerHostStageRoot(config); expect(fs.existsSync(stageRoot)).toBe(true); expect(fs.statSync(stageRoot).isDirectory()).toBe(true); @@ -99,13 +90,13 @@ describe('getDockerHostStageRoot', () => { describe('stageHostFile', () => { it('returns undefined when the source path does not exist', () => { - const config = makeConfig({ workDir: tmpDir }); + const config = makeAgentVolumeConfig({ workDir: tmpDir }); const result = stageHostFile(config, '/nonexistent/path/file.txt', 'etc/file.txt'); expect(result).toBeUndefined(); }); it('returns undefined when source path is a directory, not a file', () => { - const config = makeConfig({ workDir: tmpDir }); + const config = makeAgentVolumeConfig({ workDir: tmpDir }); // Pass a directory path as the source const result = stageHostFile(config, tmpDir, 'etc/notfile.txt'); expect(result).toBeUndefined(); @@ -115,7 +106,7 @@ describe('stageHostFile', () => { const srcFile = path.join(tmpDir, 'source.txt'); fs.writeFileSync(srcFile, 'hello staging'); - const config = makeConfig({ workDir: tmpDir }); + const config = makeAgentVolumeConfig({ workDir: tmpDir }); const result = stageHostFile(config, srcFile, 'etc/source.txt'); expect(result).toBeDefined(); expect(fs.readFileSync(result!, 'utf8')).toBe('hello staging'); @@ -124,7 +115,7 @@ describe('stageHostFile', () => { it('returns undefined when relativeTargetPath would escape the stage root (path traversal)', () => { const srcFile = path.join(tmpDir, 'source.txt'); fs.writeFileSync(srcFile, 'data'); - const config = makeConfig({ workDir: tmpDir }); + const config = makeAgentVolumeConfig({ workDir: tmpDir }); const result = stageHostFile(config, srcFile, '../../etc/passwd'); expect(result).toBeUndefined(); }); @@ -132,7 +123,7 @@ describe('stageHostFile', () => { it('returns undefined when relativeTargetPath normalizes to empty string', () => { const srcFile = path.join(tmpDir, 'source.txt'); fs.writeFileSync(srcFile, 'data'); - const config = makeConfig({ workDir: tmpDir }); + const config = makeAgentVolumeConfig({ workDir: tmpDir }); // A relative path that after stripping leading slashes is empty should be rejected const result = stageHostFile(config, srcFile, '/'); expect(result).toBeUndefined(); @@ -141,7 +132,7 @@ describe('stageHostFile', () => { it('creates nested directories as needed within the stage root', () => { const srcFile = path.join(tmpDir, 'cert.pem'); fs.writeFileSync(srcFile, 'cert-data'); - const config = makeConfig({ workDir: tmpDir }); + const config = makeAgentVolumeConfig({ workDir: tmpDir }); const result = stageHostFile(config, srcFile, 'ssl/certs/cert.pem'); expect(result).toBeDefined(); expect(fs.existsSync(result!)).toBe(true); @@ -150,7 +141,7 @@ describe('stageHostFile', () => { it('applies the specified file mode', () => { const srcFile = path.join(tmpDir, 'secret.txt'); fs.writeFileSync(srcFile, 'secret'); - const config = makeConfig({ workDir: tmpDir }); + const config = makeAgentVolumeConfig({ workDir: tmpDir }); const result = stageHostFile(config, srcFile, 'secrets/secret.txt', 0o600); expect(result).toBeDefined(); const mode = fs.statSync(result!).mode & 0o777; diff --git a/src/services/agent-volumes/docker-socket-branches.test.ts b/src/services/agent-volumes/docker-socket-branches.test.ts index 9f4595d14..3a53c18c5 100644 --- a/src/services/agent-volumes/docker-socket-branches.test.ts +++ b/src/services/agent-volumes/docker-socket-branches.test.ts @@ -7,7 +7,7 @@ */ import { buildDockerSocketMount } from './docker-socket'; -import { WrapperConfig } from '../../types'; +import { makeAgentVolumeConfig } from './agent-volumes.test-utils'; jest.mock('../../logger', () => ({ logger: { @@ -18,18 +18,9 @@ jest.mock('../../logger', () => ({ }, })); -function makeConfig(overrides: Partial = {}): WrapperConfig { - return { - allowDomains: 'example.com', - agentCommand: 'echo test', - workDir: '/tmp/awf-test', - ...overrides, - } as WrapperConfig; -} - describe('buildDockerSocketMount – non-Unix docker host branch', () => { it('returns default socket mounts when awfDockerHost uses tcp:// scheme (non-unix)', () => { - const config = makeConfig({ enableDind: true, awfDockerHost: 'tcp://192.168.1.5:2376' }); + const config = makeAgentVolumeConfig({ enableDind: true, awfDockerHost: 'tcp://192.168.1.5:2376' }); const mounts = buildDockerSocketMount(config); // Falls back to DEFAULT_DOCKER_SOCKET_PATH which is /var/run/docker.sock @@ -41,7 +32,7 @@ describe('buildDockerSocketMount – non-Unix docker host branch', () => { const original = process.env.DOCKER_HOST; try { process.env.DOCKER_HOST = 'tcp://docker-host:2375'; - const config = makeConfig({ enableDind: true }); + const config = makeAgentVolumeConfig({ enableDind: true }); const mounts = buildDockerSocketMount(config); expect(mounts).toContain('/var/run/docker.sock:/host/var/run/docker.sock:rw'); diff --git a/src/services/agent-volumes/workspace-mounts.test.ts b/src/services/agent-volumes/workspace-mounts.test.ts index 4d57bc4df..70eb01624 100644 --- a/src/services/agent-volumes/workspace-mounts.test.ts +++ b/src/services/agent-volumes/workspace-mounts.test.ts @@ -2,6 +2,7 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; import { buildWorkspaceMounts, buildCustomVolumeMounts } from './workspace-mounts'; +import { makeAgentVolumeConfig } from './agent-volumes.test-utils'; import { WrapperConfig } from '../../types'; import * as dockerHostStaging from './docker-host-staging'; @@ -14,15 +15,6 @@ jest.mock('../../logger', () => ({ }, })); -function makeConfig(overrides: Partial = {}): WrapperConfig { - return { - allowDomains: 'example.com', - agentCommand: 'echo test', - workDir: '/tmp/awf-test', - ...overrides, - } as WrapperConfig; -} - function makeParams(config: WrapperConfig, projectRoot: string, workspaceDir = '/workspace') { return { config, @@ -49,7 +41,7 @@ describe('buildWorkspaceMounts', () => { describe('standard mounts', () => { it('always includes /tmp, workspace, logs, session-state, init-signal mounts', () => { - const config = makeConfig(); + const config = makeAgentVolumeConfig(); const mounts = buildWorkspaceMounts(makeParams(config, tmpDir, '/workspace')); expect(mounts).toContain('/tmp:/tmp:rw'); @@ -66,7 +58,7 @@ describe('buildWorkspaceMounts', () => { fs.mkdirSync(healthCheckPath, { recursive: true }); fs.writeFileSync(path.join(healthCheckPath, 'api-proxy-health-check.sh'), '#!/bin/sh\n'); - const config = makeConfig({ enableApiProxy: true }); + const config = makeAgentVolumeConfig({ enableApiProxy: true }); const mounts = buildWorkspaceMounts(makeParams(config, tmpDir)); const mount = mounts.find(m => m.includes('api-proxy-health-check.sh')); @@ -75,7 +67,7 @@ describe('buildWorkspaceMounts', () => { }); it('skips api-proxy-health-check.sh mount when file does not exist', () => { - const config = makeConfig({ enableApiProxy: true }); + const config = makeAgentVolumeConfig({ enableApiProxy: true }); const mounts = buildWorkspaceMounts(makeParams(config, tmpDir)); expect(mounts.some(m => m.includes('api-proxy-health-check.sh'))).toBe(false); @@ -86,7 +78,7 @@ describe('buildWorkspaceMounts', () => { fs.mkdirSync(healthCheckPath, { recursive: true }); fs.writeFileSync(path.join(healthCheckPath, 'api-proxy-health-check.sh'), '#!/bin/sh\n'); - const config = makeConfig({ enableApiProxy: false }); + const config = makeAgentVolumeConfig({ enableApiProxy: false }); const mounts = buildWorkspaceMounts(makeParams(config, tmpDir)); expect(mounts.some(m => m.includes('api-proxy-health-check.sh'))).toBe(false); @@ -109,7 +101,7 @@ describe('buildWorkspaceMounts', () => { jest.spyOn(dockerHostStaging, 'stageHostFile').mockReturnValue(stagedPath); // Use absolute path so resolveBinaryPath finds it without PATH lookup - const config = makeConfig({ agentCommand: `${binaryPath} --flag`, dockerHostPathPrefix: '/tmp' }); + const config = makeAgentVolumeConfig({ agentCommand: `${binaryPath} --flag`, dockerHostPathPrefix: '/tmp' }); const mounts = buildWorkspaceMounts(makeParams(config, tmpDir)); const binaryMount = mounts.find(m => m.includes('/tmp/awf-runner-bin/myagent')); @@ -121,7 +113,7 @@ describe('buildWorkspaceMounts', () => { jest.spyOn(dockerHostStaging, 'extractCommandBinaryName').mockReturnValue('myagent'); jest.spyOn(dockerHostStaging, 'stageHostFile').mockReturnValue(undefined); - const config = makeConfig({ agentCommand: 'myagent', dockerHostPathPrefix: '/tmp' }); + const config = makeAgentVolumeConfig({ agentCommand: 'myagent', dockerHostPathPrefix: '/tmp' }); const mounts = buildWorkspaceMounts(makeParams(config, tmpDir)); expect(mounts.some(m => m.includes('awf-runner-bin'))).toBe(false); @@ -130,7 +122,7 @@ describe('buildWorkspaceMounts', () => { it('skips binary mount when extractCommandBinaryName returns undefined', () => { jest.spyOn(dockerHostStaging, 'extractCommandBinaryName').mockReturnValue(undefined); - const config = makeConfig({ agentCommand: '', dockerHostPathPrefix: '/tmp' }); + const config = makeAgentVolumeConfig({ agentCommand: '', dockerHostPathPrefix: '/tmp' }); const mounts = buildWorkspaceMounts(makeParams(config, tmpDir)); expect(mounts.some(m => m.includes('awf-runner-bin'))).toBe(false); @@ -144,7 +136,7 @@ describe('buildWorkspaceMounts', () => { const origPath = process.env.PATH; process.env.PATH = '/tmp/empty-dir-that-does-not-exist'; try { - const config = makeConfig({ agentCommand: 'nonexistent-binary-xyz', dockerHostPathPrefix: '/tmp' }); + const config = makeAgentVolumeConfig({ agentCommand: 'nonexistent-binary-xyz', dockerHostPathPrefix: '/tmp' }); const mounts = buildWorkspaceMounts(makeParams(config, tmpDir)); expect(mounts.some(m => m.includes('awf-runner-bin'))).toBe(false); @@ -161,7 +153,7 @@ describe('buildWorkspaceMounts', () => { describe('no DinD staging when shouldUseDockerHostStaging=false', () => { it('does not add binary mount in non-DinD mode', () => { - const config = makeConfig({ agentCommand: 'echo test', dockerHostPathPrefix: undefined }); + const config = makeAgentVolumeConfig({ agentCommand: 'echo test', dockerHostPathPrefix: undefined }); const mounts = buildWorkspaceMounts(makeParams(config, tmpDir)); expect(mounts.some(m => m.includes('awf-runner-bin'))).toBe(false);