Skip to content

Feat/git integration - #1097

Draft
ddecrulle wants to merge 7 commits into
mainfrom
feat/git-integration
Draft

ddecrulle wants to merge 7 commits into
mainfrom
feat/git-integration

Conversation

@ddecrulle

Copy link
Copy Markdown
Member

No description provided.

ddecrulle and others added 6 commits October 19, 2026 10:22
- 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>
@coderabbitai

coderabbitai Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 40b23b49-0a4f-40a4-9d0b-c163fa8090e1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-21T13:58:04.130288Z 15e151b PR opened
🔒 Security Review ✅ Completed 2026-10-21T13:55:02.220720Z 15e151b PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@ddecrulle
ddecrulle marked this pull request as draft October 21, 2026 13:51

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 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".

Comment on lines +457 to +459
case "scoped-access-token":
case "oauth":
return token_legacy;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge 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 👍 / 👎.

Comment on lines +289 to +294
try {
await revokeTokens({ refreshToken: session.refreshToken });
} catch {
// NOTE: Signed out locally anyway, the grant can still be revoked on
// the provider.
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge 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 👍 / 👎.

Comment on lines +164 to +171
refreshTokens: ({ refreshToken }) =>
requestOAuthTokens({
tokenUrl,
body: {
grant_type: "refresh_token",
client_id: clientId,
refresh_token: refreshToken
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge 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 👍 / 👎.

Comment on lines +15 to +17
// 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"];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge 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 👍 / 👎.

Comment on lines +129 to +133
const intervalId = setInterval(() => {
if (!popup.closed) {
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge 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();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge 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>
@sonarqubecloud

Copy link
Copy Markdown

This branch has not been deployed

No deployments
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