Skip to content

fix(oauth2): log database token failures - #42644

Open
aminghadersohi wants to merge 4 commits into
apache:masterfrom
aminghadersohi:aminghadersohi/log-oauth2-db-auth-failures
Open

fix(oauth2): log database token failures#42644
aminghadersohi wants to merge 4 commits into
apache:masterfrom
aminghadersohi:aminghadersohi/log-oauth2-db-auth-failures

Conversation

@aminghadersohi

@aminghadersohi aminghadersohi commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

SUMMARY

Why

OAuth2 database token exchange and refresh failures lacked queryable context, and the callback emitted an outcome-neutral event metric that did not represent failures. Provider exception details and callback request metadata also needed an end-to-end redaction boundary.

What

  • Log token exchange and refresh failures with database_id, canonical engine, and exception type while excluding OAuth codes, tokens, exception text, and provider payloads.
  • Convert provider-facing exchange and refresh exceptions to sanitized OAuth2 domain exceptions before they reach Flask's generic traceback logging.
  • Exclude OAuth callback query, form, JSON, and referrer data from event logs while retaining safe request metadata.
  • Use the standard REST API StatsD decorator so exactly one of DatabaseRestApi.oauth2.success, .warning, or .error is emitted after transaction completion.
  • Run event logging outside the token transaction so an event-log rollback cannot discard a successful token write.
  • Make callback event logging and StatsD explicitly best-effort so observability failures cannot change a committed success or mask the original OAuth error.
  • Treat the sanitized refresh failure marker as a re-authentication signal independently of vendor-specific exception classifiers.
  • Document the metric migration and add focused regression coverage for logging, redaction, transaction ordering, event-log failures, and callback metrics.

Blast radius

Limited to OAuth2 database token exchange/refresh error handling and callback observability. Success-path token persistence remains unchanged. Provider exceptions crossing the OAuth2 boundary are intentionally replaced with sanitized OAuth2 domain exceptions; OAuth-specific refresh failures still trigger token cleanup and re-authentication. The redaction guarantee covers logs, event-log request data, and provider exception/response-body details; it intentionally does not change the existing callback API contract that returns the provider-defined error code in OAuth2Error.extra.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

Not applicable; this is backend observability and error-handling work.

TESTING INSTRUCTIONS

pytest -q tests/unit_tests/commands/databases/oauth2_test.py tests/unit_tests/utils/oauth2_tests.py tests/unit_tests/databases/oauth2_api_test.py tests/unit_tests/databases/api_test.py -k oauth2 --disable-warnings
pytest -q tests/unit_tests/db_engine_specs/test_base.py -k oauth2_fresh_token --disable-warnings
pre-commit run

Results:

  • OAuth2 selection: 45 passed, 121 deselected
  • Base engine OAuth2 token tests: 5 passed, 69 deselected
  • All staged-file pre-commit hooks passed, including MyPy, Ruff, Ruff format, and Pylint.

pre-commit run --all-files was also attempted. Backend checks passed, but this worktree's frontend hooks cannot load the uninstalled glob and postcss-styled-syntax packages (and docs Yarn cannot read the worktree user's .npmrc); the repository-wide formatter and Ruff hooks also report unrelated existing files outside this PR.

RISK & ROLLBACK

Low-to-moderate risk: the success path is unchanged, but failure paths now expose only sanitized OAuth2 domain exceptions, and event logging runs after the token transaction. Revert the four PR commits (0de0fcd076, b807e190bf, 4246a417b6, and b1768e7a07) to restore the prior OAuth2 behavior.

REVIEW GUIDANCE

Please focus on:

  • the exception sanitization boundary and absence of provider data from all loggers/API responses;
  • decorator ordering: StatsD → event logging → transaction;
  • event-log and StatsD failure isolation from committed callback outcomes;
  • vendor-specific refresh failures still triggering the OAuth2 dance;
  • consistency of structured log dimensions and callback metric classification.

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API
    • Replaces the outcome-neutral DatabaseRestApi.oauth2 counter with outcome-qualified counters documented in UPDATING.md.

@github-actions github-actions Bot added the api Related to the REST API label Jul 31, 2026
Comment thread superset/commands/database/oauth2.py Fixed
@bito-code-review

Copy link
Copy Markdown
Contributor

The logging changes in this pull request are designed to avoid logging sensitive information by using structured logging that captures only metadata, such as database_id, engine, and error_type. The code explicitly avoids logging the raw exception object or user-specific data that might contain credentials. These changes are appropriate and follow security best practices for structured logging.

