Repository navigation
[2.0] fix(security): apply service connection visibility to MCP and ingestion clients - #36316
mohityadav766 wants to merge 5 commits into
Conversation
…on clients MCP get_entity and patch_entity drop a service's connection for callers without EditAll on it, through the ServiceConnectionAccess check that ServiceEntityResource now shares; editors still get it masked. Ingestion copes with a connection that does not come back: dbt takes the lineage SQL dialect from the service's serviceType instead of failing lineage for every model, and other workflows and the data quality SDK fail with an error naming the token as the cause. Amends the service-connection visibility and MCP credential-masking decision records. (cherry picked from commit 845ac76)
…age dialect basedpyright reports the optional serviceConnection config and serviceName as new errors. (cherry picked from commit 230ca60)
❌ 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 |
| try (MockedStatic<Entity> entityMock = mockStatic(Entity.class); | ||
| MockedStatic<McpChangeEventUtil> changeEventMock = mockStatic(McpChangeEventUtil.class); | ||
| MockedStatic<JsonUtils> jsonMock = mockStatic(JsonUtils.class)) { | ||
| entityMock | ||
| .when(() -> Entity.getEntityRepository(Entity.DATABASE_SERVICE)) | ||
| .thenReturn(serviceRepository); | ||
| jsonMock.when(() -> JsonUtils.convertValue(any(), eq(Map.class))).thenReturn(Map.of()); | ||
|
|
||
| new PatchEntityTool().execute(authorizer, securityContext, params); | ||
|
|
||
| verify(serviceRepository).patch(any(), any(String.class), any(), any(), any(), any(), any()); |
There was a problem hiding this comment.
execute_servicePatchOutsideTheConnectionReachesTheRepository mocks Entity, McpChangeEventUtil, JsonUtils, and the repository, then only checks that patch was called. It can pass while the saved service or returned response is wrong. The repository guide requires tests to check observable outcomes rather than internal calls. Replace this test with an outcome-based test; the new integration test already checks that the description is saved and the connection stays unchanged. This requirement must be satisfied before merging.
Context Used: CLAUDE.md (source)
| public static Map<String, Object> hideConnectionFromNonEditors( | ||
| Map<String, Object> doc, | ||
| EntityInterface entity, | ||
| Authorizer authorizer, | ||
| SecurityContext securityContext) { | ||
| if (entity instanceof ServiceEntityInterface) { | ||
| String entityType = Entity.getEntityTypeFromObject(entity); |
There was a problem hiding this comment.
Unchanged variables omit required
final
The new Java helpers leave unchanged parameters and local variables without final, including doc, entityType, and copy. The repository guide explicitly requires final on variables and parameters that do not change. This also occurs in maskedCopy and ServiceConnectionAccess.canEditConnection, with the pattern appearing elsewhere in the added Java code. Apply the requirement before merging.
Context Used: CLAUDE.md (source)
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
|
|
||
| assertThat(patched.path("result").path("isError").asBoolean(false)).isFalse(); | ||
| assertThat(refused.path("result").path("isError").asBoolean(false)).isTrue(); | ||
| JsonNode stored = get("services/databaseServices/name/" + serviceFqn, JsonNode.class); |
There was a problem hiding this comment.
Test bypasses the required client
The new assertion reads the saved service through get(...). The repository guide requires backend integration tests to use SdkClients for API calls. Read the service through the SDK so this assertion also exercises the supported client. This requirement must be satisfied before merging.
Context Used: CLAUDE.md (source)
jsonpatch 1.38 types JsonPatch.patch as a Sequence, so basedpyright rejects the append that adds array-field replace operations and fails the Python static checks. The patches built there always hold a list, so the append is unchanged at runtime. (cherry picked from commit 7887432)
…ponse PATCH, follow and unfollow, restore and the timestamp history now pass the service through decryptOrNullify, as GET and list do. A stored version that cannot be decrypted is returned without its connection, and a JSON Patch that copies or moves from another path needs EditAll on the service. (cherry picked from commit eb67b5c)
Code Review ✅ Approved🔴 High risk · Applying EDIT_ALL checks to service-connection responses and MCP patches changes credential access; a mistake could expose stored secrets or disrupt ingestion. Backports service connection visibility to 2.0: MCP VerificationRules No rules evaluated Functional validation Not enabledAuto-approval Not enabledFor more verification details, comment OptionsDisplay: compact → Showing compact verification results. Comment with these commands to change the behavior for this request:
Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source |
|



Describe your changes:
Backport of #36312 to 2.0, for 2.0.7. #36266, the 2.0 backport of #36219, is already on 2.0.
This also backports #35774 first, because 2.0 lacked it. On 2.0, MCP
get_entityreturned a service's stored connection without masking, andpatch_entitycould read or change/connection. With #35774, MCP masks credentials; the follow-up then drops the connection entirely for callers withoutEditAllon the service.Commits:
EntityInterface, and 2.0'sJsonUtils.deepCopysignature./historypass the service throughdecryptOrNullify; a JSON Patchcopy/moveon a service needs EditAll.castinpatch_request.py. jsonpatch 1.38 (released 2026-10-26) makes basedpyright fail the Python static checks on 2.0 as well.Type of change:
Tests:
The unit tests of both PRs, on 2.0:
ServiceConnectionAccessTest,McpResponseUtilsTest,GetEntityToolTest,PatchEntityToolTest,PasswordEntityMaskerTest;test_dbt.py::TestLineageDialectWithoutConnection,test_base_workflow.py,test_workflow_config_builder.py. The integration-test module compiles (McpIntegrationITfrom #35774).🤖 Generated with Claude Code
Summary by Gitar
get_entitycallers without PII access, asUserResourcedoesserviceTypewhen no connection is returnedThis will update automatically on new commits.