diff --git a/packages/k8s/src/k8s/utils.ts b/packages/k8s/src/k8s/utils.ts index 20da57a3..51ed4245 100644 --- a/packages/k8s/src/k8s/utils.ts +++ b/packages/k8s/src/k8s/utils.ts @@ -1,5 +1,6 @@ import * as k8s from '@kubernetes/client-node' import * as fs from 'fs' +import * as path from 'path' import * as yaml from 'js-yaml' import * as core from '@actions/core' import { v1 as uuidv4 } from 'uuid' @@ -45,8 +46,13 @@ cp -R /__w/_temp/_github_workflow /github/workflow mkdir -p ${mountDirs} ` + const runnerTemp = process.env.RUNNER_TEMP + if (!runnerTemp) { + throw new Error('RUNNER_TEMP is not set') + } const filename = `${uuidv4()}.sh` - const entryPointPath = `${process.env.RUNNER_TEMP}/${filename}` + const entryPointPath = `${runnerTemp}/${filename}` + fs.mkdirSync(path.dirname(entryPointPath), { recursive: true }) fs.writeFileSync(entryPointPath, content) return { containerPath: `/__w/_temp/${filename}`, @@ -80,8 +86,13 @@ exec ${environmentPrefix} ${entryPoint} ${ entryPointArgs?.length ? entryPointArgs.join(' ') : '' } ` + const runnerTemp = process.env.RUNNER_TEMP + if (!runnerTemp) { + throw new Error('RUNNER_TEMP is not set') + } const filename = `${uuidv4()}.sh` - const entryPointPath = `${process.env.RUNNER_TEMP}/${filename}` + const entryPointPath = `${runnerTemp}/${filename}` + fs.mkdirSync(path.dirname(entryPointPath), { recursive: true }) fs.writeFileSync(entryPointPath, content) return { containerPath: `/__w/_temp/${filename}`, @@ -117,6 +128,7 @@ exec ${environmentPrefix} ${entryPoint} ${ const filename = `${uuidv4()}.sh` const entryPointPath = `${dst}/${filename}` core.debug(`Writing container step script to ${entryPointPath}`) + fs.mkdirSync(path.dirname(entryPointPath), { recursive: true }) fs.writeFileSync(entryPointPath, content) return { containerPath: `/__w/_temp/${filename}`, diff --git a/packages/k8s/tests/k8s-utils-test.ts b/packages/k8s/tests/k8s-utils-test.ts index bfb6c453..bc836286 100644 --- a/packages/k8s/tests/k8s-utils-test.ts +++ b/packages/k8s/tests/k8s-utils-test.ts @@ -1,7 +1,11 @@ import * as fs from 'fs' +import * as os from 'os' +import * as path from 'path' import { containerPorts } from '../src/k8s' import { generateContainerName, + prepareJobScript, + writeContainerStepScript, writeRunScript, mergePodSpecWithOptions, mergeContainerWithOptions, @@ -121,6 +125,55 @@ describe('k8s utils', () => { }) }) + describe('defensive parent-dir creation', () => { + let tempRoot: string + + beforeEach(() => { + tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'pr05-')) + }) + + afterEach(() => { + fs.rmSync(tempRoot, { recursive: true, force: true }) + }) + + it('writeRunScript creates RUNNER_TEMP parent directory when missing', () => { + const missingDir = path.join(tempRoot, 'nested', 'runner_temp') + expect(fs.existsSync(missingDir)).toBe(false) + process.env.RUNNER_TEMP = missingDir + + const { runnerPath } = writeRunScript('/test', 'sh', ['-e', 'script.sh']) + + expect(fs.existsSync(missingDir)).toBe(true) + expect(fs.existsSync(runnerPath)).toBe(true) + }) + + it('prepareJobScript creates RUNNER_TEMP parent directory when missing', () => { + const missingDir = path.join(tempRoot, 'nested', 'runner_temp') + expect(fs.existsSync(missingDir)).toBe(false) + process.env.RUNNER_TEMP = missingDir + + const { runnerPath } = prepareJobScript([]) + + expect(fs.existsSync(missingDir)).toBe(true) + expect(fs.existsSync(runnerPath)).toBe(true) + }) + + it('writeContainerStepScript creates dst parent directory when missing', () => { + const missingDst = path.join(tempRoot, 'nested', 'step_dst') + expect(fs.existsSync(missingDst)).toBe(false) + + const { runnerPath } = writeContainerStepScript( + missingDst, + '/__w/repo/repo', + 'sh', + ['-e', 'script.sh'] + ) + + expect(fs.existsSync(missingDst)).toBe(true) + expect(fs.existsSync(runnerPath)).toBe(true) + }) + }) + describe('container volumes', () => { beforeEach(async () => { testHelper = new TestHelper()