Skip to content

CXP-1296 Refresh every workspace entitlement role on updateUser/updateGroup - #92

Open
JavierCarnelli-ConductorOne wants to merge 3 commits into
stagingfrom
fix/cxp-1296
Open

JavierCarnelli-ConductorOne wants to merge 3 commits into
stagingfrom
fix/cxp-1296

Conversation

@JavierCarnelli-ConductorOne

Copy link
Copy Markdown
Contributor

Problem

A workspace entitlement change made through the workspace SCIM API (a PATCH on a user's or group's entitlements) is logged as a single accounts/updateUser or accounts/updateGroup row. That row names the principal but not the entitlement, and no changeDatabricksSqlAcl / changeDatabricksWorkspaceAcl row is logged alongside it.

The event feed mapped updateUser / updateGroup to only allow-cluster-create and allow-instance-pool-create, so a grant or revoke of databricks-sql-access or workspace-access reached C1 only on the next full sync.

Fix

  • updateUser and updateGroup now refresh all four workspace entitlement roles. They reuse the entitlements list from roles.go, so a future entitlement is covered automatically.
  • Unchanged:
    • Roles are emitted only when the row resolves to an in-scope workspace. Account-level rows (workspace_id = 0) still refresh only the principal.
    • changeDatabricksWorkspaceAcl / changeDatabricksSqlAcl mappings, the audit query and event IDs.

Cost

Each workspace-scoped updateUser / updateGroup now emits 5 events instead of 3. Each role refresh re-lists the workspace's principals. No new API calls happen while the feed is polled.

Tests

  • Updated the workspace updateUser case: it now expects the user plus all four roles.
  • Added three cases:
    • workspace updateGroup
    • account-level updateUser
    • account-level updateGroup
  • test-server/README.md: row 19 now lists all four ws-alpha roles; the expected total goes from 25 to 27 events.

go build ./..., go test ./pkg/connector/... ./test-server/..., go vet ./... and golangci-lint (0 issues) all pass.

Manual QA (pending)

Repeat a SCIM PATCH of databricks-sql-access and of workspace-access, as a grant and as a revoke, for a user and for a group. After the audit log lag (about 4h), confirm the feed lists the matching role/<deployment>:<entitlement> change.

🤖 Generated with Claude Code

…er/updateGroup

Workspace SCIM entitlement changes are logged only as accounts/updateUser or
updateGroup, with no ACL row and no detail about which entitlement changed.
The feed refreshed only allow-cluster-create and allow-instance-pool-create
for those actions, so databricks-sql-access and workspace-access changes
waited for the next full sync. Refresh all four workspace entitlement roles.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@linear-code

linear-code Bot commented Nov 4, 2026

Copy link
Copy Markdown

CXP-1296

@JavierCarnelli-ConductorOne JavierCarnelli-ConductorOne changed the title fix(databricks): refresh every workspace entitlement role on updateUser/updateGroup CXP-1296 Refresh every workspace entitlement role on updateUser/updateGroup Nov 4, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… page

Each workspace updateUser/updateGroup row refreshes all four entitlement
roles, and every role refresh pages through all principals in the
workspace. ListEvents now keeps only the last resource change per
resource within a page, so the surviving event carries the newest row's
ID and time. Grant and revoke events are never collapsed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
var unmappedRows, skippedLookupRows, resourceChangeEvents, grantEvents, revokeEvents int
var unmappedRows, skippedLookupRows, resourceChangeEvents, grantEvents, revokeEvents, duplicateResourceChanges int
principalTypes := principalTypeCache{}
// Keep only the last resource change per resource in a page: each one triggers a full refetch

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The four-role refresh on updateUser/updateGroup is right. The per-page collapse added on top of it in 7db2e2a is work the platform already does: its feed consumer dedupes resource-change events for each ListEvents page by (resourceType, resourceID), folds OccurredAt to the most recent, and queues one targeted re-sync per surviving resource. The duplicate 19/1-style events never cost a refetch, so collapsing here only saves bytes on the wire — about 5k tiny events at a full auditLogPageLimit page, well inside the 4 MiB gRPC ceiling.

The shipped audit feeds emit one event per audit row and leave the collapse to the platform:

  • baton-ramp — "emits one ResourceChangeEvent per event", "the platform ... turns ResourceChangeEvents into targeted-sync tasks".
  • baton-teleport — flat append over the audit rows, no page-level map.

The cost of keeping it lands in testdata/expected-events.jsonl, which is now globally coupled: add one seed row naming a resource an earlier row already named and an unrelated line disappears (row 19's alice line goes the moment any later row touches alice). I'd drop lastResourceChange, resourceChangeKey and the slices.DeleteFunc pass and ship the role-mapping change on its own.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants