fix: handle empty EMAIL_PORT in test-email endpoint (HTTP 500 β 400) - #9491
fix: handle empty EMAIL_PORT in test-email endpoint (HTTP 500 β 400)#9491eltypical wants to merge 1 commit into
Conversation
When SMTP settings have never been saved (fresh Plane install with SKIP_ENV_VAR=True), the EMAIL_PORT row exists in InstanceConfiguration with value "" (empty string). The call to int(EMAIL_PORT) raised an unhandled ValueError, surfacing as an opaque HTTP 500 to the user. Fix: wrap int(EMAIL_PORT) in a try/except (ValueError, TypeError) that returns HTTP 400 with a descriptive error message, consistent with all other error branches in this endpoint. Regression tests added in tests/test_email_credential_check.py covering empty string, None, and non-numeric port values. Fixes makeplane#9472 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
|
π WalkthroughWalkthroughThe email credential check endpoint now validates ChangesSMTP port validation
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested reviewers: π₯ Pre-merge checks | β 5β Passed checks (5 passed)
β¨ 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: 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/api/tests/test_email_credential_check.py`:
- Around line 49-71: Update all three invalid EMAIL_PORT tests in
test_returns_400_for_empty_email_port, test_returns_400_for_none_email_port, and
test_returns_400_for_non_numeric_email_port to assert that
response.data["error"] contains the configuration-specific message instructing
users to save their email settings, rather than only checking that the error key
exists.
πͺ 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 Plus
Run ID: ec8efff6-e17a-421e-a904-1829add638e3
π Files selected for processing (2)
apps/api/plane/license/api/views/configuration.pyapps/api/tests/test_email_credential_check.py
| @patch("plane.license.api.views.configuration.get_email_configuration") | ||
| def test_returns_400_for_empty_email_port(self, mock_config): | ||
| """Regression for #9472: int('') must not propagate as HTTP 500.""" | ||
| mock_config.return_value = self._make_config("") | ||
| response = self._post({"receiver_email": "test@example.com"}) | ||
| assert response.status_code == status.HTTP_400_BAD_REQUEST | ||
| assert "error" in response.data | ||
|
|
||
| @patch("plane.license.api.views.configuration.get_email_configuration") | ||
| def test_returns_400_for_none_email_port(self, mock_config): | ||
| """EMAIL_PORT of None (missing DB row) must not raise TypeError β HTTP 500.""" | ||
| mock_config.return_value = self._make_config(None) | ||
| response = self._post({"receiver_email": "test@example.com"}) | ||
| assert response.status_code == status.HTTP_400_BAD_REQUEST | ||
| assert "error" in response.data | ||
|
|
||
| @patch("plane.license.api.views.configuration.get_email_configuration") | ||
| def test_returns_400_for_non_numeric_email_port(self, mock_config): | ||
| """Non-numeric EMAIL_PORT (corrupt config row) must not cause HTTP 500.""" | ||
| mock_config.return_value = self._make_config("not-a-port") | ||
| response = self._post({"receiver_email": "test@example.com"}) | ||
| assert response.status_code == status.HTTP_400_BAD_REQUEST | ||
| assert "error" in response.data |
There was a problem hiding this comment.
π― Functional Correctness | π‘ Minor | β‘ Quick win
Assert the configuration-specific error message.
These tests only verify that an "error" key exists, so they would pass if the required instruction to save email settings were replaced with a generic message.
Suggested assertion
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert "error" in response.data
+ assert "save your email settings before sending a test email" in response.data["error"]Apply this assertion to all three invalid-port cases.
Based on the PR objective, the endpoint must return a descriptive message instructing users to save their email settings.
π€ 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/api/tests/test_email_credential_check.py` around lines 49 - 71, Update
all three invalid EMAIL_PORT tests in test_returns_400_for_empty_email_port,
test_returns_400_for_none_email_port, and
test_returns_400_for_non_numeric_email_port to assert that
response.data["error"] contains the configuration-specific message instructing
users to save their email settings, rather than only checking that the error key
exists.
Summary
Fixes #9472
Bug
On a fresh Plane installation with
SKIP_ENV_VAR=True, theEMAIL_PORTrow exists inInstanceConfigurationwith value""(empty string) because no SMTP settings have been saved yet.Clicking Send Test Email before saving the form calls
EmailCredentialCheckEndpoint.post(), which reaches:The unhandled
ValueErrorpropagates as an opaque HTTP 500, giving the user no indication of what went wrong.Root Cause
get_email_configuration()readsEMAIL_PORTfrom the DB viaget_configuration_value(). WhenSKIP_ENV_VAR=Trueand the row exists with"", the function returns""instead of falling back to the env-var default (587). The call site did not guard against this before attemptingint().Fix
Wrap the
int(EMAIL_PORT)conversion in atry/except (ValueError, TypeError)block that returns HTTP 400 with a descriptive message, consistent with every other error branch in this endpoint:Tests
Four pytest unit tests added in
apps/api/tests/test_email_credential_check.py:test_returns_400_for_empty_email_portEMAIL_PORT = ""β the exact regression casetest_returns_400_for_none_email_portEMAIL_PORT = Noneβ missing DB rowtest_returns_400_for_non_numeric_email_portEMAIL_PORT = "not-a-port"β corrupt valuetest_returns_400_when_receiver_email_is_missingAll tests mock
get_email_configurationat the call site and assertHTTP 400+"error"key in the response β no network or DB required.Change surface
apps/api/plane/license/api/views/configuration.pyβ 8-line guard added beforeget_connection();port=smtp_portreplaces inlineint()callapps/api/tests/test_email_credential_check.pyβ new regression test fileSummary by CodeRabbit
Bug Fixes
Tests