@theia/ai-copilot 1.76.0-next.4 → 1.76.0-next.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/README.md +87 -14
  2. package/lib/browser/copilot-auth-dialog.d.ts.map +1 -1
  3. package/lib/browser/copilot-auth-dialog.js +19 -11
  4. package/lib/browser/copilot-auth-dialog.js.map +1 -1
  5. package/lib/browser/copilot-frontend-application-contribution.d.ts +21 -1
  6. package/lib/browser/copilot-frontend-application-contribution.d.ts.map +1 -1
  7. package/lib/browser/copilot-frontend-application-contribution.js +129 -26
  8. package/lib/browser/copilot-frontend-application-contribution.js.map +1 -1
  9. package/lib/common/copilot-auth-service.d.ts +27 -24
  10. package/lib/common/copilot-auth-service.d.ts.map +1 -1
  11. package/lib/common/copilot-language-models-manager.d.ts +6 -22
  12. package/lib/common/copilot-language-models-manager.d.ts.map +1 -1
  13. package/lib/common/copilot-language-models-manager.js +1 -13
  14. package/lib/common/copilot-language-models-manager.js.map +1 -1
  15. package/lib/common/copilot-preferences.d.ts +1 -0
  16. package/lib/common/copilot-preferences.d.ts.map +1 -1
  17. package/lib/common/copilot-preferences.js +24 -6
  18. package/lib/common/copilot-preferences.js.map +1 -1
  19. package/lib/common/index.d.ts +0 -1
  20. package/lib/common/index.d.ts.map +1 -1
  21. package/lib/common/index.js +0 -1
  22. package/lib/common/index.js.map +1 -1
  23. package/lib/node/copilot-auth-service-impl.d.ts +25 -16
  24. package/lib/node/copilot-auth-service-impl.d.ts.map +1 -1
  25. package/lib/node/copilot-auth-service-impl.js +67 -183
  26. package/lib/node/copilot-auth-service-impl.js.map +1 -1
  27. package/lib/node/copilot-auth-service-impl.spec.js +104 -168
  28. package/lib/node/copilot-auth-service-impl.spec.js.map +1 -1
  29. package/lib/node/copilot-backend-module.d.ts.map +1 -1
  30. package/lib/node/copilot-backend-module.js +10 -2
  31. package/lib/node/copilot-backend-module.js.map +1 -1
  32. package/lib/node/copilot-cli-auth-provider.d.ts +146 -0
  33. package/lib/node/copilot-cli-auth-provider.d.ts.map +1 -0
  34. package/lib/node/copilot-cli-auth-provider.js +430 -0
  35. package/lib/node/copilot-cli-auth-provider.js.map +1 -0
  36. package/lib/node/copilot-cli-auth-provider.spec.d.ts +2 -0
  37. package/lib/node/copilot-cli-auth-provider.spec.d.ts.map +1 -0
  38. package/lib/node/copilot-cli-auth-provider.spec.js +249 -0
  39. package/lib/node/copilot-cli-auth-provider.spec.js.map +1 -0
  40. package/lib/node/copilot-cli-locator.d.ts +120 -0
  41. package/lib/node/copilot-cli-locator.d.ts.map +1 -0
  42. package/lib/node/copilot-cli-locator.js +348 -0
  43. package/lib/node/copilot-cli-locator.js.map +1 -0
  44. package/lib/node/copilot-cli-locator.spec.d.ts +2 -0
  45. package/lib/node/copilot-cli-locator.spec.d.ts.map +1 -0
  46. package/lib/node/copilot-cli-locator.spec.js +327 -0
  47. package/lib/node/copilot-cli-locator.spec.js.map +1 -0
  48. package/lib/node/copilot-credential-store.d.ts +45 -0
  49. package/lib/node/copilot-credential-store.d.ts.map +1 -0
  50. package/lib/node/copilot-credential-store.js +96 -0
  51. package/lib/node/copilot-credential-store.js.map +1 -0
  52. package/lib/node/copilot-credential-store.spec.d.ts +2 -0
  53. package/lib/node/copilot-credential-store.spec.d.ts.map +1 -0
  54. package/lib/node/copilot-credential-store.spec.js +93 -0
  55. package/lib/node/copilot-credential-store.spec.js.map +1 -0
  56. package/lib/node/copilot-language-models-manager-impl.d.ts +44 -20
  57. package/lib/node/copilot-language-models-manager-impl.d.ts.map +1 -1
  58. package/lib/node/copilot-language-models-manager-impl.js +112 -65
  59. package/lib/node/copilot-language-models-manager-impl.js.map +1 -1
  60. package/lib/node/copilot-language-models-manager-impl.spec.d.ts +2 -0
  61. package/lib/node/copilot-language-models-manager-impl.spec.d.ts.map +1 -0
  62. package/lib/node/copilot-language-models-manager-impl.spec.js +162 -0
  63. package/lib/node/copilot-language-models-manager-impl.spec.js.map +1 -0
  64. package/lib/node/copilot-runtime-env.d.ts +20 -0
  65. package/lib/node/copilot-runtime-env.d.ts.map +1 -0
  66. package/lib/node/copilot-runtime-env.js +49 -0
  67. package/lib/node/copilot-runtime-env.js.map +1 -0
  68. package/lib/node/copilot-sdk-client-provider.d.ts +103 -0
  69. package/lib/node/copilot-sdk-client-provider.d.ts.map +1 -0
  70. package/lib/node/copilot-sdk-client-provider.js +247 -0
  71. package/lib/node/copilot-sdk-client-provider.js.map +1 -0
  72. package/lib/node/copilot-sdk-client-provider.spec.d.ts +2 -0
  73. package/lib/node/copilot-sdk-client-provider.spec.d.ts.map +1 -0
  74. package/lib/node/copilot-sdk-client-provider.spec.js +215 -0
  75. package/lib/node/copilot-sdk-client-provider.spec.js.map +1 -0
  76. package/lib/node/copilot-sdk-language-model.d.ts +85 -0
  77. package/lib/node/copilot-sdk-language-model.d.ts.map +1 -0
  78. package/lib/node/copilot-sdk-language-model.js +301 -0
  79. package/lib/node/copilot-sdk-language-model.js.map +1 -0
  80. package/lib/node/copilot-sdk-language-model.spec.d.ts +2 -0
  81. package/lib/node/copilot-sdk-language-model.spec.d.ts.map +1 -0
  82. package/lib/node/copilot-sdk-language-model.spec.js +315 -0
  83. package/lib/node/copilot-sdk-language-model.spec.js.map +1 -0
  84. package/lib/node/copilot-sdk-loader.d.ts +57 -0
  85. package/lib/node/copilot-sdk-loader.d.ts.map +1 -0
  86. package/lib/node/copilot-sdk-loader.js +133 -0
  87. package/lib/node/copilot-sdk-loader.js.map +1 -0
  88. package/lib/node/copilot-sdk-loader.spec.d.ts +2 -0
  89. package/lib/node/copilot-sdk-loader.spec.d.ts.map +1 -0
  90. package/lib/node/copilot-sdk-loader.spec.js +113 -0
  91. package/lib/node/copilot-sdk-loader.spec.js.map +1 -0
  92. package/lib/node/copilot-sdk-mappers.d.ts +54 -0
  93. package/lib/node/copilot-sdk-mappers.d.ts.map +1 -0
  94. package/lib/node/copilot-sdk-mappers.js +158 -0
  95. package/lib/node/copilot-sdk-mappers.js.map +1 -0
  96. package/lib/node/copilot-sdk-mappers.spec.d.ts +2 -0
  97. package/lib/node/copilot-sdk-mappers.spec.d.ts.map +1 -0
  98. package/lib/node/copilot-sdk-mappers.spec.js +168 -0
  99. package/lib/node/copilot-sdk-mappers.spec.js.map +1 -0
  100. package/lib/node/copilot-sdk-types.d.ts +208 -0
  101. package/lib/node/copilot-sdk-types.d.ts.map +1 -0
  102. package/lib/{common/copilot-oauth-config.js → node/copilot-sdk-types.js} +2 -13
  103. package/lib/node/copilot-sdk-types.js.map +1 -0
  104. package/lib/node/index.d.ts +9 -1
  105. package/lib/node/index.d.ts.map +1 -1
  106. package/lib/node/index.js +9 -1
  107. package/lib/node/index.js.map +1 -1
  108. package/package.json +4 -6
  109. package/src/browser/copilot-auth-dialog.tsx +20 -16
  110. package/src/browser/copilot-frontend-application-contribution.ts +144 -31
  111. package/src/common/copilot-auth-service.ts +28 -24
  112. package/src/common/copilot-language-models-manager.ts +6 -29
  113. package/src/common/copilot-preferences.ts +24 -5
  114. package/src/common/index.ts +0 -1
  115. package/src/node/copilot-auth-service-impl.spec.ts +122 -207
  116. package/src/node/copilot-auth-service-impl.ts +63 -218
  117. package/src/node/copilot-backend-module.ts +11 -2
  118. package/src/node/copilot-cli-auth-provider.spec.ts +315 -0
  119. package/src/node/copilot-cli-auth-provider.ts +444 -0
  120. package/src/node/copilot-cli-locator.spec.ts +386 -0
  121. package/src/node/copilot-cli-locator.ts +363 -0
  122. package/src/node/copilot-credential-store.spec.ts +106 -0
  123. package/src/node/copilot-credential-store.ts +99 -0
  124. package/src/node/copilot-language-models-manager-impl.spec.ts +188 -0
  125. package/src/node/copilot-language-models-manager-impl.ts +131 -84
  126. package/src/node/copilot-runtime-env.ts +46 -0
  127. package/src/node/copilot-sdk-client-provider.spec.ts +253 -0
  128. package/src/node/copilot-sdk-client-provider.ts +241 -0
  129. package/src/node/copilot-sdk-language-model.spec.ts +377 -0
  130. package/src/node/copilot-sdk-language-model.ts +330 -0
  131. package/src/node/copilot-sdk-loader.spec.ts +126 -0
  132. package/src/node/copilot-sdk-loader.ts +142 -0
  133. package/src/node/copilot-sdk-mappers.spec.ts +190 -0
  134. package/src/node/copilot-sdk-mappers.ts +172 -0
  135. package/src/node/copilot-sdk-types.ts +290 -0
  136. package/src/node/index.ts +9 -1
  137. package/lib/common/copilot-oauth-config.d.ts +0 -33
  138. package/lib/common/copilot-oauth-config.d.ts.map +0 -1
  139. package/lib/common/copilot-oauth-config.js.map +0 -1
  140. package/lib/node/copilot-language-model.d.ts +0 -34
  141. package/lib/node/copilot-language-model.d.ts.map +0 -1
  142. package/lib/node/copilot-language-model.js +0 -236
  143. package/lib/node/copilot-language-model.js.map +0 -1
  144. package/lib/node/copilot-language-model.spec.d.ts +0 -2
  145. package/lib/node/copilot-language-model.spec.d.ts.map +0 -1
  146. package/lib/node/copilot-language-model.spec.js +0 -89
  147. package/lib/node/copilot-language-model.spec.js.map +0 -1
  148. package/src/common/copilot-oauth-config.ts +0 -55
  149. package/src/node/copilot-language-model.spec.ts +0 -106
  150. package/src/node/copilot-language-model.ts +0 -273
