mirror of
https://github.com/lancedikson/bowser
synced 2026-09-22 12:05:23 +00:00
fix(test): extract the smoke-test tarball with Node built-ins
Replaces the external tar process with zlib.gunzipSync plus a minimal ustar reader, so the smoke test spawns nothing but Node and behaves identically on every OS and Node version in the matrix. npm tarballs are gzipped ustar archives of regular files only, which is the one shape the reader accepts; a path-escape guard rejects anything else.
This commit is contained in:
@@ -18,6 +18,7 @@ var cp = require('child_process');
|
||||
var fs = require('fs');
|
||||
var os = require('os');
|
||||
var path = require('path');
|
||||
var zlib = require('zlib');
|
||||
|
||||
var tarball = process.argv[2];
|
||||
|
||||
@@ -40,12 +41,42 @@ var tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'bowser-smoke-'));
|
||||
var modules = path.join(tmp, 'node_modules');
|
||||
fs.mkdirSync(modules);
|
||||
|
||||
// `npm install <tarball>` would work too, but plain tar keeps this dependency
|
||||
// free and identical across the whole Node matrix, and sidesteps the
|
||||
// npm.cmd-needs-a-shell quirks of spawning npm on Windows. tar itself is on
|
||||
// PATH everywhere this runs: Linux, macOS, and Windows 10 1803+ (bsdtar).
|
||||
/**
|
||||
* Extracts an npm tarball using only Node built-ins, so the test needs no
|
||||
* external `tar`/`npm` process and runs identically on every OS and every
|
||||
* Node version in the support matrix.
|
||||
*
|
||||
* npm tarballs are gzipped ustar archives of regular files (npm rejects
|
||||
* anything else at publish time), which is the only shape handled here:
|
||||
* pax/global extended headers and directory entries are skipped, and parent
|
||||
* directories are created per file instead.
|
||||
*/
|
||||
function extractNpmTarball(tgz, dest) {
|
||||
var buf = zlib.gunzipSync(fs.readFileSync(tgz));
|
||||
var offset = 0;
|
||||
while (offset + 512 <= buf.length) {
|
||||
var header = buf.slice(offset, offset + 512);
|
||||
offset += 512;
|
||||
if (header[0] === 0) break; // zero block: end of archive
|
||||
var name = header.slice(0, 100).toString('utf8').replace(/\0[\s\S]*$/, '');
|
||||
var prefix = header.slice(345, 500).toString('utf8').replace(/\0[\s\S]*$/, '');
|
||||
if (prefix) name = prefix + '/' + name;
|
||||
var size = parseInt(header.slice(124, 136).toString('utf8'), 8) || 0;
|
||||
var type = header[156];
|
||||
if (type === 48 /* '0' */ || type === 0) {
|
||||
var target = path.join(dest, name);
|
||||
if (target.indexOf(dest + path.sep) !== 0) {
|
||||
throw new Error('tarball entry escapes destination: ' + name);
|
||||
}
|
||||
fs.mkdirSync(path.dirname(target), { recursive: true });
|
||||
fs.writeFileSync(target, buf.slice(offset, offset + size));
|
||||
}
|
||||
offset += Math.ceil(size / 512) * 512;
|
||||
}
|
||||
}
|
||||
|
||||
// npm tarballs always unpack to a single top-level `package/` directory.
|
||||
cp.execFileSync('tar', ['-xzf', tarball, '-C', modules], { stdio: 'inherit' });
|
||||
extractNpmTarball(tarball, modules);
|
||||
fs.renameSync(path.join(modules, 'package'), path.join(modules, 'bowser'));
|
||||
|
||||
var runner = path.join(tmp, 'assertions.cjs');
|
||||
|
||||
Reference in New Issue
Block a user