master
John Lauer docs: first-run contract in the Rust plan (arav-rog findings), changelog 2.0.397-2.0.399, ship.sh publishes pkg before… 47808a0 2mo ago
// Gate: the supervised unpack (v2.0.398). Builds a small zip, unpacks it through chrome.js's
// unpackSupervised (child process + watchdog), and checks the bytes land and a bad archive fails
// cleanly (dest removed, error surfaced) instead of hanging.
const assert = require('assert');
const fs = require('fs'); const os = require('os'); const path = require('path');
const { execFileSync } = require('child_process');
const chrome = require('../src/chrome.js');

(async () => {
  const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'pup-unpack-'));
  const src = path.join(tmp, 'src'); fs.mkdirSync(path.join(src, 'chrome-linux64'), { recursive: true });
  fs.writeFileSync(path.join(src, 'chrome-linux64', 'chrome'), Buffer.alloc(200000, 7));
  fs.writeFileSync(path.join(src, 'chrome-linux64', 'ABOUT'), 'about');
  const zip = path.join(tmp, 'a.zip');
  execFileSync('python3', ['-c', `import shutil,sys; shutil.make_archive(sys.argv[1][:-4], 'zip', sys.argv[2])`, zip, src]);
  assert.ok(fs.existsSync(zip), 'test zip built');

  // happy path
  const dest = path.join(tmp, 'linux64-1.2.3.partial');
  let seenBytes = 0, method = null;
  const r = await chrome.unpackSupervised(zip, dest, { onBytes: (b) => { seenBytes = Math.max(seenBytes, b); }, onMethod: (m) => { method = method || m; } });
  assert.ok(['extract-zip', 'tar'].includes(r.method), 'a real method was used: ' + r.method);
  assert.ok(fs.existsSync(path.join(dest, 'chrome-linux64', 'chrome')), 'executable landed');
  assert.strictEqual(fs.statSync(path.join(dest, 'chrome-linux64', 'chrome')).size, 200000);
  assert.ok(chrome.dirBytes(dest) >= 200005, 'dirBytes counts the tree');
  assert.ok(chrome.hasCftExecutable(dest), 'hasCftExecutable sees the linux chrome binary');

  // a corrupt archive fails fast and leaves no folder behind
  const bad = path.join(tmp, 'bad.zip'); fs.writeFileSync(bad, Buffer.from('this is not a zip file at all'));
  const dest2 = path.join(tmp, 'linux64-9.9.9.partial');
  let err = null;
  try { await chrome.unpackSupervised(bad, dest2, {}); } catch (e) { err = e; }
  assert.ok(err, 'corrupt archive rejects');
  assert.ok(!fs.existsSync(dest2), 'failed unpack leaves no partial folder');

  fs.rmSync(tmp, { recursive: true, force: true });
  console.log('check_unpack: OK (' + r.method + ', ' + r.ms + 'ms)');
})().catch((e) => { console.error('check_unpack FAILED:', e && e.stack || e); process.exit(1); });