Skip to content

feat: GitHub provider lifecycle and onboarding hardening#351

Merged
kevincodex1 merged 8 commits intoGitlawb:mainfrom
Varshith-JV-1410:feat/github-provider-lifecycle
Apr 6, 2026
Merged

feat: GitHub provider lifecycle and onboarding hardening#351
kevincodex1 merged 8 commits intoGitlawb:mainfrom
Varshith-JV-1410:feat/github-provider-lifecycle

Conversation

@Varshith-JV-1410
Copy link
Copy Markdown
Contributor

@Varshith-JV-1410 Varshith-JV-1410 commented Apr 4, 2026

Summary

  • what changed
    • Added GitHub as a virtual provider in Provider Manager for Set and Delete flows only (not Add/Edit).
    • Enforced GitHub-only model options in /model when GitHub provider is active.
    • Deleting GitHub provider now clears stored GitHub credentials and relevant runtime/settings env state.
    • Improved onboarding and provider/profile env interactions, including relogin handling and startup consistency checks.
    • Added regression tests covering GitHub summary/model options, onboarding token/relogin behavior, OAuth scope fallback, and profile env drift handling.
  • why it changed
    • To support the requested GitHub provider lifecycle: onboard -> select -> use model -> delete -> re-onboard cleanly without stale auth/provider state.

Impact

  • user-facing impact:
    • After /onboard-github, GitHub can be selected/deleted in provider management without appearing in Add/Edit provider flows.
    • /model shows only GitHub-appropriate options when GitHub provider is active.
    • Removing GitHub provider clears auth details so users can log in again.
  • developer/maintainer impact:
    • Provider/profile env handling is more robust under restart and mixed-provider transitions.
    • Added focused regression coverage for GitHub provider lifecycle edge cases.

Testing

  • bun run build
  • bun run smoke
  • focused tests:
    • bun test src/commands/provider/provider.test.tsx src/utils/model/modelOptions.github.test.ts src/utils/providerProfiles.test.ts
    • bun test src/commands/onboard-github/onboard-github.test.ts

Notes

  • provider/model path tested:
    • GitHub provider activation/deletion and model options behavior.
    • Onboarding relogin/token detection and device-flow scope fallback behavior.
  • screenshots attached (if UI changed):
    • Not applicable (terminal UI flow changes only).
  • follow-up work or known limitations:
    • none

Copilot AI review requested due to automatic review settings April 4, 2026 16:30
@Varshith-JV-1410 Varshith-JV-1410 changed the title feat: improve GitHub provider onboarding and lifecycle feat: GitHub provider lifecycle and onboarding hardening Apr 4, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR improves GitHub Models onboarding and provider lifecycle handling by integrating GitHub as a “virtual provider” alongside saved provider profiles, tightening model-option behavior while GitHub is active, and adding regression tests around provider/profile env syncing.

Changes:

  • Add GitHub Models lifecycle + onboarding safeguards (device-flow scope fallback, skip onboarding when already logged in unless forced).
  • Improve provider-profile env management (track applied profile ID, safer auto-heal behavior, persist active profile model on /model changes).
  • Enforce GitHub-specific model options/strings behavior and add targeted regression tests.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/utils/providerProfiles.ts Adds profile-applied ID tracking, safer re-apply logic, and persists active profile model updates.
src/utils/providerProfiles.test.ts Adds coverage for env drift auto-heal and persisted model syncing behavior.
src/utils/providerProfile.ts Treats profile-managed env as an explicit provider selection for startup env behavior.
src/utils/providerProfile.test.ts Tests that profile-managed env is preserved during startup env build.
src/utils/model/modelStrings.ts Treats github like openai for builtin model string mapping.
src/utils/model/modelStrings.github.test.ts New tests ensuring GitHub model strings are concrete and parseable.
src/utils/model/modelOptions.ts Restricts model options when GitHub provider is active.
src/utils/model/modelOptions.github.test.ts New tests verifying GitHub-only model options behavior.
src/utils/model/model.ts Ensures GitHub provider reads/uses OPENAI_MODEL for user/default model resolution.
src/state/onChangeAppState.ts Syncs /model changes back into the active provider profile when profile-managed.
src/services/github/deviceFlow.ts Changes default scope to OAuth-safe and retries with fallback scope on invalid_scope.
src/services/github/deviceFlow.test.ts Adds tests for the OAuth-safe default scope and retry behavior.
src/components/ProviderManager.tsx Adds GitHub virtual provider activation/deletion flows and updates provider selection UI.
src/commands/provider/provider.tsx Extends provider summary to recognize GitHub Models mode.
src/commands/provider/provider.test.tsx Adds regression test for GitHub Models provider summary.
src/commands/onboard-github/onboard-github.tsx Adds “already logged in” guard + --force relogin handling; minor copy tweaks.
src/commands/onboard-github/onboard-github.test.ts New tests for relogin arg parsing and token-existence detection.
src/commands/onboard-github/index.ts Adds aliases for the onboard-github command.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/components/ProviderManager.tsx Outdated
Comment thread src/components/ProviderManager.tsx Outdated
Comment thread src/components/ProviderManager.tsx Outdated
@kevincodex1
Copy link
Copy Markdown
Contributor

