…ix search escaping (#2194)
Three defects from the bullmq/jwks-rsa/escape-string-regexp majors (#2188).
None reached production: only the frontend redeployed on that commit.
bullmq 6 moved ioredis from a direct dependency to an OPTIONAL peer, and
pnpm's auto-install-peers does not install optional peers, so the driver
dropped out of the lockfile entirely. bull.config.ts passes a plain options
object as `connection`, so bullmq has to require('ioredis') itself and threw
"BullMQ could not load the optional 'ioredis' package". initQueues is awaited
before app.listen inside a catch that exits, so this was a whole-backend
outage on next deploy. ioredis is now a direct dependency, pinned to the
5.11.1 line main already ran.
The scheduler ids carried across the migration unchanged, but that was the
wrong thing to check: bullmq 5 never keyed a repeatable by jobId, it keyed by
the md5 of name:jobId:endDate:tz:every. upsertJobScheduler keys by the plain
id, so the upsert added a second entry beside the old one in the same repeat
zset, and bullmq 6 still schedules from the legacy shape. Every recurring job
would have fired twice, indefinitely: duplicate no-show marking, duplicate
task reminders to users, doubled lab polling. initQueues now prunes the md5
entries before upserting.
The escape helper was replaced by a LIKE escape. Both call sites feed the
value into Prisma `contains`, which is an ILIKE pattern and not a regular
expression, so regex escaping was always wrong. It only looked correct
because a backslash before an ordinary character is a no-op in LIKE. Emitting
\x2d for a hyphen broke that: "Jean-Luc" searched for "Jeanx2dLuc" and matched
nothing. Escaping backslash, percent and underscore instead makes the search
mean exactly what was typed, and stops user input acting as a wildcard.
The scheduler suites mock every queue module, so no real Queue is ever built
and they could not have caught the first two. redis-driver.test.ts checks the
dependency graph itself instead.
Co-authored-by: Ankit Upadhyay <ankit@dunexploration.com>
PR Checklist
On the middle box: this is a branch promotion rather than a change of its own. The single commit below arrived through its own reviewed PR.
What is the current behavior?
maincurrently cannot boot the backend.The promotion in #2193 carried #2188, which took bullmq 5 to 6. bullmq 6 moved
ioredisfrom a direct dependency to an optional peer, and pnpm'sauto-install-peersdoes not install optional peers, so the Redis driver dropped out of the lockfile entirely.git show origin/main:pnpm-lock.yaml | grep '^ /ioredis@'returns nothing.apps/backend/src/queues/bull.config.tspasses a plain options object asconnectionrather than a client instance, so bullmq has to load a driver itself and throws:initQueues()is awaited inmain.tsbeforeapp.listen, inside acatchthat callsprocess.exit(1), so the HTTP server never binds.This has not reached production. Only
CD Frontendhas run onmainsince #2193; the production backend is still serving (api.yosemitecrew.com/healthreturns 200) because it has not been redeployed onto this code. The next backend deploy frommainwould fail.mainalso carries two further defects from the same commit, described below.What is the new behavior?
mainmatchesdev. One commit, 13 files, all inapps/backendplus one dependabot config entry.The three defects this clears
1. The backend can boot again.
ioredisis now a direct dependency ofapps/backend, pinned to^5.11.1- the same versionmainran before #2188, so nothing changes except the driver being present.2. Recurring jobs will not double-fire. bullmq 5 never keyed a repeatable by
jobId; it keyed by the md5 ofname:jobId:endDate:tz:every.upsertJobSchedulerkeys by the plain id, so carrying the ids across the migration added a second entry beside each old one in the samerepeatsorted set, and bullmq 6 still schedules from the legacy shape. Without this, a deploy would have produced duplicate no-show marking, duplicate task reminders to users, duplicate recurring-task generation, and doubled polling against the external lab APIs.initQueues()now prunes the legacy entries before upserting.3. Hyphenated searches work again. Both search call sites feed their value into Prisma
contains, which is anILIKEpattern rather than a regular expression. The regex escape introduced in #2188 emitted\x2dfor a hyphen, whichILIKEreads as the literal textx2d, soJean-Lucsearched forJeanx2dLucand matched nothing, silently. It is replaced by a proper LIKE escape, which also closes a pre-existing issue where%and_in user input acted as wildcards.Validation
#2194 merged with the full pipeline green: 58 checks, zero failures, zero unresolved review comments, and the SonarCloud gate OK on all of Frontend, Backend and Desktop.
Locally on that branch:
pnpm run type-check17/17,pnpm run lint10/10, and the backend suite at 257 suites / 4866 tests. Both new files (legacy-repeatables.ts,escape-like.ts) are at 100 percent statements, branches, functions and lines.Each fix was mutation tested by restoring the exact defect that shipped and confirming the suite went red, then restoring it and confirming green. Defect 1 was additionally verified end to end by constructing a real
Queueand observing the driver error before the fix and an ordinary connection attempt after it.The promotion itself is content-clean in both directions:
git diff --name-only origin/main...origin/devgives 13 files, the changes being promotedgit diff --name-only origin/dev...origin/mainis empty, somainholds no content this would dropRelated Issue(s)
Promotes #2194. Repairs the defects introduced by #2188 and promoted by #2193.