fix(worker): contain workspace paths against symlinks
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
import { mkdir, mkdtemp, rm, symlink, writeFile } from 'node:fs/promises';
|
||||
import { tmpdir } from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { afterEach, describe, expect, test } from 'vitest';
|
||||
|
||||
import { assertContainedRealPath } from '../../src/path-containment';
|
||||
|
||||
let dir: string;
|
||||
|
||||
afterEach(async () => {
|
||||
if (dir) await rm(dir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
describe('assertContainedRealPath', () => {
|
||||
test('allows a normal file inside the root', async () => {
|
||||
dir = await mkdtemp(path.join(tmpdir(), 'spoon-'));
|
||||
const root = path.join(dir, 'repo');
|
||||
await mkdir(root, { recursive: true });
|
||||
await writeFile(path.join(root, 'a.txt'), 'hi');
|
||||
await expect(assertContainedRealPath(root, 'a.txt')).resolves.toBe(
|
||||
path.join(root, 'a.txt'),
|
||||
);
|
||||
});
|
||||
|
||||
test('rejects a lexical .. escape', async () => {
|
||||
dir = await mkdtemp(path.join(tmpdir(), 'spoon-'));
|
||||
const root = path.join(dir, 'repo');
|
||||
await mkdir(root, { recursive: true });
|
||||
await expect(assertContainedRealPath(root, '../secret')).rejects.toThrow();
|
||||
});
|
||||
|
||||
test('rejects reading through a symlink that escapes the root', async () => {
|
||||
dir = await mkdtemp(path.join(tmpdir(), 'spoon-'));
|
||||
const root = path.join(dir, 'repo');
|
||||
const outside = path.join(dir, 'outside');
|
||||
await mkdir(root, { recursive: true });
|
||||
await mkdir(outside, { recursive: true });
|
||||
await writeFile(path.join(outside, 'secret'), 'S');
|
||||
await symlink(outside, path.join(root, 'link'));
|
||||
await expect(
|
||||
assertContainedRealPath(root, 'link/secret'),
|
||||
).rejects.toThrow();
|
||||
});
|
||||
|
||||
test('rejects a write whose final target is a symlink', async () => {
|
||||
dir = await mkdtemp(path.join(tmpdir(), 'spoon-'));
|
||||
const root = path.join(dir, 'repo');
|
||||
await mkdir(root, { recursive: true });
|
||||
await symlink(path.join(dir, 'evil'), path.join(root, 'out'));
|
||||
await expect(
|
||||
assertContainedRealPath(root, 'out', { forWrite: true }),
|
||||
).rejects.toThrow();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user