codeant-ai-for-open-source[bot] commented on code in PR #37398:
URL: https://github.com/apache/superset/pull/37398#discussion_r2721947637


##########
superset/utils/oauth2.py:
##########
@@ -96,10 +99,20 @@ def refresh_oauth2_token(
         user_id=user_id,
         database_id=database_id,
     ):
-        token_response = db_engine_spec.get_oauth2_fresh_token(
-            config,
-            token.refresh_token,
-        )
+        try:
+            token_response = db_engine_spec.get_oauth2_fresh_token(
+                config,
+                token.refresh_token,
+            )
+        except Exception:
+            # If token refresh failed, delete the invalid token to prevent 
retry loops
+            logger.warning(
+                "OAuth2 token refresh failed for user=%s db=%s, deleting 
invalid token",
+                user_id,
+                database_id,
+            )
+            db.session.delete(token)
+            return None

Review Comment:
   **Suggestion:** The broad `except Exception` swallows all errors from the 
OAuth2 refresh call, deletes the stored token even for transient/network/server 
errors, and prevents OAuth2-specific exceptions (like `oauth2_exception` used 
by engine specs such as GSheets) from propagating to `check_for_oauth2`, which 
can stop the OAuth2 dance from being triggered correctly; instead, only delete 
and re-raise for OAuth2-specific exceptions and let other exceptions bubble up 
without deleting the token. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ⚠️ GSheets OAuth2 token refresh flow may delete valid tokens.
   - ❌ Users forced to re-authorize after transient network errors.
   - ⚠️ OAuth2 dance (start_oauth2_dance) may not trigger.
   - ⚠️ Token retry loops prevented but at data loss cost.
   ```
   </details>
   
   ```suggestion
           except db_engine_spec.oauth2_exception as ex:
               # Token is no longer valid for OAuth2; delete it and trigger 
normal OAuth2 flow
               logger.warning(
                   "OAuth2 token refresh failed for user=%s db=%s, deleting 
invalid token",
                   user_id,
                   database_id,
               )
               db.session.delete(token)
               raise ex
           except Exception:
               # For non-OAuth2-specific failures, keep the token and surface 
the error
               logger.warning(
                   "OAuth2 token refresh failed for user=%s db=%s",
                   user_id,
                   database_id,
               )
               raise
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Ensure an OAuth2 token exists in DB for a user+database: see 
DatabaseUserOAuth2Tokens
   query at superset/utils/oauth2.py:70-75 which returns token 
(get_oauth2_access_token).
   
   2. Trigger token refresh path by calling get_oauth2_access_token such that
   token.refresh_token is present (call site returns refresh path at
   superset/utils/oauth2.py:81-82). This happens during a normal DB request 
using an
   OAuth2-enabled Database (e.g., GSheets integration).
   
   3. Execution enters refresh_oauth2_token at superset/utils/oauth2.py:90 and 
attempts
   db_engine_spec.get_oauth2_fresh_token at superset/utils/oauth2.py:102-106.
   
   4. If get_oauth2_fresh_token raises a transient/network/server error 
(non-OAuth2-specific
   exception), the current code hits the broad except Exception at
   superset/utils/oauth2.py:107-115 which logs and unconditionally deletes the 
stored token
   (db.session.delete(token)), causing the token to be removed even though the 
failure may be
   recoverable. Subsequent calls will find no token 
(superset/utils/oauth2.py:70-76) and
   users will be forced to re-authorize unnecessarily.
   
   5. Additionally, if an engine-specific OAuth2 sentinel exception (e.g., an 
oauth2-specific
   exception class defined by a DB engine spec like GSheets) should instead 
propagate to
   check_for_oauth2 to trigger start_oauth2_dance, that signal is swallowed by 
the broad
   except, preventing the proper OAuth2 dance flow in check_for_oauth2 
(check_for_oauth2 uses
   database.db_engine_spec.needs_oauth2 at superset/utils/oauth2.py:224-228).
   
   6. The proposed change narrows exception handling to delete-and-rethrow only 
for
   OAuth2-specific errors (db_engine_spec.oauth2_exception) and re-raise 
non-OAuth2
   exceptions without deleting the token, preventing token loss on transient 
failures.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/utils/oauth2.py
   **Line:** 107:115
   **Comment:**
        *Logic Error: The broad `except Exception` swallows all errors from the 
OAuth2 refresh call, deletes the stored token even for transient/network/server 
errors, and prevents OAuth2-specific exceptions (like `oauth2_exception` used 
by engine specs such as GSheets) from propagating to `check_for_oauth2`, which 
can stop the OAuth2 dance from being triggered correctly; instead, only delete 
and re-raise for OAuth2-specific exceptions and let other exceptions bubble up 
without deleting the token.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   </details>



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to