Skip to content

CXH-2163: gracefully handle 403 on inaccessible workspaces - #51

Open
al-conductorone wants to merge 6 commits into
mainfrom
cxh-2163-baton-databricks-graceful-403
Open

CXH-2163: gracefully handle 403 on inaccessible workspaces#51
al-conductorone wants to merge 6 commits into
mainfrom
cxh-2163-baton-databricks-graceful-403

Conversation

@al-conductorone

Copy link
Copy Markdown
Contributor

Databricks syncs no longer fail when the connector can read the account but lacks admin access to one workspace. That workspace's roles are skipped and the rest of the sync completes, instead of the whole sync erroring out.

…e sync

When the OAuth2 service principal has account-level access but is not an
admin on a specific workspace, listing users, groups, or service
principals for that workspace's roles returns 403 and previously failed
the entire sync. Skip the workspace-scoped listing on a 403 (log and
return empty) instead, mirroring the existing 400 handling in
workspaces.go. Account-scoped 403s still propagate.
@al-conductorone
al-conductorone requested a review from a team July 28, 2026 19:26
@linear-code

linear-code Bot commented Jul 28, 2026

Copy link
Copy Markdown

CXH-2163

Comment thread pkg/connector/roles.go Outdated
Comment on lines +135 to +145
// Grants returns all the grants for a given role.
// Since Databricks API does not support listing grants for a role, so that it aligns with the sdk API,
// we have to go through all the users, groups and servicePrincipals to check if they have the role.
// isWorkspaceAccessForbidden reports whether err is a 403 from a workspace-scoped
// API call. This happens when the service principal has account-level access but is
// not an admin on that specific workspace; such workspaces are skipped so one
// inaccessible workspace does not fail the whole sync.
func isWorkspaceAccessForbidden(err error) bool {
var apiErr *databricks.APIError
return errors.As(err, &apiErr) && apiErr.StatusCode == http.StatusForbidden
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Suggestion: Inserting isWorkspaceAccessForbidden here orphans the Grants doc comment (lines 135-137). With no blank line between line 137 and 138, godoc now attaches the whole block to isWorkspaceAccessForbidden, and Grants (line 147) is left undocumented. Move the helper above the Grants doc comment (or below the Grants function) so each comment documents its intended function. (confidence: high)

Comment thread pkg/connector/roles.go Outdated
if err != nil {
return nil, nil, fmt.Errorf("databricks-connector: failed to list users: %w", err)
if isWorkspaceRole && isWorkspaceAccessForbidden(err) {
l.Info("databricks-connector: workspace not accessible to service principal, skipping users",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Suggestion: Skipping an inaccessible workspace is logged at Info. The repo-local log-level criteria (L1/L4) classify a 4xx skip-and-continue as Warn so operators can see that a workspace's role grants were dropped from the sync — Info is often filtered out. Same applies to the groups (line 243) and service-principals (line 288) branches. (confidence: medium)

@github-actions

github-actions Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Connector PR Review: CXH-2163: gracefully handle 403 on inaccessible workspaces

Blocking Issues: 0 | Suggestions: 0 | Threads Resolved: 0
Criteria: Criteria status: loaded .claude/skills/ci-review.md from trusted base 5aba277cd2a6.
Review mode: incremental since 5236c455
View review run: https://github.com/ConductorOne/baton-databricks/actions/runs/30491646070

Review Summary

The new commit is the deprecated-trait migration: profile and status move from trait-level options to resource-level, and all reads switch to rs.GetProfile(resource). This is SDK-supported (GetProfile/GetStatus in baton-sdk v0.20.5 read the resource field first and fall back to the deprecated trait fields), and the connector sets and reads consistently, so grants/entitlements resolve correctly. The UserTrait status enum swap to resource-level status is value-identical per the SDK. The full PR diff was scanned for security and correctness; the 403 skip-and-continue behavior is unchanged and terminates pagination correctly. No new issues found. Note: this commit also lowered the workspace-403 skip logs from Info to Debug; the previously-raised log-level suggestion (L4 leans toward Warn for skip-and-continue so operators retain visibility of skipped workspaces) still applies and is not re-posted.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

None.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No blocking issues found.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No blocking issues found.

Skip-and-continue on a per-workspace 403 was logged at Info. Portfolio bans
Warn (log cost/noise) and prescribes Debug for non-error diagnostics, so drop
these skip notices to Debug. The pr-review bot suggested Warn per the repo's
baton-admin error-handling criteria; the portfolio's no-Warn rule overrides it.
golangci-lint (staticcheck SA1019) fails on the deprecated RoleTrait/GroupTrait/
UserTrait Profile field and the WithRoleProfile/WithGroupProfile/WithUserProfile/
WithStatus trait options, which the recent baton-sdk bump marked deprecated in
favor of resource-level attributes.

Writes now use WithResourceProfile / WithResourceStatus resource options; reads
use rs.GetProfile(resource). Behavior is unchanged: NewXResource still attaches
the trait, GetProfile falls back to trait-level data, and UserTrait_Status_Status
and Status_ResourceStatus share identical enum values.

Clears all 21 SA1019 lint errors (verify/lint was red here and on main from the
SDK bump).

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No blocking issues found.

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.

2 participants