Repository navigation
Feat/git integration - #1097
Feat/git integration#1097ddecrulle wants to merge 7 commits into
Conversation
- GitProvider port with GitLab, Forgejo and GitHub adapters (ui: oauth or PAT; service: PAT, scoped-access-token or oauth), GitHub API URL derived from the provider URL - GIT_PROVIDERS env (JSON5), unsupported combinations and duplicate ids refused at startup; empty: integration disabled - OAuthAuthorization port (PKCE in a popup, callback on /git/oauth/callback intercepted in main.tsx before oidc-spa) and GitSessionStore (refresh tokens in localStorage keyed by Keycloak sub, cross tab lock) - gitProvidersManagement usecase: load, OAuth refresh with retry on 401, sign in/out, PATs and favorite in gitConfigStr, one-time migration of the former GitHub PAT - gitAccountUiController usecase for the Account > Git tab (UI not built yet) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A config with initScriptUrl or oauthClientId now says the format changed and points to the .env documentation, instead of dumping the zod issues. Also adds a "web" dev server to .claude/launch.json. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- One card per configured provider: sign in with a popup (OAuth) or a personal access token checked before being saved, sign out (with a link to the authorized applications when the provider can't revoke), favorite provider, documentation; translated in the 9 languages - When GIT_PROVIDERS is set, the former name / email / GitHub token fields are hidden: each card shows its Git identity, the favorite's is used at launch, the Onyxia (Keycloak) account fills what it doesn't give - Launcher: git context from gitProvidersManagement.getGitContext(), git.token is the favorite's PAT; scoped tokens and service OAuth fall back to the former field until phase 3 - A denied OAuth sign-in shows the provider's error_description - GitProviderCard stories; web-mock launch config Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- gitAccountUiController now has a state per card: action in progress, last error, revocation hint, token replacement mode. Its thunks never reject. - Errors are mapped in the core, including Forgejo's "a grant exists with different scope", which now gets an explicit message and a link to revoke the previous authorization on the provider. - The view computes the status, message, git identity, favorite, link to the authorized applications and which buttons are shown or disabled. - GitProviderCard only displays the view; the token being typed stays in a small form component (a secret never goes through the state). - A denied OAuth sign-in keeps the provider's error_description. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
True once at least one Git provider is connected, always true without GIT_PROVIDERS (former behavior), false when personal infos aren't injected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…forge Each connected Git provider gets its commit identity and the credentials the service can use (personal access token, or OAuth config for git-credential-oauth). The single forge fields at the root (name, email, token, credentials_cache_duration) are kept, deprecated, filled from the favorite provider. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 15e151bb3e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| case "scoped-access-token": | ||
| case "oauth": | ||
| return token_legacy; |
There was a problem hiding this comment.
Implement configured service credential modes before accepting them
When the favorite provider uses either accepted scoped-access-token or oauth service authentication—including the documented GitLab example—this branch returns the legacy GitHub PAT instead of invoking createAccessToken or the provider's service authorization. Most users will therefore launch services with no token, while users retaining a legacy GitHub token will receive an unrelated credential that cannot clone their selected provider's repositories. These modes should either provision the configured credentials here or be rejected until that flow exists.
Useful? React with 👍 / 👎.
| try { | ||
| await revokeTokens({ refreshToken: session.refreshToken }); | ||
| } catch { | ||
| // NOTE: Signed out locally anyway, the grant can still be revoked on | ||
| // the provider. | ||
| } |
There was a problem hiding this comment.
Surface failed OAuth revocation to the user
When the provider's revocation request fails because of a network or server error, this catch converts the operation into a successful sign-out even though the grant remains active. The inspected gitAccountUiController.signOut consequently clears the pending action as successful and only shows the manual-revocation link when no revocation function exists, so affected GitLab users receive neither an error nor instructions to revoke the surviving grant.
Useful? React with 👍 / 👎.
| refreshTokens: ({ refreshToken }) => | ||
| requestOAuthTokens({ | ||
| tokenUrl, | ||
| body: { | ||
| grant_type: "refresh_token", | ||
| client_id: clientId, | ||
| refresh_token: refreshToken | ||
| } |
There was a problem hiding this comment.
Include the redirect URI in GitLab refresh requests
For a GitLab OAuth connection, restoring the session after a reload—or refreshing it after the access token expires—uses this body without redirect_uri. GitLab's PKCE refresh flow includes that parameter and requires it to match the URI from the original authorization request, so the real provider rejects this refresh and getOAuthAccessToken deletes the stored session as expired. Preserve the redirect URI and send it with refresh requests as specified by the GitLab OAuth documentation.
Useful? React with 👍 / 👎.
| // TODO(phase 1): Check that these scopes are enforced, older versions ignore them and | ||
| // issue tokens with every right (minimal version to document). | ||
| const UI_SCOPES = ["read:user", "read:repository"]; |
There was a problem hiding this comment.
Reject Forgejo OAuth when scopes are not enforced
On Forgejo versions that ignore OAuth scopes, requesting these apparently read-only scopes still produces a token capable of performing every action for the user, and this integration then persists its refresh token in browser storage. The current Forgejo OAuth documentation explicitly states that OAuth scopes are not implemented and that such tokens can execute any action on the user's behalf. Forgejo OAuth should therefore be refused unless the instance is known to enforce scopes, rather than silently granting substantially broader access than configured.
Useful? React with 👍 / 👎.
| const intervalId = setInterval(() => { | ||
| if (!popup.closed) { | ||
| return; | ||
| } | ||
|
|
There was a problem hiding this comment.
Do not treat a COOP-severed popup as user cancellation
When an authorization page sends Cross-Origin-Opener-Policy: same-origin, the browser can report this popup as closed even though the user is still completing authorization; the interval then rejects the flow after 500 ms instead of relying on the BroadcastChannel callback and overall timeout as the preceding comment proposes. This occurs in GitLab.com's documented Cloudflare managed-challenge OAuth flow, so challenged users cannot sign in even if they successfully finish the provider interaction.
Useful? React with 👍 / 👎.
| export function createGitSessionStore(params: { userSub: string }): GitSessionStore { | ||
| const { userSub } = params; | ||
|
|
||
| const { localStorage } = getLocalStorage(); |
There was a problem hiding this comment.
Preserve startup when local storage access is denied
With Git providers configured, bootstrap always creates this store and calls getLocalStorage; that helper evaluates window.localStorage before entering its try block. Browsers or sandboxed deployments where reading the storage property raises SecurityError therefore abort the entire core bootstrap instead of using the helper's in-memory fallback, making all of Onyxia unavailable rather than merely making Git sessions nonpersistent.
Useful? React with 👍 / 👎.
- getGitContext puts markers in git.token and git.providers for what only exists once "Launch" is clicked: the token of a scoped-access-token provider (and its git username), the access and refresh tokens of the favorite's service OAuth authorization. The fallback to the former GitHub PAT is gone. - getServiceGitCredentials, dispatched synchronously from the click: creates the tokens (onyxia-<service name>, lifetimeDays of the config, refreshed and retried once when rejected) and authorizes the service in a popup opened before anything is awaited. No marker left: nothing created, no popup. - The launcher replaces the markers only in the values sent to the API, the form state, saved configurations and shared links never hold a secret. - Nothing is launched when the credentials can't be obtained: a dialog says why (popup blocked, authorization cancelled or denied, session expired, provider error), translated in the 9 languages. - lifetimeDays on the scoped-access-token service of the GitProvider port. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|



No description provided.