f38f218 failed to build: .dockerignore is an allowlist and kept
moments.js out of the build context. Verified by building the image and
starting the reader from it (health ok).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
28 lines
1.6 KiB
JavaScript
28 lines
1.6 KiB
JavaScript
'use strict';
|
|
// The image copies top-level modules by name; a new module missing there crashes the reader at start.
|
|
const test = require('node:test'), assert = require('node:assert/strict');
|
|
const fs = require('fs'), path = require('path');
|
|
const root = path.resolve(__dirname, '..');
|
|
|
|
test('every top-level module the reader requires is copied into the image', () => {
|
|
const dockerfile = fs.readFileSync(path.join(root, 'Dockerfile'), 'utf8');
|
|
const copied = new Set(dockerfile.split('\n').filter(line => line.startsWith('COPY ')).flatMap(line => line.split(/\s+/).slice(1, -1)));
|
|
const pending = ['server.js'], seen = new Set();
|
|
while (pending.length) {
|
|
const file = pending.pop();
|
|
if (seen.has(file)) continue;
|
|
seen.add(file);
|
|
for (const [, name] of fs.readFileSync(path.join(root, file), 'utf8').matchAll(/require\('\.\/([\w.-]+?)(?:\.js)?'\)/g)) {
|
|
// A folder (e.g. ./greatest) is copied as a whole; only single files need their own name in COPY.
|
|
if (fs.existsSync(path.join(root, name)) && fs.statSync(path.join(root, name)).isDirectory()) assert.ok(copied.has(name), `${name}/ is not copied`);
|
|
else pending.push(name + '.js');
|
|
}
|
|
}
|
|
// .dockerignore is an allowlist too: a file not let through never reaches COPY.
|
|
const allowed = new Set(fs.readFileSync(path.join(root, '.dockerignore'), 'utf8').split(/\r?\n/).filter(line => line.startsWith('!')).map(line => line.slice(1)));
|
|
for (const file of seen) {
|
|
assert.ok(copied.has(file), `${file} is required but not copied by the Dockerfile`);
|
|
assert.ok(allowed.has(file), `${file} is required but not allowed through .dockerignore`);
|
|
}
|
|
});
|