diff --git a/packages/k8s/src/k8s/utils.ts b/packages/k8s/src/k8s/utils.ts index 9e744004..7d1f6bac 100644 --- a/packages/k8s/src/k8s/utils.ts +++ b/packages/k8s/src/k8s/utils.ts @@ -301,5 +301,5 @@ export async function sleep(ms: number): Promise { } export function listDirAllCommand(dir: string): string { - return `cd ${shlex.quote(dir)} && find . -type f -not -path '*/_runner_hook_responses*' -exec stat -c '%s %n' {} \\;` + return `cd ${shlex.quote(dir)} && find . -type f -not -path '*/_runner_hook_responses*' -exec stat -c '%s %n' -- {} +` } diff --git a/packages/k8s/tests/k8s-utils-test.ts b/packages/k8s/tests/k8s-utils-test.ts index bfb6c453..87a01809 100644 --- a/packages/k8s/tests/k8s-utils-test.ts +++ b/packages/k8s/tests/k8s-utils-test.ts @@ -6,6 +6,7 @@ import { mergePodSpecWithOptions, mergeContainerWithOptions, readExtensionFromFile, + listDirAllCommand, ENV_HOOK_TEMPLATE_PATH } from '../src/k8s/utils' import * as k8s from '@kubernetes/client-node' @@ -406,4 +407,32 @@ spec: expect(base).toStrictEqual(expected) }) + + describe('listDirAllCommand', () => { + it('should use batched exec (+ not \\;)', () => { + const cmd = listDirAllCommand('/workspace') + expect(cmd).toContain('{} +') + expect(cmd).not.toContain('\\;') + }) + + it('should include end-of-options marker before filenames', () => { + const cmd = listDirAllCommand('/workspace') + expect(cmd).toMatch(/stat -c '%s %n' -- \{\} \+/) + }) + + it('should quote the directory path', () => { + const cmd = listDirAllCommand('/path with spaces') + expect(cmd).toContain("'/path with spaces'") + }) + + it('should exclude _runner_hook_responses', () => { + const cmd = listDirAllCommand('/workspace') + expect(cmd).toContain("-not -path '*/_runner_hook_responses*'") + }) + + it('should only find regular files', () => { + const cmd = listDirAllCommand('/workspace') + expect(cmd).toContain('-type f') + }) + }) })