@@ -19,223 +19,107 @@ exports.CopilotAuthServiceImpl = void 0;
19
19
  const tslib_1 = require("tslib");
20
20
  const inversify_1 = require("@theia/core/shared/inversify");
21
21
  const core_1 = require("@theia/core");
22
- const key_store_1 = require("@theia/core/lib/common/key-store");
23
- const copilot_oauth_config_1 = require("../common/copilot-oauth-config");
24
- const COPILOT_SCOPE = 'read:user';
25
- const COPILOT_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:device_code';
22
+ const copilot_cli_auth_provider_1 = require("./copilot-cli-auth-provider");
23
+ const copilot_cli_locator_1 = require("./copilot-cli-locator");
24
+ const copilot_credential_store_1 = require("./copilot-credential-store");
26
25
  /**
27
- * Maximum number of polling attempts for token retrieval.
28
- * With a default 5-second interval, this allows approximately 5 minutes of polling.
29
- */
30
- const MAX_POLLING_ATTEMPTS = 60;
31
- /**
32
- * Backend implementation of the GitHub Copilot OAuth Device Flow authentication service.
33
- * Handles device code generation, token polling, and credential storage.
26
+ * Backend implementation of the GitHub Copilot authentication service.
27
+ *
28
+ * All Copilot requests are served by the official Copilot CLI, which owns its credentials, so this
29
+ * service only drives the sign-in of the CLI and reports its state, see {@link CopilotCliAuthProvider}.
34
30
  */
