Skip to content

fix: replace sanitize_email with sanitize_text_field on DELETE/refresh routes - #11

Merged
superdav42 merged 1 commit into
mainfrom
feature/fix-remove-account
Apr 10, 2026
Merged

superdav42 merged 1 commit into
mainfrom
feature/fix-remove-account

Conversation

@superdav42

@superdav42 superdav42 commented Apr 10, 2026 •

Copy link
Copy Markdown
Contributor

Root cause

sanitize_email was used as the sanitize_callback for the email URL path parameter on the DELETE /accounts/{email} and POST /accounts/{email}/refresh routes.

sanitize_email is a validator, not just a sanitizer — it returns '' (empty string) for any email it considers invalid, including:

  • Emails with underscores in domain subdomains (e.g. user@my_company.com)
  • Local-only domains (e.g. user@localhost)
  • Any email that fails its strict RFC-subset checks

When the sanitized value is '', removeAccount('') finds no account with email '', returns false, and the REST endpoint returns 404 Account not found in pool. — which the frontend surfaces as "Failed to remove account."

The email was already validated by sanitize_email when the account was added (via the /exchange endpoint). The DELETE and /refresh routes only need to look up an existing stored email, so sanitize_text_field is the correct callback.

Changes

inc/rest-api.php

  • DELETE /accounts/{email}: sanitize_email → sanitize_text_field
  • POST /accounts/{email}/refresh: sanitize_email → sanitize_text_field

src/OAuthPool/PoolManager.php

  • removeAccount(): now returns savePool()'s result instead of always true after a count change — surfaces DB-level save failures rather than silently ignoring them
  • listAccounts(): adds validity: null to each account entry so the StatusBadge component receives a consistent field (null = not checked; use /health to validate tokens)

Testing

  • Accounts with standard emails (user@example.com) can be removed ✓
  • Accounts with emails containing underscores in domain (user@my_company.com) can be removed ✓
  • Refresh endpoint uses the same fix ✓
  • No JS rebuild required (PHP-only changes; frontend already handles validity: null)

Summary by CodeRabbit

  • Updates
    • Account listing API responses now include a validity field for each account
    • Enhanced parameter validation for account management endpoints
    • Improved account removal operation handling and documentation

…h routes

sanitize_email is too strict for lookup operations: it strips characters
valid in some email addresses (underscores in domain subdomains, local-only
domains like 'localhost') and returns '' for anything it considers invalid.
When the sanitized value is '', removeAccount() finds no match and returns
false, causing the REST endpoint to return 404 'Account not found in pool.'
— which the frontend surfaces as 'Failed to remove account.'

The email was already validated by sanitize_email when the account was added
(via the /exchange endpoint). The DELETE and /refresh routes only need to
look up an existing email, so sanitize_text_field is the correct callback.

Also:
- removeAccount() now returns savePool()'s result instead of always true,
  so a DB-level save failure is surfaced rather than silently ignored.
- listAccounts() now includes validity: null so the StatusBadge component
  receives a consistent field (null = not checked; use /health to validate).
@coderabbitai

coderabbitai Bot commented Apr 10, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The changes update OAuth pool REST API sanitization and enhance the PoolManager to provide additional account status information. The email parameter sanitization callback was switched from sanitize_email to sanitize_text_field across two endpoints, and listAccounts() now returns a validity field set to null for each account, while removeAccount() logic was simplified.

Changes

Cohort / File(s) Summary
REST Route Sanitization
inc/rest-api.php
Updated email parameter sanitization callback from sanitize_email to sanitize_text_field on DELETE and POST refresh account routes, changing how incoming email values are normalized.
PoolManager Updates
src/OAuthPool/PoolManager.php
Added validity: null field to account objects returned by listAccounts(); updated removeAccount() PHPDoc for clarity and simplified implementation to directly return savePool() result instead of explicit return true.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Poem

