Skip to content

fix(dashboard): allow deleting SCM identities with slash in provider key#156

Merged
coopernetes merged 1 commit intomainfrom
fix/scm-identity-delete-provider-slash
Apr 15, 2026
Merged

fix(dashboard): allow deleting SCM identities with slash in provider key#156
coopernetes merged 1 commit intomainfrom
fix/scm-identity-delete-provider-slash

Conversation

@coopernetes
Copy link
Copy Markdown
Owner

Summary

  • Fixes Failed to remove SCM identity (HTTP 400) when the provider ID contains a / (e.g. github/<host> for a GHES deployment).
  • Root cause: GitProxyProvider.getProviderId() synthesizes {type}/{host}. When embedded in a DELETE URL path, the / encodes to %2F and Spring Security's default StrictHttpFirewall rejects the request with HTTP 400 before the controller runs — so the store-layer LockedByConfigException path and hooks never get a chance.
  • Fix: swap /@ at the URL boundary only. Frontend's providerToPathKey() encodes /@ on the way out; ProfileController / UserController reverse it before calling the user store. @ is legal in URL path segments (RFC 3986 sub-delims) and never appears in DNS hostnames, so the mapping is unambiguous.
  • Internal format is unchanged: DB (user_scm_identities.provider), token cache keys, permissions, and all core code still see {type}/{host}. No migration needed.

Affects:

  • DELETE /api/me/identities/{provider}/{scmUsername}
  • DELETE /api/users/{u}/identities/{provider}/{scmUsername}

Also folds in an unrelated Dockerfile doc fix (config profile example) and a palantir-format reflow in SecurityConfig.java that were sitting in the working tree.

Test plan

  • Start dashboard against an h2-file DB with a GHES-style provider configured (type github, non-default host).
  • From the Profile page, add a bogus SCM identity for that provider; verify it appears.
  • Remove the identity; verify it disappears without the HTTP 400 error.
  • Repeat via the admin Users page (UserController route) to cover both endpoints.
  • Confirm identities for providers without a host component (e.g. default github/github.com) still remove cleanly — ensures the @ swap doesn't break the common case.

Provider IDs are internally `{type}/{host}` (e.g. `github/github.corp.example.com`).
When embedded in a URL path, the `/` encodes to `%2F` and Spring Security's
default StrictHttpFirewall rejects the request with HTTP 400 before the
controller runs, leaving the user with an unusable "Failed to remove SCM
identity (HTTP 400)" error.

Swap `/` for `@` at the URL boundary only — frontend encodes it on the way
out, controllers decode it on the way in. Internal format (DB, token cache,
permissions, logging) is unchanged. `@` is legal in URL path segments and
never appears in DNS hostnames, so the mapping is unambiguous.

Affects `DELETE /api/me/identities/{provider}/{scmUsername}` and
`DELETE /api/users/{u}/identities/{provider}/{scmUsername}`.
@coopernetes coopernetes force-pushed the fix/scm-identity-delete-provider-slash branch from dc51ef7 to 088ef44 Compare April 15, 2026 15:21
@coopernetes coopernetes enabled auto-merge (squash) April 15, 2026 15:23
@coopernetes coopernetes merged commit 6b89f4e into main Apr 15, 2026
11 checks passed
@coopernetes coopernetes deleted the fix/scm-identity-delete-provider-slash branch April 15, 2026 15:24
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.

1 participant