35
31
  let CopilotAuthServiceImpl = class CopilotAuthServiceImpl {
36
32
  constructor() {
33
+ this.migrationRequired = false;
37
34
  this.onAuthStateChangedEmitter = new core_1.Emitter();
38
35
  this.onAuthStateChanged = this.onAuthStateChangedEmitter.event;
39
36
  }
37
+ init() {
38
+ // The previous integration signed in with an OAuth application of its own and stored a token
39
+ // that is of no use here. Remove it instead of leaving it on the machine of the user.
40
+ this.legacyCleanup = this.credentialStore.deleteLegacy().then(async (removed) => {
41
+ this.migrationRequired = removed;
42
+ if (removed) {
43
+ this.logger.info('Copilot: discarded the sign-in of the previous integration, a new sign-in is required.');
44
+ this.updateAuthState(await this.computeAuthState());
45
+ }
46
+ }, error => this.logger.warn('Copilot: failed to clean up the previous sign-in:', error));
47
+ }
40
48
  setClient(client) {
41
49
  this.client = client;
42
50
  }
43
- getOAuthEndpoints(enterpriseUrl) {
44
- if (enterpriseUrl) {
45
- const domain = enterpriseUrl
46
- .replace(/^https?:\/\//, '')
47
- .replace(/\/$/, '');
48
- return {
49
- deviceCodeUrl: `https://${domain}/login/device/code`,
50
- accessTokenUrl: `https://${domain}/login/oauth/access_token`
51
- };
52
- }
53
- return {
54
- deviceCodeUrl: 'https://github.com/login/device/code',
55
- accessTokenUrl: 'https://github.com/login/oauth/access_token'
56
- };
51
+ async setExecutablePath(path) {
52
+ this.cliLocator.setConfiguredPath(path);
57
53
  }
58
- async initiateDeviceFlow(enterpriseUrl) {
59
- const endpoints = this.getOAuthEndpoints(enterpriseUrl);
60
- const response = await fetch(endpoints.deviceCodeUrl, {
61
- method: 'POST',
62
- headers: {
63
- 'Accept': 'application/json',
64
- 'Content-Type': 'application/json',
65
- 'User-Agent': this.oauthConfig.userAgent
66
- },
67
- body: JSON.stringify({
68
- client_id: this.oauthConfig.clientId,
69
- scope: COPILOT_SCOPE
70
- })
71
- });
72
- if (!response.ok) {
73
- const errorText = await response.text();
74
- throw new Error(`Failed to initiate device authorization: ${response.status} - ${errorText}`);
75
- }
76
- const data = await response.json();
77
- return data;
54
+ async startSignIn(enterpriseUrl) {
55
+ return this.cliAuthProvider.startLogin(enterpriseUrl);
78
56
  }
79
- async pollForToken(deviceCode, interval, enterpriseUrl) {
80
- const endpoints = this.getOAuthEndpoints(enterpriseUrl);
81
- let attempts = 0;
82
- while (attempts < MAX_POLLING_ATTEMPTS) {
83
- await this.delay(interval * 1000);
84
- attempts++;
85
- const response = await fetch(endpoints.accessTokenUrl, {
86
- method: 'POST',
87
- headers: {
88
- 'Accept': 'application/json',
89
- 'Content-Type': 'application/json',
90
- 'User-Agent': this.oauthConfig.userAgent
91
- },
92
- body: JSON.stringify({
93
- client_id: this.oauthConfig.clientId,
94
- device_code: deviceCode,
95
- grant_type: COPILOT_GRANT_TYPE
96
- })
97
- });
98
- if (!response.ok) {
99
- this.logger.error(`Token request failed: ${response.status}`);
100
- continue;
101
- }
102
- const data = await response.json();
103
- if (data.access_token) {
104
- // Get user info for account label
105
- const accountLabel = await this.fetchAccountLabel(data.access_token, enterpriseUrl);
106
- // Store credentials
107
- const credentials = {
108
- accessToken: data.access_token,
109
- accountLabel,
110
- enterpriseUrl
111
- };
112
- await this.keyStoreService.setPassword(this.oauthConfig.keystoreService, this.oauthConfig.keystoreAccount, JSON.stringify(credentials));
113
- // Update cached state and notify
114
- const newState = {
115
- isAuthenticated: true,
116
- accountLabel,
117
- enterpriseUrl
118
- };
119
- this.updateAuthState(newState);
120
- return true;
121
- }
122
- if (data.error === 'authorization_pending') {
123
- // User hasn't authorized yet, continue polling
124
- continue;
125
- }
126
- if (data.error === 'slow_down') {
127
- // Increase polling interval
128
- interval += 5;
129
- continue;
130
- }
131
- if (data.error === 'expired_token' || data.error === 'access_denied') {
132
- this.logger.error(`Authorization failed: ${data.error} - ${data.error_description}`);
133
- return false;
134
- }
135
- if (data.error) {
136
- this.logger.error(`Unexpected error: ${data.error} - ${data.error_description}`);
137
- return false;
138
- }
57
+ async waitForSignIn() {
58
+ const success = await this.cliAuthProvider.waitForLogin();
59
+ if (success) {
60
+ this.cachedState = undefined;
61
+ this.updateAuthState(await this.cliAuthProvider.getAuthState());
139
62
  }
140
- return false;
63
+ return success;
141
64
  }
142
- async fetchAccountLabel(accessToken, enterpriseUrl) {
143
- try {
144
- const apiBaseUrl = enterpriseUrl
145
- ? `https://${enterpriseUrl.replace(/^https?:\/\//, '').replace(/\/$/, '')}/api/v3`
146
- : 'https://api.github.com';
147
- const response = await fetch(`${apiBaseUrl}/user`, {
148
- headers: {
149
- 'Authorization': `Bearer ${accessToken}`,
150
- 'User-Agent': this.oauthConfig.userAgent,
151
- 'Accept': 'application/vnd.github.v3+json'
152
- }
153
- });
154
- if (response.ok) {
155
- const userData = await response.json();
156
- return userData.login;
157
- }
158
- }
159
- catch (error) {
160
- this.logger.warn('Failed to fetch GitHub user info:', error);
161
- }
162
- return undefined;
65
+ async cancelSignIn() {
66
+ await this.cliAuthProvider.cancelLogin();
67
+ }
68
+ async signOut() {
69
+ await this.cliAuthProvider.signOut();
70
+ this.cachedState = undefined;
71
+ this.updateAuthState(await this.getAuthState());
163
72
  }
164
73
  async getAuthState() {
165
- if (this.cachedState) {
166
- return this.cachedState;
167
- }
168
- try {
169
- const stored = await this.keyStoreService.getPassword(this.oauthConfig.keystoreService, this.oauthConfig.keystoreAccount);
170
- if (stored) {
171
- const credentials = JSON.parse(stored);
172
- // Tokens from the current OAuth App start with 'gho_'; other prefixes (e.g. 'ghu_') indicate a token from the previous GitHub App (Iv-prefixed client ID).
173
- if (!credentials.accessToken.startsWith('gho_')) {
174
- this.logger.info('Copilot: clearing outdated GitHub App token. Please sign in again.');
175
- await this.keyStoreService.deletePassword(this.oauthConfig.keystoreService, this.oauthConfig.keystoreAccount);
176
- this.cachedState = { isAuthenticated: false, migrationRequired: true };
177
- return this.cachedState;
178
- }
179
- this.cachedState = {
180
- isAuthenticated: true,
181
- accountLabel: credentials.accountLabel,
182
- enterpriseUrl: credentials.enterpriseUrl
183
- };
184
- return this.cachedState;
185
- }
186
- }
187
- catch (error) {
188
- this.logger.warn('Failed to retrieve Copilot credentials:', error);
74
+ // Awaited so that a state requested early cannot be cached without the migration flag, which
75
+ // is the only thing that tells the user why they were signed out. The frontend evaluates it
76
+ // once at startup, so losing it there means losing it altogether.
77
+ await this.legacyCleanup;
78
+ if (!this.cachedState) {
79
+ this.cachedState = await this.computeAuthState();
189
80
  }
190
- this.cachedState = { isAuthenticated: false };
191
81
  return this.cachedState;
192
82
  }
193
- async getAccessToken() {
194
- try {
195
- const stored = await this.keyStoreService.getPassword(this.oauthConfig.keystoreService, this.oauthConfig.keystoreAccount);
196
- if (stored) {
197
- const credentials = JSON.parse(stored);
198
- return credentials.accessToken;
199
- }
200
- }
201
- catch (error) {
202
- this.logger.warn('Failed to retrieve Copilot access token:', error);
203
- }
204
- return undefined;
205
- }
206
- async signOut() {
207
- try {
208
- await this.keyStoreService.deletePassword(this.oauthConfig.keystoreService, this.oauthConfig.keystoreAccount);
209
- }
210
- catch (error) {
211
- this.logger.warn('Failed to delete Copilot credentials:', error);
212
- }
213
- const newState = { isAuthenticated: false };
214
- this.updateAuthState(newState);
83
+ /**
84
+ * The state as it currently is, with the request for a new sign-in attached when the credentials
85
+ * of the previous integration had to be discarded and none have been established since.
86
+ *
87
+ * Does not await the cleanup, so that it can be used from it.
88
+ */
89
+ async computeAuthState() {
90
+ const state = await this.cliAuthProvider.getAuthState();
91
+ return state.isAuthenticated || !this.migrationRequired ? state : { ...state, migrationRequired: true };
215
92
  }
216
93
  updateAuthState(state) {
217
94
  this.cachedState = state;
218
95
  this.onAuthStateChangedEmitter.fire(state);
219
96
  this.client?.onAuthStateChanged(state);
220
97
  }
221
- delay(ms) {
222
- return new Promise(resolve => setTimeout(resolve, ms));
223
- }
224
98
  };
225
99
  exports.CopilotAuthServiceImpl = CopilotAuthServiceImpl;
226
100
  tslib_1.__decorate([
227
- (0, inversify_1.inject)(key_store_1.KeyStoreService),
228
- tslib_1.__metadata("design:type", Object)
229
- ], CopilotAuthServiceImpl.prototype, "keyStoreService", void 0);
101
+ (0, inversify_1.inject)(copilot_cli_auth_provider_1.CopilotCliAuthProvider),
102
+ tslib_1.__metadata("design:type", copilot_cli_auth_provider_1.CopilotCliAuthProvider)
103
+ ], CopilotAuthServiceImpl.prototype, "cliAuthProvider", void 0);
104
+ tslib_1.__decorate([
105
+ (0, inversify_1.inject)(copilot_credential_store_1.CopilotCredentialStore),
106
+ tslib_1.__metadata("design:type", copilot_credential_store_1.CopilotCredentialStore)
107
+ ], CopilotAuthServiceImpl.prototype, "credentialStore", void 0);
108
+ tslib_1.__decorate([
109
+ (0, inversify_1.inject)(copilot_cli_locator_1.CopilotCliLocator),
110
+ tslib_1.__metadata("design:type", copilot_cli_locator_1.CopilotCliLocator)
111
+ ], CopilotAuthServiceImpl.prototype, "cliLocator", void 0);
230
112
  tslib_1.__decorate([
231
113
  (0, inversify_1.inject)(core_1.ILogger),
232
114
  (0, inversify_1.named)('ai-copilot:CopilotAuthServiceImpl'),
233
115
  tslib_1.__metadata("design:type", Object)
234
116
  ], CopilotAuthServiceImpl.prototype, "logger", void 0);
235
117
  tslib_1.__decorate([
236
- (0, inversify_1.inject)(copilot_oauth_config_1.CopilotOAuthConfig),
237
- tslib_1.__metadata("design:type", Object)
238
- ], CopilotAuthServiceImpl.prototype, "oauthConfig", void 0);
118
+ (0, inversify_1.postConstruct)(),
119
+ tslib_1.__metadata("design:type", Function),
120
+ tslib_1.__metadata("design:paramtypes", []),
121
+ tslib_1.__metadata("design:returntype", void 0)
122
+ ], CopilotAuthServiceImpl.prototype, "init", null);
239
123
  exports.CopilotAuthServiceImpl = CopilotAuthServiceImpl = tslib_1.__decorate([
240
124
  (0, inversify_1.injectable)()
241
125
  ], CopilotAuthServiceImpl);
@@ -1 +1 @@
1
- {"version":3,"file":"copilot-auth-service-impl.js","sourceRoot":"","sources":["../../src/node/copilot-auth-service-impl.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"copilot-auth-service-impl.js","sourceRoot":"","sources":["../../src/node/copilot-auth-service-impl.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  // *****************************************************************************
3
- // Copyright (C) 2026 EclipseSource and others.
3
+ // Copyright (C) 2026 EclipseSource GmbH and others.
4
4
  //
5
5
  // This program and the accompanying materials are made available under the
6
6
  // terms of the Eclipse Public License v. 2.0 which is available at
@@ -16,183 +16,119 @@
16
16
  // *****************************************************************************
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  const chai_1 = require("chai");
19
- const sinon = require("sinon");
20
- const inversify_1 = require("@theia/core/shared/inversify");
21
- const key_store_1 = require("@theia/core/lib/common/key-store");
22
- const copilot_oauth_config_1 = require("../common/copilot-oauth-config");
23
- const copilot_auth_service_impl_1 = require("./copilot-auth-service-impl");
24
- const logger_1 = require("@theia/core/lib/common/logger");
25
19
  const mock_logger_1 = require("@theia/core/lib/common/test/mock-logger");
26
- describe('CopilotAuthServiceImpl', () => {
27
- let authService;
28
- let keyStoreService;
29
- let getPasswordStub;
30
- beforeEach(() => {
31
- const container = new inversify_1.Container();
32
- getPasswordStub = sinon.stub();
33
- keyStoreService = {
34
- setPassword: sinon.stub().resolves(),
35
- getPassword: getPasswordStub.resolves(undefined),
36
- deletePassword: sinon.stub().resolves(true),
37
- findPassword: sinon.stub().resolves(undefined),
38
- findCredentials: sinon.stub().resolves([]),
39
- keys: sinon.stub().resolves([])
20
+ const copilot_auth_service_impl_1 = require("./copilot-auth-service-impl");
21
+ class TestableCopilotAuthServiceImpl extends copilot_auth_service_impl_1.CopilotAuthServiceImpl {
22
+ constructor() {
23
+ super();
24
+ this.stubs = {
25
+ legacyRemoved: false,
26
+ legacyDelay: 0,
27
+ authState: { isAuthenticated: false },
28
+ authStateCalls: 0,
29
+ configuredPath: undefined,
30
+ deleted: 0
40
31
  };
41
- container.bind(key_store_1.KeyStoreService).toConstantValue(keyStoreService);
42
- container.bind(copilot_oauth_config_1.CopilotOAuthConfig).toConstantValue(copilot_oauth_config_1.DEFAULT_COPILOT_OAUTH_CONFIG);
43
- container.bind(copilot_auth_service_impl_1.CopilotAuthServiceImpl).toSelf().inSingletonScope();
44
- container.bind(logger_1.ILogger).to(mock_logger_1.MockLogger).inSingletonScope();
45
- authService = container.get(copilot_auth_service_impl_1.CopilotAuthServiceImpl);
46
- });
47
- afterEach(() => {
48
- sinon.restore();
49
- });
50
- describe('getAccessToken', () => {
51
- it('should return undefined when no credentials are stored', async () => {
52
- getPasswordStub.resolves(undefined);
53
- const token = await authService.getAccessToken();
54
- (0, chai_1.expect)(token).to.be.undefined;
55
- });
56
- it('should return the stored access token directly', async () => {
57
- const oauthToken = 'ghu_test_token';
58
- getPasswordStub.resolves(JSON.stringify({
59
- accessToken: oauthToken,
60
- accountLabel: 'testuser'
61
- }));
62
- const token = await authService.getAccessToken();
63
- (0, chai_1.expect)(token).to.equal(oauthToken);
64
- });
65
- it('should return undefined when stored data is malformed', async () => {
66
- getPasswordStub.resolves('not-valid-json');
67
- const token = await authService.getAccessToken();
68
- (0, chai_1.expect)(token).to.be.undefined;
32
+ const stubs = this.stubs;
33
+ Object.assign(this, {
34
+ logger: new mock_logger_1.MockLogger(),
35
+ credentialStore: {
36
+ deleteLegacy: async () => {
37
+ await new Promise(resolve => setTimeout(resolve, stubs.legacyDelay));
38
+ return stubs.legacyRemoved;
39
+ }
40
+ },
41
+ cliLocator: { setConfiguredPath: (path) => { stubs.configuredPath = path; } },
42
+ cliAuthProvider: {
43
+ getAuthState: async () => {
44
+ stubs.authStateCalls++;
45
+ return stubs.authState;
46
+ },
47
+ signOut: async () => {
48
+ stubs.deleted++;
49
+ stubs.authState = { isAuthenticated: false };
50
+ },
51
+ waitForLogin: async () => true
52
+ }
69
53
  });
54
+ }
55
+ /** Runs what `@postConstruct` runs in production. */
56
+ start() {
57
+ this.init();
58
+ }
59
+ }
60
+ describe('CopilotAuthServiceImpl - migration of the previous sign-in', () => {
61
+ it('should report that a new sign-in is required, even when asked before the cleanup finished', async () => {
62
+ const service = new TestableCopilotAuthServiceImpl();
63
+ service.stubs.legacyRemoved = true;
64
+ // The frontend evaluates the flag once at startup, so a state cached without it loses it.
65
+ service.stubs.legacyDelay = 20;
66
+ service.start();
67
+ (0, chai_1.expect)(await service.getAuthState()).to.deep.include({ isAuthenticated: false, migrationRequired: true });
70
68
  });
71
- describe('getAuthState', () => {
72
- it('should return not authenticated when no credentials are stored', async () => {
73
- getPasswordStub.resolves(undefined);
74
- const state = await authService.getAuthState();
75
- (0, chai_1.expect)(state.isAuthenticated).to.be.false;
76
- (0, chai_1.expect)(state.accountLabel).to.be.undefined;
77
- });
78
- it('should return authenticated with account label when credentials exist', async () => {
79
- getPasswordStub.resolves(JSON.stringify({
80
- accessToken: 'gho_test',
81
- accountLabel: 'testuser',
82
- enterpriseUrl: undefined
83
- }));
84
- const state = await authService.getAuthState();
85
- (0, chai_1.expect)(state.isAuthenticated).to.be.true;
86
- (0, chai_1.expect)(state.accountLabel).to.equal('testuser');
87
- });
88
- it('should return enterprise URL when stored', async () => {
89
- getPasswordStub.resolves(JSON.stringify({
90
- accessToken: 'gho_test',
91
- accountLabel: 'testuser',
92
- enterpriseUrl: 'github.mycompany.com'
93
- }));
94
- const state = await authService.getAuthState();
95
- (0, chai_1.expect)(state.isAuthenticated).to.be.true;
96
- (0, chai_1.expect)(state.enterpriseUrl).to.equal('github.mycompany.com');
97
- });
98
- it('should clear outdated non-gho_ token and flag migration', async () => {
99
- getPasswordStub.resolves(JSON.stringify({
100
- accessToken: 'ghu_old_token',
101
- accountLabel: 'testuser'
102
- }));
103
- const state = await authService.getAuthState();
104
- (0, chai_1.expect)(state.isAuthenticated).to.be.false;
105
- (0, chai_1.expect)(state.migrationRequired).to.be.true;
106
- (0, chai_1.expect)(keyStoreService.deletePassword.calledOnce).to.be.true;
107
- });
108
- it('should cache the auth state after first retrieval', async () => {
109
- getPasswordStub.resolves(JSON.stringify({
110
- accessToken: 'gho_test',
111
- accountLabel: 'testuser'
112
- }));
113
- const state1 = await authService.getAuthState();
114
- const state2 = await authService.getAuthState();
115
- (0, chai_1.expect)(state1).to.equal(state2);
116
- (0, chai_1.expect)(getPasswordStub.calledOnce).to.be.true;
117
- });
69
+ it('should not claim a migration when there was nothing to discard', async () => {
70
+ const service = new TestableCopilotAuthServiceImpl();
71
+ service.start();
72
+ (0, chai_1.expect)(await service.getAuthState()).to.not.have.property('migrationRequired');
118
73
  });
119
- describe('signOut', () => {
120
- it('should clear cached auth state on sign out', async () => {
121
- getPasswordStub.resolves(JSON.stringify({
122
- accessToken: 'gho_test',
123
- accountLabel: 'testuser'
124
- }));
125
- const stateBefore = await authService.getAuthState();
126
- (0, chai_1.expect)(stateBefore.isAuthenticated).to.be.true;
127
- await authService.signOut();
128
- // After sign out, cached state should be cleared
129
- // getAuthState should now return the new state without hitting keystore cache
130
- const stateAfter = await authService.getAuthState();
131
- (0, chai_1.expect)(stateAfter.isAuthenticated).to.be.false;
132
- });
133
- it('should fire auth state changed event on sign out', async () => {
134
- const stateChanges = [];
135
- authService.onAuthStateChanged(state => stateChanges.push(state));
136
- await authService.signOut();
137
- (0, chai_1.expect)(stateChanges).to.have.lengthOf(1);
138
- (0, chai_1.expect)(stateChanges[0].isAuthenticated).to.be.false;
139
- });
140
- it('should delete credentials from keystore on sign out', async () => {
141
- await authService.signOut();
142
- (0, chai_1.expect)(keyStoreService.deletePassword.calledOnce).to.be.true;
143
- });
144
- it('should notify client on sign out', async () => {
145
- const client = { onAuthStateChanged: sinon.stub() };
146
- authService.setClient(client);
147
- await authService.signOut();
148
- (0, chai_1.expect)(client.onAuthStateChanged.calledOnce).to.be.true;
149
- (0, chai_1.expect)(client.onAuthStateChanged.firstCall.args[0].isAuthenticated).to.be.false;
150
- });
74
+ it('should not claim a migration for a user who is signed in', async () => {
75
+ const service = new TestableCopilotAuthServiceImpl();
76
+ service.stubs.legacyRemoved = true;
77
+ service.stubs.authState = { isAuthenticated: true, accountLabel: 'octocat' };
78
+ service.start();
79
+ (0, chai_1.expect)(await service.getAuthState()).to.not.have.property('migrationRequired');
80
+ });
81
+ it('should survive a keychain that cannot be read', async () => {
82
+ const service = new TestableCopilotAuthServiceImpl();
83
+ Object.assign(service, { credentialStore: { deleteLegacy: async () => { throw new Error('keychain unavailable'); } } });
84
+ service.start();
85
+ (0, chai_1.expect)(await service.getAuthState()).to.deep.equal({ isAuthenticated: false });
151
86
  });
152
87
  });
153
- describe('CopilotAuthServiceImpl with custom CopilotOAuthConfig', () => {
154
- const customConfig = {
155
- clientId: 'CustomClientId',
156
- userAgent: 'MyApp/1.0.0',
157
- keystoreService: 'myapp-copilot',
158
- keystoreAccount: 'myapp-github'
159
- };
160
- let authService;
161
- let getPasswordStub;
162
- let deletePasswordStub;
163
- beforeEach(() => {
164
- const container = new inversify_1.Container();
165
- container.bind(logger_1.ILogger).to(mock_logger_1.MockLogger).inSingletonScope();
166
- getPasswordStub = sinon.stub().resolves(undefined);
167
- deletePasswordStub = sinon.stub().resolves(true);
168
- const keyStoreService = {
169
- setPassword: sinon.stub().resolves(),
170
- getPassword: getPasswordStub,
171
- deletePassword: deletePasswordStub,
172
- findPassword: sinon.stub().resolves(undefined),
173
- findCredentials: sinon.stub().resolves([]),
174
- keys: sinon.stub().resolves([])
175
- };
176
- container.bind(key_store_1.KeyStoreService).toConstantValue(keyStoreService);
177
- container.bind(copilot_oauth_config_1.CopilotOAuthConfig).toConstantValue(customConfig);
178
- container.bind(copilot_auth_service_impl_1.CopilotAuthServiceImpl).toSelf().inSingletonScope();
179
- authService = container.get(copilot_auth_service_impl_1.CopilotAuthServiceImpl);
88
+ describe('CopilotAuthServiceImpl - state', () => {
89
+ it('should ask the provider once and serve the cached state afterwards', async () => {
90
+ const service = new TestableCopilotAuthServiceImpl();
91
+ service.start();
92
+ await service.getAuthState();
93
+ await service.getAuthState();
94
+ (0, chai_1.expect)(service.stubs.authStateCalls).to.equal(1);
180
95
  });
181
- afterEach(() => {
182
- sinon.restore();
96
+ it('should report the new state after a sign-in', async () => {
97
+ const service = new TestableCopilotAuthServiceImpl();
98
+ service.start();
99
+ await service.getAuthState();
100
+ service.stubs.authState = { isAuthenticated: true, accountLabel: 'octocat' };
101
+ const reported = [];
102
+ service.onAuthStateChanged(state => reported.push(state));
103
+ (0, chai_1.expect)(await service.waitForSignIn()).to.be.true;
104
+ (0, chai_1.expect)(reported).to.deep.equal([{ isAuthenticated: true, accountLabel: 'octocat' }]);
105
+ (0, chai_1.expect)(await service.getAuthState()).to.deep.equal({ isAuthenticated: true, accountLabel: 'octocat' });
183
106
  });
184
- it('should read credentials from the custom keystore service and account', async () => {
185
- getPasswordStub.resolves(JSON.stringify({
186
- accessToken: 'gho_custom_token',
187
- accountLabel: 'customuser'
188
- }));
189
- const token = await authService.getAccessToken();
190
- (0, chai_1.expect)(token).to.equal('gho_custom_token');
191
- (0, chai_1.expect)(getPasswordStub.calledOnceWith(customConfig.keystoreService, customConfig.keystoreAccount)).to.be.true;
107
+ it('should report the new state after signing out', async () => {
108
+ const service = new TestableCopilotAuthServiceImpl();
109
+ service.stubs.authState = { isAuthenticated: true, accountLabel: 'octocat' };
110
+ service.start();
111
+ await service.getAuthState();
112
+ const reported = [];
113
+ service.onAuthStateChanged(state => reported.push(state));
114
+ await service.signOut();
115
+ (0, chai_1.expect)(service.stubs.deleted).to.equal(1);
116
+ (0, chai_1.expect)(reported).to.deep.equal([{ isAuthenticated: false }]);
117
+ });
118
+ });
119
+ describe('CopilotAuthServiceImpl - executable path', () => {
120
+ it('should hand the configured location to the lookup, which cannot read preferences itself', async () => {
121
+ const service = new TestableCopilotAuthServiceImpl();
122
+ service.start();
123
+ await service.setExecutablePath('/opt/copilot/copilot');
124
+ (0, chai_1.expect)(service.stubs.configuredPath).to.equal('/opt/copilot/copilot');
192
125
  });
193
- it('should delete credentials from the custom keystore service and account on sign out', async () => {
194
- await authService.signOut();
195
- (0, chai_1.expect)(deletePasswordStub.calledOnceWith(customConfig.keystoreService, customConfig.keystoreAccount)).to.be.true;
126
+ it('should hand on that nothing is configured, so that the CLI is searched for', async () => {
127
+ const service = new TestableCopilotAuthServiceImpl();
128
+ service.start();
129
+ await service.setExecutablePath('/opt/copilot/copilot');
130
+ await service.setExecutablePath(undefined);
131
+ (0, chai_1.expect)(service.stubs.configuredPath).to.be.undefined;
196
132
  });
197
133
  });
198
134
  //# sourceMappingURL=copilot-auth-service-impl.spec.js.map