superset/commands/database/oauth2.py

except Exception as ex:
            logger.error(
                "OAuth2 token exchange failed: database_id=%s engine=%s "
                "error_type=%s",
                self._state["database_id"],
                self._database.backend,
                type(ex).__name__,
            )

@codecov

codecov Bot commented Jul 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 61.66667% with 23 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.64%. Comparing base (cc35056) to head (b1768e7).

Files with missing lines Patch % Lines
superset/commands/database/oauth2.py 25.00% 6 Missing ⚠️
superset/views/base_api.py 76.92% 4 Missing and 2 partials ⚠️
superset/utils/log.py 68.75% 4 Missing and 1 partial ⚠️
superset/utils/oauth2.py 16.66% 4 Missing and 1 partial ⚠️
superset/db_engine_specs/base.py 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #42644      +/-   ##
==========================================
- Coverage   66.64%   66.64%   -0.01%     
==========================================
  Files        2863     2863              
  Lines      162155   162183      +28     
  Branches    37405    37409       +4     
==========================================
+ Hits       108076   108085       +9     
- Misses      52020    52035      +15     
- Partials     2059     2063       +4     
Flag Coverage Δ
hive 38.32% <61.66%> (+<0.01%) ⬆️
mysql 57.87% <61.66%> (-0.01%) ⬇️
postgres 57.90% <61.66%> (-0.01%) ⬇️
presto 40.29% <61.66%> (+<0.01%) ⬆️
python 59.30% <61.66%> (-0.01%) ⬇️
sqlite 57.53% <61.66%> (-0.01%) ⬇️
unit 100.00% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@aminghadersohi
aminghadersohi marked this pull request as ready for review August 1, 2026 00:41
@dosubot dosubot Bot added authentication:sso Single Sign On logging Creates a UI or API endpoint that could benefit from logging. labels Aug 1, 2026
Comment thread superset/databases/api.py Outdated
@aminghadersohi
aminghadersohi marked this pull request as draft August 1, 2026 00:52
@aminghadersohi
aminghadersohi marked this pull request as ready for review August 4, 2026 19:31
@dosubot dosubot Bot added change:backend Requires changing the backend data:connect Namespace | Anything related to db connections / integrations labels Aug 4, 2026
@bito-code-review

bito-code-review Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #8ea754

Actionable Suggestions - 0
Review Details
  • Files reviewed - 7 · Commit Range: a829277..724e4fc
    • superset/commands/database/oauth2.py
    • superset/databases/api.py
    • superset/utils/log.py
    • superset/utils/oauth2.py
    • tests/unit_tests/commands/databases/oauth2_test.py
    • tests/unit_tests/databases/oauth2_api_test.py
    • tests/unit_tests/utils/oauth2_tests.py
  • Files skipped - 1
    • UPDATING.md - Reason: Filter setting
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@netlify

netlify Bot commented Aug 5, 2026

Copy link
Copy Markdown

Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit ca1f23d
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6a7cd062d52d370008e297f7
😎 Deploy Preview https://deploy-preview-42644--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@bito-code-review

bito-code-review Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #d5dd55

Actionable Suggestions - 0
Filtered by Review Rules

Bito filtered these suggestions based on rules created automatically for your feedback. Manage rules.

  • superset/databases/api.py - 1
Review Details
  • Files reviewed - 11 · Commit Range: 724e4fc..a79b4d9
    • superset/commands/database/oauth2.py
    • superset/databases/api.py
    • superset/db_engine_specs/base.py
    • superset/exceptions.py
    • superset/utils/log.py
    • superset/utils/oauth2.py
    • tests/unit_tests/commands/databases/oauth2_test.py
    • tests/unit_tests/databases/oauth2_api_test.py
    • tests/unit_tests/db_engine_specs/test_base.py
    • tests/unit_tests/utils/oauth2_tests.py
    • tests/unit_tests/mcp_service/common/test_time_range_validation.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@richardfogaca

Copy link
Copy Markdown
Contributor

Richard's agent here:

Thanks for the thorough OAuth2 hardening. I reviewed 69a0873 and found two blocking correctness issues plus one non-blocking clarification.

Blocking

1. Refresh sanitization can lose the re-authentication signal

Current flow

  1. refresh_oauth2_token() catches an engine-declared OAuth exception.
  2. It replaces that exception with OAuth2TokenRefreshError.
  3. check_for_oauth2() asks the engine spec to classify the replacement.

Engine specs whose oauth2_exception or needs_oauth2() recognizes only the original vendor exception will therefore skip start_oauth2_dance().

Impact

The token is deleted, but re-authentication may not start. If the replacement reaches browser or MCP consumers, it also lacks the authorization URL and tab metadata they require.

Requested change

Preserve the re-authentication decision before sanitizing the exception, or make the sanitized refresh marker unconditionally trigger the OAuth dance.

Please add an end-to-end regression test using an engine spec with a vendor-specific OAuth exception.


2. Observability failures can escape after the token is committed

The new decorator order commits the token before event logging and metrics finish.

Impact

  • A custom event logger failure can return 500 after the one-shot callback successfully persisted the token.
  • A StatsD failure can replace the original sanitized OAuth exception.
  • Retrying the callback may not be safe because the authorization code is single-use.

The current event-log test only raises SQLAlchemyError, which DBEventLogger already catches and suppresses. It does not prove isolation from arbitrary custom logger failures.

Requested change

Make both callback observability hooks best-effort, and cover:

  • an arbitrary event-logger exception after a successful token write;
  • a metric failure on the success path;
  • a metric failure while handling an OAuth error.

This also encompasses the existing StatsD review thread.

Non-blocking clarification

3. Clarify the API-response redaction guarantee

The existing provider-denial path passes the callback’s arbitrary error value into OAuth2Error.extra, and the existing API test expects that value in the response.

This predates the PR, so I would not block on it independently. However, the PR description should either:

  • narrow the guarantee to provider exception and response-body details; or
  • sanitize this legacy field and document the resulting API change.

Could we address the two blockers before merging and clarify the intended redaction boundary?

@aminghadersohi
aminghadersohi force-pushed the aminghadersohi/log-oauth2-db-auth-failures branch from 69a0873 to 14ed35c Compare August 6, 2026 06:46

@bito-code-review bito-code-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review Agent Run #238c06

Actionable Suggestions - 1
  • superset/utils/oauth2.py - 1
Additional Suggestions - 3
  • superset/utils/oauth2.py - 1
    • Non-OAuth exception message lost · Line 180-188
      In the non-OAuth exception handler, only the exception type name is logged but the actual error message (str(ex)) is captured but not included in the structured log. This limits diagnostic capability when debugging token refresh failures.
  • superset/utils/log.py - 2
    • Weakened type annotation · Line 123-123
      The type hint change from `**payload_override: dict[str, Any]` to `**payload_override: Any` reduces type safety with no documented justification. This makes it harder for static type checkers to catch misuse at call sites. Either revert to the specific type or document why `Any` is necessary.
    • Inconsistent type annotation · Line 180-180
      Same type hint change applies here: `**payload_override: dict[str, Any] | None` became `**payload_override: Any`. Apply same decision as line 123 for consistency.
Filtered by Review Rules

Bito filtered these suggestions based on rules created automatically for your feedback. Manage rules.

  • superset/databases/api.py - 1
Review Details
  • Files reviewed - 10 · Commit Range: bb48c71..14ed35c
    • superset/commands/database/oauth2.py
    • superset/databases/api.py
    • superset/db_engine_specs/base.py
    • superset/exceptions.py
    • superset/utils/log.py
    • superset/utils/oauth2.py
    • tests/unit_tests/commands/databases/oauth2_test.py
    • tests/unit_tests/databases/oauth2_api_test.py
    • tests/unit_tests/db_engine_specs/test_base.py
    • tests/unit_tests/utils/oauth2_tests.py
  • Files skipped - 1
    • UPDATING.md - Reason: Filter setting
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

Comment thread superset/utils/oauth2.py Outdated
@aminghadersohi
aminghadersohi requested review from rebenitez1802 and removed request for richardfogaca August 12, 2026 05:53

@rebenitez1802 rebenitez1802 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Requesting changes on the one remaining blocker from the earlier review. For context on the other two items: the OAuth re-authentication concern is effectively fixed in code — OAuth2TokenRefreshError subclasses OAuth2RedirectError, so needs_oauth2 still classifies the sanitized marker for every in-tree spec and start_oauth2_dance re-attaches the auth URL/tab — though it still lacks the requested end-to-end regression test with a vendor-specific OAuth exception. The API-response redaction wording is a non-blocking follow-up (the provider error query param is still reflected into the JSON body via OAuth2Error.extra; low severity, but the guarantee should be narrowed or the field sanitized). Nice work on the redaction boundary otherwise — I verified codes/secrets/tokens/provider payloads no longer reach logs, exceptions, or responses.

Blocker — observability failures can still escape after the token is committed. With @transaction() innermost, the single-use token is persisted before the event-logger and StatsD hooks run, but neither hook is best-effort, so a post-commit failure can turn a committed (un-retriable) callback into a 500 or mask the sanitized OAuth error. Details inline. The three requested regression tests are still missing — the added test_oauth2_callback_event_log_failure_preserves_business_write only injects SQLAlchemyError, which DBEventLogger already swallows, so it doesn't prove isolation from arbitrary logger failures.

Comment thread superset/databases/api.py Outdated
@aminghadersohi
aminghadersohi force-pushed the aminghadersohi/log-oauth2-db-auth-failures branch from 14ed35c to ca1f23d Compare August 12, 2026 19:58
@aminghadersohi

aminghadersohi commented Aug 12, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the outstanding review feedback in b1768e7a07 and rebased the PR onto cc35056bc9:

  • added opt-in best-effort modes to the shared REST StatsD and event-logger wrappers, enabled for the OAuth callback;
  • added regressions for arbitrary custom event-logger failure after commit, StatsD failure after success, and StatsD failure while preserving the original OAuth error;
  • made the sanitized refresh marker unconditionally trigger re-authentication before consulting vendor classifiers, with a vendor-specific end-to-end regression;
  • tightened arbitrary payload override values from Any to object;
  • documented why the provider boundary must catch heterogeneous Exception types. Exception messages remain intentionally omitted because they can contain provider bodies/tokens;
  • clarified in the PR description that the existing provider-defined callback error field returned in OAuth2Error.extra is outside this PR’s redaction contract.

Validation: OAuth-focused selection 45 passed / 121 deselected, base engine refresh selection 5 passed / 69 deselected, and all changed-file pre-commit hooks passed (MyPy, Ruff format/lint, and Pylint included). All review threads have replies and are resolved.

CI follow-up on the final head: current pre-commit, Python unit/integration, required Playwright/Cypress, CodeQL, dependency, license, and build checks passed. The non-blocking experimental embedded-dashboard Playwright jobs hit an unrelated frontend slice_id render error on both the original run and a failed-jobs rerun; that workflow still concluded successfully.

@aminghadersohi
aminghadersohi force-pushed the aminghadersohi/log-oauth2-db-auth-failures branch from ca1f23d to b1768e7 Compare August 12, 2026 20:05
@aminghadersohi

Copy link
Copy Markdown
Contributor Author

All required checks are green; the non-required experimental Playwright gate is showing the same embedded-dashboard timeout seen repo-wide on other open PRs (for example #43088 and #43081).

@bito-code-review bito-code-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review Agent Run #5912dc

Actionable Suggestions - 1
  • superset/utils/oauth2.py - 1
    • Replace broad Exception catch with specific · Line 183-183
Filtered by Review Rules

Bito filtered these suggestions based on rules created automatically for your feedback. Manage rules.

  • tests/unit_tests/db_engine_specs/test_base.py - 1
Review Details
  • Files reviewed - 11 · Commit Range: 0de0fcd..b1768e7
    • superset/commands/database/oauth2.py
    • superset/databases/api.py
    • superset/db_engine_specs/base.py
    • superset/exceptions.py
    • superset/utils/log.py
    • superset/utils/oauth2.py
    • superset/views/base_api.py
    • tests/unit_tests/commands/databases/oauth2_test.py
    • tests/unit_tests/databases/oauth2_api_test.py
    • tests/unit_tests/db_engine_specs/test_base.py
    • tests/unit_tests/utils/oauth2_tests.py
  • Files skipped - 1
    • UPDATING.md - Reason: Filter setting
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

Comment thread superset/utils/oauth2.py
# Engine specs can delegate to arbitrary provider clients that do not share an
# exception base class. Sanitize every other provider-boundary failure while
# preserving the refresh token for a later retry.
except Exception as ex: # pylint: disable=broad-except

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Replace broad Exception catch with specific

Catching a broad Exception is discouraged. If this is intentional for handling various provider errors, consider documenting why and potentially narrowing the scope.

Code Review Run #5912dc


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them

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

Labels

api Related to the REST API authentication:sso Single Sign On change:backend Requires changing the backend data:connect Namespace | Anything related to db connections / integrations logging Creates a UI or API endpoint that could benefit from logging. size/XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants