docker-test
Skill65 starsChanged 14 days agoMITView on GitHub
Build and smoke-test the Docker images with docker compose, and run the golden end-to-end suite against them. Use when touching a Dockerfile, the bundle build, compose config, or a *.e2e.test.ts.
- Reads credentials
2 other projects use a version of this, 1 of them edited.
Adopted by
Most recently taken up by
- nrjdalal/inscopeedited, first seen Oct 13, 2026
- peteonrails/voxtypetheir own version, first seen Oct 8, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 1
- nrjdalal/inscope★ 398% same
Wrote their own version · 1
- peteonrails/voxtype★ 1.8ksame name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository20 other files it gives its agents.
- AGENTS.mdAGENTS.md
- add-packageSkill
- agent-browserSkill
- api-endpointSkill
- auditSkill
- codebase-mapSkill
- db-migrationSkill
- designSkill
- devSkill
- doc-syncSkill
- fontsSkill
- gh-commitSkill
- iceboxSkill
- ignore-syncSkill
- portlessSkill
- releaseSkill
- runtime-apisSkill
- shadcn-syncSkill
- skills-managerSkill
- ui-verifySkill
The file
We split this skill into the rules it gives an agent
2 rules. About 0 are common, 0 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 45
Direct
docker run --env-file: does not strip inline comments: HONO_RATE_LIMIT=60 # note arrives as "60 # note", coerces to NaN, and … - Very specific: line 94
Start the daemon if needed: open -a Docker, then poll docker info until ready.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Docker Testing
Full stack, the same Dockerfiles prod ships:
docker compose build --no-cache && docker compose upScope to one service while iterating:
docker compose build --no-cache api && docker compose up -d api
curl -sf --retry 30 --retry-delay 1 --retry-connrefused http://localhost:4000/api/health
docker compose logs -f api
docker compose down.env
- Where it comes from. The build reads
.envas a BuildKit secret (compose wiressecrets: dotenvfrom./.env; a plain build passes--secret id=dotenv,src=.env) and validates it in full;uploads it viaenv_file: .env. The secret mounts only during the build RUN and never lands in a layer. A missing.envfails fast: compose reports "secret file not found", docker build "secret not provided"; invalid runtime env crashes the container loudly at boot. Smoke build vs deploy image. A clean checkout has no real
.env, so give a smoke build a dummy from.env.examplewith the required blanks filled:sed -e 's|^BETTER_AUTH_SECRET=$|BETTER_AUTH_SECRET=dummy|' \ -e 's|^GITHUB_CLIENT_ID=$|GITHUB_CLIENT_ID=dummy|' \ -e 's|^GITHUB_CLIENT_SECRET=$|GITHUB_CLIENT_SECRET=dummy|' \ -e 's|^GOOGLE_CLIENT_ID=$|GOOGLE_CLIENT_ID=dummy|' \ -e 's|^GOOGLE_CLIENT_SECRET=$|GOOGLE_CLIENT_SECRET=dummy|' \ -e 's|^POSTGRES_URL=$|POSTGRES_URL=postgres://dummy:dummy@localhost:5432/dummy|' \ -e 's|^AGENT_SIGNIN_ENABLED=$|AGENT_SIGNIN_ENABLED=true|' \ .env.example > .envEmpty optionals (e.g.
NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN=) pass viaemptyStringAsUndefined. A smoke build is disposable: Next inlinesNEXT_PUBLIC_*into the bundle at build, so a dummy-built web image carries dummy URLs forever. Deploy images build with the real.env.--no-cacheafter any.envedit. Secret contents are not part of BuildKit's cache key, so a plain rebuild reuses the cached build RUN and silently ships stale baked values (web'sNEXT_PUBLIC_*).- Skip
SKIP_ENV_VALIDATION. Build and runtime both load a real.env, so both validate real values. The flag no longer bypasses validation anyway: it only substitutes shape-valid dummies for missing required vars while zod defaults and transforms still run (HONO_PORTdefaults to 4000,HONO_TRUSTED_ORIGINSparses to an array). Reserve it for CI, which genuinely lacks a.env. The web deploy uses the narrowerSKIP_ENV_VALIDATION_SERVER, which dummies only server secrets while still validating theNEXT_PUBLIC_*it inlines. NODE_ENVis read at runtime. The API bundle is built withbun build --env disable, so bun does not bakeprocess.env.NODE_ENVfrom the build shell, where.envis never sourced and the value would always be "development". Whatuploads from.envwins:/api/healthreports it asenvironment, andNODE_ENV=localwithAGENT_SIGNIN_ENABLED=truemounts the agent sign-in inside the container.- Database. Without a reachable
POSTGRES_URL, DB-backed routes (e.g./api/v1/user) return 500 while/api/healthstays green. The end-to-end suite below needs one: a disposable container (bunx pglaunch -k), written into.envashost.docker.internal:<port>so the containers reach it, and migrated first withPOSTGRES_URL=<the localhost form> bun run db:migrate. - Direct
docker run --env-filedoes not strip inline comments:HONO_RATE_LIMIT=60 # notearrives as"60 # note", coerces to NaN, and validation rejects it. Compose's parser strips them; fordocker run, sanitize first:sed 's/ #.*//' .env > .env.docker. - Ports
4000and3000collide with a running dev stack; for side-by-side testing bump the compose mappings (e.g.14000:4000) in a scratch checkout.
Self-containment check (catches runtime auto-install)
The api runner ships only bundle/, so the bundle must resolve every import with no node_modules. When one is missing, Bun's runtime auto-install fetches it from npm, so a container that "works" online may be downloading packages at cold start or on a later request. The image runs bun --no-install, which turns that off: a missing import fails at once instead. Two probes prove both halves, offline:
sed 's/ #.*//' .env > .env.docker
docker run -d --name t-offline --network=none --env-file .env.docker <image>
docker exec t-offline sh -c 'for i in $(seq 1 30); do wget -qO- http://localhost:4000/api/health && exit 0; sleep 1; done; exit 1'
docker logs t-offline # on failure: "Cannot find package 'X'" = an import the bundle needs and does not carry
# the first sign-in is where Better Auth reaches for its optional telemetry import; it answers with the database error here (nothing is reachable), and it must answer at once
time docker exec t-offline sh -c 'wget -qO- --post-data=x --header="Origin: http://localhost:3000" http://localhost:4000/api/agents/sign-in-as; echo'
docker diff t-offline | grep .bun/install/cache # must print nothing
docker rm -f t-offlineHealth alone proves nothing about sign-in: the telemetry import fires on the first Better Auth call, not at boot. Before --no-install, this container fetched @opentelemetry/api (some 640 files) on that call whenever it had a network, and stalled on it when it did not. Run the same docker diff on the online container after the golden suite; entries under .bun/install/cache mean a runtime install got past the flag (history: --external hono in the bundle build fetched hono from npm at cold start).
Single-libc check (web image, catches silent re-bloat)
The web build prunes the unused libc stack from standalone (libc is auto-detected at build; an alpine base means musl). Store-layout or dep-rename drift regresses it back into bloat silently, so assert after any web image build:
docker run --rm --entrypoint sh zerostarter-web -c \
'find /app/node_modules \( -name "*linux-*-gnu*" -o -name "*sharp-linux-*" -o -name "*libvips-linux-*" \) ! -type l | grep . && echo "FAIL: glibc stack shipped" && exit 1; echo OK'Expect OK. ! -type l skips dangling glibc-named symlinks (expected leftovers); only real files count. Any hit means the excludes in web/next/next.config.ts stopped matching, so fix the patterns, never delete the assertion.
End-to-end golden suite
With the stack up on a fresh disposable database, run every *.e2e.test.ts under tests/ against it:
E2E_POSTGRES_URL=postgres://postgres:postgres@localhost:<port>/postgres bun run test:e2eE2E_API_URL and E2E_WEB_URL default to the compose ports. The suite signs in as LocalAgent and asserts the stage is local (so .env needs NODE_ENV=local and AGENT_SIGNIN_ENABLED=true, plus both OAuth credential pairs set, the id and the secret of each, which the dummy .env above already does: left blank, the providers endpoint lists only agent and its snapshot fails; it is a suite for a local-stage stack, never a deployed one, and a URL whose host is not local is refused at load), drives the organization plugin, the console routes, the waitlist and the web pages, and snapshots every contract response after normalizing ids, timestamps and the build version. A snapshot mismatch is a contract change: review it, then bun run test:e2e --update-snapshots. The users list assumes LocalAgent is the only account, which is why the database is fresh; E2E_POSTGRES_URL is what lets the suite seed and remove a second account for the role and ban flows, and it refuses any host that is not local and any database holding an account beyond the agent and the seed, so neither the shared database nor a populated local one can be seeded by mistake; the stack's own POSTGRES_URL must be disposable for the same reason, since the suite writes through the API. Done when it prints 0 fail twice in a row: the second run proves the goldens are deterministic and that a run removes what it created (its organization, rules, signups, seeded account and sessions; the audit log keeps its rows by design, and the goldens read only the entries a run adds).
In a browser against the images the Login (agents) button is absent: its guard is Next's build-time NODE_ENV, so a production build compiles it out. Submit the same form it posts from the page's console, and the 302 lands on the dashboard with the session (cookies on localhost do not isolate by port):
document.body.appendChild(Object.assign(document.createElement("form"), { method: "POST", action: "http://localhost:4000/api/agents/sign-in-as" })).submit()Notes
- Start the daemon if needed:
open -a Docker, then polldocker infountil ready. .dockerignoreexcludes real.env*from the build context (only.env.exampleenters), so the context itself carries no secret.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

