Skip to content

Fixes 33170: fail fast when DQ SDK credentials come back masked - #33171

Merged
TeddyCr merged 1 commit into
open-metadata:mainfrom
TeddyCr:fix/dq-sdk-masked-credentials
Sep 11, 2026
Merged

Fixes 33170: fail fast when DQ SDK credentials come back masked#33171
TeddyCr merged 1 commit into
open-metadata:mainfrom
TeddyCr:fix/dq-sdk-masked-credentials

Conversation

@TeddyCr

@TeddyCr TeddyCr commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Describe your changes:

Fixes #33170

WorkflowConfigBuilder.with_table() fetches the database service with get_by_id, which the API masks for every caller that is not a bot (ServiceEntityResource.decryptOrNullifyAuthorizer.shouldMaskPasswords!subjectContext.isBot()). The masked value was stored on service_connection and passed straight into Source(...), so a run started with a personal access token failed much later as an authentication error from the source — pointing at the source rather than at the token that actually caused it.

This detects PasswordEntityMasker.PASSWORD_MASK right after the service is fetched and raises with the offending field paths and the remedy.

The check walks the dumped connection rather than the model, which matters: secret: references are valid credentials resolved at connection time by get_connection_url_common, and reading one through get_secret_value() would fire a live secrets-manager call from what should be a cheap validation. model_dump() leaves them intact, so references pass through untouched and only the literal mask trips the guard.

Type of change:

  • Bug fix

High-level design:

N/A — small change.

Tests:

Use cases covered

  • SDK driven with a personal access token gets an immediate, actionable error naming the masked field instead of a downstream source authentication failure
  • SDK driven with a bot token against a server using an external secrets manager still builds — secret: references are not treated as masks
  • SDK driven with a bot token against a server storing credentials inline still builds

Unit tests

  • I added unit tests for the new logic.
  • Files updated: ingestion/tests/unit/sdk/data_quality/test_workflow_config_builder.py
  • Added 4 tests: masked credentials raise; secret: reference passes; real credential passes; _find_masked_fields walks nested dicts and lists
  • Both behaviour changes were RED-checked — reverting the guard fails exactly test_with_table_raises_when_credentials_are_masked, and reverting the model_str() call fails the same test on service 'root='MySQL''

Backend integration tests

  • Not applicable (no backend API changes).

Ingestion integration tests

  • Not applicable — the change is a validation guard in the SDK builder, covered by unit tests.

Playwright (UI) tests

  • Not applicable (no UI changes).

Manual testing performed

  1. ruff format --check and ruff check clean on both changed files
  2. pytest ingestion/tests/unit/sdk/ — 454 passed, 1 skipped
  3. Reproduced the original behaviour against a live instance: with a PAT the connection came back *********; with the ingestion-bot token it came back as a secret: reference that resolved to a real password at engine-build time

UI screen recording / screenshots:

Not applicable.

Checklist:

  • I have read the CONTRIBUTING document.

  • My PR title is Fixes <issue-number>: <short explanation>

  • My PR is linked to a GitHub issue via Fixes #<issue-number> above.

  • I have commented on my code, particularly in hard-to-understand areas.

  • For JSON Schema changes: I updated the migration scripts or explained why it is not needed. (No schema changes.)

  • For UI changes: I attached a screen recording and/or screenshots above. (No UI changes.)

  • I have added tests (unit / integration / Playwright as applicable) and listed them above.

  • I have added a test that covers the exact scenario we are fixing.

🤖 Generated with Claude Code

https://claude.ai/code/session_01CLaYpRGBYYQbd4hZKhHpgT

WorkflowConfigBuilder.with_table fetches the database service with get_by_id,
which the API masks for every caller that is not a bot -- shouldMaskPasswords
is !subjectContext.isBot(). The masked value was stored and passed straight
into Source(...), so the run failed much later as an authentication error from
the source, pointing at the source rather than at the token that caused it.

Detect PasswordEntityMasker.PASSWORD_MASK in the connection and raise with the
offending field paths and the remedy. The check walks the dumped connection so
that `secret:` references are left alone: they are valid credentials resolved
at connection time, and touching one here would trigger a live secrets-manager
call from what should be a cheap validation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CLaYpRGBYYQbd4hZKhHpgT
Copilot AI lite review requested due to automatic review settings September 10, 2026 20:55
@TeddyCr
TeddyCr requested review from a team and akashverma0786 as code owners September 10, 2026 20:55

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

Copy link
Copy Markdown
Contributor

❌ PR checklist incomplete

This PR cannot be merged until the following are addressed on its linked issue:

The fields live on the linked issue in the Shipping project (open the issue → right sidebar → Projects). After you set them, re-run this check (or push a commit) — issue/project changes do not re-trigger it automatically.

Maintainers can bypass this check by adding the skip-pr-checks label.

@github-actions github-actions Bot added Ingestion safe to test Add this label to run secure Github workflows on PRs labels Sep 10, 2026
@gitar-bot

gitar-bot Bot commented Sep 10, 2026

Copy link
Copy Markdown
Code Review ✅ Approved

Adds a fail-fast check when DQ SDK credentials come back masked from the API, raising an immediate error with the offending field paths instead of letting the masked value cause a downstream authentication failure. The implementation walks the dumped connection model to preserve secret: references (which resolve at engine-build time) while catching literal mask values. Unit tests cover masked credentials, secret: references, real credentials, and nested field detection. No issues found.

Options

Display: compact → Counting what did not apply, without listing it.

Comment with these commands to change the behavior for this request:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source

@sonarqubecloud

Copy link
Copy Markdown

@TeddyCr
TeddyCr added this pull request to the merge queue Sep 11, 2026
Merged via the queue into open-metadata:main with commit 0b8c357 Sep 11, 2026
110 of 111 checks passed
@TeddyCr
TeddyCr deleted the fix/dq-sdk-masked-credentials branch September 11, 2026 14:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Ingestion safe to test Add this label to run secure Github workflows on PRs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Data quality SDK silently builds a workflow from masked credentials

3 participants