refactor(auth/mfa): use sentinel errors in mapMFAServiceError#883
refactor(auth/mfa): use sentinel errors in mapMFAServiceError#883cristim wants to merge 3 commits into
Conversation
…512) Replace substring matching in mapMFAServiceError with typed sentinel errors checked via errors.Is. Define 8 new exported sentinels in internal/auth/errors.go (ErrMFAInvalidPassword, ErrMFAInvalidCode, ErrMFACodeRequired, ErrMFANoEnrollmentInProgress, ErrMFAEnrollmentExpired, ErrMFANotEnabled, ErrMFANotConfigured, ErrMFAAuthFailed). Each service method in service_mfa.go and the one site in service.go now wraps the appropriate sentinel via fmt.Errorf("%w", ...) so renaming an error string in the service can never silently drift the HTTP status code. Add 18 new tests: 9 sentinel-identity tests in service_mfa_test.go (assert errors.Is on real service calls) and 9 handler-mapping tests in handler_auth_test.go (assert each sentinel routes to the expected HTTP status via mapMFAServiceError). Message strings are preserved unchanged so existing substring-based tests continue to pass.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughThis PR refactors MFA error handling from brittle substring matching to robust sentinel-based error detection. Eight new exported error sentinels are defined in the auth package, service methods now wrap and return these sentinels, and the API handler detects them via ChangesMFA Sentinel Error Refactoring
Sequence Diagram(s)No sequence diagrams generated. The primary flow (service returns sentinel → handler detects sentinel → HTTP code returned) is straightforward and better represented by the review stack flowchart. Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes The changes span six files with mixed complexity: low-complexity sentinel definitions and test assertions, medium-complexity handler and service refactoring with logic density around error classification. Sentinel wrapping and detection patterns are consistent across methods, reducing heterogeneous reasoning required per file. Possibly related PRs
Poem
🚥 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 docstrings
🧪 Generate unit tests (beta)
Comment |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
… test - Add mockStore.AssertExpectations(t) to 8 sentinel-identity tests in service_mfa_test.go that called On() without asserting all expectations were met (violates feedback_mock_assert_expectations pattern). - Add mockAuth.AssertExpectations(t) to 8 new handler MFA tests in handler_auth_test.go for the same reason. - Add TestMapMFAServiceError_AuthFailed_Is401 to cover the ErrMFAAuthFailed -> 401 branch in mapMFAServiceError, which had no corresponding test case.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
TestLogin_WithMFA_NoSecret was using assert.Contains on err.Error() (substring matching) for the ErrMFANotConfigured case. Since service.go now wraps the sentinel via %w, update the assertion to assert.ErrorIs so renaming the message string would be caught at compile/test time, consistent with the sentinel-identity pattern from issue #512.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
Summary
mapMFAServiceErrorwith typed sentinel errors checked viaerrors.Is, so renaming an error message string in the service can never silently drift the HTTP status codeinternal/auth/errors.gocovering all MFA lifecycle error conditions, each wrapping the original message string so existing substring-based tests continue to passerrors.Ison real service returns) + 9 handler-mapping tests (assert each sentinel routes to the expected HTTP status code viamapMFAServiceError)Closes #512
Test plan
go test ./internal/auth/ -count=1passes (506 tests, +9 new sentinel-identity tests)go test ./internal/api/ -count=1passes (1364 tests, +9 new handler-mapping tests)go vet ./internal/auth/... ./internal/api/...cleanstrings.Contains(err.Error(), ...)remains inmapMFAServiceError;isResetPasswordClientError(out of scope per issue) is unchangedSummary by CodeRabbit
Bug Fixes
Tests