Skip to content

Fixes 4362: preserve secret: prefix during Python SDK serialization#28625

Open
pmbrull wants to merge 1 commit into
mainfrom
pmbrull/unit-test-issue-4362
Open

Fixes 4362: preserve secret: prefix during Python SDK serialization#28625
pmbrull wants to merge 1 commit into
mainfrom
pmbrull/unit-test-issue-4362

Conversation

@pmbrull
Copy link
Copy Markdown
Member

@pmbrull pmbrull commented Jun 2, 2026

Basically, if we created a service with the YAML putting in secret:redshift-pwd, it got sent deserialized with the password as-is, so then the server saved it with the "internal" secret path like "secret:openmetadata-database-red-sm-new-authtype-password"
So you ended up with the service misaligned with how you have your secrets set up locally
So anyway, this cleans up the serde step when we send the payload

Describe your changes:

Fixes open-metadata/openmetadata-collate#4362

CustomSecretStr serialization resolved secret:<id> external secret references through the configured secrets manager, stripping the secret: prefix from model_dump / model_dump_json output. On create/update the SDK sent that resolved (or, with the default DB manager, prefix-stripped) value to the server, so external references were stored as plain secrets instead of being preserved. handle_secret now serializes with skip_secret_manager=True, keeping the raw secret:<id> reference intact for transport; resolution still happens at use-time via the direct get_secret_value() call when a connection is built, so ingestion keeps resolving references exactly as before.

Type of change:

  • Bug fix

High-level design:

N/A — small change (2 files). Serialization (transport) preserves the reference; resolution (use-time, e.g. builders.get_password_secret) is a separate, untouched path.

Tests:

Use cases covered

  • Creating a service via the Python SDK with a secret:<id> external reference keeps the reference in the serialized create/update payload (so the server stores it as an external reference, not a plain secret).
  • Ingestion still resolves secret:<id> against the configured secrets manager when building a connection.

Unit tests

  • Added unit tests for the changed logic.
  • Files: ingestion/tests/unit/models/test_custom_pydantic.py
    • TestExternalSecretReferenceSerialization — asserts the secret: prefix survives model_dump_json(context={"mask_secrets": False}) for both a plain CustomSecretStr model and a typed MysqlConnection.
    • TestExternalSecretReferenceResolution — guards the connect-time path: with an external secrets manager active, get_password_secret().get_secret_value() still resolves the reference, while serialization does not leak the resolved value.

Backend integration tests

  • Not applicable (no backend API changes).

Ingestion integration tests

  • Not applicable (covered by unit tests above).

Playwright (UI) tests

  • Not applicable (no UI changes).

Manual testing performed

  1. Ran a Redshift metadata ingestion from YAML with authType.password: secret:redshift-pwd and a Kubernetes secrets manager.
  2. Verified the created service GET .../databaseServices/name/<svc>?fields=* returns authType.password = secret:redshift-pwd (reference preserved) instead of a server-wrapped secret:openmetadata-... plain secret.

UI screen recording / screenshots:

Not applicable.

