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
8 changes: 8 additions & 0 deletions docs/awf-config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,14 @@
"runnerToolCachePath": {
"type": "string",
"description": "Host runner tool cache directory to mount read-only into chroot mode. When set, AWF checks this path first before environment-based auto-detection."
},
"mounts": {
"type": "array",
"items": {
"type": "string",
"pattern": "^/[^:]+:/[^:]+(:(ro|rw))?$"
},
"description": "Custom volume mounts for the agent container. Format: \"/host_path:/container_path[:ro|rw]\" (both paths must be absolute). In chroot mode, container paths are automatically prefixed with /host."
}
}
},
Expand Down
8 changes: 8 additions & 0 deletions src/awf-config-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,14 @@
"runnerToolCachePath": {
"type": "string",
"description": "Host runner tool cache directory to mount read-only into chroot mode. When set, AWF checks this path first before environment-based auto-detection."
},
"mounts": {
"type": "array",
"items": {
"type": "string",
"pattern": "^/[^:]+:/[^:]+(:(ro|rw))?$"
},
"description": "Custom volume mounts for the agent container. Format: \"/host_path:/container_path[:ro|rw]\" (both paths must be absolute). In chroot mode, container paths are automatically prefixed with /host."
}
}
},
Expand Down
21 changes: 21 additions & 0 deletions src/config-file-mapping.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,27 @@ describe('mapAwfFileConfigToCliOptions', () => {
expect(result.runnerToolCachePath).toBe('/opt/hostedtoolcache');
});

it('maps container.mounts to mount array', () => {
const result = mapAwfFileConfigToCliOptions({
container: {
mounts: [
'/tmp/gh-aw:/tmp/gh-aw:ro',
'/tmp/gh-aw/home:/tmp/gh-aw/home:rw',
],
},
});

expect(result.mount).toEqual([
'/tmp/gh-aw:/tmp/gh-aw:ro',
'/tmp/gh-aw/home:/tmp/gh-aw/home:rw',
]);
});

it('leaves mount undefined when container.mounts is not set', () => {
const result = mapAwfFileConfigToCliOptions({ container: {} });
expect(result.mount).toBeUndefined();
});

it('maps environment fields', () => {
const result = mapAwfFileConfigToCliOptions({
environment: {
Expand Down
1 change: 1 addition & 0 deletions src/config-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ export interface AwfFileConfig {
dockerHost?: string;
dockerHostPathPrefix?: string;
runnerToolCachePath?: string;
mounts?: string[];
};
chroot?: {
binariesSourcePath?: string;
Expand Down
1 change: 1 addition & 0 deletions src/config-mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ export function mapAwfFileConfigToCliOptions(config: AwfFileConfig): Record<stri
dockerHost: config.container?.dockerHost,
dockerHostPathPrefix: config.container?.dockerHostPathPrefix,
runnerToolCachePath: config.container?.runnerToolCachePath,
mount: config.container?.mounts,
chrootBinariesSourcePath: config.chroot?.binariesSourcePath,
chrootIdentityHome: config.chroot?.identity?.home,
chrootIdentityUser: config.chroot?.identity?.user,
Expand Down
16 changes: 16 additions & 0 deletions src/schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,22 @@ describe('awf-config.schema.json', () => {
expect(validate({ container: { runnerToolCachePath: 123 } })).toBe(false);
});

it('accepts valid container.mounts array', () => {
expect(validate({ container: { mounts: ['/tmp/gh-aw:/tmp/gh-aw:ro'] } })).toBe(true);
expect(validate({ container: { mounts: ['/tmp/gh-aw:/tmp/gh-aw:rw', '/data:/data'] } })).toBe(true);
expect(validate({ container: { mounts: [] } })).toBe(true);
});

it('rejects invalid container.mounts entries', () => {
expect(validate({ container: { mounts: ['invalid-no-colon'] } })).toBe(false);
expect(validate({ container: { mounts: ['/src:/dst:invalid-mode'] } })).toBe(false);
expect(validate({ container: { mounts: 'not-an-array' } })).toBe(false);
// Relative paths must be rejected (runtime validator requires absolute paths)
expect(validate({ container: { mounts: ['relative/path:/container/dst'] } })).toBe(false);
expect(validate({ container: { mounts: ['/host/src:relative/container'] } })).toBe(false);
expect(validate({ container: { mounts: ['./relative:/container/dst:ro'] } })).toBe(false);
});
Comment on lines +247 to +261

it('accepts runner.topology and runner.sysrootImage', () => {
expect(validate({ runner: { topology: 'arc-dind' } })).toBe(true);
expect(validate({ runner: { topology: 'invalid' } })).toBe(false);
Expand Down
Loading