feat(auth): add zxcvbn-based password strength validation across auth flows#204
feat(auth): add zxcvbn-based password strength validation across auth flows#204NAYAMATVISION wants to merge 4 commits into
Conversation
|
Warning Review limit reached
More reviews will be available in 49 minutes and 12 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds zxcvbn-based password strength validation: a shared validator exported from common, Zod schema refinements, a PasswordStrengthMeter React component, and gating of signup, settings, and forgot-password flows plus a register-schema switch in the auth controller. ChangesPassword Strength Validation Feature
🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested labels: Suggested reviewers:
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
apps/web-dashboard/src/components/PasswordStrengthMeter.jsx (1)
4-4: 🏗️ Heavy liftAvoid duplicating password policy thresholds in the UI.
MIN_SCOREis hardcoded locally while backend enforces its own threshold. This is a cross-layer contract and can drift. Please source the minimum score from a shared policy constant/config so client gating always matches server validation.Also applies to: 34-34
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web-dashboard/src/components/PasswordStrengthMeter.jsx` at line 4, The local constant MIN_SCORE in PasswordStrengthMeter.jsx duplicates the backend policy; replace it by importing the shared policy value (e.g., PASSWORD_MIN_SCORE or passwordPolicy.minScore) from the shared config/module used by the backend and use that instead anywhere MIN_SCORE is referenced (including the check in the PasswordStrengthMeter component around line 34); if import may be undefined at runtime, add a small fallback default and a clear TODO to remove it once the shared policy is guaranteed available.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/web-dashboard/src/components/PasswordStrengthMeter.jsx`:
- Around line 45-96: Wrap the visual strength bar and textual status in
accessible semantics: add progress semantics to the inner strength bar div
(role="progressbar", aria-valuemin="0", aria-valuemax="100",
aria-valuenow={Math.round(barWidth)} and aria-valuetext={`${config.label}
(${Math.round(barWidth)}%)`}) and add a polite live region for updates (e.g.,
aria-live="polite" aria-atomic="true") around the score label/feedback block so
changes to config.label, the "Too weak to submit" message (when score <
MIN_SCORE) and feedback.warning/suggestions are announced; ensure unique content
uses existing symbols barWidth, config.label, MIN_SCORE, feedback to populate
ARIA attributes.
In `@apps/web-dashboard/src/pages/ForgotPassword.jsx`:
- Around line 102-105: The submit gating currently reads stale
passwordStrength.isStrongEnough (used in handleResetPassword and the submit
button disabled logic) which is updated asynchronously by PasswordStrengthMeter;
instead derive the strength synchronously from the current formData.newPassword
in the parent: add a local synchronous check (e.g.,
computeIsStrongEnoughFrom(formData.newPassword) using the same validation logic
as PasswordStrengthMeter) and use that boolean for both the early-return in
handleResetPassword and the disabled prop on the submit button so both places
use the up-to-date value from formData.newPassword rather than the
effect-updated passwordStrength.
In `@packages/common/src/utils/input.validation.js`:
- Around line 19-27: The loginSchema currently calls validatePasswordStrength
inside its .superRefine (see loginSchema, superRefine, validatePasswordStrength
and ctx.addIssue with path ["password"]), which rejects older but valid
passwords before authentication; remove the strength check from
loginSchema.superRefine so login only validates presence/format and does not
call validatePasswordStrength, and ensure validatePasswordStrength remains used
only in registration/change-password flows (e.g., signupSchema or changePassword
handlers) instead.
- Line 7: signupSchema and userSignupSchema currently allow weak passwords;
update both schemas to apply the same backend strength enforcement used in
password-change/reset flows by invoking validatePasswordStrength as the password
field's validator (same pattern used for change/reset flows). Locate
signupSchema and userSignupSchema and replace their plain password validation
with the custom validator call to validatePasswordStrength so registrations
enforce the same strength rules as passwordChange/passwordReset.
In `@packages/common/src/utils/passwordStrength.js`:
- Around line 12-23: The server-side validatePasswordStrength function currently
only accepts a single password and therefore cannot penalize passwords that
include user-specific tokens (name/email); update validatePasswordStrength to
accept an optional tokens parameter (e.g., tokens: string[] or null), validate
that tokens is an array of strings (default to [] if absent), and pass those
tokens into zxcvbn (call zxcvbn(password, tokens)) so zxcvbn can penalize
matches against user identifiers; keep the existing return semantics (return {
message: WEAK_PASSWORD_MESSAGE } when typeof password !== "string" ||
password.length === 0 or result.score < MIN_SCORE, otherwise return null).
---
Nitpick comments:
In `@apps/web-dashboard/src/components/PasswordStrengthMeter.jsx`:
- Line 4: The local constant MIN_SCORE in PasswordStrengthMeter.jsx duplicates
the backend policy; replace it by importing the shared policy value (e.g.,
PASSWORD_MIN_SCORE or passwordPolicy.minScore) from the shared config/module
used by the backend and use that instead anywhere MIN_SCORE is referenced
(including the check in the PasswordStrengthMeter component around line 34); if
import may be undefined at runtime, add a small fallback default and a clear
TODO to remove it once the shared policy is guaranteed available.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 68b43af3-d178-455e-89ff-2d1b9e0336b2
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (9)
apps/web-dashboard/package.jsonapps/web-dashboard/src/components/PasswordStrengthMeter.jsxapps/web-dashboard/src/pages/ForgotPassword.jsxapps/web-dashboard/src/pages/Settings.jsxapps/web-dashboard/src/pages/Signup.jsxpackages/common/package.jsonpackages/common/src/index.jspackages/common/src/utils/input.validation.jspackages/common/src/utils/passwordStrength.js
| <div style={{ marginTop: '0.5rem' }}> | ||
| {/* Strength bar */} | ||
| <div style={{ | ||
| height: '4px', | ||
| borderRadius: '2px', | ||
| background: 'var(--color-border)', | ||
| overflow: 'hidden', | ||
| marginBottom: '0.4rem', | ||
| }}> | ||
| <div style={{ | ||
| height: '100%', | ||
| width: `${barWidth}%`, | ||
| background: config.color, | ||
| borderRadius: '2px', | ||
| transition: 'width 0.3s ease, background 0.3s ease', | ||
| }} /> | ||
| </div> | ||
|
|
||
| {/* Score label */} | ||
| <div style={{ | ||
| display: 'flex', | ||
| justifyContent: 'space-between', | ||
| alignItems: 'center', | ||
| marginBottom: feedback.warning || feedback.suggestions?.length ? '0.4rem' : 0, | ||
| }}> | ||
| <span style={{ fontSize: '0.78rem', color: config.color, fontWeight: 600 }}> | ||
| {config.label} | ||
| </span> | ||
| {score < MIN_SCORE && ( | ||
| <span style={{ fontSize: '0.75rem', color: 'var(--color-text-muted)' }}> | ||
| Too weak to submit | ||
| </span> | ||
| )} | ||
| </div> | ||
|
|
||
| {/* Warning */} | ||
| {feedback.warning && ( | ||
| <p style={{ fontSize: '0.78rem', color: 'var(--color-text-muted)', margin: '0 0 0.25rem' }}> | ||
| {feedback.warning} | ||
| </p> | ||
| )} | ||
|
|
||
| {/* Suggestions */} | ||
| {feedback.suggestions?.length > 0 && ( | ||
| <ul style={{ margin: 0, padding: '0 0 0 1rem' }}> | ||
| {feedback.suggestions.map((s) => ( | ||
| <li key={s} style={{ fontSize: '0.78rem', color: 'var(--color-text-muted)', marginBottom: '0.15rem' }}> | ||
| {s} | ||
| </li> | ||
| ))} | ||
| </ul> | ||
| )} |
There was a problem hiding this comment.
Add ARIA semantics for live password-strength feedback.
The meter and “Too weak to submit” feedback are currently visual-only. Add progress semantics and a polite live region so assistive tech announces strength changes.
♿ Suggested patch
- return (
- <div style={{ marginTop: '0.5rem' }}>
+ return (
+ <div style={{ marginTop: '0.5rem' }} aria-live="polite">
{/* Strength bar */}
- <div style={{
+ <div
+ role="progressbar"
+ aria-label="Password strength"
+ aria-valuemin={0}
+ aria-valuemax={4}
+ aria-valuenow={score}
+ aria-valuetext={config.label}
+ style={{
height: '4px',
borderRadius: '2px',
background: 'var(--color-border)',
overflow: 'hidden',
marginBottom: '0.4rem',
- }}>
+ }}>
<div style={{
height: '100%',
width: `${barWidth}%`,
background: config.color,
borderRadius: '2px',
transition: 'width 0.3s ease, background 0.3s ease',
}} />
</div>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/web-dashboard/src/components/PasswordStrengthMeter.jsx` around lines 45
- 96, Wrap the visual strength bar and textual status in accessible semantics:
add progress semantics to the inner strength bar div (role="progressbar",
aria-valuemin="0", aria-valuemax="100", aria-valuenow={Math.round(barWidth)} and
aria-valuetext={`${config.label} (${Math.round(barWidth)}%)`}) and add a polite
live region for updates (e.g., aria-live="polite" aria-atomic="true") around the
score label/feedback block so changes to config.label, the "Too weak to submit"
message (when score < MIN_SCORE) and feedback.warning/suggestions are announced;
ensure unique content uses existing symbols barWidth, config.label, MIN_SCORE,
feedback to populate ARIA attributes.
| if (!passwordStrength.isStrongEnough) { | ||
| toast.error('Please choose a stronger password.'); | ||
| return; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In React 19, does state updated from a child component's useEffect run after render/paint such that parent submit guards can observe the previous value for one render?
💡 Result:
Short answer: No—React doesn’t let a child component’s passive effect (useEffect) “race” with the parent’s render/paint such that a parent event handler (like an onSubmit) observes the previous state for one render. However, state updates scheduled from effects are not guaranteed to be applied before paint in all circumstances, so you also shouldn’t rely on useEffect timing for “next render” ordering unless you structure code around explicit user events or use layout effects when you must block painting. What the React docs guarantee / imply: - useEffect callbacks are deferred relative to the browser paint in the general case, and are run after layout and paint via a deferred event [1]. - React guarantees that even when effects are deferred until after the browser has painted, React will flush a previous render’s effects before starting a new update (so updates from the effect can’t be missed or applied “after” a newer render has begun) [2]. What that means for your scenario (child useEffect updates state used by a parent submit guard): - If the submit guard logic runs in response to a user interaction (e.g., the onSubmit handler), React will process updates such that the “next” UI/event system view isn’t allowed to “skip” the update that was scheduled earlier; useEffect timing is about when the effect runs, not about producing a one-render-old observable state to an unrelated later user event [1][2]. - Also, React’s own docs note that timing can differ for certain cases (e.g., effects caused by discrete user input or flushSync may be processed differently, and it’s also not guaranteed that useEffect always runs after paint) [1][3]. So while you typically won’t see a parent submit guard observe a previous value “for one render” due to passive-effect updates, you should not design the app assuming a strict paint-phase ordering across all scheduling situations. If you need the parent guard to observe the child-driven state change immediately before a user event: - Don’t depend on child useEffect for that; instead, update the parent state in the same interaction path (e.g., lift state up and call the parent’s state update directly, or call setState in an event handler). This avoids the asynchronous/deferred nature of passive effects [1][2]. - If you truly must block paint and ensure ordering with layout, useLayoutEffect is the correct tool (but note it has different performance/ordering semantics and can effectively make passive effects flush earlier) [4][2][5]. Conclusion: - In React 19, a passive child useEffect-driven state update is not expected to be applied “after render/paint” in a way that causes the parent’s next submit guard to see the previous value for exactly one render. React flushes previous effects before starting a new update [2]. - But you should avoid assuming a rigid “after paint” timing relationship for correctness, because React documentation and discussions note that effect timing can vary in special cases [1][3].
Citations:
- 1: https://react.dev/reference/react/useEffect
- 2: https://legacy.reactjs.org/docs/hooks-reference.html
- 3: Add a note that useEffect is not guaranteed to run after paint reactjs/react.dev#4107
- 4: why setState in useLayoutEffect forces useEffects to run before paint? facebook/react#17334
- 5: https://thoughtspile.github.io/2021/11/15/unintentional-layout-effect/
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="apps/web-dashboard/src/pages/ForgotPassword.jsx"
# Show the relevant sections around the mentioned line ranges
nl -ba "$FILE" | sed -n '70,140p'
nl -ba "$FILE" | sed -n '190,260p'Repository: geturbackend/urBackend
Length of output: 109
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="apps/web-dashboard/src/pages/ForgotPassword.jsx"
# Print with line numbers (avoid nl since it's missing)
echo "== $FILE : lines ~70-140 =="
cat -n "$FILE" | sed -n '70,140p'
echo
echo "== $FILE : lines ~190-260 =="
cat -n "$FILE" | sed -n '190,260p'Repository: geturbackend/urBackend
Length of output: 5865
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Find where PasswordStrengthMeter is defined/implemented
rg -n "function PasswordStrengthMeter|const PasswordStrengthMeter|PasswordStrengthMeter" apps/web-dashboard/src -S
# 2) Find the prop name `onStrengthChange` usage
rg -n "onStrengthChange" apps/web-dashboard/src -S
# 3) Inspect how `handleResetPassword` is connected (form onSubmit / button type submit)
rg -n "handleResetPassword|onSubmit=\{handleResetPassword\}|type=\"submit\"" apps/web-dashboard/src/pages/ForgotPassword.jsx -nRepository: geturbackend/urBackend
Length of output: 2041
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE1="apps/web-dashboard/src/components/PasswordStrengthMeter.jsx"
FILE2="apps/web-dashboard/src/pages/ForgotPassword.jsx"
echo "== $FILE1 : lines 1-140 =="
cat -n "$FILE1" | sed -n '1,160p'
echo
echo "== $FILE2 : lines 1-120 =="
cat -n "$FILE2" | sed -n '1,140p'
echo
echo "== $FILE2 : around form onSubmit + submit button area =="
cat -n "$FILE2" | sed -n '140,320p'Repository: geturbackend/urBackend
Length of output: 15117
Avoid effect-lagged password strength in reset submit gating
handleResetPassword (102-105) and the reset submit button disabled logic (252-256) depend on passwordStrength.isStrongEnough, but passwordStrength is updated via PasswordStrengthMeter using a useEffect (wiring at 218-222). If the user submits right after changing the password, this state can be temporarily out of date. Derive isStrongEnough directly from the current formData.newPassword in the parent (or otherwise ensure synchronous/ordered gating) for both the submit guard and button disabled state.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/web-dashboard/src/pages/ForgotPassword.jsx` around lines 102 - 105, The
submit gating currently reads stale passwordStrength.isStrongEnough (used in
handleResetPassword and the submit button disabled logic) which is updated
asynchronously by PasswordStrengthMeter; instead derive the strength
synchronously from the current formData.newPassword in the parent: add a local
synchronous check (e.g., computeIsStrongEnoughFrom(formData.newPassword) using
the same validation logic as PasswordStrengthMeter) and use that boolean for
both the early-return in handleResetPassword and the disabled prop on the submit
button so both places use the up-to-date value from formData.newPassword rather
than the effect-updated passwordStrength.
| function validatePasswordStrength(password) { | ||
| if (typeof password !== "string" || password.length === 0) { | ||
| return { message: WEAK_PASSWORD_MESSAGE }; | ||
| } | ||
|
|
||
| const result = zxcvbn(password); | ||
|
|
||
| if (result.score < MIN_SCORE) { | ||
| return { message: WEAK_PASSWORD_MESSAGE }; | ||
| } | ||
|
|
||
| return null; |
There was a problem hiding this comment.
Add contextual token support to backend strength validation.
Line 12 currently accepts only password, so server-side validation cannot penalize passwords derived from user identifiers (e.g., name/email tokens). That leaves a bypass gap if client checks are skipped.
🔧 Proposed change
-function validatePasswordStrength(password) {
+function validatePasswordStrength(password, userInputs = []) {
if (typeof password !== "string" || password.length === 0) {
return { message: WEAK_PASSWORD_MESSAGE };
}
- const result = zxcvbn(password);
+ const result = zxcvbn(password, Array.isArray(userInputs) ? userInputs : []);
if (result.score < MIN_SCORE) {
return { message: WEAK_PASSWORD_MESSAGE };
}
return null;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function validatePasswordStrength(password) { | |
| if (typeof password !== "string" || password.length === 0) { | |
| return { message: WEAK_PASSWORD_MESSAGE }; | |
| } | |
| const result = zxcvbn(password); | |
| if (result.score < MIN_SCORE) { | |
| return { message: WEAK_PASSWORD_MESSAGE }; | |
| } | |
| return null; | |
| function validatePasswordStrength(password, userInputs = []) { | |
| if (typeof password !== "string" || password.length === 0) { | |
| return { message: WEAK_PASSWORD_MESSAGE }; | |
| } | |
| const result = zxcvbn(password, Array.isArray(userInputs) ? userInputs : []); | |
| if (result.score < MIN_SCORE) { | |
| return { message: WEAK_PASSWORD_MESSAGE }; | |
| } | |
| return null; | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/common/src/utils/passwordStrength.js` around lines 12 - 23, The
server-side validatePasswordStrength function currently only accepts a single
password and therefore cannot penalize passwords that include user-specific
tokens (name/email); update validatePasswordStrength to accept an optional
tokens parameter (e.g., tokens: string[] or null), validate that tokens is an
array of strings (default to [] if absent), and pass those tokens into zxcvbn
(call zxcvbn(password, tokens)) so zxcvbn can penalize matches against user
identifiers; keep the existing return semantics (return { message:
WEAK_PASSWORD_MESSAGE } when typeof password !== "string" || password.length ===
0 or result.score < MIN_SCORE, otherwise return null).
|
@NAYAMATVISION |
|
Thanks for pointing this out. The login/signup schema issue has been addressed in commit I'm reviewing the remaining comments:
I'll either address them or provide justification before marking the review thread resolved. |
|
Thanks for pointing that out. While reviewing the remaining comments, I found an additional backend enforcement gap: the dashboard registration endpoint was still validating with I've addressed this by introducing a dedicated The remaining review comments have been reviewed, and the backend enforcement is now applied consistently across registration, password reset, and password change flows. |
|
The failing dashboard-api test was caused by the Jest mock for Production exports were correct; the mock returned I've updated the mock and verified the auth controller test suite passes locally again. |
1 similar comment
|
The failing dashboard-api test was caused by the Jest mock for Production exports were correct; the mock returned I've updated the mock and verified the auth controller test suite passes locally again. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/dashboard-api/src/controllers/auth.controller.js`:
- Line 11: The runtime error means registerSchema is not actually exported from
the common package; inspect packages/common/src/utils/input.validation.js to
ensure registerSchema is defined, confirm packages/common/src/index.js
re-exports registerSchema (search for "registerSchema" in that index), and if
missing add the explicit export so module.exports.registerSchema (or export {
registerSchema }) is present; after fixing exports, rebuild the common package
and reinstall/rebuild apps/dashboard-api so it picks up the updated bundle
(ensure the controller import in auth.controller.js still points to the correct
package entry that now exports registerSchema).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 585fbe5e-ef5f-4819-b6ad-bcee7990c6dc
📒 Files selected for processing (3)
apps/dashboard-api/src/controllers/auth.controller.jspackages/common/src/index.jspackages/common/src/utils/input.validation.js
| const crypto = require("crypto"); | ||
| const { | ||
| loginSchema, | ||
| registerSchema, |
There was a problem hiding this comment.
CRITICAL: registerSchema is undefined at runtime.
The pipeline failure indicates that registerSchema.parse throws "Cannot read properties of undefined (reading 'parse')", meaning registerSchema itself is undefined when this code executes. While the import statement on line 11 looks syntactically correct, the export chain from @urbackend/common appears broken at runtime.
Run the following script to verify the export chain:
#!/bin/bash
# Verify registerSchema is properly exported from `@urbackend/common`
echo "=== Checking input.validation.js export ==="
rg -n "module\.exports\.registerSchema" packages/common/src/utils/input.validation.js
echo -e "\n=== Checking index.js import from input.validation ==="
rg -n "registerSchema" packages/common/src/index.js
echo -e "\n=== Checking if common package needs rebuild ==="
# Check if there's a build script
cat packages/common/package.json | jq -r '.scripts.build // "No build script found"'
echo -e "\n=== Verifying the export is reachable ==="
# Try to require and inspect the export in a Node context
node -e "
try {
const common = require('./packages/common/src/index.js');
if (common.registerSchema === undefined) {
console.error('ERROR: registerSchema is undefined in common exports');
process.exit(1);
}
console.log('✓ registerSchema is exported and defined');
console.log('✓ Type:', typeof common.registerSchema);
} catch (err) {
console.error('ERROR loading common:', err.message);
process.exit(1);
}
"If the script confirms the export exists, the dashboard-api package may need to reinstall dependencies or rebuild to pick up the changes:
#!/bin/bash
cd apps/dashboard-api
npm install
# or if using a monorepo tool:
# npm run build --workspace=`@urbackend/common`Also applies to: 278-278
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/dashboard-api/src/controllers/auth.controller.js` at line 11, The
runtime error means registerSchema is not actually exported from the common
package; inspect packages/common/src/utils/input.validation.js to ensure
registerSchema is defined, confirm packages/common/src/index.js re-exports
registerSchema (search for "registerSchema" in that index), and if missing add
the explicit export so module.exports.registerSchema (or export { registerSchema
}) is present; after fixing exports, rebuild the common package and
reinstall/rebuild apps/dashboard-api so it picks up the updated bundle (ensure
the controller import in auth.controller.js still points to the correct package
entry that now exports registerSchema).
|
Verified this issue.
registerSchema is defined in input.validation.js and re-exported from
packages/common/src/index.js. The runtime failure was caused by the Jest
mock in auth.controller.test.js not including the newly added registerSchema,
which resulted in undefined.parse(...) during tests.
The mock has been updated, the auth controller test suite passes locally,
and all CI checks are now green. No production export changes were required.
…On Tue, May 26, 2026 at 12:48 PM coderabbitai[bot] ***@***.***> wrote:
***@***.***[bot]* commented on this pull request.
*Actionable comments posted: 1*
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In ***@***.***/dashboard-api/src/controllers/auth.controller.js`:
- Line 11: The runtime error means registerSchema is not actually exported from
the common package; inspect packages/common/src/utils/input.validation.js to
ensure registerSchema is defined, confirm packages/common/src/index.js
re-exports registerSchema (search for "registerSchema" in that index), and if
missing add the explicit export so module.exports.registerSchema (or export {
registerSchema }) is present; after fixing exports, rebuild the common package
and reinstall/rebuild apps/dashboard-api so it picks up the updated bundle
(ensure the controller import in auth.controller.js still points to the correct
package entry that now exports registerSchema).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
------------------------------
ℹ️ Review info ⚙️ Run configuration
*Configuration used*: defaults
*Review profile*: CHILL
*Plan*: Pro
*Run ID*: 585fbe5e-ef5f-4819-b6ad-bcee7990c6dc
📥 Commits
Reviewing files that changed from the base of the PR and between 3542751
<3542751>
and 94973ff
<94973ff>
.
📒 Files selected for processing (3)
- apps/dashboard-api/src/controllers/auth.controller.js
- packages/common/src/index.js
- packages/common/src/utils/input.validation.js
------------------------------
In apps/dashboard-api/src/controllers/auth.controller.js
<#204 (comment)>
:
> @@ -8,6 +8,7 @@ const { sendOtp } = ***@***.***/common");
const crypto = require("crypto");
const {
loginSchema,
+ registerSchema,
*
|
Summary
This PR introduces password strength validation using zxcvbn across authentication flows.
Backend
Added reusable password strength validation utility
Enforced minimum password strength in:
Preserved existing validation and error handling patterns
Frontend
PasswordStrengthMetercomponentSecurity Improvements
Penalizes passwords derived from:
Prevents common personal-information-based passwords from being accepted
Testing
Verified:
Summary by CodeRabbit
New Features
Bug Fixes