Fixes 33170: fail fast when DQ SDK credentials come back masked - #33171
Conversation
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
❌ PR checklist incompleteThis 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 |
Code Review ✅ ApprovedAdds 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 OptionsDisplay: compact → Counting what did not apply, without listing it. Comment with these commands to change the behavior for this request:
Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source |
|
0b8c357



Describe your changes:
Fixes #33170
WorkflowConfigBuilder.with_table()fetches the database service withget_by_id, which the API masks for every caller that is not a bot (ServiceEntityResource.decryptOrNullify→Authorizer.shouldMaskPasswords→!subjectContext.isBot()). The masked value was stored onservice_connectionand passed straight intoSource(...), 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_MASKright 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 byget_connection_url_common, and reading one throughget_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:
High-level design:
N/A — small change.
Tests:
Use cases covered
secret:references are not treated as masksUnit tests
ingestion/tests/unit/sdk/data_quality/test_workflow_config_builder.pysecret:reference passes; real credential passes;_find_masked_fieldswalks nested dicts and liststest_with_table_raises_when_credentials_are_masked, and reverting themodel_str()call fails the same test onservice 'root='MySQL''Backend integration tests
Ingestion integration tests
Playwright (UI) tests
Manual testing performed
ruff format --checkandruff checkclean on both changed filespytest ingestion/tests/unit/sdk/— 454 passed, 1 skipped*********; with theingestion-bottoken it came back as asecret:reference that resolved to a real password at engine-build timeUI 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