Skip to content

Commit 4cde6be

Browse files
fix
Signed-off-by: Roman Nikitenko <rnikiten@redhat.com>
1 parent dae9b23 commit 4cde6be

3 files changed

Lines changed: 40 additions & 37 deletions

File tree

code/extensions/che-github-authentication/src/github.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,15 +199,28 @@ export class GitHubAuthProvider implements vscode.AuthenticationProvider {
199199
const token = await this.githubService.getToken();
200200
const existingScopes = await this.githubService.getTokenScopes(token);
201201
if (!hasAllScopes(existingScopes, sortedScopes)) {
202-
this.logger.info(`GitHubAuthProvider: token lacks required scopes, starting device flow`);
202+
this.logger.info('GitHubAuthProvider: token lacks required scopes, starting device flow');
203203
return await this.getDeviceAuthentication().runInteractiveFlow(sortedScopes);
204204
}
205+
206+
const isDeviceAuth = await this.githubService.isDeviceAuthToken();
207+
if (!isDeviceAuth) {
208+
const sessions = await this.sessionsPromise;
209+
const hasExistingSession = sessions.some(s =>
210+
sessionMatchesRequestedScopes(s.scopes, sortedScopes)
211+
);
212+
if (hasExistingSession) {
213+
this.logger.info('GitHubAuthProvider: PAT session already exists for requested scopes, starting device auth flow');
214+
return await this.getDeviceAuthentication().runInteractiveFlow(sortedScopes);
215+
}
216+
}
217+
205218
return token;
206219
} catch (error) {
207220
if (isUnauthorizedError(error)) {
208-
this.logger.info(`GitHubAuthProvider: token is not valid, starting device flow`);
221+
this.logger.info('GitHubAuthProvider: token is not valid, starting device flow');
209222
} else {
210-
this.logger.info(`GitHubAuthProvider: no token available, starting device flow`);
223+
this.logger.info('GitHubAuthProvider: no token available, starting device flow');
211224
}
212225
return await this.getDeviceAuthentication().runInteractiveFlow(sortedScopes);
213226
}

code/extensions/copilot/src/platform/authentication/vscode-node/copilotTokenManager.ts

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,6 @@ import { getAnyAuthSession } from './session';
2121
//Flag if we've shown message about broken oauth token.
2222
let shown401Message = false;
2323

24-
const CHE_WORKSPACE_PAT_SCOPE = 'che:workspace-pat';
25-
26-
/** Sessions hydrated from a workspace PAT carry the che:workspace-pat marker scope. */
27-
function isWorkspacePatSession(session: { accessToken: string; scopes: readonly string[] }): boolean {
28-
return session.scopes?.includes(CHE_WORKSPACE_PAT_SCOPE) ||
29-
session.accessToken.startsWith('ghp_') || session.accessToken.startsWith('github_pat_');
30-
}
31-
3224
export class NotSignedUpError extends Error { }
3325
export class SubscriptionExpiredError extends Error { }
3426
export class ContactSupportError extends Error { }
@@ -86,21 +78,19 @@ export class VSCodeCopilotTokenManager extends BaseCopilotTokenManager {
8678
return { kind: 'failure', reason: 'GitHubLoginFailed' };
8779
}
8880
if (session) {
89-
if (isWorkspacePatSession(session)) {
90-
this._logService.info('Copilot token exchange skipped (workspace PAT session detected via scope marker; device authentication is required)');
91-
this._telemetryService.sendGHTelemetryErrorEvent('auth.github_login_failed');
92-
return { kind: 'failure', reason: 'GitHubLoginFailed' };
93-
}
9481
// Log the steps by default, but only log actual token values when the log level is set to debug.
9582
this._logService.info(`Logged in as ${session.account.label}`);
9683
const tokenResult = await this.authFromGitHubToken(session.accessToken, session.account.label);
9784
if (tokenResult.kind === 'success') {
9885
this._logService.info(`Got Copilot token for ${session.account.label}`);
9986
this._logService.info(`Copilot Chat: ${this._envService.getVersion()}, VS Code: ${this._envService.vscodeVersion}`);
100-
} else if (tokenResult.kind === 'failure' && (tokenResult.reason === 'ParseFailed' || tokenResult.reason === 'RequestFailed' || tokenResult.reason === 'NotAuthorized')) {
87+
}
88+
89+
if (tokenResult.kind === 'failure' && tokenResult.reason === 'NotAuthorized' && !tokenResult.notification_id) {
10190
this._logService.info('Copilot token exchange failed (workspace token cannot be exchanged for Copilot token), triggering sign-in flow');
10291
return { kind: 'failure', reason: 'GitHubLoginFailed' };
10392
}
93+
10494
return tokenResult;
10595
} else {
10696
this._logService.info(`Allowing anonymous access with devDeviceId`);

code/src/vs/workbench/contrib/chat/browser/chatSetup/chatSetupContributions.ts

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -136,29 +136,29 @@ export class ChatSetupContribution extends Disposable implements IWorkbenchContr
136136
panelAgentDisposables.dispose();
137137
}
138138
}));
139-
}
139+
}
140140

141-
// Proactively clear panel agents when Copilot reports GitHub login failure
142-
// (e.g. workspace PAT cannot be exchanged for a Copilot token)
143-
const gitHubLoginFailedKey = 'github.copilot.interactiveSession.gitHubLoginFailed';
144-
const checkGitHubLoginFailed = () => {
145-
if (this.contextKeyService.getContextKeyValue<boolean>(gitHubLoginFailedKey)) {
146-
const panelAgentHasGuidance = chatViewsWelcomeRegistry.get().some(descriptor => this.contextKeyService.contextMatchesRules(descriptor.when));
147-
if (panelAgentHasGuidance) {
148-
this.logService.error('[chat setup] GitHub login failed detected, clearing panel agent registration to show welcome view.');
149-
panelAgentDisposables.dispose();
141+
// Proactively clear panel agents when Copilot reports GitHub login failure
142+
// (e.g. workspace PAT cannot be exchanged for a Copilot token)
143+
const gitHubLoginFailedKey = 'github.copilot.interactiveSession.gitHubLoginFailed';
144+
const checkGitHubLoginFailed = () => {
145+
if (this.contextKeyService.getContextKeyValue<boolean>(gitHubLoginFailedKey)) {
146+
const panelAgentHasGuidance = chatViewsWelcomeRegistry.get().some(descriptor => this.contextKeyService.contextMatchesRules(descriptor.when));
147+
if (panelAgentHasGuidance) {
148+
this.logService.error('[chat setup] GitHub login failed detected, clearing panel agent registration to show welcome view.');
149+
panelAgentDisposables.dispose();
150+
}
150151
}
151-
}
152-
};
153-
panelAgentDisposables.add(this.contextKeyService.onDidChangeContext(e => {
154-
if (e.affectsSome(new Set([gitHubLoginFailedKey]))) {
155-
checkGitHubLoginFailed();
156-
}
157-
}));
158-
checkGitHubLoginFailed();
152+
};
153+
panelAgentDisposables.add(this.contextKeyService.onDidChangeContext(e => {
154+
if (e.affectsSome(new Set([gitHubLoginFailedKey]))) {
155+
checkGitHubLoginFailed();
156+
}
157+
}));
158+
checkGitHubLoginFailed();
159159

160-
// Inline Agents
161-
disposables.add(SetupAgent.registerDefaultAgents(this.instantiationService, ChatAgentLocation.Terminal, ChatModeKind.Ask, context, controller).disposable);
160+
// Inline Agents
161+
disposables.add(SetupAgent.registerDefaultAgents(this.instantiationService, ChatAgentLocation.Terminal, ChatModeKind.Ask, context, controller).disposable);
162162
disposables.add(SetupAgent.registerDefaultAgents(this.instantiationService, ChatAgentLocation.Notebook, ChatModeKind.Ask, context, controller).disposable);
163163
disposables.add(SetupAgent.registerDefaultAgents(this.instantiationService, ChatAgentLocation.EditorInline, ChatModeKind.Ask, context, controller).disposable);
164164
}

0 commit comments

Comments
 (0)