Reject ingestion pipeline sourceConfig without type - #29566
Conversation
|
The Java checkstyle failed. Please run You can install the pre-commit hooks with |
❌ 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 |
|
Pushed a fix for the current migration review thread in |
|
Fresh author summary for current head |
651fe14 to
a6e25e2
Compare
|
Want your agent to iterate on Greptile's feedback? Try greploops. |
✅ TypeScript Types Auto-UpdatedThe generated TypeScript types have been automatically updated based on JSON schema changes in this PR. |
|
|
Follow-up on the latest Gitar review summary: it reflects the superseded broad implementation. Current head The cited |
Code Review 👍 Approved with suggestions 3 resolved / 4 findingsEnforces 💡 Edge Case: Snapshot emitted after listener registration can duplicate a live event📄 openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/IngestionPipelineRepository.java:1290-1303 📄 openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/IngestionPipelineRepository.java:1316-1322 In the refactored progressTracker.registerProgressListener(pipelineFQN, runId, listener);
ProgressUpdate snapshot = getLatestProgressUpdate(pipelineFQN, runId);
if (snapshot != null) {
emitProgressUpdate(eventSink, sse, snapshot);
}The previous implementation emitted the snapshot before registering the listener. With the new ordering, if a live ✅ 3 resolved✅ Bug: Backfill added to already-released v1131 migration may never run
✅ Edge Case: Backfill no-ops on scalar sourceConfig.config rows, leaving them typeless
✅ Edge Case: Backfill only types databaseService metadata pipelines
🤖 Prompt for agentsOptionsDisplay: compact → Showing less information. Comment with these commands to change the behavior for this request:
Was this helpful? React with 👍 / 👎 | Gitar | Powered by Gitar — free for open source |
|
Follow-up for the review rerun on rebased head The duplicate-event race is plausible in the pre-existing implementation, but reading the snapshot first trades it for a lost-update race. A correct fix would need atomic snapshot/registration semantics or sequence-aware de-duplication and belongs in a separate progress-streaming change. No progress-streaming modification is applicable to this PR. |



Fixes #28818.
Summary
Prevent future invalid ingestion-pipeline writes by requiring
sourceConfig.configto be an object with a usabletypediscriminator at repository persistence time. Validation runs fromIngestionPipelineRepository.prepare()after service resolution and therefore applies to POST, PUT/upsert, and PATCH.Behavior
sourceConfig, missing/nullconfig, or a missing/null/non-string/blanktypereturns HTTP 400 withsourceConfig.config.type is required.sourceConfig.config must be an object with type.typeand generated Java config objects carrying their discriminator remain valid.Scope
This PR prevents new invalid writes only. The JSON schema and generated clients are unchanged, and there are no Python serialization changes, database migrations, or automatic legacy repairs. Existing affected installations require an independent operational database repair; reads and persisted legacy data are not modified by this change.
Python
BaseWorkflowself-registration may receive HTTP 400 when its serializer omits a defaulted discriminator. Producer-side handling is intentionally deferred to a separate follow-up.Changes
PipelineClassfixture with the runtime requirement.Validation
IngestionPipelineRepositoryTest: 30 passed.mvn -pl openmetadata-service -Dskip.npm -Dskip.yarn -DskipDocker spotless:check: passed.PipelineExecution.spec.ts: 4 passed, including setup and teardown.git diff --check: passed.mainreports unrelated existing errors, with no error in the changed fixture.Local REST persistence reproduction
The same invalid POST payload used
sourceConfig.config: {}.6b1a2e8d201 Created73c3e589400 Bad Request:sourceConfig.config.type is requiredThe fixed-side request was repeated with fresh service and pipeline names and again returned HTTP 400 with zero persisted rows.
Greptile Summary
This PR adds server-side validation in
IngestionPipelineRepository.prepare()to reject ingestion pipeline writes whosesourceConfig.configis missing, non-object, or lacks a non-blanktypediscriminator, returning HTTP 400 in all such cases. Existing persisted data and reads are unaffected; no migrations or schema changes are included.validateSourceConfigHasType(static, package-private) handles three config shapes: rawMap(readstypedirectly), generated Java objects (converts viaJsonUtils.getMap/ Jackson, then readstype), and non-object types like scalars or lists (Jackson throwsIllegalArgumentException, mapped to a distinct 400 message).PipelineClassfixture is updated to supplytype: 'PipelineMetadata'so E2E tests pass the new validation.Confidence Score: 5/5
Safe to merge — the change is additive validation only, with no data mutation, no schema changes, and no side effects on existing valid pipelines.
The validation logic correctly handles all documented input shapes, the error messages are consistent with the test assertions, and the Playwright fixture is aligned with the new requirement. The only untested branch is the Enum path inside the generated-config arm, which is harmless dead code under standard Jackson configuration.
Files Needing Attention: No files require special attention.
Important Files Changed
validateSourceConfigHasTypestatic helper inprepare()to reject pipelines missing a non-blanksourceConfig.config.type; handles raw Maps, generated Java objects, and non-object types correctly.type: 'PipelineMetadata'insourceConfig.config, aligning the E2E test payload with the new server-side validation requirement.Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[POST / PUT / PATCH IngestionPipeline] --> B[EntityRepository.prepareInternal] B --> C[IngestionPipelineRepository.prepare] C --> D[getCachedParentOrLoad - resolve service] D --> E[validateSourceConfigHasType] E --> F{sourceConfig or config is null?} F -- yes --> G[400: sourceConfig.config.type is required] F -- no --> H{config instanceof Map?} H -- yes raw Map --> I[get type from Map directly] H -- no generated object --> J[JsonUtils.getMap convert to Map via Jackson] J --> K{IllegalArgumentException? scalar or list} K -- yes --> L[400: sourceConfig.config must be an object with type] I --> M{type is non-blank String?} J --> M M -- yes --> N[Valid - proceed] M -- no --> O{generatedConfig AND type instanceof Enum?} O -- yes --> N O -- no --> GReviews (14): Last reviewed commit: "ingestion: reject source configs without..." | Re-trigger Greptile