Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea8a5b40e7 | ||
|
|
f38f218ae0 |
No files matched your search
@@ -10,6 +10,7 @@
|
||||
!backup.js
|
||||
!reading-analytics.js
|
||||
!reading-access.js
|
||||
!moments.js
|
||||
!public/
|
||||
!public/**
|
||||
!greatest/
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ RUN apk add --no-cache tzdata openssl
|
||||
WORKDIR /app
|
||||
ARG VCS_REF=development
|
||||
LABEL org.opencontainers.image.title="MangaCircus" org.opencontainers.image.revision=$VCS_REF
|
||||
COPY package.json server.js library.js reading-direction.js chapter-identity.js chapter-dates.js reading-analytics.js reading-access.js catalog.js backup.js ./
|
||||
COPY package.json server.js library.js reading-direction.js chapter-identity.js chapter-dates.js reading-analytics.js reading-access.js catalog.js backup.js moments.js ./
|
||||
COPY public ./public
|
||||
COPY greatest ./greatest
|
||||
COPY discovery ./discovery
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
'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`);
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user