atris 3.58.6 → 3.58.7

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.
package/utils/auth.js CHANGED
@@ -202,6 +202,51 @@ function loadPlacedAgentToken() {
202
202
  }
203
203
  }
204
204
 
205
+ function leftoverStoredAgentToken(parsed, envToken) {
206
+ if (!parsed || !envToken) return null;
207
+ const leftover = typeof parsed.agent_token === 'string' ? parsed.agent_token.trim() : '';
208
+ if (!leftover || leftover !== envToken) return null;
209
+ const expiresAt = parsed.agent_token_expires_at;
210
+ if (expiryTimeMs(expiresAt) === null) return null;
211
+ const scopes = Array.isArray(parsed.agent_token_scopes) ? parsed.agent_token_scopes : [];
212
+ return {
213
+ token: leftover,
214
+ expires_at: expiresAt,
215
+ scopes,
216
+ provider: null,
217
+ source: 'env',
218
+ agent_token: leftover,
219
+ agent_token_scopes: scopes,
220
+ agent_token_expires_at: expiresAt,
221
+ };
222
+ }
223
+
224
+ function loadLeftoverCredentialsAgentToken(envToken) {
225
+ if (!envToken) return null;
226
+ try {
227
+ return leftoverStoredAgentToken(JSON.parse(fs.readFileSync(getCredentialsPath(), 'utf8')), envToken);
228
+ } catch {
229
+ return null;
230
+ }
231
+ }
232
+
233
+ function resolveProfileOverride(profileOverride) {
234
+ if (!profileOverride) return null;
235
+ if (loadProfile(profileOverride)) return profileOverride;
236
+ const profiles = listProfiles();
237
+ const q = String(profileOverride).toLowerCase();
238
+ return profiles.find((name) => name.toLowerCase() === q)
239
+ || profiles.find((name) => name.toLowerCase().startsWith(q))
240
+ || profiles.find((name) => name.toLowerCase().includes(q))
241
+ || null;
242
+ }
243
+
244
+ function loadLeftoverProfileAgentToken(envToken) {
245
+ const name = resolveProfileOverride(process.env.ATRIS_PROFILE) || getSessionProfile();
246
+ if (!envToken || !name) return null;
247
+ return leftoverStoredAgentToken(loadProfile(name), envToken);
248
+ }
249
+
205
250
  function isUnexpiredCredential(credentials) {
206
251
  const expiresAt = expiryTimeMs(credentials?.expires_at);
207
252
  return expiresAt !== null && expiresAt > Date.now();
@@ -417,7 +462,8 @@ async function repairLoginCredentials(credentials, apiRequestJson) {
417
462
  function readCredentials() {
418
463
  // Priority: ATRIS_TOKEN env var → placed agent token → ATRIS_PROFILE env var
419
464
  // → per-terminal session file → global credentials.json. A fresh placed token
420
- // overrides a different env token because cloud images can carry a stale one.
465
+ // overrides env when the leftover is newer or when env only repeats that
466
+ // leftover, so billed auth still sees leftover scopes.
421
467
 
422
468
  // 0. Raw token injection. Headless boxes (cloud business computers) have no
423
469
  // browser for `atris login`; the runner injects a scoped token as env
@@ -425,15 +471,24 @@ function readCredentials() {
425
471
  const envToken = process.env.ATRIS_TOKEN;
426
472
  const normalizedEnvToken = envToken && envToken.trim();
427
473
  const placedAgentToken = loadPlacedAgentToken();
428
- if (
429
- normalizedEnvToken &&
430
- placedAgentToken &&
431
- placedAgentToken.token !== normalizedEnvToken &&
432
- isUnexpiredCredential(placedAgentToken)
433
- ) {
474
+ if (normalizedEnvToken && placedAgentToken && isUnexpiredCredential(placedAgentToken)) {
475
+ // Fresh placed leftover wins over env, including when env repeats the same
476
+ // token, so billed auth still sees leftover scopes and does not remint.
434
477
  return placedAgentToken;
435
478
  }
436
479
  if (normalizedEnvToken) {
480
+ const leftoverCredentials = loadLeftoverCredentialsAgentToken(normalizedEnvToken);
481
+ if (leftoverCredentials && isUnexpiredCredential(leftoverCredentials)) {
482
+ // Env repeating leftover credentials.agent_token keeps leftover scopes
483
+ // and expiry so billed auth does not remint.
484
+ return leftoverCredentials;
485
+ }
486
+ const leftoverProfile = loadLeftoverProfileAgentToken(normalizedEnvToken);
487
+ if (leftoverProfile && isUnexpiredCredential(leftoverProfile)) {
488
+ // Env repeating leftover profile or session-profile agent_token keeps
489
+ // leftover scopes and expiry so billed auth does not remint.
490
+ return leftoverProfile;
491
+ }
437
492
  return { token: normalizedEnvToken, provider: null, source: 'env' };
438
493
  }
439
494