mirror of
https://github.com/lancedikson/bowser
synced 2026-10-08 03:41:50 +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 fs = require('fs');
|
||||||
var os = require('os');
|
var os = require('os');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
|
var zlib = require('zlib');
|
||||||
|
|
||||||
var tarball = process.argv[2];
|
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');
|
var modules = path.join(tmp, 'node_modules');
|
||||||
fs.mkdirSync(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
|
* Extracts an npm tarball using only Node built-ins, so the test needs no
|
||||||
// npm.cmd-needs-a-shell quirks of spawning npm on Windows. tar itself is on
|
* external `tar`/`npm` process and runs identically on every OS and every
|
||||||
// PATH everywhere this runs: Linux, macOS, and Windows 10 1803+ (bsdtar).
|
* 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.
|
// 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'));
|
fs.renameSync(path.join(modules, 'package'), path.join(modules, 'bowser'));
|
||||||
|
|
||||||
var runner = path.join(tmp, 'assertions.cjs');
|
var runner = path.join(tmp, 'assertions.cjs');
|
||||||
|
|||||||
Reference in New Issue
Block a user