mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-08-17 18:25:42 +02:00
57 lines
2.4 KiB
JavaScript
57 lines
2.4 KiB
JavaScript
#!/usr/bin/env node
|
|
// Audits backend/requirements.txt for fully-pinned versions. Header comment says reproducible builds, so any "no-version" or ">=" entry means two builds from the same git sha could resolve different package versions - the classic invisible "works on my machine" drift.
|
|
|
|
'use strict';
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const h = require('./lib/app-harness');
|
|
|
|
const REQ_FILE = path.join(h.REPO_ROOT, 'backend', 'requirements.txt');
|
|
|
|
function parseRequirements(text) {
|
|
const items = [];
|
|
for (let raw of text.split(/\r?\n/)) {
|
|
const line = raw.replace(/#.*$/, '').trim();
|
|
if (!line) continue;
|
|
if (/^-r\s/.test(line)) continue; // file include, treated separately
|
|
if (/^(--|-)/.test(line)) continue; // pip flags
|
|
items.push(line);
|
|
}
|
|
return items;
|
|
}
|
|
|
|
// A line is "fully pinned" if it carries an exact-version operator (==) OR
|
|
// a hash-pinned wheel via --hash (treated as canonical pin). Floors (>=, ~=,
|
|
// >, <, <=) and bare names all FAIL because they leave room for drift.
|
|
function isFullyPinned(line) {
|
|
if (line.includes('==')) return true;
|
|
if (line.includes(' --hash=')) return true;
|
|
return false;
|
|
}
|
|
|
|
module.exports = { parseRequirements, isFullyPinned };
|
|
|
|
function main() {
|
|
const text = fs.readFileSync(REQ_FILE, 'utf8');
|
|
const reqs = parseRequirements(text);
|
|
const unpinned = reqs.filter((r) => !isFullyPinned(r));
|
|
|
|
process.stdout.write(`Audit: ${REQ_FILE}\n`);
|
|
process.stdout.write(` ${reqs.length} requirement(s) parsed, ${reqs.length - unpinned.length} fully pinned\n`);
|
|
|
|
if (unpinned.length === 0) {
|
|
process.stdout.write('\nDEPS-PINNED PASS: every backend requirement is exact-version (==X.Y.Z) or hash-pinned.\n');
|
|
process.exit(0);
|
|
}
|
|
|
|
process.stderr.write(`\nDEPS-PINNED FAIL: ${unpinned.length} requirement(s) are NOT fully pinned:\n`);
|
|
for (const r of unpinned) process.stderr.write(` - ${r}\n`);
|
|
process.stderr.write('\nThe header of requirements.txt promises reproducible builds, but pip will resolve these\n');
|
|
process.stderr.write('to latest-matching at install time, so a build on Monday can ship different bytes than\n');
|
|
process.stderr.write('Tuesday from the same git sha. Pin to ==X.Y.Z (run `pip freeze` against the working env\n');
|
|
process.stderr.write('to capture the current resolved versions, then commit them).\n');
|
|
process.exit(1);
|
|
}
|
|
|
|
if (require.main === module) main();
|