Skip to content

Commit 97706e6

Browse files
Fix: Replace axios with fetch + https fallback in che-api/github-service
Signed-off-by: Roman Nikitenko <rnikiten@redhat.com> Assisted-by: Cursor AI
1 parent f7b1772 commit 97706e6

1 file changed

Lines changed: 61 additions & 0 deletions

File tree

code/extensions/che-api/src/impl/github-service-impl.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
/* eslint-disable header/header */
1212

13+
import * as https from 'https';
1314
import * as k8s from '@kubernetes/client-node';
1415
import * as fs from 'fs-extra';
1516
import { inject, injectable } from 'inversify';
@@ -67,6 +68,28 @@ export class GithubServiceImpl implements GithubService {
6768
}
6869

6970
private async fetchGithubUser(token: string): Promise<{ user: GithubUser; scopes: string[] }> {
71+
try {
72+
this.logger.info('Github Service: fetching GitHub user using fetch...');
73+
const result = await this.fetchGithubUserWithFetch(token);
74+
this.logger.info('Github Service: successfully fetched GitHub user using fetch');
75+
76+
return result;
77+
} catch (fetchError: any) {
78+
this.logger.warn(`Github Service: fetch failed: ${fetchError.message}${fetchError.cause ? ` (cause: ${fetchError.cause.message})` : ''}`);
79+
try {
80+
this.logger.info('Github Service: falling back to https module...');
81+
const result = await this.fetchGithubUserWithHttps(token);
82+
this.logger.info('Github Service: successfully fetched GitHub user using https fallback');
83+
84+
return result;
85+
} catch (httpsError: any) {
86+
this.logger.error(`Github Service: https fallback also failed: ${httpsError.message}`);
87+
throw httpsError;
88+
}
89+
}
90+
}
91+
92+
private async fetchGithubUserWithFetch(token: string): Promise<{ user: GithubUser; scopes: string[] }> {
7093
const response = await fetch('https://api.github.com/user', {
7194
headers: { Authorization: `Bearer ${token}` },
7295
});
@@ -83,6 +106,44 @@ export class GithubServiceImpl implements GithubService {
83106
return { user, scopes };
84107
}
85108

109+
private fetchGithubUserWithHttps(token: string): Promise<{ user: GithubUser; scopes: string[] }> {
110+
return new Promise((resolve, reject) => {
111+
const req = https.request('https://api.github.com/user', {
112+
method: 'GET',
113+
headers: {
114+
'Authorization': `Bearer ${token}`,
115+
'User-Agent': 'che-code',
116+
'Accept': 'application/json',
117+
},
118+
}, (res) => {
119+
const chunks: Buffer[] = [];
120+
res.on('data', (chunk: Buffer) => chunks.push(chunk));
121+
res.on('end', () => {
122+
const body = Buffer.concat(chunks).toString();
123+
if (!res.statusCode || res.statusCode < 200 || res.statusCode >= 300) {
124+
reject(new Error(`GitHub user request failed: ${res.statusCode} ${res.statusMessage} - ${body}`));
125+
return;
126+
}
127+
try {
128+
const user = JSON.parse(body) as GithubUser;
129+
const scopesHeader = res.headers['x-oauth-scopes'] ?? '';
130+
const scopes = (Array.isArray(scopesHeader) ? scopesHeader[0] : scopesHeader)
131+
.split(', ')
132+
.map(scope => scope.trim())
133+
.filter(scope => scope.length > 0);
134+
resolve({ user, scopes });
135+
} catch (err) {
136+
reject(err);
137+
}
138+
});
139+
res.on('error', reject);
140+
});
141+
req.setTimeout(60 * 1000);
142+
req.on('error', reject);
143+
req.end();
144+
});
145+
}
146+
86147
async persistDeviceAuthToken(token: string): Promise<void> {
87148
this.token = token;
88149
this.logger.info(`Github Service: adding token to the device-authentication secret...`);

0 commit comments

Comments
 (0)