@antasphere/chassis-cli 1.0.1 → 1.1.0
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/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/auth.js +36 -18
- package/dist/commands/auth.js.map +1 -1
- package/dist/context.d.ts +8 -2
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +89 -41
- package/dist/context.js.map +1 -1
- package/dist/identity.d.ts +8 -0
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +8 -0
- package/dist/identity.js.map +1 -1
- package/package.json +4 -4
- package/src/commands/auth.ts +39 -19
- package/src/context.ts +109 -49
- package/src/identity.ts +9 -0
- package/test/suite/hub-selection.test.ts +588 -0
- package/test/suite/login.test.ts +3 -1
- package/test/suite/profiles.test.ts +6 -1
- package/test/suite/recovery.test.ts +46 -11
- package/test/suite/whoami.test.ts +12 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { HUB_TOOL, saveConfig as saveCoreConfig } from '@antasphere/cli-core';
|
|
2
|
+
import { HUB_TOOL, loadConfig as loadCoreConfig, saveConfig as saveCoreConfig } from '@antasphere/cli-core';
|
|
3
3
|
import { routedHarness, tempConfigEnv, type Route } from '@antasphere/chassis-cli/testing';
|
|
4
4
|
import { cli, run } from '@chassis-cli-test/host';
|
|
5
5
|
import {
|
|
@@ -45,7 +45,9 @@ async function cachedEnv(): Promise<Record<string, string>> {
|
|
|
45
45
|
seedHubLogin(env);
|
|
46
46
|
saveConfig(env, {
|
|
47
47
|
activeProfile: 'work',
|
|
48
|
-
profiles: {
|
|
48
|
+
profiles: {
|
|
49
|
+
work: { baseUrl: 'http://tool', connectKeys: { default: { apiKey: OLD, email: 'ada@x.co' } } }
|
|
50
|
+
}
|
|
49
51
|
});
|
|
50
52
|
return env;
|
|
51
53
|
}
|
|
@@ -319,19 +321,52 @@ describe('a cached key of another Antasphere account (PRDCT-3032)', () => {
|
|
|
319
321
|
expect(JSON.stringify(loadConfig(env))).not.toContain(OLD);
|
|
320
322
|
});
|
|
321
323
|
|
|
322
|
-
it(
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
324
|
+
it.each([
|
|
325
|
+
[
|
|
326
|
+
'a cache entry with no address',
|
|
327
|
+
{ apiKey: OLD },
|
|
328
|
+
'bob@x.co',
|
|
329
|
+
'cached for an unknown login is retired: the Antasphere login is now bob@x.co.\n'
|
|
330
|
+
],
|
|
331
|
+
[
|
|
332
|
+
'a hub login with no address',
|
|
333
|
+
{ apiKey: OLD, email: 'ada@x.co' },
|
|
334
|
+
undefined,
|
|
335
|
+
'cached for ada@x.co is retired: the Antasphere login carries no address to match it with.\n'
|
|
336
|
+
]
|
|
337
|
+
] as const)(
|
|
338
|
+
'%s is never served: the key is retired and revoked, the exchange mints anew, the hub profile carries the address after (verifier round 1, F1 and F5)',
|
|
339
|
+
async (_label, cached, hubEmail, retired) => {
|
|
327
340
|
const env = await switchedEnv(cached, hubEmail);
|
|
328
341
|
const h = routedHarness(routesFor([OLD, NEW]), env);
|
|
329
342
|
expect(await run(['whoami'], h.io)).toBe(0);
|
|
330
|
-
expect(trace(h)).toEqual([
|
|
331
|
-
|
|
332
|
-
|
|
343
|
+
expect(trace(h)).toEqual([
|
|
344
|
+
`DELETE http://tool/api/v1/cli/auth/key Bearer ${OLD}`,
|
|
345
|
+
'GET http://tool/api/v1/instance -',
|
|
346
|
+
`POST ${HUB}/api/v1/sso/tool-token Bearer ${BOB_HUB_KEY}`,
|
|
347
|
+
'POST http://tool/api/v1/sso/cli-connect -',
|
|
348
|
+
`GET http://tool/api/v1/me Bearer ${NEW}`
|
|
349
|
+
]);
|
|
350
|
+
expect(h.wire.filter((c) => c.auth === `Bearer ${OLD}`).map((c) => c.method)).toEqual(['DELETE']);
|
|
351
|
+
expect(h.err()).toContain(`The ${displayName} key ${retired}`);
|
|
352
|
+
const work = loadConfig(env).profiles.work;
|
|
353
|
+
expect(Object.keys(work?.connectKeys ?? {})).toEqual(['default']);
|
|
354
|
+
expect(work?.connectKeys?.default).toMatchObject({ apiKey: NEW, email: 'bob@x.co' });
|
|
355
|
+
expect(JSON.stringify(loadConfig(env))).not.toContain(OLD);
|
|
356
|
+
// The hub profile is healed with the address the exchange answered
|
|
357
|
+
// (when it had none), and nothing else of it moves.
|
|
358
|
+
expect(loadCoreConfig(env, HUB_TOOL)).toEqual({
|
|
359
|
+
activeProfile: 'default',
|
|
360
|
+
profiles: { default: { apiKey: BOB_HUB_KEY, baseUrl: HUB, email: 'bob@x.co' } }
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
// The next command is served from the cache: zero hub calls.
|
|
364
|
+
const next = routedHarness(routesFor([NEW]), env);
|
|
365
|
+
expect(await run(['whoami'], next.io)).toBe(0);
|
|
366
|
+
expect(trace(next)).toEqual([`GET http://tool/api/v1/me Bearer ${NEW}`]);
|
|
367
|
+
expect(next.err()).toBe('');
|
|
333
368
|
}
|
|
334
|
-
|
|
369
|
+
);
|
|
335
370
|
|
|
336
371
|
it('the same account in another case is the same account: the cached key is served (verifier M3)', async () => {
|
|
337
372
|
const env = await switchedEnv({ apiKey: OLD, email: 'ada@x.co' }, 'ADA@X.CO');
|
|
@@ -95,7 +95,12 @@ describe('whoami', () => {
|
|
|
95
95
|
seedHubLogin(env);
|
|
96
96
|
saveConfig(env, {
|
|
97
97
|
activeProfile: 'work',
|
|
98
|
-
profiles: {
|
|
98
|
+
profiles: {
|
|
99
|
+
work: {
|
|
100
|
+
baseUrl: 'http://tool',
|
|
101
|
+
connectKeys: { default: { apiKey: key('cached'), email: 'ada@x.co' } }
|
|
102
|
+
}
|
|
103
|
+
}
|
|
99
104
|
});
|
|
100
105
|
const h = routedHarness([meRoute()], env);
|
|
101
106
|
expect(await run(['whoami'], h.io)).toBe(0);
|
|
@@ -133,7 +138,12 @@ describe('whoami', () => {
|
|
|
133
138
|
seedHubLogin(env);
|
|
134
139
|
saveConfig(env, {
|
|
135
140
|
activeProfile: 'work',
|
|
136
|
-
profiles: {
|
|
141
|
+
profiles: {
|
|
142
|
+
work: {
|
|
143
|
+
baseUrl: 'http://tool',
|
|
144
|
+
connectKeys: { default: { apiKey: key('cached'), email: 'ada@x.co' } }
|
|
145
|
+
}
|
|
146
|
+
}
|
|
137
147
|
});
|
|
138
148
|
const h = routedHarness([meRoute()], env);
|
|
139
149
|
expect(await run(['whoami', '--json', '--workspace', 'w1'], h.io)).toBe(0);
|