@contrail/cli 3.5.5-alpha.a73fd77 → 3.5.5-alpha.bd66bf6
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/README.md +1 -1
- package/dist/auth/login.js +37 -15
- package/dist/auth/login.spec.js +87 -0
- package/dist/commands/app/upgrade.js +0 -4
- package/dist/interfaces.d.ts +0 -1
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
- package/dist/commands/app/upgrade.spec.d.ts +0 -1
- package/dist/commands/app/upgrade.spec.js +0 -36
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ $ npm install -g @contrail/cli
|
|
|
17
17
|
$ contrail COMMAND
|
|
18
18
|
running command...
|
|
19
19
|
$ contrail (--version)
|
|
20
|
-
@contrail/cli/3.5.5-alpha.
|
|
20
|
+
@contrail/cli/3.5.5-alpha.bd66bf6 linux-x64 node-v24.22.1
|
|
21
21
|
$ contrail --help [COMMAND]
|
|
22
22
|
USAGE
|
|
23
23
|
$ contrail COMMAND
|
package/dist/auth/login.js
CHANGED
|
@@ -9,10 +9,10 @@ const config_1 = require("../helpers/config/config");
|
|
|
9
9
|
const logger_1 = tslib_1.__importDefault(require("../logger"));
|
|
10
10
|
const path_1 = tslib_1.__importDefault(require("path"));
|
|
11
11
|
const fs_1 = tslib_1.__importDefault(require("fs"));
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
const DEFAULT_API_GATEWAY = config_1.ENVIRONMENTS.prod;
|
|
13
|
+
const COGNITO_CONFIGS = {
|
|
14
|
+
dev: { userPoolId: 'us-east-1_e2cA0nJWu', clientId: '209s9c62o165cqab0fu5ihjtu9' },
|
|
15
|
+
prod: { userPoolId: 'us-east-1_qIaNZdUfm', clientId: '7knkt34gfacbgd0ghnuspefdfg' },
|
|
16
16
|
};
|
|
17
17
|
async function authUser() {
|
|
18
18
|
logger_1.default.debug('authorizing user...');
|
|
@@ -66,7 +66,7 @@ async function getOrgSlug(config) {
|
|
|
66
66
|
return orgSlug;
|
|
67
67
|
}
|
|
68
68
|
async function authenticateWithApiKey(config, apiKey, orgSlug) {
|
|
69
|
-
const apiGateway = config?.apiGateway ??
|
|
69
|
+
const apiGateway = config?.apiGateway ?? DEFAULT_API_GATEWAY;
|
|
70
70
|
sdk_1.Auth.config = {
|
|
71
71
|
apiUserToken: apiKey,
|
|
72
72
|
apiRefreshToken: null,
|
|
@@ -78,6 +78,10 @@ async function authenticateWithApiKey(config, apiKey, orgSlug) {
|
|
|
78
78
|
return returnAndStoreConfig(sdk_1.Auth.config);
|
|
79
79
|
}
|
|
80
80
|
async function authenticateWithUsernamePassword(config) {
|
|
81
|
+
const apiGateway = config?.apiGateway ?? DEFAULT_API_GATEWAY;
|
|
82
|
+
const cognitoConfig = getCognitoConfig(apiGateway);
|
|
83
|
+
const environment = describeEnvironment(apiGateway);
|
|
84
|
+
logger_1.default.info(`Signing in to ${environment} — use your ${environment} VibeIQ credentials.`);
|
|
81
85
|
const questions = [];
|
|
82
86
|
if (!process.env.CONTRAIL_CLI_EMAIL) {
|
|
83
87
|
questions.push({
|
|
@@ -100,14 +104,14 @@ async function authenticateWithUsernamePassword(config) {
|
|
|
100
104
|
email: process.env.CONTRAIL_CLI_EMAIL || answers.email,
|
|
101
105
|
password: process.env.CONTRAIL_CLI_PASSWORD || answers.password,
|
|
102
106
|
orgSlug: await getOrgSlug(config),
|
|
103
|
-
|
|
107
|
+
apiGateway,
|
|
104
108
|
};
|
|
105
109
|
if (!params.email || !params.password) {
|
|
106
110
|
throw new Error('Email and Password required');
|
|
107
111
|
}
|
|
108
112
|
const poolData = {
|
|
109
|
-
UserPoolId:
|
|
110
|
-
ClientId:
|
|
113
|
+
UserPoolId: cognitoConfig.userPoolId,
|
|
114
|
+
ClientId: cognitoConfig.clientId,
|
|
111
115
|
};
|
|
112
116
|
const userPool = new amazon_cognito_identity_js_1.CognitoUserPool(poolData);
|
|
113
117
|
const authData = {
|
|
@@ -123,9 +127,12 @@ async function authenticateWithUsernamePassword(config) {
|
|
|
123
127
|
return new Promise((resolve, reject) => {
|
|
124
128
|
cognitoUser.authenticateUser(authDetails, {
|
|
125
129
|
onSuccess: async (result) => {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
130
|
+
try {
|
|
131
|
+
resolve(await setAuthContext(result, params));
|
|
132
|
+
}
|
|
133
|
+
catch (e) {
|
|
134
|
+
reject(e);
|
|
135
|
+
}
|
|
129
136
|
},
|
|
130
137
|
onFailure: (err) => {
|
|
131
138
|
reject(err);
|
|
@@ -134,7 +141,7 @@ async function authenticateWithUsernamePassword(config) {
|
|
|
134
141
|
});
|
|
135
142
|
}
|
|
136
143
|
async function setAuthContext(user, params) {
|
|
137
|
-
const apiGateway = params
|
|
144
|
+
const apiGateway = params.apiGateway;
|
|
138
145
|
const { vibeAccessToken, vibeRefreshToken } = await getVibeAccessTokenFromCognitoAccessToken(user.idToken.jwtToken, apiGateway);
|
|
139
146
|
// Set Auth Config
|
|
140
147
|
sdk_1.Auth.config = {
|
|
@@ -171,6 +178,19 @@ async function refreshCurrentUserOrg() {
|
|
|
171
178
|
// await checkTelemetry(current_Version);
|
|
172
179
|
return returnAndStoreConfig(sdk_1.Auth.config);
|
|
173
180
|
}
|
|
181
|
+
function getCognitoConfig(apiGateway) {
|
|
182
|
+
const environment = findEnvironmentName(apiGateway);
|
|
183
|
+
if (!environment) {
|
|
184
|
+
throw new Error(`No Cognito user pool is known for ${new URL(apiGateway).host}. Email and password sign-in works for ${Object.keys(COGNITO_CONFIGS).join(' and ')}; use CONTRAIL_CLI_API_KEY for other environments.`);
|
|
185
|
+
}
|
|
186
|
+
return COGNITO_CONFIGS[environment];
|
|
187
|
+
}
|
|
188
|
+
function findEnvironmentName(apiGateway) {
|
|
189
|
+
return Object.keys(config_1.ENVIRONMENTS).find((name) => config_1.ENVIRONMENTS[name] === apiGateway);
|
|
190
|
+
}
|
|
191
|
+
function describeEnvironment(apiGateway) {
|
|
192
|
+
return findEnvironmentName(apiGateway) ?? new URL(apiGateway).host;
|
|
193
|
+
}
|
|
174
194
|
async function getVibeAccessTokenFromCognitoAccessToken(cognitoAccessToken, apiGateway) {
|
|
175
195
|
const url = `${apiGateway}/auth/cognito/`;
|
|
176
196
|
const response = await fetch(url, {
|
|
@@ -181,9 +201,11 @@ async function getVibeAccessTokenFromCognitoAccessToken(cognitoAccessToken, apiG
|
|
|
181
201
|
},
|
|
182
202
|
body: JSON.stringify({ accessToken: cognitoAccessToken }),
|
|
183
203
|
});
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
204
|
+
if (!response.ok) {
|
|
205
|
+
throw new Error(`${describeEnvironment(apiGateway)} rejected the sign-in (${response.status}).`);
|
|
206
|
+
}
|
|
207
|
+
const data = await response.json();
|
|
208
|
+
return { vibeAccessToken: data.accessToken, vibeRefreshToken: data.refreshToken };
|
|
187
209
|
}
|
|
188
210
|
async function requestRefreshedAccessToken(vibeRefreshToken, apiGateway) {
|
|
189
211
|
const url = `${apiGateway}/auth/jwt_refresh/`;
|
package/dist/auth/login.spec.js
CHANGED
|
@@ -1,6 +1,93 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const amazon_cognito_identity_js_1 = require("amazon-cognito-identity-js");
|
|
4
|
+
const sdk_1 = require("@contrail/sdk");
|
|
5
|
+
const config_1 = require("../helpers/config/config");
|
|
3
6
|
const login_1 = require("./login");
|
|
7
|
+
jest.mock('amazon-cognito-identity-js', () => ({
|
|
8
|
+
CognitoUserPool: jest.fn(),
|
|
9
|
+
AuthenticationDetails: jest.fn(),
|
|
10
|
+
CognitoUser: jest.fn().mockImplementation(() => ({
|
|
11
|
+
authenticateUser: (_details, callbacks) => callbacks.onSuccess({ idToken: { jwtToken: 'cognito-id-token' } }),
|
|
12
|
+
})),
|
|
13
|
+
}));
|
|
14
|
+
jest.mock('@contrail/sdk', () => ({
|
|
15
|
+
Auth: { config: {} },
|
|
16
|
+
getCurrentUser: jest.fn(),
|
|
17
|
+
setConfig: jest.fn(),
|
|
18
|
+
}));
|
|
19
|
+
jest.mock('../helpers/config/config', () => ({
|
|
20
|
+
...jest.requireActual('../helpers/config/config'),
|
|
21
|
+
getConfig: jest.fn(),
|
|
22
|
+
storeConfig: jest.fn(),
|
|
23
|
+
}));
|
|
24
|
+
jest.mock('../logger', () => ({
|
|
25
|
+
__esModule: true,
|
|
26
|
+
default: { debug: jest.fn(), info: jest.fn() },
|
|
27
|
+
}));
|
|
28
|
+
const DEV_GATEWAY = 'https://api.dev.vibeiq.com/dev/api';
|
|
29
|
+
function jsonResponse(status, body = {}) {
|
|
30
|
+
return new Response(JSON.stringify(body), { status });
|
|
31
|
+
}
|
|
32
|
+
describe('authUser with email and password', () => {
|
|
33
|
+
const originalFetch = global.fetch;
|
|
34
|
+
const originalEmail = process.env.CONTRAIL_CLI_EMAIL;
|
|
35
|
+
const originalPassword = process.env.CONTRAIL_CLI_PASSWORD;
|
|
36
|
+
let fetchMock;
|
|
37
|
+
beforeEach(() => {
|
|
38
|
+
jest.clearAllMocks();
|
|
39
|
+
process.env.CONTRAIL_CLI_EMAIL = 'dev@vibeiq.com';
|
|
40
|
+
process.env.CONTRAIL_CLI_PASSWORD = 'secret';
|
|
41
|
+
config_1.getConfig.mockResolvedValue({ apiGateway: DEV_GATEWAY, orgSlug: 'adam-zone-1' });
|
|
42
|
+
sdk_1.getCurrentUser.mockResolvedValue({ id: 'user-1' });
|
|
43
|
+
fetchMock = jest.fn();
|
|
44
|
+
global.fetch = fetchMock;
|
|
45
|
+
});
|
|
46
|
+
afterEach(() => {
|
|
47
|
+
global.fetch = originalFetch;
|
|
48
|
+
process.env.CONTRAIL_CLI_EMAIL = originalEmail;
|
|
49
|
+
process.env.CONTRAIL_CLI_PASSWORD = originalPassword;
|
|
50
|
+
});
|
|
51
|
+
it('should sign in through the dev pool when the config points at dev', async () => {
|
|
52
|
+
fetchMock.mockResolvedValueOnce(jsonResponse(200, { accessToken: 'vibe-access', refreshToken: 'vibe-refresh' }));
|
|
53
|
+
const context = await (0, login_1.authUser)();
|
|
54
|
+
expect(amazon_cognito_identity_js_1.CognitoUserPool).toHaveBeenCalledWith({
|
|
55
|
+
UserPoolId: 'us-east-1_e2cA0nJWu',
|
|
56
|
+
ClientId: '209s9c62o165cqab0fu5ihjtu9',
|
|
57
|
+
});
|
|
58
|
+
expect(context).toEqual({
|
|
59
|
+
apiUserToken: 'vibe-access',
|
|
60
|
+
apiRefreshToken: 'vibe-refresh',
|
|
61
|
+
apiGateway: DEV_GATEWAY,
|
|
62
|
+
orgSlug: 'adam-zone-1',
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
it('should sign in through the prod pool when the config points at prod', async () => {
|
|
66
|
+
config_1.getConfig.mockResolvedValue({
|
|
67
|
+
apiGateway: 'https://api.vibeiq.com/prod/api',
|
|
68
|
+
orgSlug: 'adam-zone-1',
|
|
69
|
+
});
|
|
70
|
+
fetchMock.mockResolvedValueOnce(jsonResponse(200, { accessToken: 'vibe-access', refreshToken: 'vibe-refresh' }));
|
|
71
|
+
await (0, login_1.authUser)();
|
|
72
|
+
expect(amazon_cognito_identity_js_1.CognitoUserPool).toHaveBeenCalledWith({
|
|
73
|
+
UserPoolId: 'us-east-1_qIaNZdUfm',
|
|
74
|
+
ClientId: '7knkt34gfacbgd0ghnuspefdfg',
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
it('should fail without saving tokens when no pool is known for the environment', async () => {
|
|
78
|
+
config_1.getConfig.mockResolvedValue({
|
|
79
|
+
apiGateway: 'http://localhost:3000/api',
|
|
80
|
+
orgSlug: 'adam-zone-1',
|
|
81
|
+
});
|
|
82
|
+
await expect((0, login_1.authUser)()).rejects.toThrow('No Cognito user pool is known for localhost:3000.');
|
|
83
|
+
expect(config_1.storeConfig).not.toHaveBeenCalled();
|
|
84
|
+
});
|
|
85
|
+
it('should fail without saving tokens when the environment rejects the sign-in', async () => {
|
|
86
|
+
fetchMock.mockResolvedValueOnce(jsonResponse(401, { message: 'Unauthorized' }));
|
|
87
|
+
await expect((0, login_1.authUser)()).rejects.toThrow('dev rejected the sign-in (401).');
|
|
88
|
+
expect(config_1.storeConfig).not.toHaveBeenCalled();
|
|
89
|
+
});
|
|
90
|
+
});
|
|
4
91
|
describe('getVersionFromPackageJson', () => {
|
|
5
92
|
it('should return the version value from package.json', () => {
|
|
6
93
|
const version = (0, login_1.getVersionFromPackageJson)();
|
|
@@ -95,10 +95,6 @@ async function upgradeAndWait(appOrgToUpgrade, versionToUpgrade) {
|
|
|
95
95
|
entityName: 'app-org',
|
|
96
96
|
id: appOrgToUpgrade.id,
|
|
97
97
|
});
|
|
98
|
-
if (appStillUpgrading.status === 'READY' && appStillUpgrading.lastInstallError) {
|
|
99
|
-
logger_1.default.info(`${chalk_1.default.red.bold('APP UPGRADE')} ${appStillUpgrading.lastInstallError}`);
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
98
|
if (appStillUpgrading.status === 'READY') {
|
|
103
99
|
logger_1.default.info(`${chalk_1.default.green.bold('APP UPGRADE')} App Upgraded`);
|
|
104
100
|
return;
|
package/dist/interfaces.d.ts
CHANGED
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const get = jest.fn();
|
|
4
|
-
const update = jest.fn();
|
|
5
|
-
const info = jest.fn();
|
|
6
|
-
jest.mock('@contrail/sdk', () => ({
|
|
7
|
-
Auth: jest.fn(),
|
|
8
|
-
Entities: jest.fn(() => ({
|
|
9
|
-
get: (...args) => get(...args),
|
|
10
|
-
update: (...args) => update(...args),
|
|
11
|
-
})),
|
|
12
|
-
}));
|
|
13
|
-
jest.mock('../../common', () => ({ delay: () => Promise.resolve() }));
|
|
14
|
-
jest.mock('../../logger', () => ({ info: (...args) => info(...args) }));
|
|
15
|
-
const upgrade_1 = require("./upgrade");
|
|
16
|
-
describe('upgradeAndWait', () => {
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
get.mockReset();
|
|
19
|
-
update.mockReset().mockResolvedValue({});
|
|
20
|
-
info.mockReset();
|
|
21
|
-
});
|
|
22
|
-
it('should report success once the app is ready', async () => {
|
|
23
|
-
get.mockResolvedValue({ status: 'READY' });
|
|
24
|
-
await (0, upgrade_1.upgradeAndWait)({ id: 'app-org-1' }, 'version-2');
|
|
25
|
-
expect(info).toHaveBeenLastCalledWith(expect.stringContaining('App Upgraded'));
|
|
26
|
-
});
|
|
27
|
-
it('should report why the upgrade was reverted instead of calling it upgraded', async () => {
|
|
28
|
-
get.mockResolvedValue({
|
|
29
|
-
status: 'READY',
|
|
30
|
-
lastInstallError: '1.0.1 could not finish installing (template write failed); reverted to 1.0.0',
|
|
31
|
-
});
|
|
32
|
-
await (0, upgrade_1.upgradeAndWait)({ id: 'app-org-1' }, 'version-2');
|
|
33
|
-
expect(info).toHaveBeenLastCalledWith(expect.stringContaining('reverted to 1.0.0'));
|
|
34
|
-
expect(info).not.toHaveBeenCalledWith(expect.stringContaining('App Upgraded'));
|
|
35
|
-
});
|
|
36
|
-
});
|