@contrail/cli 3.5.5-alpha.a4b6430 → 3.5.5-alpha.a4cf3d0

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 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.a4b6430 linux-x64 node-v24.21.0
20
+ @contrail/cli/3.5.5-alpha.a4cf3d0 linux-x64 node-v24.21.0
21
21
  $ contrail --help [COMMAND]
22
22
  USAGE
23
23
  $ contrail COMMAND
package/dist/api/apps.js CHANGED
@@ -26,8 +26,6 @@ async function upgradeAppVersion(appOrg, appVersionId) {
26
26
  id: appOrg.id,
27
27
  object: {
28
28
  appVersionId: appVersionId,
29
- // The API then updates installed workflows to the new version's configuration, keeping any value the org changed.
30
- syncEventWorkflowTemplates: true,
31
29
  },
32
30
  });
33
31
  }
@@ -9,11 +9,7 @@ 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 CONFIGURATION = {
13
- userPoolId: 'us-east-1_qIaNZdUfm',
14
- clientId: process.env.CONTRAIL_COGNITO_CLIENT_ID || '7knkt34gfacbgd0ghnuspefdfg',
15
- apiGateway: 'https://api.vibeiq.com/prod/api',
16
- };
12
+ const DEFAULT_API_GATEWAY = config_1.ENVIRONMENTS.prod;
17
13
  async function authUser() {
18
14
  logger_1.default.debug('authorizing user...');
19
15
  const config = await (0, config_1.getConfig)();
@@ -66,7 +62,7 @@ async function getOrgSlug(config) {
66
62
  return orgSlug;
67
63
  }
68
64
  async function authenticateWithApiKey(config, apiKey, orgSlug) {
69
- const apiGateway = config?.apiGateway ?? CONFIGURATION.apiGateway;
65
+ const apiGateway = config?.apiGateway ?? DEFAULT_API_GATEWAY;
70
66
  sdk_1.Auth.config = {
71
67
  apiUserToken: apiKey,
72
68
  apiRefreshToken: null,
@@ -78,6 +74,10 @@ async function authenticateWithApiKey(config, apiKey, orgSlug) {
78
74
  return returnAndStoreConfig(sdk_1.Auth.config);
79
75
  }
80
76
  async function authenticateWithUsernamePassword(config) {
77
+ const apiGateway = config?.apiGateway ?? DEFAULT_API_GATEWAY;
78
+ const cognitoConfig = await fetchCognitoConfig(apiGateway);
79
+ const environment = describeEnvironment(apiGateway);
80
+ logger_1.default.info(`Signing in to ${environment} — use your ${environment} VibeIQ credentials.`);
81
81
  const questions = [];
82
82
  if (!process.env.CONTRAIL_CLI_EMAIL) {
83
83
  questions.push({
@@ -100,14 +100,14 @@ async function authenticateWithUsernamePassword(config) {
100
100
  email: process.env.CONTRAIL_CLI_EMAIL || answers.email,
101
101
  password: process.env.CONTRAIL_CLI_PASSWORD || answers.password,
102
102
  orgSlug: await getOrgSlug(config),
103
- ...(config?.apiGateway && { apiGateway: config.apiGateway }),
103
+ apiGateway,
104
104
  };
105
105
  if (!params.email || !params.password) {
106
106
  throw new Error('Email and Password required');
107
107
  }
108
108
  const poolData = {
109
- UserPoolId: CONFIGURATION.userPoolId,
110
- ClientId: CONFIGURATION.clientId,
109
+ UserPoolId: cognitoConfig.userPoolId,
110
+ ClientId: cognitoConfig.clientId,
111
111
  };
112
112
  const userPool = new amazon_cognito_identity_js_1.CognitoUserPool(poolData);
113
113
  const authData = {
@@ -123,9 +123,12 @@ async function authenticateWithUsernamePassword(config) {
123
123
  return new Promise((resolve, reject) => {
124
124
  cognitoUser.authenticateUser(authDetails, {
125
125
  onSuccess: async (result) => {
126
- const user = result;
127
- const config = await setAuthContext(user, params);
128
- resolve(config);
126
+ try {
127
+ resolve(await setAuthContext(result, params));
128
+ }
129
+ catch (e) {
130
+ reject(e);
131
+ }
129
132
  },
130
133
  onFailure: (err) => {
131
134
  reject(err);
@@ -134,7 +137,7 @@ async function authenticateWithUsernamePassword(config) {
134
137
  });
135
138
  }
136
139
  async function setAuthContext(user, params) {
137
- const apiGateway = params?.apiGateway ?? CONFIGURATION.apiGateway;
140
+ const apiGateway = params.apiGateway;
138
141
  const { vibeAccessToken, vibeRefreshToken } = await getVibeAccessTokenFromCognitoAccessToken(user.idToken.jwtToken, apiGateway);
139
142
  // Set Auth Config
140
143
  sdk_1.Auth.config = {
@@ -171,6 +174,19 @@ async function refreshCurrentUserOrg() {
171
174
  // await checkTelemetry(current_Version);
172
175
  return returnAndStoreConfig(sdk_1.Auth.config);
173
176
  }
177
+ async function fetchCognitoConfig(apiGateway) {
178
+ const response = await fetch(`${apiGateway}/auth/cognito/config`, {
179
+ headers: { Accept: 'application/json' },
180
+ });
181
+ if (!response.ok) {
182
+ throw new Error(`${describeEnvironment(apiGateway)} did not return its sign-in configuration (${response.status}).`);
183
+ }
184
+ return await response.json();
185
+ }
186
+ function describeEnvironment(apiGateway) {
187
+ return (Object.keys(config_1.ENVIRONMENTS).find((name) => config_1.ENVIRONMENTS[name] === apiGateway) ??
188
+ new URL(apiGateway).host);
189
+ }
174
190
  async function getVibeAccessTokenFromCognitoAccessToken(cognitoAccessToken, apiGateway) {
175
191
  const url = `${apiGateway}/auth/cognito/`;
176
192
  const response = await fetch(url, {
@@ -181,9 +197,11 @@ async function getVibeAccessTokenFromCognitoAccessToken(cognitoAccessToken, apiG
181
197
  },
182
198
  body: JSON.stringify({ accessToken: cognitoAccessToken }),
183
199
  });
184
- return await response.json().then((data) => {
185
- return { vibeAccessToken: data.accessToken, vibeRefreshToken: data.refreshToken };
186
- });
200
+ if (!response.ok) {
201
+ throw new Error(`${describeEnvironment(apiGateway)} rejected the sign-in (${response.status}).`);
202
+ }
203
+ const data = await response.json();
204
+ return { vibeAccessToken: data.accessToken, vibeRefreshToken: data.refreshToken };
187
205
  }
188
206
  async function requestRefreshedAccessToken(vibeRefreshToken, apiGateway) {
189
207
  const url = `${apiGateway}/auth/jwt_refresh/`;
@@ -1,6 +1,88 @@
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
+ const DEV_COGNITO_CONFIG = {
30
+ region: 'us-east-1',
31
+ userPoolId: 'us-east-1_e2cA0nJWu',
32
+ clientId: '209s9c62o165cqab0fu5ihjtu9',
33
+ };
34
+ function jsonResponse(status, body = {}) {
35
+ return new Response(JSON.stringify(body), { status });
36
+ }
37
+ describe('authUser with email and password', () => {
38
+ const originalFetch = global.fetch;
39
+ const originalEmail = process.env.CONTRAIL_CLI_EMAIL;
40
+ const originalPassword = process.env.CONTRAIL_CLI_PASSWORD;
41
+ let fetchMock;
42
+ beforeEach(() => {
43
+ jest.clearAllMocks();
44
+ process.env.CONTRAIL_CLI_EMAIL = 'dev@vibeiq.com';
45
+ process.env.CONTRAIL_CLI_PASSWORD = 'secret';
46
+ config_1.getConfig.mockResolvedValue({ apiGateway: DEV_GATEWAY, orgSlug: 'adam-zone-1' });
47
+ sdk_1.getCurrentUser.mockResolvedValue({ id: 'user-1' });
48
+ fetchMock = jest.fn();
49
+ global.fetch = fetchMock;
50
+ });
51
+ afterEach(() => {
52
+ global.fetch = originalFetch;
53
+ process.env.CONTRAIL_CLI_EMAIL = originalEmail;
54
+ process.env.CONTRAIL_CLI_PASSWORD = originalPassword;
55
+ });
56
+ it('should sign in through the pool the configured environment reports', async () => {
57
+ fetchMock
58
+ .mockResolvedValueOnce(jsonResponse(200, DEV_COGNITO_CONFIG))
59
+ .mockResolvedValueOnce(jsonResponse(200, { accessToken: 'vibe-access', refreshToken: 'vibe-refresh' }));
60
+ const context = await (0, login_1.authUser)();
61
+ expect(fetchMock.mock.calls[0][0]).toBe(`${DEV_GATEWAY}/auth/cognito/config`);
62
+ expect(amazon_cognito_identity_js_1.CognitoUserPool).toHaveBeenCalledWith({
63
+ UserPoolId: DEV_COGNITO_CONFIG.userPoolId,
64
+ ClientId: DEV_COGNITO_CONFIG.clientId,
65
+ });
66
+ expect(context).toEqual({
67
+ apiUserToken: 'vibe-access',
68
+ apiRefreshToken: 'vibe-refresh',
69
+ apiGateway: DEV_GATEWAY,
70
+ orgSlug: 'adam-zone-1',
71
+ });
72
+ });
73
+ it('should fail without saving tokens when the environment has no sign-in configuration', async () => {
74
+ fetchMock.mockResolvedValueOnce(jsonResponse(404));
75
+ await expect((0, login_1.authUser)()).rejects.toThrow('dev did not return its sign-in configuration (404).');
76
+ expect(config_1.storeConfig).not.toHaveBeenCalled();
77
+ });
78
+ it('should fail without saving tokens when the environment rejects the sign-in', async () => {
79
+ fetchMock
80
+ .mockResolvedValueOnce(jsonResponse(200, DEV_COGNITO_CONFIG))
81
+ .mockResolvedValueOnce(jsonResponse(401, { message: 'Unauthorized' }));
82
+ await expect((0, login_1.authUser)()).rejects.toThrow('dev rejected the sign-in (401).');
83
+ expect(config_1.storeConfig).not.toHaveBeenCalled();
84
+ });
85
+ });
4
86
  describe('getVersionFromPackageJson', () => {
5
87
  it('should return the version value from package.json', () => {
6
88
  const version = (0, login_1.getVersionFromPackageJson)();
@@ -168,7 +168,6 @@ export interface AppOrg {
168
168
  appVersion?: AppVersion;
169
169
  apiKey?: AppApiKey;
170
170
  appConfig?: any;
171
- syncEventWorkflowTemplates?: boolean;
172
171
  }
173
172
  export interface Webhook {
174
173
  id?: string;
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.5.5-alpha.a4b6430",
2
+ "version": "3.5.5-alpha.a4cf3d0",
3
3
  "commands": {
4
4
  "app:create": {
5
5
  "id": "app:create",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrail/cli",
3
- "version": "3.5.5-alpha.a4b6430",
3
+ "version": "3.5.5-alpha.a4cf3d0",
4
4
  "description": "VibeIQ's Contrail Platform CLI.",
5
5
  "bin": {
6
6
  "contrail-cli": "./bin/run",
@@ -1 +0,0 @@
1
- export {};
@@ -1,21 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const update = jest.fn();
4
- jest.mock('@contrail/sdk', () => ({
5
- Auth: jest.fn(),
6
- Entities: jest.fn(() => ({
7
- update: (...args) => update(...args),
8
- })),
9
- }));
10
- const apps_1 = require("./apps");
11
- describe('upgradeAppVersion', () => {
12
- it('should ask the API to apply the new version workflow configuration along with the version change', async () => {
13
- update.mockResolvedValue({ id: 'app-org-1' });
14
- await (0, apps_1.upgradeAppVersion)({ id: 'app-org-1' }, 'version-2');
15
- expect(update).toHaveBeenCalledWith({
16
- entityName: 'app-org',
17
- id: 'app-org-1',
18
- object: { appVersionId: 'version-2', syncEventWorkflowTemplates: true },
19
- });
20
- });
21
- });