Files
ECC/docker/plugin-setup/prepare-packed-cli.js
T
haelyraandGitHub d791457aca feat(docker): add hardened CLI test harness (#2625)
* feat(install): add hardened Docker test harness

* feat(docker): complete isolated CLI session lifecycle

* fix(docker): exercise packed public CLI offline

* fix(docker): close hardened harness review gaps

* test(docker): bound harness subprocesses
2026-08-06 16:52:39 -04:00

168 lines
4.9 KiB
JavaScript

#!/usr/bin/env node
'use strict';
const { spawnSync } = require('child_process');
const fs = require('fs');
const path = require('path');
const EXPECTED_NAME = 'ecc-universal';
const EXPECTED_BIN = 'scripts/ecc.js';
const CHILD_PROCESS_TIMEOUT_MS = 5 * 60 * 1000;
const REQUIRED_FILES = Object.freeze([
'scripts/ecc.js',
'manifests/install-components.json',
'manifests/install-modules.json',
'manifests/install-profiles.json',
]);
function fail(message) {
throw new Error(message);
}
function isWithin(root, candidate) {
const relative = path.relative(root, candidate);
return relative === '' || (
relative !== '..'
&& !relative.startsWith(`..${path.sep}`)
&& !path.isAbsolute(relative)
);
}
function requireRegularFile(packageRoot, relativePath) {
const resolvedPath = path.resolve(packageRoot, relativePath);
if (!isWithin(packageRoot, resolvedPath)) {
fail(`Package path escapes the extracted root: ${relativePath}`);
}
let file;
try {
file = fs.lstatSync(resolvedPath);
} catch {
fail(`Packed package is missing ${relativePath}.`);
}
if (!file.isFile() || file.isSymbolicLink()) {
fail(`Packed package path is not a regular file: ${relativePath}`);
}
return resolvedPath;
}
function validatePackedPackage(packageRoot) {
const resolvedRoot = path.resolve(packageRoot);
const packageJsonPath = requireRegularFile(resolvedRoot, 'package.json');
const manifest = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
if (manifest.name !== EXPECTED_NAME) {
fail(`Unexpected packed package name: ${manifest.name || '<missing>'}.`);
}
if (typeof manifest.version !== 'string' || manifest.version.length === 0) {
fail('Packed package version is missing.');
}
if (!manifest.bin || manifest.bin.ecc !== EXPECTED_BIN) {
fail(`Packed package bin.ecc must map to ${EXPECTED_BIN}.`);
}
for (const requiredFile of REQUIRED_FILES) {
requireRegularFile(resolvedRoot, requiredFile);
}
const binTarget = path.resolve(resolvedRoot, manifest.bin.ecc);
if (!isWithin(resolvedRoot, binTarget)) {
fail('Packed package bin.ecc escapes the extracted package root.');
}
if (process.platform !== 'win32') {
fs.accessSync(binTarget, fs.constants.X_OK);
}
return binTarget;
}
function run(executable, argv, options = {}) {
const result = spawnSync(executable, argv, {
...options,
encoding: 'utf8',
shell: false,
timeout: CHILD_PROCESS_TIMEOUT_MS,
});
if (result.error) {
fail(`Unable to run ${executable}: ${result.error.message}`);
}
if (result.status !== 0) {
const detail = (result.stderr || result.stdout || '').trim();
fail(`${executable} exited with status ${result.status}${detail ? `: ${detail}` : ''}`);
}
return result;
}
function preparePackedCli(sourceRoot, outputRoot) {
const resolvedSource = path.resolve(sourceRoot);
const resolvedOutput = path.resolve(outputRoot);
if (resolvedSource !== '/ecc') {
fail('Package source must be the read-only /ecc checkout.');
}
if (resolvedOutput !== '/tmp' && !resolvedOutput.startsWith('/tmp/')) {
fail('Packed CLI output must remain under /tmp.');
}
fs.mkdirSync(resolvedOutput, { recursive: true, mode: 0o700 });
const workRoot = fs.mkdtempSync(path.join(resolvedOutput, 'artifact-'));
const childEnv = {
...process.env,
NPM_CONFIG_CACHE: '/tmp/npm-cache',
npm_config_audit: 'false',
npm_config_fund: 'false',
npm_config_ignore_scripts: 'true',
npm_config_offline: 'true',
};
const packed = run('npm', [
'pack',
resolvedSource,
'--ignore-scripts',
'--pack-destination',
workRoot,
'--json',
], { env: childEnv });
let metadata;
try {
metadata = JSON.parse(packed.stdout);
} catch (error) {
fail(`npm pack returned invalid JSON: ${error.message}`);
}
const filename = metadata?.[0]?.filename;
if (
typeof filename !== 'string'
|| path.basename(filename) !== filename
|| !filename.endsWith('.tgz')
) {
fail('npm pack did not return a confined tarball filename.');
}
const archivePath = path.resolve(workRoot, filename);
if (!isWithin(workRoot, archivePath)) {
fail('npm pack tarball escaped the artifact directory.');
}
const extractRoot = path.join(workRoot, 'extracted');
fs.mkdirSync(extractRoot, { mode: 0o700 });
run('tar', ['-xzf', archivePath, '-C', extractRoot]);
const binTarget = validatePackedPackage(path.join(extractRoot, 'package'));
const binRoot = path.join(workRoot, 'bin');
fs.mkdirSync(binRoot, { mode: 0o700 });
const publicBin = path.join(binRoot, 'ecc');
fs.symlinkSync(binTarget, publicBin);
return publicBin;
}
function main() {
try {
const publicBin = preparePackedCli(process.argv[2], process.argv[3]);
process.stdout.write(`${publicBin}\n`);
} catch (error) {
process.stderr.write(`Error: ${error.message}\n`);
process.exitCode = 1;
}
}
if (require.main === module) main();
module.exports = { isWithin, preparePackedCli, validatePackedPackage };