Repository navigation
test(user-repository): add failure-handling regression coverage #1027 - #1179
Open
ejiromowarin wants to merge 1 commit into
Open
ejiromowarin wants to merge 1 commit into
ejiromowarin wants to merge 1 commit into
Conversation
ejiromowarin
force-pushed
the
fix/1027-user-failure-handling-regression
branch
2 times, most recently
from
October 15, 2026 05:26
d8f0a46 to
6a2c1b2
Compare
…raOrg#1027) Pin the createUser/updateUser empty-result guards and the no-op update 'User not found' exit with exact error contracts, boundary inputs and security assertions. Test-only; no production behaviour changes. Closes RevoraOrg#1027
ejiromowarin
force-pushed
the
fix/1027-user-failure-handling-regression
branch
from
October 17, 2026 15:48
6a2c1b2 to
4082e66
Compare
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.
Overview
This PR adds a focused, test-only regression suite that pins the three explicit failure / empty-result exits of
UserRepositorynamed in the issue —src/db/repositories/userRepository.ts:129,:182and:201. Production code is untouched, so the existing public contract is preserved exactly and the suite documents current behaviour instead of redefining it.Related Issue
Closes #1027
Changes
🧪 User Repository Failure Handling
src/db/repositories/userRepository.regression.test.ts— 41 focused casesline 129—createUserwith an emptyRETURNINGset: exactError('Failed to create user')class/message (neverUniqueConstraintError), never resolves with a partial or fabricated user, still throws when the driver reportsrowCount: 1for zero rows (the guard is pinned torows.length), rejects on an unusable row (rows: [null]), deterministic across repeated calls, and the message leaks no SQL text, email or password hash.line 182—updateUser({ id })with no updatable field: exactError('User not found'), exactly oneSELECTand never anUPDATE, explicitly-undefinedoptionals count as “not provided”, an empty-stringidis an ordinary lookup miss, deterministic, and never resolves with a user.line 201—updateUserwhoseUPDATE … RETURNING *matched no row: exactError('Failed to update user'), one statement only, keyed onrows.length(a stalerowCountstill throws), never resolves with a partial user,23505staysUniqueConstraintError(field: 'email'), non-23505errors are re-thrown by identity, and nothing sensitive leaks into the message.startup/standarddefaults and unknown stored tier →standard; storedNULLname →undefined;last_oidc_groups: nulltreated as a provided value that clears the column while[]serialises to"[]"; empty-string credentials/emails forwarded; hostile email payloads bound as parameters and never interpolated into SQL; the no-op update read returns the existing user without a write.updateKycRiskTierdelegation: success plus propagation of the exact'Failed to update user'/UniqueConstraintErrorcontracts.📄 Documentation
docs/user-failure-handling-regression.md— pinned contract per line, security assumptions, an abuse/failure-path table, deliberately pinned follow-up items, run instructions, evidence and the CI note below.⚙️ Tooling
package.json— addstest:coverage:user-failure, a focused run (existing contract suite + new regression suite) with a 95% threshold applied tosrc/db/repositories/userRepository.ts.Verification Results
CI note
The upstream
CI Gateworkflow (.github/workflows/ci.yml) targets themainbranch while the repository default branch ismaster, and it runs onlyaudit:ciandvalidate:alert-mappings— it does not execute Jest. The pull-request check that does run (check-postmortem) passes. Adding a Jest job and pointing the workflow at the default branch is a repository-wide change, deliberately left out of this test-only PR; happy to follow up separately if maintainers want it.Security Notes
RETURNINGset — the suite proves the call fails loudly instead of reporting success.emailcontent (including'; DROP TABLE users; --) stays a bound parameter on bothcreateUserandupdateUser; the generated SQL never contains the payload.23505→UniqueConstraintError({ field: 'email' }), empty results → plainError, so a softened guard cannot be mistaken for (or masked by) a conflict.23505driver errors are re-thrown by identity, preserving upstream retry/alerting classification.rows: [null]throws aTypeError, andupdatePasswordHashresolves for an unknown id.Acceptance Criteria Status
userRepository.tsis unchanged, messages/classes pinned as-isrows.lengthvsrowCount, empty-string id/email,NULLname,last_oidc_groups: null, hostile SQL payloadstscat its pre-existing baseline (nothing in this file)docs/user-failure-handling-regression.md