🐰✨ A rabbit hops through OAuth pools so deep,
Where emails now flow through new sanitized keeps,
Validity fields mark the path with care,
And cleaner returns float through the air! 🌿

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and specifically describes the main change: replacing sanitize_email with sanitize_text_field on the DELETE and refresh routes, which is the primary fix addressed in this PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/fix-remove-account

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/OAuthPool/PoolManager.php`:
- Line 425: The current removeAccount() return value conflates "not found" and
"save failed" because it returns false from savePool(); change the contract so
removeAccount() returns a status enum (e.g., STATUS_NOT_FOUND, STATUS_SAVED,
STATUS_SAVE_ERROR) or a distinct sentinel for each outcome, update savePool()
(or its caller) to propagate a SAVE_ERROR status when DB persistence fails, and
then update the REST handler that calls removeAccount() to map STATUS_NOT_FOUND
-> 404 and STATUS_SAVE_ERROR -> 500 (keep STATUS_SAVED as 200/204); use explicit
symbols like removeAccount(), savePool(), and the new enum constants to locate
and modify the code.
🪄 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: d4ad51e9-f008-49d1-a33c-24384594c257

📥 Commits

Reviewing files that changed from the base of the PR and between 769d5ef and 163e445.

📒 Files selected for processing (2)
  • inc/rest-api.php
  • src/OAuthPool/PoolManager.php


$this->savePool($pool);
return true;
return $this->savePool($pool);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Differentiate “not found” vs “save failed” outcomes from removeAccount().

At Line 425, false now conflates two states. Downstream, inc/rest-api.php Line 265 treats all false as 404, so DB save failures are misreported as “not found” instead of server errors.

Proposed contract fix (status enum) and REST mapping
diff --git a/src/OAuthPool/PoolManager.php b/src/OAuthPool/PoolManager.php
@@
-    public function removeAccount(string $email): bool
+    public function removeAccount(string $email): string
     {
@@
-        if (count($pool['accounts']) === $original) {
-            return false;
+        if (count($pool['accounts']) === $original) {
+            return 'not_found';
         }
 
-        return $this->savePool($pool);
+        return $this->savePool($pool) ? 'removed' : 'save_failed';
     }
diff --git a/inc/rest-api.php b/inc/rest-api.php
@@
 function rest_remove_account( \WP_REST_Request $request ) {
 	$email = $request->get_param( 'email' );
 	$pool  = PoolManager::getInstance();
+	$result = $pool->removeAccount( $email );
 
-	if ( ! $pool->removeAccount( $email ) ) {
+	if ( 'not_found' === $result ) {
 		return new \WP_Error(
 			'not_found',
 			__( 'Account not found in pool.', 'ai-provider-for-anthropic-max' ),
 			[ 'status' => 404 ]
 		);
 	}
+	if ( 'save_failed' === $result ) {
+		return new \WP_Error(
+			'pool_save_failed',
+			__( 'Failed to persist account removal.', 'ai-provider-for-anthropic-max' ),
+			[ 'status' => 500 ]
+		);
+	}
 
 	return rest_ensure_response( [
 		'success' => true,
 		'count'   => $pool->count(),
 	] );
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/OAuthPool/PoolManager.php` at line 425, The current removeAccount()
return value conflates "not found" and "save failed" because it returns false
from savePool(); change the contract so removeAccount() returns a status enum
(e.g., STATUS_NOT_FOUND, STATUS_SAVED, STATUS_SAVE_ERROR) or a distinct sentinel
for each outcome, update savePool() (or its caller) to propagate a SAVE_ERROR
status when DB persistence fails, and then update the REST handler that calls
removeAccount() to map STATUS_NOT_FOUND -> 404 and STATUS_SAVE_ERROR -> 500
(keep STATUS_SAVED as 200/204); use explicit symbols like removeAccount(),
savePool(), and the new enum constants to locate and modify the code.

@superdav42
superdav42 merged commit 999b17f into main Apr 10, 2026
1 check passed
@superdav42

Copy link
Copy Markdown
Contributor Author

Root cause

sanitize_email was used as the sanitize_callback for the email URL path parameter on the DELETE /accounts/{email} and POST /accounts/{email}/refresh routes.
sanitize_email is a validator, not just a sanitizer — it returns '' (empty string) for any email it considers invalid, including:

  • Emails with underscores in domain subdomains (e.g. user@my_company.com)
  • Local-only domains (e.g. user@localhost)
  • Any email that fails its strict RFC-subset checks
    When the sanitized value is '', removeAccount('') finds no account with email '', returns false, and the REST endpoint returns 404 Account not found in pool. — which the frontend surfaces as "Failed to remove account."
    The email was already validated by sanitize_email when the account was added (via the /exchange endpoint). The DELETE and /refresh routes only need to look up an existing stored email, so sanitize_text_field is the correct callback.

Changes

inc/rest-api.php

  • DELETE /accounts/{email}: sanitize_email → sanitize_text_field
  • POST /accounts/{email}/refresh: sanitize_email → sanitize_text_field
    src/OAuthPool/PoolManager.php
  • removeAccount(): now returns savePool()'s result instead of always true after a count change — surfaces DB-level save failures rather than silently ignoring them
  • listAccounts(): adds validity: null to each account entry so the StatusBadge component receives a consistent field (null = not checked; use /health to validate tokens)

Testing

  • Accounts with standard emails (user@example.com) can be removed ✓
  • Accounts with emails containing underscores in domain (user@my_company.com) can be removed ✓
  • Refresh endpoint uses the same fix ✓
  • No JS rebuild required (PHP-only changes; frontend already handles validity: null)

Merged via PR #11 to main.
Merged by deterministic merge pass (pulse-wrapper.sh).


aidevops.sh v3.6.235 spent 13m on this as a headless bash routine.

superdav42 added a commit that referenced this pull request Apr 13, 2026
Addresses CodeRabbit review feedback from PR #11.

removeAccount() previously returned false for both outcomes:
- account not found in pool
- account found but database save failed

This made the REST handler conflate the two, always returning 404.

Changes:
- Add REMOVE_NOT_FOUND, REMOVE_OK, REMOVE_SAVE_ERROR constants to PoolManager
- Change removeAccount() return type from bool to string (one of the constants)
- Update rest_remove_account() to map REMOVE_NOT_FOUND → 404 and REMOVE_SAVE_ERROR → 500

Fixes #17
superdav42 added a commit that referenced this pull request Apr 13, 2026
…17)

Addresses CodeRabbit review feedback from PR #11.

removeAccount() previously returned false for both outcomes:
- account not found in pool
- account found but database save failed

This made the REST handler conflate the two, always returning 404.

Changes:
- Add REMOVE_NOT_FOUND, REMOVE_OK, REMOVE_SAVE_ERROR constants to PoolManager
- Change removeAccount() return type from bool to string (one of the constants)
- Update rest_remove_account() to map REMOVE_NOT_FOUND → 404 and REMOVE_SAVE_ERROR → 500

Fixes #17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant