Skip to content

[CXH-2028] - Support workload identity federation - Databricks Connector - #84

Open
mateoHernandez123 wants to merge 6 commits into
mainfrom
mateoHernandez123/databricks-workload-identity
Open

mateoHernandez123 wants to merge 6 commits into
mainfrom
mateoHernandez123/databricks-workload-identity

Conversation

@mateoHernandez123

@mateoHernandez123 mateoHernandez123 commented Oct 27, 2026 •

Copy link
Copy Markdown

Description

  • Bug fix
  • New feature

The connector can now authenticate a service principal with workload identity federation. The client secret stays the default. Existing deployments keep working. A saved config that sets the client secret still passes validation.

This pull request replaces #49. That pull request is stale and conflicting, and it is closed in favor of this one.

What changes for the operator

The resource types and the provisioning surface do not move. What changes is how the connector gets its token.

Before. One credential, and it is required.

flowchart LR
  id["--databricks-client-id"]
  sec["--databricks-client-secret"]
  id --> cc["OAuth client credentials"]
  sec --> cc
  cc --> ep["account token endpoint"]
  ep --> bearer["Bearer token"]
Loading

After. The client id stays required. The auth method selects the credential, and the new method reads a JWT the connector exchanges.

flowchart LR
  id["--databricks-client-id (required)"]
  pick{"--auth-method"}
  sec["client-secret (default)<br/>--databricks-client-secret"]
  file["workload-identity-file (CLI only)<br/>--databricks-oidc-token-file"]
  id --> pick
  pick --> sec
  pick --> file
  sec --> cc["OAuth client credentials"]
  file --> ex["RFC 8693 token exchange"]
  cc --> ep["account token endpoint"]
  ex --> ep
  ep --> bearer["Bearer token"]
  style file fill:#1f6feb,color:#fff,stroke:#1f6feb
  style ex fill:#1f6feb,color:#fff,stroke:#1f6feb
Loading

The blue path is new. --databricks-client-secret keeps the behaviour it has today, so a saved config that sets it still validates and still syncs.

The connector reads the JWT from a file on every token refresh, so whatever rotates that file controls the lifetime and no restart is needed.

--databricks-client-id is still required. The credential is chosen by auth method rather than by constraints, so each method keeps its own required field.

Sync:

  • Users (user) — unchanged
  • Groups (group) — unchanged
  • Roles (role) — unchanged
  • Service principals (service_principal) — unchanged
  • Workspaces (workspace) — unchanged
  • Account (account) — unchanged

Provisioning:

  • Create/Delete user accounts — unchanged
  • Grant/Revoke group membership — unchanged
  • Grant/Revoke role assignment — unchanged

Auth:

The connector still authenticates as the service principal named by --databricks-client-id. That flag stays required.

Two authentication methods, selected as field groups:

  • client-secret (default): --databricks-client-secret. The connector uses the OAuth client-credentials flow.
  • workload-identity-file (command line and service mode only): --databricks-oidc-token-file. The connector reads this file on every token refresh.

On the command line, select the second with --auth-method workload-identity-file. Without it the connector validates against the default method and asks for a client secret.

A ConductorOne-hosted connector has no file system the tenant admin controls, so the web form offers the client secret only. Hosted workload identity needs ConductorOne to issue the JWT, which is tracked in CXE-1557.

The exchange is RFC 8693. The grant type is urn:ietf:params:oauth:grant-type:token-exchange. The subject token type is urn:ietf:params:oauth:token-type:jwt. The scope is all-apis. The URL is the same account token endpoint the client secret already uses.

Databricks must have a service principal federation policy that trusts the JWT issuer, subject, and audience. The connector does not create that policy.

The client secret is required inside its own group. Validation only checks the fields the selected group lists, so the secret is not asked for when the token file method is chosen, and the other way round.

Architecture highlights:

  • The token source is custom. clientcredentials.Config can override grant_type, but its public API caches the token before the connector can set an expiry. A missing expires_in would pin the first token for the life of the process.
  • A missing expires_in uses the access token exp claim, then a five-minute fallback.
  • A rejected exchange keeps a gRPC code. uhttp classifies the HTTP status. An HTTP 200 with no access token returns FailedPrecondition.

