Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/services/agent-volumes/agent-volumes.test-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { WrapperConfig } from '../../types';

export function makeAgentVolumeConfig(overrides: Partial<WrapperConfig> = {}): WrapperConfig {
return {
allowDomains: 'example.com',
agentCommand: 'echo test',
workDir: '/tmp/awf-test',
Comment on lines +3 to +7
...overrides,
} as WrapperConfig;
}
31 changes: 11 additions & 20 deletions src/services/agent-volumes/docker-host-staging.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,7 @@ import {
extractCommandBinaryName,
getDockerHostStageRoot,
} from './docker-host-staging';
import { WrapperConfig } from '../../types';

function makeConfig(overrides: Partial<WrapperConfig> = {}): 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;

Expand Down Expand Up @@ -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);
Expand All @@ -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();
Expand All @@ -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');
Expand All @@ -124,15 +115,15 @@ 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();
});

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();
Expand All @@ -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);
Expand All @@ -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;
Expand Down
15 changes: 3 additions & 12 deletions src/services/agent-volumes/docker-socket-branches.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import { buildDockerSocketMount } from './docker-socket';
import { WrapperConfig } from '../../types';
import { makeAgentVolumeConfig } from './agent-volumes.test-utils';

jest.mock('../../logger', () => ({
logger: {
Expand All @@ -18,18 +18,9 @@ jest.mock('../../logger', () => ({
},
}));

function makeConfig(overrides: Partial<WrapperConfig> = {}): 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
Expand All @@ -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');
Expand Down
28 changes: 10 additions & 18 deletions src/services/agent-volumes/workspace-mounts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -14,15 +15,6 @@ jest.mock('../../logger', () => ({
},
}));

function makeConfig(overrides: Partial<WrapperConfig> = {}): 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,
Expand All @@ -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');
Expand All @@ -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'));
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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'));
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand Down
Loading