please address copilots comment

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (1)

src/commands/onboard-github/onboard-github.tsx:64

  • Onboarding enables GitHub mode but does not clear OPENAI_API_KEY from user settings or process.env. If an OpenAI key is present, OpenAI shim GitHub normalization won’t override it (OPENAI_API_KEY ??= …), leading to GitHub requests using the wrong credential. Clear OPENAI_API_KEY when setting CLAUDE_CODE_USE_GITHUB=1 so hydrated GITHUB_TOKEN is actually used.
function mergeUserSettingsEnv(model: string): { ok: boolean; detail?: string } {
  const { error } = updateSettingsForSource('userSettings', {
    env: {
      CLAUDE_CODE_USE_GITHUB: '1',
      OPENAI_MODEL: model,
      CLAUDE_CODE_USE_OPENAI: undefined as any,
      CLAUDE_CODE_USE_GEMINI: undefined as any,
      CLAUDE_CODE_USE_BEDROCK: undefined as any,
      CLAUDE_CODE_USE_VERTEX: undefined as any,
      CLAUDE_CODE_USE_FOUNDRY: undefined as any,
    },
  })

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/components/ProviderManager.tsx
Comment thread src/components/ProviderManager.tsx
Comment thread src/components/ProviderManager.tsx
Comment thread src/components/ProviderManager.tsx Outdated
@Varshith-JV-1410
Copy link
Copy Markdown
Contributor Author

@kevincodex1 Done. Please review and let me know for any changes

@Vasanthdev2004
Copy link
Copy Markdown
Collaborator

fix conflicts

Copilot AI review requested due to automatic review settings April 5, 2026 06:36
@Varshith-JV-1410 Varshith-JV-1410 force-pushed the feat/github-provider-lifecycle branch from ce203ee to e907593 Compare April 5, 2026 06:36
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/utils/githubModelsCredentials.ts
@Varshith-JV-1410
Copy link
Copy Markdown
Contributor Author

@Vasanthdev2004 Fixed conflicts.

Copy link
Copy Markdown
Collaborator

@gnanam1990 gnanam1990 left a comment

Choose a reason for hiding this comment

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

This improves a lot of the GitHub provider lifecycle, but I don't think the onboarding flow is fully hardened yet.

The main gap I still see is onboarding when the user already has OpenAI credentials configured. The finalize path appears able to leave existing OpenAI auth in place, and the shim only hydrates the GitHub token with ??=, so requests can still go out with the wrong key.

Please fix the auth precedence/cleanup in the onboarding finalize path and add a focused test for onboarding with preexisting OpenAI credentials.

Copilot AI review requested due to automatic review settings April 6, 2026 10:40
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +290 to +298
export const call: LocalJSXCommandCall = async (onDone, context, args) => {
const forceRelogin = shouldForceGithubRelogin(args)
if (hasExistingGithubModelsLoginToken() && !forceRelogin) {
onDone(
'Already logged in to GitHub Models. Use /onboard-github --force to re-authenticate.',
{ display: 'system' },
)
return null
}
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

The early return in call short-circuits onboarding whenever any GitHub token exists (env or secure storage). This skips the side effects that /onboard-github currently performs (updating user settings + applying CLAUDE_CODE_USE_GITHUB / OPENAI_MODEL in-process), so users with an existing token can’t use the command to (re)activate GitHub Models mode without --force. Suggest: when a token already exists and --force is not set, still apply the settings/env activation steps and exit with a success message, rather than returning before the component runs.

Copilot uses AI. Check for mistakes.

export function shouldForceGithubRelogin(args?: string): boolean {
const normalized = (args ?? '').trim().toLowerCase()
return FORCE_RELOGIN_ARGS.has(normalized)
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

shouldForceGithubRelogin only returns true when the entire args string exactly matches a single token (e.g. "--force"). Command args are the full string after the command name and may contain multiple words, so /onboard-github --force something would not be treated as force re-login. Consider tokenizing args (whitespace split) and checking whether any arg is in FORCE_RELOGIN_ARGS.

Suggested change
return FORCE_RELOGIN_ARGS.has(normalized)
if (!normalized) {
return false
}
return normalized.split(/\s+/).some(arg => FORCE_RELOGIN_ARGS.has(arg))

Copilot uses AI. Check for mistakes.
Comment on lines +288 to +305
const hydratedTokenInSession = process.env.GITHUB_TOKEN?.trim()
if (
process.env[GITHUB_MODELS_HYDRATED_ENV_MARKER] === '1' &&
hydratedTokenInSession &&
(!storedTokenBeforeClear || hydratedTokenInSession === storedTokenBeforeClear)
) {
delete process.env.GITHUB_TOKEN
}

delete process.env.CLAUDE_CODE_USE_GITHUB
delete process.env[GITHUB_MODELS_HYDRATED_ENV_MARKER]
delete process.env.OPENAI_MODEL
delete process.env.OPENAI_BASE_URL
delete process.env.OPENAI_API_BASE

// Restore active provider profile immediately when one exists.
applyActiveProviderProfileFromConfig()

Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

deleteGithubProvider() clears GITHUB_TOKEN (when hydrated) and some OpenAI env keys, but it doesn’t clear OPENAI_API_KEY. Since createOpenAIShimClient sets OPENAI_API_KEY from the GitHub token in GitHub mode, deleting GitHub can leave OPENAI_API_KEY pointing at the GitHub token when there is no active provider profile to immediately re-apply. Consider clearing OPENAI_API_KEY (and related OpenAI auth env like org/project if present) as part of GitHub provider deletion when GitHub mode is being turned off.

Copilot uses AI. Check for mistakes.
@Varshith-JV-1410 Varshith-JV-1410 force-pushed the feat/github-provider-lifecycle branch from 9ad57bb to a318975 Compare April 6, 2026 10:51
Copilot AI review requested due to automatic review settings April 6, 2026 11:01
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 30 to 41
export function hydrateGithubModelsTokenFromSecureStorage(): void {
if (!isEnvTruthy(process.env.CLAUDE_CODE_USE_GITHUB)) {
delete process.env[GITHUB_MODELS_HYDRATED_ENV_MARKER]
return
}
if (process.env.GITHUB_TOKEN?.trim() || process.env.GH_TOKEN?.trim()) {
if (process.env.GH_TOKEN?.trim()) {
delete process.env[GITHUB_MODELS_HYDRATED_ENV_MARKER]
return
}
if (process.env.GITHUB_TOKEN?.trim()) {
delete process.env[GITHUB_MODELS_HYDRATED_ENV_MARKER]
return
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

hydrateGithubModelsTokenFromSecureStorage() always deletes CLAUDE_CODE_GITHUB_TOKEN_HYDRATED when GITHUB_TOKEN is already set. Since createOpenAIShimClient() calls this hydrator on every client creation, a token that was hydrated from secure storage will typically lose its marker on the next call, making it indistinguishable from a user-provided token. This breaks later cleanup logic that relies on the marker (e.g., ProviderManager’s GitHub delete flow) and can leave hydrated tokens in process.env after deleting the GitHub provider. Consider preserving the marker when it is already set (or re-deriving it by comparing against secure storage) so it remains stable for the session, or adjust the delete logic to not depend on a marker that can be cleared by subsequent hydration calls.

Copilot uses AI. Check for mistakes.
Comment on lines +115 to +119
// Keep active provider profiles in sync with /model choices so restarts
// keep using the last selected model instead of the profile's old default.
if (process.env.CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED === '1') {
persistActiveProviderProfileModel(newState.mainLoopModel)
}
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

The profile-model sync on /model changes only checks CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED === '1' before persisting into the active provider profile. Since this PR introduced CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED_ID to disambiguate which profile applied the env, it’s possible to persist the model into the wrong profile if the applied flag is stale or the active profile changed. Consider also validating CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED_ID against the current active profile (or moving that validation into persistActiveProviderProfileModel() before mutating config).

Copilot uses AI. Check for mistakes.
Comment on lines +290 to +292
process.env[GITHUB_MODELS_HYDRATED_ENV_MARKER] === '1' &&
hydratedTokenInSession &&
(!storedTokenBeforeClear || hydratedTokenInSession === storedTokenBeforeClear)
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

deleteGithubProvider() only clears process.env.GITHUB_TOKEN when CLAUDE_CODE_GITHUB_TOKEN_HYDRATED === '1'. With the current hydrator behavior, this marker is often cleared on subsequent hydrator calls once GITHUB_TOKEN exists, so GitHub provider deletion can leave the hydrated token in the running process env. Consider basing this cleanup on a more stable signal (e.g., comparing the current env token to the stored token captured before clearing, and/or keeping the hydrated marker stable for the session).

Suggested change
process.env[GITHUB_MODELS_HYDRATED_ENV_MARKER] === '1' &&
hydratedTokenInSession &&
(!storedTokenBeforeClear || hydratedTokenInSession === storedTokenBeforeClear)
storedTokenBeforeClear &&
hydratedTokenInSession &&
hydratedTokenInSession === storedTokenBeforeClear

Copilot uses AI. Check for mistakes.
@gnanam1990
Copy link
Copy Markdown
Collaborator

I have been involved in the latest fixes on this branch, so I should not be the final approver here. The remaining step should be an independent review from another maintainer/collaborator before merge.

Copy link
Copy Markdown
Collaborator

@Vasanthdev2004 Vasanthdev2004 left a comment

Choose a reason for hiding this comment

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

Rechecked the latest head 446e112bc4c6476960ea831ac4c472690520eecb against current origin/main.

The earlier auth-precedence blocker is fixed on this revision, and I did not find a remaining branch-specific correctness blocker.

What I verified on this head:

  • onboarding activation now clears preexisting OpenAI auth state before enabling GitHub mode
    • direct helper repro via buildGithubOnboardingSettingsEnv() / applyGithubOnboardingProcessEnv() clears:
      • OPENAI_API_KEY
      • OPENAI_ORG
      • OPENAI_PROJECT
      • OPENAI_ORGANIZATION
      • OPENAI_BASE_URL
      • OPENAI_API_BASE
    • and sets:
      • CLAUDE_CODE_USE_GITHUB=1
      • OPENAI_MODEL=github:copilot
  • existing-token onboarding path now activates GitHub mode instead of just bailing out
  • force relogin parsing now handles multi-word args (foo --force bar, abc reauth xyz, etc.)
  • focused lifecycle coverage passes:
    • bun test src/commands/onboard-github/onboard-github.test.ts src/commands/provider/provider.test.tsx src/utils/providerProfile.test.ts src/utils/providerProfiles.test.ts src/utils/model/modelOptions.github.test.ts src/utils/model/modelStrings.github.test.ts src/services/github/deviceFlow.test.ts src/utils/githubModelsCredentials.hydrate.test.ts -> 85 pass
  • bun run build -> success
  • bun run smoke -> success

Residual risk is mostly ergonomics rather than a demonstrated bug: the GitHub virtual provider still relies on some synchronous secure-storage reads for availability/summary state in ProviderManager, and there still is no full component-level test of the virtual provider UI flow itself. But the current head does address the GitHub lifecycle/auth issues that were blocking the earlier review.

Copy link
Copy Markdown
Contributor

@kevincodex1 kevincodex1 left a comment

Choose a reason for hiding this comment

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

Alright this is good

@kevincodex1 kevincodex1 merged commit ff7d499 into Gitlawb:main Apr 6, 2026
3 of 4 checks passed

This comment was marked as off-topic.

Vasanthdev2004

This comment was marked as off-topic.

euxaristia pushed a commit to euxaristia/openclaude that referenced this pull request Apr 13, 2026
* feat: improve GitHub provider onboarding and lifecycle

* fix: address copilot review in provider manager

* fix: address follow-up copilot review comments

* test: resolve rebase conflict in provider profiles suite

* fix: clear stale github hydrated marker

* fix: harden github onboarding auth precedence

* fix: remove merge markers from provider tests

* fix: resolve latest copilot onboarding comments

---------

Co-authored-by: KRATOS <84986124+gnanam1990@users.noreply.github.com>
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.

5 participants