- td toolchain install / td_toolchain_install: downloads the compiler package (approved accounts) and sets up local checks; td-server toolchain pack builds it from the compile image. - td_check compiles on the contributor machine only (includers: true for header changes, using the server include map). - td_regions, td_claim_region, td_release_region; td_submit adds rewritten functions of shared regions as competing candidates. - AGENTS.md, MCP instructions and guidance describe the region loop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
48 lines
2.2 KiB
JavaScript
48 lines
2.2 KiB
JavaScript
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
import zlib from 'node:zlib';
|
|
import { extractTarGz } from '../src/shared/tar.js';
|
|
|
|
function header(name, size, type = '0') {
|
|
const h = Buffer.alloc(512);
|
|
h.write(name.slice(0, 100), 0);
|
|
h.write('0000644\0', 100);
|
|
h.write(size.toString(8).padStart(11, '0') + '\0', 124);
|
|
h.write('00000000000\0', 136);
|
|
h[156] = type.charCodeAt(0);
|
|
h.write('ustar\0', 257);
|
|
h.write('00', 263);
|
|
h.fill(' ', 148, 156);
|
|
let sum = 0;
|
|
for (const b of h) sum += b;
|
|
h.write(sum.toString(8).padStart(6, '0') + '\0 ', 148);
|
|
return h;
|
|
}
|
|
const pad = (b) => Buffer.concat([b, Buffer.alloc((512 - (b.length % 512)) % 512)]);
|
|
|
|
test('extracts files, GNU long names and pax paths; refuses paths outside the target', async () => {
|
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'tar-'));
|
|
const long = 'toolchain/vs2010sp1/vc_stdamd64/Program Files(64)/Microsoft Visual Studio 10.0/VC/bin/amd64/1033/clui.dll';
|
|
const pax = Buffer.from(`${`path=toolchain/pax/name.h`.length + 4} path=toolchain/pax/name.h\n`);
|
|
const parts = [
|
|
header('toolchain/', 0, '5'),
|
|
header('toolchain/a.txt', 5), pad(Buffer.from('hello')),
|
|
header('././@LongLink', long.length + 1, 'L'), pad(Buffer.from(long + '\0')), header(long.slice(0, 99), 3), pad(Buffer.from('dll')),
|
|
header('PaxHeader', pax.length, 'x'), pad(pax), header('short', 2), pad(Buffer.from('ok')),
|
|
Buffer.alloc(1024),
|
|
];
|
|
const file = path.join(dir, 'a.tar.gz');
|
|
fs.writeFileSync(file, zlib.gzipSync(Buffer.concat(parts)));
|
|
assert.equal(await extractTarGz(file, path.join(dir, 'out')), 3);
|
|
assert.equal(fs.readFileSync(path.join(dir, 'out/toolchain/a.txt'), 'utf8'), 'hello');
|
|
assert.equal(fs.readFileSync(path.join(dir, 'out', long), 'utf8'), 'dll');
|
|
assert.equal(fs.readFileSync(path.join(dir, 'out/toolchain/pax/name.h'), 'utf8'), 'ok');
|
|
|
|
const evil = path.join(dir, 'evil.tar.gz');
|
|
fs.writeFileSync(evil, zlib.gzipSync(Buffer.concat([header('../escape.txt', 1), pad(Buffer.from('x')), Buffer.alloc(1024)])));
|
|
await assert.rejects(extractTarGz(evil, path.join(dir, 'out2')), /outside the target/);
|
|
fs.rmSync(dir, { recursive: true, force: true });
|
|
});
|