mirror of
https://github.com/whyour/qinglong.git
synced 2026-11-02 06:58:52 +08:00
Pin Alpine amd64 to the verified upstream Node runtime without retaining temporary binaries in image layers. Bound fresh-process URL probes and verify serialized amd64/ARMv6 layers in CI. Keep existing Sequelize, SQLite and Debian runtime behavior unchanged.
63 lines
2.3 KiB
JavaScript
63 lines
2.3 KiB
JavaScript
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const os = require('node:os');
|
|
const path = require('node:path');
|
|
const { createHash } = require('node:crypto');
|
|
const { spawnSync } = require('node:child_process');
|
|
|
|
// Run in new processes: a healthy parent can outlive a broken native runtime.
|
|
function probeNodeRuntime(executable = process.execPath) {
|
|
const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'ql-node-url-'));
|
|
const source = `
|
|
const assert = require('node:assert/strict');
|
|
const { pathToFileURL, fileURLToPath } = require('node:url');
|
|
for (let i = 0; i < 1000; i++) {
|
|
assert.equal(new URL('/任务?q=' + i, 'https://example.com').hostname, 'example.com');
|
|
assert.equal(new URL('https://例子.测试').hostname, 'xn--fsqu00a.xn--0zwm56d');
|
|
assert.equal(new URL('http://[::1]:5700').port, '5700');
|
|
const filename = '/tmp/中文 path/' + i + '.cjs';
|
|
assert.equal(fileURLToPath(pathToFileURL(filename)), filename);
|
|
}
|
|
console.log('QINGLONG_NODE_URL_OK');
|
|
`;
|
|
const file = path.join(directory, 'probe.cjs');
|
|
fs.writeFileSync(file, source);
|
|
try {
|
|
for (let i = 0; i < 4; i++) {
|
|
const args = process.execArgv.includes('--jitless') ? ['--jitless'] : [];
|
|
args.push(...(i % 2 ? [file] : ['-e', source]));
|
|
const child = spawnSync(executable, args, {
|
|
encoding: 'utf8',
|
|
// Multi-architecture CI runs this same probe through QEMU.
|
|
timeout: 120000,
|
|
maxBuffer: 65536,
|
|
env: { ...process.env, NODE_OPTIONS: '' },
|
|
});
|
|
assert.equal(
|
|
child.status,
|
|
0,
|
|
`Node URL runtime probe failed (${i % 2 ? 'file' : 'eval'}): signal=${
|
|
child.signal
|
|
}; status=${child.status}; ${child.error?.message || child.stderr}`,
|
|
);
|
|
assert.match(child.stdout, /QINGLONG_NODE_URL_OK/);
|
|
}
|
|
return {
|
|
ok: true,
|
|
node: process.version,
|
|
architecture: process.arch,
|
|
ada: process.versions.ada,
|
|
processes: 4,
|
|
urlIterationsPerProcess: 1000,
|
|
nodeSha256: createHash('sha256')
|
|
.update(fs.readFileSync(executable))
|
|
.digest('hex'),
|
|
};
|
|
} finally {
|
|
fs.rmSync(directory, { recursive: true, force: true });
|
|
}
|
|
}
|
|
|
|
module.exports = { probeNodeRuntime };
|
|
if (require.main === module) console.log(JSON.stringify(probeNodeRuntime()));
|