Validation:

  • Client secret: full sync against the Baton Databricks account, exit 0, 0 connector errors.
  • Federation: temporary policy on service principal baton-uc-cxh2341, then a full sync with no client secret, exit 0. The policy and the test key were deleted after the run.
  • A 75-second JWT failed the sync when the file was not rotated, and passed when the file was rotated mid-sync.
  • Service mode against a Squire tenant: Hello succeeded for both credential types.

Useful links:

Merge order and release flow

The team does not merge to staging any more. A PR targets main, and the test release comes from the feature branch:

  1. The PR targets main. Reviewers read it there.
  2. When the ticket is ready, cut a test release (-test) from the feature branch and move the PR to draft. The ticket moves to validation.
  3. QA validates that release.
  4. Merge to main.
  5. Cut the official release from main. The ticket moves to rollout.

This PR targets staging today, and it can move to main at any time. The branch left main at c0a09af4, which is also where it left staging, and it carries no staging-only commit. The diff therefore does not move: 4 commits and 10 files against either base, and it merges to main with no conflict.

That is not true of the Unity Catalog stack (#71, #72, #73) or of #90. staging is 42 commits ahead of main, and those branches would swallow every staging-only commit on a retarget. They wait until staging lands in main. This PR does not depend on them, and they do not depend on it.

Co-authored-by: Cursor <cursoragent@cursor.com>
@linear-code

linear-code Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

CXH-2028

CXE-1557

@sergiocorral-conductorone sergiocorral-conductorone 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.

Automated review (follow-up/first pass) — drafted 1 → confirmed 1, low-confidence 0, dropped 0, added 0 (panel: opus-5.5 / gpt-6-astra / gemini-4-argon, all high).

Comment thread pkg/config/config.go Resolved
…mselves

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread pkg/config/config.go Resolved

@sergiocorral-conductorone sergiocorral-conductorone 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.

Automated review

drafted 5 → confirmed 4, low-confidence 1, dropped 0, added 0 unique (panel: opus-5.5 / gpt-6-astra / gemini-4-argon, all high).

Comment thread pkg/config/config.go Resolved
Comment thread docs/connector.mdx Resolved
Comment thread pkg/config/config.go Resolved
…they carry

databricks-token reads as a Databricks personal access token: that is what
DATABRICKS_TOKEN means in Databricks' own tooling, and what a bare token field
means across the connectors. This credential is an externally issued JWT, which
Databricks itself calls DATABRICKS_OIDC_TOKEN, so the flags are now
databricks-oidc-token and databricks-oidc-token-file. Nothing ships with the old
names yet, so no deployed configuration changes.

The Kubernetes example also promised a token file that nothing created: the
secret pointed the token file at /var/run/secrets/databricks/token while the
Deployment below mounted no such volume, so the first exchange failed unless the
operator supplied the mount themselves. It now carries the matching projected
serviceAccountToken volume and mount, commented out like the secret line it
pairs with.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@mateoHernandez123
mateoHernandez123 changed the base branch from staging to main November 3, 2026 15:05
@mateoHernandez123
mateoHernandez123 requested a review from a team November 3, 2026 15:05
Comment thread pkg/config/config.go Outdated
field.WithRequired(true),
field.WithDisplayName("OAuth2 Client Secret"),
)
DatabricksOIDCTokenField = field.StringField(

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.

Hosted C1 is part of the request, and these fields don't cover it. A hosted connector has no file to point databricks-oidc-token-file at. A JWT pasted into databricks-oidc-token fails the sync once it expires (the exchanged token's lifetime follows the JWT's exp, typically about an hour). The service-mode Hello check runs before that.

For hosted, C1 itself has to issue the JWT, which the customer then trusts in the service principal federation policy. C1 already has most of the plumbing for AWS:

  • A per-tenant OIDC issuer at <tenant>/auth/v1/aws-sts, with discovery and JWKS (pkg/api/auth/http_aws_sts_oidc.go), behind FEATURE_FLAG_ID_AWS_STS_OIDC_ISSUER.
  • Per-purpose RS256 signer keys with rotation (ExternalTokenSignerPurpose_AWS_STS_V1, pkg/temporal/activity/keyrotate). Databricks accepts RS256.
  • Delivery is a one-shot action argument today (baton-aws assume_role_with_web_identity). A sync needs a fresh JWT for every exchange.

Could we open a CXE Linear issue (or ask for a c1 investigation) to add a Databricks purpose? It would need:

  1. A new signer purpose with its own issuer route, so a Databricks policy only trusts Databricks-purpose tokens.
  2. Minting with a stable sub and a configurable aud that the customer copies into the federation policy. I couldn't find the AWS minting code on c1 main, so it's worth confirming where it lives.
  3. Token-source delivery to the hosted runtime, so the connector can ask for a fresh JWT on each exchange instead of getting it once. GetConnectorOauthToken is the closest existing pattern.

Connector side, so this PR is ready for that:

  • Use field groups instead of the mutually-exclusive/at-least-one constraints:
    • client-secret (default): client id plus client secret, with WithRequired back on the secret.
    • workload-identity-file (CLI-only): client id plus databricks-oidc-token-file.
    • workload-identity-c1 (hosted): client id only. The JWT comes from C1, and the docs give the issuer URL, audience and subject for the policy.
  • Turn the JWT lookup in subjectToken() into a small source interface (file now, C1 token source later), so federationTokenSource.Token() stays the same.
  • NewConnector currently ignores cli.ConnectorOpts. The C1 group would read the token source from there, the same way OAuth2 connectors consume opts.TokenSource.
  • Drop databricks-oidc-token. A static JWT doesn't stay valid in either mode.

@mateoHernandez123 mateoHernandez123 Nov 3, 2026 •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

You are right. Both workload-identity fields defaulted to gui, and neither works there: there is no filesystem for the file, and a static JWT cannot be refreshed because Token() asks for a fresh one on every exchange.

Done in 80463512: field groups instead of the constraints, client-secret as the default with WithRequired back on the secret, workload-identity-file as a CLI-only group, the JWT lookup behind a SubjectTokenSource, and databricks-oidc-token removed.

I left out workload-identity-c1. Without the minting it would be a third hosted option that does not work, so it lands with CXE-1557, which I filed on Connector Engine and linked to CXE-718, IGA-5233, IGA-2165, CXH-2028, CXH-2220 and CXH-116. On the minting code you could not find: it is not there. ExternalTokenSignerPurpose_EXTERNAL_TOKEN_SIGNER_PURPOSE_AWS_STS_V1 appears only in key rotation.

Verified against the tenant, with a temporary federation policy carrying an inline JWKS: the federated sync matched the client-secret sync exactly, and an expired JWT, a JWT signed by an untrusted key and a missing file are each refused. The policy is deleted.

The exported config schema gave neither workload identity field an export
target, so both reached the hosted web form, and neither works there. A hosted
connector has no file system the tenant admin controls, and a pasted JWT is
never refreshed: Token() asks for a fresh subject token on every exchange, so a
static string returns the same expired JWT once its hour is up. The Hello check
runs while that JWT is still valid, so the configuration validates and the sync
breaks later.

Field groups replace the mutually exclusive and at-least-one constraints. The
client secret is the default and is required again, which the constraints had
forced off. The token file is its own CLI-only group, so hosted no longer
offers it. The static token field is removed: it works in neither mode.

Validation skips any field the selected group does not list, so each group
repeats the common fields; account-id is required and would otherwise stop
being checked. Selecting the file method on the command line needs
--auth-method, which the README now shows.

The JWT lookup moves behind SubjectTokenSource, with the file as its only
implementation. A source that reads from ConductorOne lands when CXE-1557 adds
the minting, and Token() will not change.

Verified against the tenant with a temporary federation policy carrying an
inline JWKS: a locally signed JWT exchanged for a Databricks token, and the
sync through it matched the client-secret sync exactly (322 resources, 279
entitlements, 789 grants). An expired JWT, a JWT signed by an untrusted key and
a missing file are each refused, and restoring the file syncs again, which is
the rotation the source exists for. The policy was deleted afterwards.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor
Superseded — see the current review report for commit 804635124cd4

Connector PR Review: [CXH-2028] - Support workload identity federation - Databricks Connector

Blocking Issues: 0 | Suggestions: 4 | Threads Resolved: 0
Criteria: Criteria status: loaded .claude/skills/ci-review.md from trusted base 0c145865eb23.
Review mode: full
View review run

Review Summary

This PR adds a CLI-only workload-identity-file auth group next to the default client-secret group. A new TokenFederation auth reads a JWT from --databricks-oidc-token-file on every refresh and trades it for a Databricks token at the account token endpoint (RFC 8693). The exchange goes through uhttp.BaseHttpClient, has a 30s timeout, and never sets a zero expiry. NewConnector now re-validates the config against opts.SelectedAuthMethod.

I scanned the whole diff for security and correctness, and checked group handling against the vendored SDK (field.Validate / FieldGroupFields in vendor/.../field/validation.go:413 and struct.go:94). There are no sync or provisioning changes, so S/R7/P rules don't apply. Error codes follow E1/E2: uhttp maps statuses itself, and FailedPrecondition is used only for local and 200-with-no-token failures. No spans or new logs are added (sections A/C). Response structs follow J3 in practice. No go.mod change; no endpoint added beyond the existing token URL. The repo-local criteria loaded and were applied as above.

Security Issues

None found. The subject JWT goes only in the POST form body. Errors include only the file path and the vendor's error description, never the token.

Correctness Issues

None found.

Suggestions

  • New (medium) pkg/connector/connector.go:189: prepareClientAuth picks federation whenever a token file is set and ignores SelectedAuthMethod. Under the default client-secret method, a leftover BATON_DATABRICKS_OIDC_TOKEN_FILE silently switches the credential, even though the docs say passing more than one credential is an error. auth_selection_test.go ("both") locks this behavior in.
  • New (high) docs/connector.mdx:241: the Kubernetes example swaps in BATON_DATABRICKS_OIDC_TOKEN_FILE but never sets BATON_AUTH_METHOD: workload-identity-file. Validation then falls back to the default group and fails on the missing client secret. The comment also still says "one of the token options".
  • New (high) docs/docs-info.md:23: still says the JWT is "supplied as a value or as a file path". The static value option is gone.
  • New (high) PR description: it doesn't match the diff. It describes three mutually exclusive credentials, including --databricks-token, and says the client secret is "no longer marked required". The code has only the file option, uses field groups instead of a mutual-exclusion constraint, and keeps databricks-client-secret WithRequired(true) (tested in config_test.go). Please update the description so QA and release notes match what ships.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `pkg/connector/connector.go`:
- Around line 183-205: prepareClientAuth chooses TokenFederation whenever cfg.DatabricksOidcTokenFile is non-empty, regardless of the selected auth method. Pass opts.SelectedAuthMethod from NewConnector into prepareClientAuth and branch on it ("workload-identity-file" -> TokenFederation, otherwise OAuth2). Update pkg/connector/auth_selection_test.go to match (the "both" case should follow the selected method).

In `docs/connector.mdx`:
- Around line 235-241: In the Kubernetes Secret example, add a commented `BATON_AUTH_METHOD: workload-identity-file` next to BATON_DATABRICKS_OIDC_TOKEN_FILE and say it is required. Without it, validation falls back to the client-secret group. Change "one of the token options" to "the token file".

In `docs/docs-info.md`:
- Around line 23: Replace "supplied as a value or as a file path" with wording that says the JWT is read from a file, and only when the connector is self-hosted (CLI or service mode).

In the PR description:
- Rewrite the Auth/flowchart sections to describe the single token-file option selected with --auth-method workload-identity-file. Remove --databricks-token and the claims about mutual exclusivity and the client secret no longer being required.

Comment thread pkg/connector/connector.go Resolved
Comment thread docs/connector.mdx Resolved
Comment thread docs/docs-info.md Resolved
@github-actions

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor
Superseded — see the current review report for commit 1c442e773664

Connector PR Review: [CXH-2028] - Support workload identity federation - Databricks Connector

Blocking Issues: 0 | Suggestions: 4 | Threads Resolved: 0
Criteria: Criteria status: loaded .claude/skills/ci-review.md from trusted base 0c145865eb23.
Review mode: full
View review run

Review Summary

This PR adds a CLI-only workload-identity-file auth group next to the default client-secret group. A new TokenFederation auth reads a JWT from --databricks-oidc-token-file on every refresh and trades it for a Databricks token at the account token endpoint (RFC 8693). The exchange goes through uhttp.BaseHttpClient, has a 30s timeout, and never sets a zero expiry. NewConnector now re-validates the config against opts.SelectedAuthMethod.

I scanned the whole diff for security and correctness, and checked group handling against the vendored SDK (field.Validate / FieldGroupFields in vendor/.../field/validation.go:413 and struct.go:94). There are no sync or provisioning changes, so S/R7/P rules don't apply. Error codes follow E1/E2: uhttp maps statuses itself, and FailedPrecondition is used only for local and 200-with-no-token failures. No spans or new logs are added (sections A/C). Response structs follow J3 in practice. No go.mod change; no endpoint added beyond the existing token URL. The repo-local criteria loaded and were applied as above.

Security Issues

None found. The subject JWT goes only in the POST form body. Errors include only the file path and the vendor's error description, never the token.

Correctness Issues

None found.

Suggestions

  • New (medium) pkg/connector/connector.go:189: prepareClientAuth picks federation whenever a token file is set and ignores SelectedAuthMethod. Under the default client-secret method, a leftover BATON_DATABRICKS_OIDC_TOKEN_FILE silently switches the credential, even though the docs say passing more than one credential is an error. auth_selection_test.go ("both") locks this behavior in.
  • New (high) docs/connector.mdx:241: the Kubernetes example swaps in BATON_DATABRICKS_OIDC_TOKEN_FILE but never sets BATON_AUTH_METHOD: workload-identity-file. Validation then falls back to the default group and fails on the missing client secret. The comment also still says "one of the token options".
  • New (high) docs/docs-info.md:23: still says the JWT is "supplied as a value or as a file path". The static value option is gone.
  • New (high) PR description: it doesn't match the diff. It describes three mutually exclusive credentials, including --databricks-token, and says the client secret is "no longer marked required". The code has only the file option, uses field groups instead of a mutual-exclusion constraint, and keeps databricks-client-secret WithRequired(true) (tested in config_test.go). Please update the description so QA and release notes match what ships.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `pkg/connector/connector.go`:
- Around line 183-205: prepareClientAuth chooses TokenFederation whenever cfg.DatabricksOidcTokenFile is non-empty, regardless of the selected auth method. Pass opts.SelectedAuthMethod from NewConnector into prepareClientAuth and branch on it ("workload-identity-file" -> TokenFederation, otherwise OAuth2). Update pkg/connector/auth_selection_test.go to match (the "both" case should follow the selected method).

In `docs/connector.mdx`:
- Around line 235-241: In the Kubernetes Secret example, add a commented `BATON_AUTH_METHOD: workload-identity-file` next to BATON_DATABRICKS_OIDC_TOKEN_FILE and say it is required. Without it, validation falls back to the client-secret group. Change "one of the token options" to "the token file".

In `docs/docs-info.md`:
- Around line 23: Replace "supplied as a value or as a file path" with wording that says the JWT is read from a file, and only when the connector is self-hosted (CLI or service mode).

In the PR description:
- Rewrite the Auth/flowchart sections to describe the single token-file option selected with --auth-method workload-identity-file. Remove --databricks-token and the claims about mutual exclusivity and the client secret no longer being required.

Reviewed commit: 804635124cd4

@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 — see the full review report

…edential

prepareClientAuth switched to federation whenever a token file was set, so a
file left over from another deployment replaced the credential the operator
had selected, and validation did not catch it: the file is not in the client
secret group, so that group never checks it. The method is the explicit
choice, so the branch reads it. The group names move to constants that both
the group definitions and the branch share.

The Kubernetes example set BATON_DATABRICKS_OIDC_TOKEN_FILE without
BATON_AUTH_METHOD, which validates against the client secret group and fails
on the missing secret, so copying it produced a deployment that could not
start. Both variables are now shown together.

docs-info.md still described the JWT as a value or a file path, and two lines
still said exactly one of two credentials is supplied. The static value is
gone and the method selects the credential.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor
Superseded — see the current review report for commit 1c442e773664

Connector PR Review: [CXH-2028] - Support workload identity federation - Databricks Connector

Blocking Issues: 0 | Suggestions: 0 | Threads Resolved: 0
Criteria: Criteria status: loaded .claude/skills/ci-review.md from trusted base 0c145865eb23.
Review mode: incremental since 8046351
View review run

Review Summary

The new commit makes the selected auth method choose the credential. prepareClientAuth(cfg, authMethod) (pkg/connector/connector.go:185-205) builds TokenFederation only when the method is workload-identity-file. It gets the same opts.SelectedAuthMethod that field.Validate uses at line 158, so validation and credential choice can no longer disagree. The group names are now shared constants in pkg/config/config.go:9-12. The table test now passes the method and covers a leftover token file or secret under each method, plus the case where no method is selected. The docs drop "exactly one credential", the Kubernetes Secret example adds BATON_AUTH_METHOD: workload-identity-file and says it is required, and docs-info.md drops the "value or file path" wording.

I scanned the full PR diff for security and correctness, including pkg/databricks/auth.go, the token-exchange source:

  • The JWT is read on every exchange.
  • Token() checks the error before defer resp.Body.Close().
  • The exchange call has a 30-second timeout.
  • The exchange runs through uhttp.BaseHttpClient, so HTTP failures keep a gRPC code.
  • A 200 response with an empty token returns FailedPrecondition.
  • An expiry is always set, never the zero time.
  • Nothing logs the JWT.

The repo-local criteria loaded. I applied E1/E2 (error wrapping and codes), H1–H5 (HTTP safety), L-series logging and G1–G3 (config) to the auth and config changes. Section S, provisioning (P/PR) and B10 (API spec drift) do not apply because no sync, provisioning or API endpoint code changed. No resource types or entitlements change, so this is not a breaking change (B1–B9). The PR description now matches the diff: two methods, field groups, and the client secret required inside its own group. The incremental diff was complete, with no dropped paths and no truncation.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

None.

Resolved prior findings

  • Fixed: federation was chosen whenever a token file was set, ignoring the selected method. It now depends only on the method (pkg/connector/connector.go:190). auth_selection_test.go covers a leftover file under the client-secret method and the case with no method selected.
  • Fixed: the Kubernetes example did not set BATON_AUTH_METHOD. docs/connector.mdx:235-244 now includes # BATON_AUTH_METHOD: workload-identity-file, says it is required, and drops "one of the token options".
  • Fixed: docs/docs-info.md:23 claimed the JWT could be supplied "as a value or as a file path". It now says "read from a file", names the selection flag, and drops "Exactly one".
  • Fixed: the PR description did not match the diff. It now describes the two field-group methods, keeps the client secret required in its own group, and no longer mentions --databricks-token.

@github-actions

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Connector PR Review: [CXH-2028] - Support workload identity federation - Databricks Connector

Blocking Issues: 0 | Suggestions: 0 | Threads Resolved: 0
Criteria: Criteria status: loaded .claude/skills/ci-review.md from trusted base 0c145865eb23.
Review mode: incremental since 8046351
View review run

Review Summary

The new commit makes the selected auth method choose the credential. prepareClientAuth(cfg, authMethod) (pkg/connector/connector.go:185-205) builds TokenFederation only when the method is workload-identity-file. It gets the same opts.SelectedAuthMethod that field.Validate uses at line 158, so validation and credential choice can no longer disagree. The group names are now shared constants in pkg/config/config.go:9-12. The table test now passes the method and covers a leftover token file or secret under each method, plus the case where no method is selected. The docs drop "exactly one credential", the Kubernetes Secret example adds BATON_AUTH_METHOD: workload-identity-file and says it is required, and docs-info.md drops the "value or file path" wording.

I scanned the full PR diff for security and correctness, including pkg/databricks/auth.go, the token-exchange source:

  • The JWT is read on every exchange.
  • Token() checks the error before defer resp.Body.Close().
  • The exchange call has a 30-second timeout.
  • The exchange runs through uhttp.BaseHttpClient, so HTTP failures keep a gRPC code.
  • A 200 response with an empty token returns FailedPrecondition.
  • An expiry is always set, never the zero time.
  • Nothing logs the JWT.

The repo-local criteria loaded. I applied E1/E2 (error wrapping and codes), H1–H5 (HTTP safety), L-series logging and G1–G3 (config) to the auth and config changes. Section S, provisioning (P/PR) and B10 (API spec drift) do not apply because no sync, provisioning or API endpoint code changed. No resource types or entitlements change, so this is not a breaking change (B1–B9). The PR description now matches the diff: two methods, field groups, and the client secret required inside its own group. The incremental diff was complete, with no dropped paths and no truncation.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

None.

Resolved prior findings

  • Fixed: federation was chosen whenever a token file was set, ignoring the selected method. It now depends only on the method (pkg/connector/connector.go:190). auth_selection_test.go covers a leftover file under the client-secret method and the case with no method selected.
  • Fixed: the Kubernetes example did not set BATON_AUTH_METHOD. docs/connector.mdx:235-244 now includes # BATON_AUTH_METHOD: workload-identity-file, says it is required, and drops "one of the token options".
  • Fixed: docs/docs-info.md:23 claimed the JWT could be supplied "as a value or as a file path". It now says "read from a file", names the selection flag, and drops "Exactly one".
  • Fixed: the PR description did not match the diff. It now describes the two field-group methods, keeps the client secret required in its own group, and no longer mentions --databricks-token.

Reviewed commit: 1c442e773664

@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 — see the full review report

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.

7 participants