Checklist:

  • I have read the CONTRIBUTING document.
  • My PR is linked to a GitHub issue via Fixes above.
  • I have commented on my code, particularly in hard-to-understand areas.
  • I have added tests (unit) and listed them above.
  • I have added a test that covers the exact scenario we are fixing (issue Deploy Profiler Workflow UI #4362 referenced in the test docstrings).

CustomSecretStr serialization resolved `secret:<id>` external references
through the configured secrets manager, stripping the `secret:` prefix from
model_dump / model_dump_json output. On create/update the SDK then sent the
resolved (or, with the default DB manager, prefix-stripped) value to the
server, so external references were stored as plain secrets instead of being
preserved.

handle_secret now serializes with skip_secret_manager=True so the raw stored
reference survives transport. Secret resolution still happens at use-time via
the direct get_secret_value() call when building a connection, so ingestion
keeps resolving secret:<id> as before.

Fixes open-metadata/openmetadata-collate#4362

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 2, 2026 09:54
@pmbrull pmbrull requested a review from a team as a code owner June 2, 2026 09:54
@github-actions github-actions Bot added Ingestion safe to test Add this label to run secure Github workflows on PRs labels Jun 2, 2026
@gitar-bot
Copy link
Copy Markdown

gitar-bot Bot commented Jun 2, 2026

Code Review ✅ Approved

Updates CustomSecretStr serialization to skip secret manager resolution during model dumps, ensuring 'secret:' prefixes are preserved in payloads. No issues found.

Options

Display: compact → Showing less information.

Comment with these commands to change:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@pmbrull pmbrull added the To release Will cherry-pick this PR into the release branch label Jun 2, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes Python SDK secret serialization so external secret references (secret:<id>) are preserved in create/update payloads instead of being resolved (and having the secret: prefix stripped) during model_dump_json().

Changes:

  • Update CustomSecretStr serialization to skip secrets-manager resolution during transport serialization (skip_secret_manager=True), preserving raw secret:<id> references.
  • Add unit tests to ensure secret: references survive model_dump_json(context={"mask_secrets": False}) and that connect-time resolution via get_secret_value() still works with an external secrets manager.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
ingestion/src/metadata/ingestion/models/custom_pydantic.py Adjusts secret serialization to preserve secret: references by skipping secrets-manager resolution during serialization.
ingestion/tests/unit/models/test_custom_pydantic.py Adds regression tests for serialization preservation and runtime resolution behavior for external secret references.

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Jun 2, 2026

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 2, 2026

🔴 Playwright Results — 2 failure(s), 15 flaky

✅ 4255 passed · ❌ 2 failed · 🟡 15 flaky · ⏭️ 88 skipped

Shard Passed Failed Flaky Skipped
✅ Shard 1 299 0 0 4
🔴 Shard 2 800 2 5 9
✅ Shard 3 807 0 0 8
🟡 Shard 4 841 0 5 12
🟡 Shard 5 718 0 2 47
🟡 Shard 6 790 0 3 8

Genuine Failures (failed on all attempts)

Features/Glossary/GlossaryWorkflow.spec.ts › should display correct status badge color and icon (shard 2)
Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).�[22mtoHaveText�[2m(�[22m�[32mexpected�[39m�[2m)�[22m failed

Locator:  locator('[data-row-key*="StatusBadgeTerm1780402235124"]').locator('.status-badge')
Expected: �[32m"Draft"�[39m
Received: �[31m"In Review"�[39m
Timeout:  15000ms

Call log:
�[2m  - Expect "toHaveText" with timeout 15000ms�[22m
�[2m  - waiting for locator('[data-row-key*="StatusBadgeTerm1780402235124"]').locator('.status-badge')�[22m
�[2m    18 × locator resolved to <div class="status-badge inReview" data-testid=""PW%'a50fd8c9.Dark55d0b302".StatusBadgeTerm1780402235124-status">…</div>�[22m
�[2m       - unexpected value "In Review"�[22m

Features/Glossary/GlossaryWorkflow.spec.ts › should start term as Draft when glossary has reviewers (shard 2)
Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).�[22mtoHaveText�[2m(�[22m�[32mexpected�[39m�[2m)�[22m failed

Locator:  locator('[data-row-key*="DraftTerm1780402319467"]').locator('.status-badge')
Expected: �[32m"Draft"�[39m
Received: �[31m"In Review"�[39m
Timeout:  15000ms

Call log:
�[2m  - Expect "toHaveText" with timeout 15000ms�[22m
�[2m  - waiting for locator('[data-row-key*="DraftTerm1780402319467"]').locator('.status-badge')�[22m
�[2m    18 × locator resolved to <div class="status-badge inReview" data-testid=""PW%'a78383c8.Noblea8300e0e".DraftTerm1780402319467-status">…</div>�[22m
�[2m       - unexpected value "In Review"�[22m

🟡 15 flaky test(s) (passed on retry)
  • Features/BulkEditEntity.spec.ts › Glossary (shard 2, 1 retry)
  • Features/BulkImport.spec.ts › Keyboard Delete selection (shard 2, 1 retry)
  • Features/DataQuality/ColumnLevelTests.spec.ts › Column Values To Match Regex (shard 2, 1 retry)
  • Features/DataQuality/TestCaseImportExportE2eFlow.spec.ts › Admin: Complete export-import-validate flow (shard 2, 1 retry)
  • Features/DataQuality/TestCaseResultPermissions.spec.ts › User with only VIEW cannot PATCH results (shard 2, 1 retry)
  • Flow/PersonaFlow.spec.ts › Set default persona for team should work properly (shard 4, 1 retry)
  • Pages/CustomProperties.spec.ts › Integer (shard 4, 1 retry)
  • Pages/CustomProperties.spec.ts › Should clear search and show all properties for apiCollection in right panel (shard 4, 1 retry)
  • Pages/CustomProperties.spec.ts › Date Time (shard 4, 1 retry)
  • Pages/DataContractsSemanticRules.spec.ts › Validate Description Rule Is_Not_Set (shard 4, 1 retry)
  • Pages/EntityDataSteward.spec.ts › User as Owner Add, Update and Remove (shard 5, 1 retry)
  • Pages/ExplorePageRightPanel_KnowledgeCenter.spec.ts › Should remove user owner for knowledgeCenter (shard 5, 1 retry)
  • Pages/InputOutputPorts.spec.ts › Cancel port removal (shard 6, 1 retry)
  • Pages/Lineage/LineageFilters.spec.ts › Verify lineage schema filter selection (shard 6, 1 retry)
  • Pages/ODCSImportExport.spec.ts › Multi-object ODCS contract - object selector shows all schema objects (shard 6, 1 retry)

📦 Download artifacts

How to debug locally
# Download playwright-test-results-<shard> artifact and unzip
npx playwright show-trace path/to/trace.zip    # view trace

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 To release Will cherry-pick this PR into the release branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants