Files
top-tickets/Dockerfile
T
ogrechkoandClaude Sonnet 5 93e17c37c7 Fix LDAP directory import: paginate past server size limits, stop leaking bind password into error messages
The "import accounts" browse was shelling out a single unbounded
ldapsearch call, which failed outright with "Size limit exceeded (4)"
once the directory grew past whatever sizeLimit the LDAP server enforces
for this bind account. Added RFC 2696 paged results (-E pr=500/noprompt)
so ldapsearch transparently walks the whole base DN in pages instead of
one request that trips the limit.

Separately: execFile's rejection .message is "Command failed: <full
argv>\n<stderr>", and the full argv includes the bind password passed via
-w — that was reaching the admin UI verbatim in the error banner shown
after a failed search. Only stderr (ldapsearch's own diagnostic text,
which never echoes its invocation) is now surfaced.

Also fixes an unrelated image-build flake: drizzle-kit's migrate step
leaves db.sqlite in SQLite's default (non-WAL) journal mode, and next
build's parallel page-data-collection workers then race to perform the
first-ever journal_mode=WAL switch — a mode change that, unlike ordinary
statements, doesn't reliably honor busy_timeout, so one worker's pragma
call throws SQLITE_BUSY regardless of the configured timeout. Switching
to WAL once, single-process, right after migration avoids the race
entirely.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gh2UXUQUVBWroWEnn1FLFG
2026-10-07 07:14:07 +00:00

43 lines
2.1 KiB
Docker

FROM node:20-bookworm-slim
# python3/make/g++ let npm fall back to compiling better-sqlite3/argon2 from
# source if no prebuilt binary matches this platform. ldap-utils provides
# the `ldapsearch` binary used for the LDAP directory browse — ldapjs's own
# BER decoder proved unreliable against real AD responses for that query.
RUN apt-get update && apt-get install -y --no-install-recommends \
python3 make g++ ca-certificates ldap-utils \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
# `next build`'s page-data collection spins up several parallel workers that
# each import the db client at module-eval time. If data/db.sqlite doesn't
# exist yet, every worker races to create it from scratch — that race is at
# the file-creation level, before our code ever gets to run a busy_timeout
# pragma, so it can throw SQLITE_BUSY (or worse) independent of pragma order.
# Migrating first — as its own isolated, single-process step — means the
# workers only ever see an already-existing, already-stable file.
RUN mkdir -p data && npm run db:migrate
# A second, separate race: drizzle-kit's migrate command opens its own
# connection and leaves the file in SQLite's default (non-WAL) journal
# mode. The *first* pragma("journal_mode = WAL") call on a file is a real
# mode switch requiring a brief exclusive lock — and unlike ordinary
# statements, that specific switch doesn't reliably honor busy_timeout, so
# when all of next build's workers race to be the one performing it, one
# loses and throws SQLITE_BUSY regardless of the 30s timeout configured in
# lib/db/client.ts. Switching to WAL here, once, single-process, means
# every worker's own pragma call below is just a no-op mode check.
RUN node -e "require('better-sqlite3')('data/db.sqlite').pragma('journal_mode = WAL')"
RUN npm run build
ENV NODE_ENV=production
EXPOSE 8081
# Migrate the (volume-mounted) SQLite DB and bootstrap the admin account on
# every start — both are no-ops once already applied.
CMD ["sh", "-c", "npm run db:migrate && npm run bootstrap-admin && npm start"]