Repository navigation
Docker multi stage - #346
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The published image carried its whole build environment: compilers, the npm cache, an 800 MB Cypress binary nothing in the container runs, the Next.js build cache and every devDependency. This PR moves the build into its own stage and ships only what the lab runs. Nothing changes for players: first run, upgrading an existing volume and every challenge behave the same.
Size
leogra/oss-oopssec-store:latest(2026-09-22)mainbuilt locallySizes from
docker image ls, Node 22.23.2.Changes
tsxanddotenvmove todependencies. The entrypoint seeds throughtsx, and both the seed andprisma.config.tsloaddotenv, so pruning devDependencies would break the first run and everyprismacommand. In the lockfile, only"dev": truegoes away for tsx, dotenv and their transitive packages; no version changes.CYPRESS_INSTALL_BINARY=0, cleans the npm cache in the same layer, builds as before, then prunes devDependencies and drops.next/cache. The runtime stage copies/apponto the samenode:22-alpinebase and installs no apk packages.npx --noin the entrypoint. Without a TTY, npx assumes--yes, so a package missing from the image was quietly fetched from the registry instead of failing. I checked this with an image stripped of tsx: plainnpxinstalledtsx@4.23.15, which is not the locked version, and carried on. With--noit fails.docker-build.ymlbuilt the image but never started it. It now runs the container with--network none, waits for the seed, and queries/api/flags/count..dockerignorejoins the path filter..dockerignoredrops untracked local folders (.claude/,.plan/,.venv/), so an image built locally matches the published one.Trade-offs
content/,documents/,flag-xxe.txt,prisma/schema.prismaandnext.config.ts. The supply-chain challenge readspackages/react-toastfy/andlab/quarantine/through path traversal. With an allowlist, a forgotten path would break a challenge without any error at startup. The sources are about 2.5 MB, so there is nothing to gain.python3 make g++. On Node 22, libxmljs2 and better-sqlite3 install as prebuilt binaries. The toolchain only matters if node-gyp has to compile them, andnpm rebuild --build-from-sourceworks with these three packages alone. libxmljs2 compiles its bundled libxml2, so the runtime stage needs nolibxml2.typescriptstays in the image (23 MB). It is an optional peer dependency ofprisma, which--omit=devkeeps.output: "standalone"and the single-arch build. Those are separate changes.Verification
Run against the image from this branch:
db:upgrade, 36 flags both times.leogra/oss-oopssec-store:latest: offline, flag progress kept.npm run test:apiwith the container on the host database: 296/297. The XXE test fails the same way againstmain: it builds itsfile://URL from the host working directory, which does not exist in the container. The exploit works withfile:///app/flag-xxe.txt.npm run test:e2e: 70/70./vulnerabilities/react2shelland/_next/imagewith an Unsplash URL return 200, which meanscontent/andnext.config.tsare loaded.docker compose up --buildon a fresh project: first run OK.npm run test:unit,npm run lint(0 errors) andnpm run format:checkpass.Left for later
npm cialso installs the glibc builds of@next/swc(137 MB),@napi-rs/canvas(32 MB) and sharp, because the lockfile recordsosandcpubut notlibc. Leaving them out would take about another 170 MB off disk.