36 lines
1.8 KiB
TypeScript
36 lines
1.8 KiB
TypeScript
import { describe, it, expect } from '@jest/globals';
|
|
import { promises as fs } from 'node:fs';
|
|
import * as path from 'node:path';
|
|
import * as os from 'node:os';
|
|
import { prepareArtifactBuild, validateArtifactOutput } from './artifact-build-context';
|
|
|
|
describe('bounded artifact build context', () => {
|
|
it.each(['../dist', '/tmp/output', '.', 'dist/../etc', 'dist\\etc', ''])('rejects unsafe output: %s', (value) => {
|
|
expect(() => validateArtifactOutput(value)).toThrow();
|
|
});
|
|
|
|
it('keeps credentials out of the source and forces a fresh bounded build', async () => {
|
|
const source = await fs.mkdtemp(path.join(os.tmpdir(), 'artifact-context-test-'));
|
|
let root: string | undefined;
|
|
try {
|
|
for (const dir of ['.git', 'node_modules', 'dist']) {
|
|
await fs.mkdir(path.join(source, dir));
|
|
await fs.writeFile(path.join(source, dir, 'private'), 'not-build-input');
|
|
}
|
|
await fs.writeFile(path.join(source, 'package.json'), '{"name":"test"}');
|
|
const plan = await prepareArtifactBuild(source, 'dist', 'npm ci', 'npm run build:linux', [{ key: 'BUILD_TOKEN', value: 'private-token' }]);
|
|
root = plan.root;
|
|
expect(await fs.readdir(path.join(root, 'context/source'))).toEqual(['package.json']);
|
|
const config = JSON.parse(await fs.readFile(path.join(root, 'config.json'), 'utf8'));
|
|
expect(config.env).toEqual({ BUILD_TOKEN: 'private-token' });
|
|
expect((await fs.stat(path.join(root, 'config.json'))).mode & 0o777).toBe(0o600);
|
|
expect(plan.args).toContain('--artifact-output');
|
|
expect(plan.args.join(' ')).not.toContain('private-token');
|
|
expect(plan.args.some((arg) => arg.startsWith('BUILD_REQUEST_ID='))).toBe(true);
|
|
} finally {
|
|
await fs.rm(source, { recursive: true, force: true });
|
|
if (root) await fs.rm(root, { recursive: true, force: true });
|
|
}
|
|
});
|
|
});
|