@unito/integration-cli 0.58.9 → 0.60.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/schemas/authorization.json +4 -4
- package/dist/schemas/configuration.json +10 -0
- package/dist/src/commands/dev.js +22 -11
- package/dist/src/commands/oauth2.js +4 -4
- package/dist/src/commands/test.js +22 -11
- package/dist/src/configurationTypes.d.ts +13 -2
- package/dist/src/configurationTypes.js +2 -1
- package/dist/src/errors.d.ts +1 -2
- package/dist/src/errors.js +2 -4
- package/dist/src/resources/decryption.d.ts +4 -9
- package/dist/src/resources/decryption.js +22 -14
- package/dist/test/commands/dev.test.js +20 -0
- package/dist/test/commands/oauth2.test.js +21 -34
- package/dist/test/commands/test.test.js +24 -0
- package/dist/test/errors.test.js +1 -1
- package/dist/test/resources/configuration.test.js +30 -0
- package/dist/test/resources/decryption.test.js +8 -8
- package/dist/test/services/integrationsPlatform.test.js +1 -0
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
|
@@ -163,15 +163,15 @@
|
|
|
163
163
|
},
|
|
164
164
|
"grantType": {
|
|
165
165
|
"type": "string",
|
|
166
|
-
"description": "The type of grant of the OAuth 2 authorization",
|
|
167
|
-
"enum": ["authorization_code", "password"],
|
|
168
|
-
"tsEnumNames": ["AUTHORIZATION_CODE", "PASSWORD"]
|
|
166
|
+
"description": "The type of grant of the OAuth 2 authorization.",
|
|
167
|
+
"enum": ["authorization_code", "password", "client_credentials"],
|
|
168
|
+
"tsEnumNames": ["AUTHORIZATION_CODE", "PASSWORD", "CLIENT_CREDENTIALS"]
|
|
169
169
|
},
|
|
170
170
|
"scopes": {
|
|
171
171
|
"type": "array",
|
|
172
172
|
"items": {
|
|
173
173
|
"type": "object",
|
|
174
|
-
"description": "The requested scope of access to the user account",
|
|
174
|
+
"description": "The requested scope of access to the user account.",
|
|
175
175
|
"additionalProperties": false,
|
|
176
176
|
"required": ["name"],
|
|
177
177
|
"properties": {
|
|
@@ -84,6 +84,16 @@
|
|
|
84
84
|
"type": "string",
|
|
85
85
|
"pattern": "^unito-secret-v[0-9]+:\/\/.*$"
|
|
86
86
|
}
|
|
87
|
+
},
|
|
88
|
+
"environmentVariables": {
|
|
89
|
+
"type": "object",
|
|
90
|
+
"description": "The environment variables of the integration",
|
|
91
|
+
"patternProperties": {
|
|
92
|
+
"^[A-Z0-9_]+$": {
|
|
93
|
+
"type": "string"
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"additionalProperties": false
|
|
87
97
|
}
|
|
88
98
|
}
|
|
89
99
|
}
|
package/dist/src/commands/dev.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const core_1 = require("@oclif/core");
|
|
5
|
+
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
5
6
|
const child_process_1 = tslib_1.__importDefault(require("child_process"));
|
|
6
7
|
const baseCommand_1 = require("../baseCommand");
|
|
7
8
|
const errors_1 = require("../errors");
|
|
@@ -81,7 +82,7 @@ class Dev extends baseCommand_1.BaseCommand {
|
|
|
81
82
|
// Resolve the configuration.
|
|
82
83
|
const environment = flags.environment ?? GlobalConfiguration.Environment.Production;
|
|
83
84
|
const configuration = await (0, configuration_1.getConfiguration)(environment, flags['config-path']);
|
|
84
|
-
let credentialPayload;
|
|
85
|
+
let credentialPayload = '{}';
|
|
85
86
|
let readOnly = flags['read-only'] ?? false;
|
|
86
87
|
if (flags['credential-id']) {
|
|
87
88
|
const credential = await (0, credentials_1.fetchCredential)(environment, this.config.configDir, flags['credential-id']);
|
|
@@ -93,18 +94,28 @@ class Dev extends baseCommand_1.BaseCommand {
|
|
|
93
94
|
credentialPayload = flags['credential-payload'];
|
|
94
95
|
}
|
|
95
96
|
else {
|
|
96
|
-
|
|
97
|
+
const credentials = configuration.testAccounts?.[flags['test-account']];
|
|
97
98
|
if (credentials) {
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
const decryptedEntries = await (0, decryption_1.decryptEntries)(configuration.name, environment, this.config.configDir, credentials);
|
|
100
|
+
if (decryptedEntries.failed.length) {
|
|
101
|
+
throw new errors_1.EntryDecryptionError(decryptedEntries.failed.at(0), environment);
|
|
102
|
+
}
|
|
103
|
+
credentialPayload = JSON.stringify(decryptedEntries.successful);
|
|
100
104
|
}
|
|
101
|
-
credentialPayload = JSON.stringify(credentials);
|
|
102
105
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
// Load secrets.
|
|
107
|
+
const { successful: secrets, failed: failedSecrets } = await (0, decryption_1.decryptEntries)(configuration.name, environment, this.config.configDir, configuration.secrets ?? {});
|
|
108
|
+
if (failedSecrets.length) {
|
|
109
|
+
throw new errors_1.EntryDecryptionError(failedSecrets.at(0), environment);
|
|
110
|
+
}
|
|
111
|
+
// Load environment variables.
|
|
112
|
+
const { successful: environmentVariables, failed: failedEnvironmentVariables } = await (0, decryption_1.decryptEntries)(configuration.name, environment, this.config.configDir, configuration.environmentVariables ?? {});
|
|
113
|
+
for (const environmentVariable of failedEnvironmentVariables) {
|
|
114
|
+
core_1.ux.log();
|
|
115
|
+
core_1.ux.log(`Could not decrypt the environment variable ${chalk_1.default.yellowBright(environmentVariable)}.`);
|
|
116
|
+
core_1.ux.log('It may be a normal behavior locally as some environment variables are sensitive secrets.');
|
|
117
|
+
core_1.ux.log(`You can still pass ${chalk_1.default.yellowBright(`${environmentVariable}=<value>`)} to the CLI command to provide a value for this environment variable.`);
|
|
118
|
+
core_1.ux.log(`Example: ${chalk_1.default.yellowBright(`${environmentVariable}=foo ${this.config.bin} ${this.id}`)}`);
|
|
108
119
|
}
|
|
109
120
|
// Launch the debugger.
|
|
110
121
|
const commandArguments = [
|
|
@@ -150,7 +161,7 @@ class Dev extends baseCommand_1.BaseCommand {
|
|
|
150
161
|
const child = child_process_1.default.spawn('node', commandArguments, {
|
|
151
162
|
detached: true,
|
|
152
163
|
stdio: 'inherit',
|
|
153
|
-
env: { ...process.env, NODE_ENV: 'development', PORT: '9200' },
|
|
164
|
+
env: { ...process.env, ...environmentVariables, NODE_ENV: 'development', PORT: '9200' },
|
|
154
165
|
});
|
|
155
166
|
// istanbul ignore next
|
|
156
167
|
child.on('exit', (code) => {
|
|
@@ -69,7 +69,7 @@ class Oauth2 extends core_1.Command {
|
|
|
69
69
|
throw new errors_1.MissingAuth2AuthorizationError();
|
|
70
70
|
}
|
|
71
71
|
// Decrypt any encrypted oauth2 fields (mainly clientSecret)
|
|
72
|
-
oauth2 = (await (0, decryption_1.decryptEntries)(configuration.name, environment, this.config.configDir, oauth2)).
|
|
72
|
+
oauth2 = (await (0, decryption_1.decryptEntries)(configuration.name, environment, this.config.configDir, oauth2)).successful;
|
|
73
73
|
const testAccount = flags['test-account'];
|
|
74
74
|
const testAccountCredentials = configuration.testAccounts?.[testAccount];
|
|
75
75
|
let credentials;
|
|
@@ -84,17 +84,17 @@ class Oauth2 extends core_1.Command {
|
|
|
84
84
|
return;
|
|
85
85
|
}
|
|
86
86
|
const decryptionResult = await (0, decryption_1.decryptEntries)(configuration.name, environment, this.config.configDir, testAccountCredentials);
|
|
87
|
-
const refreshToken = decryptionResult.
|
|
87
|
+
const refreshToken = decryptionResult.successful.refreshToken;
|
|
88
88
|
core_1.ux.action.start(`Refreshing test account ${testAccount}`, undefined, { stdout: true });
|
|
89
89
|
credentials = await Oauth2Resource.updateToken(oauth2, refreshToken);
|
|
90
90
|
// If provider response doesn't contain a new refresh token, use the one we already have
|
|
91
91
|
if (!credentials.refreshToken) {
|
|
92
92
|
credentials.refreshToken = refreshToken;
|
|
93
93
|
}
|
|
94
|
-
if (decryptionResult.
|
|
94
|
+
if (decryptionResult.successful.accessToken) {
|
|
95
95
|
credentials.accessToken = (await IntegrationsPlatform.encryptData(configuration.name, credentials.accessToken, false)).encryptedData;
|
|
96
96
|
}
|
|
97
|
-
if (decryptionResult.
|
|
97
|
+
if (decryptionResult.successful.refreshToken) {
|
|
98
98
|
credentials.refreshToken = (await IntegrationsPlatform.encryptData(configuration.name, credentials.refreshToken, false)).encryptedData;
|
|
99
99
|
}
|
|
100
100
|
core_1.ux.action.stop();
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const core_1 = require("@oclif/core");
|
|
5
|
+
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
5
6
|
const child_process_1 = tslib_1.__importDefault(require("child_process"));
|
|
6
7
|
const crawlerDriver_1 = require("@unito/integration-debugger/dist/src/services/crawlerDriver");
|
|
7
8
|
const baseCommand_1 = require("../baseCommand");
|
|
@@ -99,7 +100,7 @@ class Test extends baseCommand_1.BaseCommand {
|
|
|
99
100
|
// Resolve the configuration.
|
|
100
101
|
const environment = flags.environment ?? GlobalConfiguration.Environment.Production;
|
|
101
102
|
const configuration = await (0, configuration_1.getConfiguration)(environment, flags['config-path']);
|
|
102
|
-
let credentialPayload;
|
|
103
|
+
let credentialPayload = '{}';
|
|
103
104
|
let readOnly = flags['read-only'] ?? false;
|
|
104
105
|
if (flags['credential-id']) {
|
|
105
106
|
const credential = await (0, credentials_1.fetchCredential)(environment, this.config.configDir, flags['credential-id']);
|
|
@@ -111,18 +112,28 @@ class Test extends baseCommand_1.BaseCommand {
|
|
|
111
112
|
credentialPayload = flags['credential-payload'];
|
|
112
113
|
}
|
|
113
114
|
else {
|
|
114
|
-
|
|
115
|
+
const credentials = configuration.testAccounts?.[flags['test-account']];
|
|
115
116
|
if (credentials) {
|
|
116
|
-
|
|
117
|
-
|
|
117
|
+
const decryptedEntries = await (0, decryption_1.decryptEntries)(configuration.name, environment, this.config.configDir, credentials);
|
|
118
|
+
if (decryptedEntries.failed.length) {
|
|
119
|
+
throw new errors_1.EntryDecryptionError(decryptedEntries.failed.at(0), environment);
|
|
120
|
+
}
|
|
121
|
+
credentialPayload = JSON.stringify(decryptedEntries.successful);
|
|
118
122
|
}
|
|
119
|
-
credentialPayload = JSON.stringify(credentials);
|
|
120
123
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
// Load secrets.
|
|
125
|
+
const { successful: secrets, failed: failedSecrets } = await (0, decryption_1.decryptEntries)(configuration.name, environment, this.config.configDir, configuration.secrets ?? {});
|
|
126
|
+
if (failedSecrets.length) {
|
|
127
|
+
throw new errors_1.EntryDecryptionError(failedSecrets.at(0), environment);
|
|
128
|
+
}
|
|
129
|
+
// Load environment variables.
|
|
130
|
+
const { successful: environmentVariables, failed: failedEnvironmentVariables } = await (0, decryption_1.decryptEntries)(configuration.name, environment, this.config.configDir, configuration.environmentVariables ?? {});
|
|
131
|
+
for (const environmentVariable of failedEnvironmentVariables) {
|
|
132
|
+
core_1.ux.log();
|
|
133
|
+
core_1.ux.log(`Could not decrypt the environment variable ${chalk_1.default.yellowBright(environmentVariable)}.`);
|
|
134
|
+
core_1.ux.log('It may be a normal behavior locally as some environment variables are sensitive secrets.');
|
|
135
|
+
core_1.ux.log(`You can still pass ${chalk_1.default.yellowBright(`${environmentVariable}=<value>`)} to the CLI command to provide a value for this environment variable.`);
|
|
136
|
+
core_1.ux.log(`Example: ${chalk_1.default.yellowBright(`${environmentVariable}=foo ${this.config.bin} ${this.id}`)}`);
|
|
126
137
|
}
|
|
127
138
|
// Launch the tests.
|
|
128
139
|
const commandArguments = [
|
|
@@ -176,7 +187,7 @@ class Test extends baseCommand_1.BaseCommand {
|
|
|
176
187
|
const child = child_process_1.default.spawn('node', commandArguments, {
|
|
177
188
|
detached: true,
|
|
178
189
|
stdio: 'inherit',
|
|
179
|
-
env: { ...process.env, NODE_ENV: 'development', PORT: '9200' },
|
|
190
|
+
env: { ...process.env, ...environmentVariables, NODE_ENV: 'development', PORT: '9200' },
|
|
180
191
|
});
|
|
181
192
|
// istanbul ignore next
|
|
182
193
|
child.on('exit', (code) => {
|
|
@@ -75,6 +75,16 @@ export interface Configuration {
|
|
|
75
75
|
secrets?: {
|
|
76
76
|
[k: string]: string;
|
|
77
77
|
};
|
|
78
|
+
/**
|
|
79
|
+
* The environment variables of the integration
|
|
80
|
+
*/
|
|
81
|
+
environmentVariables?: {
|
|
82
|
+
/**
|
|
83
|
+
* This interface was referenced by `undefined`'s JSON-Schema definition
|
|
84
|
+
* via the `patternProperty` "^[A-Z0-9_]+$".
|
|
85
|
+
*/
|
|
86
|
+
[k: string]: string;
|
|
87
|
+
};
|
|
78
88
|
}
|
|
79
89
|
/**
|
|
80
90
|
* An authorization is a way to obtain and generate credentials for an integration
|
|
@@ -180,11 +190,12 @@ export declare enum Method {
|
|
|
180
190
|
OAUTH2 = "oauth2"
|
|
181
191
|
}
|
|
182
192
|
/**
|
|
183
|
-
* The type of grant of the OAuth 2 authorization
|
|
193
|
+
* The type of grant of the OAuth 2 authorization.
|
|
184
194
|
*/
|
|
185
195
|
export declare enum GrantType {
|
|
186
196
|
AUTHORIZATION_CODE = "authorization_code",
|
|
187
|
-
PASSWORD = "password"
|
|
197
|
+
PASSWORD = "password",
|
|
198
|
+
CLIENT_CREDENTIALS = "client_credentials"
|
|
188
199
|
}
|
|
189
200
|
/**
|
|
190
201
|
* The content type of exchanged information with the provider
|
|
@@ -16,12 +16,13 @@ var Method;
|
|
|
16
16
|
Method["OAUTH2"] = "oauth2";
|
|
17
17
|
})(Method || (exports.Method = Method = {}));
|
|
18
18
|
/**
|
|
19
|
-
* The type of grant of the OAuth 2 authorization
|
|
19
|
+
* The type of grant of the OAuth 2 authorization.
|
|
20
20
|
*/
|
|
21
21
|
var GrantType;
|
|
22
22
|
(function (GrantType) {
|
|
23
23
|
GrantType["AUTHORIZATION_CODE"] = "authorization_code";
|
|
24
24
|
GrantType["PASSWORD"] = "password";
|
|
25
|
+
GrantType["CLIENT_CREDENTIALS"] = "client_credentials";
|
|
25
26
|
})(GrantType || (exports.GrantType = GrantType = {}));
|
|
26
27
|
/**
|
|
27
28
|
* The content type of exchanged information with the provider
|
package/dist/src/errors.d.ts
CHANGED
|
@@ -31,9 +31,8 @@ export declare class IntegrationAlreadyExistsError extends Error {
|
|
|
31
31
|
}
|
|
32
32
|
export declare class EntryDecryptionError extends Error {
|
|
33
33
|
key: string;
|
|
34
|
-
value: string;
|
|
35
34
|
environment: string;
|
|
36
|
-
constructor(key: string,
|
|
35
|
+
constructor(key: string, targetEnvironment: string);
|
|
37
36
|
}
|
|
38
37
|
export declare class ConfigurationInvalid extends Error {
|
|
39
38
|
details: unknown;
|
package/dist/src/errors.js
CHANGED
|
@@ -55,12 +55,10 @@ class IntegrationAlreadyExistsError extends Error {
|
|
|
55
55
|
exports.IntegrationAlreadyExistsError = IntegrationAlreadyExistsError;
|
|
56
56
|
class EntryDecryptionError extends Error {
|
|
57
57
|
key;
|
|
58
|
-
value;
|
|
59
58
|
environment;
|
|
60
|
-
constructor(key,
|
|
59
|
+
constructor(key, targetEnvironment) {
|
|
61
60
|
super();
|
|
62
61
|
this.key = key;
|
|
63
|
-
this.value = value;
|
|
64
62
|
this.environment = targetEnvironment;
|
|
65
63
|
}
|
|
66
64
|
}
|
|
@@ -134,7 +132,7 @@ function handleError(command, error) {
|
|
|
134
132
|
else if (error instanceof EntryDecryptionError) {
|
|
135
133
|
command.logToStderr();
|
|
136
134
|
command.logToStderr(chalk_1.default.redBright('A secret cannot be decrypted!'));
|
|
137
|
-
command.logToStderr(`The secret ${chalk_1.default.yellowBright(error.key)}
|
|
135
|
+
command.logToStderr(`The secret ${chalk_1.default.yellowBright(error.key)} could not be decrypted.`);
|
|
138
136
|
command.logToStderr();
|
|
139
137
|
command.logToStderr(`To decrypt this secret locally, make sure:`);
|
|
140
138
|
command.logToStderr();
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import * as GlobalConfiguration from './globalConfiguration';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* Allows the caller to know which keys were decrypted to reencrypt them later as needed
|
|
6
|
-
*/
|
|
7
|
-
export type DecryptionResult = {
|
|
8
|
-
decryptedKeys: string[];
|
|
9
|
-
entries: Record<string, unknown>;
|
|
2
|
+
export type DecryptedEntries = {
|
|
3
|
+
successful: Record<string, unknown>;
|
|
4
|
+
failed: string[];
|
|
10
5
|
};
|
|
11
|
-
export declare function decryptEntries(configurationName: string, environment: GlobalConfiguration.Environment, configDir: string, entries: Record<string, unknown
|
|
6
|
+
export declare function decryptEntries(configurationName: string, environment: GlobalConfiguration.Environment, configDir: string, entries: Record<string, unknown>): Promise<DecryptedEntries>;
|
|
@@ -7,29 +7,37 @@ const GlobalConfiguration = tslib_1.__importStar(require("./globalConfiguration"
|
|
|
7
7
|
const integrationsPlatform_1 = require("./integrationsPlatform");
|
|
8
8
|
const configuration_1 = require("./configuration");
|
|
9
9
|
const integrationsPlatform_2 = require("../services/integrationsPlatform");
|
|
10
|
-
async function decryptEntries(configurationName, environment, configDir, entries
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
async function decryptEntries(configurationName, environment, configDir, entries) {
|
|
11
|
+
if (!Object.keys(entries).length) {
|
|
12
|
+
return { successful: entries, failed: [] };
|
|
13
|
+
}
|
|
14
|
+
const toDecrypt = {};
|
|
15
|
+
const toKeepAsIs = {};
|
|
16
|
+
for (const [key, value] of Object.entries(entries)) {
|
|
17
|
+
if (typeof value === 'string' && value.startsWith(configuration_1.ENCRYPTION_PREFIX)) {
|
|
18
|
+
toDecrypt[key] = value;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
toKeepAsIs[key] = value;
|
|
22
|
+
}
|
|
15
23
|
}
|
|
16
24
|
const globalConfiguration = await GlobalConfiguration.read(configDir);
|
|
17
25
|
try {
|
|
18
26
|
await (0, integrationsPlatform_1.validateAuthenticated)(globalConfiguration, environment);
|
|
19
27
|
}
|
|
20
|
-
catch
|
|
21
|
-
throw new errors_1.DecryptionAuthenticationError(
|
|
28
|
+
catch {
|
|
29
|
+
throw new errors_1.DecryptionAuthenticationError();
|
|
22
30
|
}
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
for (const [key,
|
|
31
|
+
const decrypted = {};
|
|
32
|
+
const failed = [];
|
|
33
|
+
for (const [key, encryptedValue] of Object.entries(toDecrypt)) {
|
|
26
34
|
try {
|
|
27
|
-
|
|
35
|
+
decrypted[key] = (await (0, integrationsPlatform_2.decryptData)(configurationName, encryptedValue)).decryptedData;
|
|
28
36
|
}
|
|
29
|
-
catch
|
|
30
|
-
|
|
37
|
+
catch {
|
|
38
|
+
failed.push(key);
|
|
31
39
|
}
|
|
32
40
|
}
|
|
33
|
-
return {
|
|
41
|
+
return { successful: { ...toKeepAsIs, ...decrypted }, failed };
|
|
34
42
|
}
|
|
35
43
|
exports.decryptEntries = decryptEntries;
|
|
@@ -10,6 +10,8 @@ const IntegrationsPlatformResource = tslib_1.__importStar(require("../../src/res
|
|
|
10
10
|
const ConfigurationResource = tslib_1.__importStar(require("../../src/resources/configuration"));
|
|
11
11
|
const IntegrationResource = tslib_1.__importStar(require("../../src/resources/integrations"));
|
|
12
12
|
const CredentialResource = tslib_1.__importStar(require("../../src/resources/credentials"));
|
|
13
|
+
const DecryptionResource = tslib_1.__importStar(require("../../src/resources/decryption"));
|
|
14
|
+
const styles_1 = require("../helpers/styles");
|
|
13
15
|
describe('Dev', () => {
|
|
14
16
|
const debuggerConfiguration = {
|
|
15
17
|
...IntegrationDebugger.getDefaultConfiguration(),
|
|
@@ -185,4 +187,22 @@ describe('Dev', () => {
|
|
|
185
187
|
(0, test_1.expect)(spawnStub.getCall(0).args.at(1)).to.include('--credential-payload={"from":"credential"}');
|
|
186
188
|
(0, test_1.expect)(spawnStub.getCall(0).args.at(1)).to.not.include('--read-only');
|
|
187
189
|
});
|
|
190
|
+
test_1.test
|
|
191
|
+
.stdout()
|
|
192
|
+
.stub(ConfigurationResource, 'getConfiguration', stub => stub.resolves(cliConfiguration))
|
|
193
|
+
.stub(IntegrationResource, 'validateIsIntegrationDirectory', stub => stub.returns(true))
|
|
194
|
+
.stub(CredentialResource, 'fetchCredential', stub => stub.resolves({ payload: { from: 'credential' } }))
|
|
195
|
+
.stub(DecryptionResource, 'decryptEntries', stub => stub
|
|
196
|
+
.onFirstCall()
|
|
197
|
+
.resolves({ successful: {}, failed: [] })
|
|
198
|
+
.onSecondCall()
|
|
199
|
+
.resolves({ successful: {}, failed: [] })
|
|
200
|
+
.onThirdCall()
|
|
201
|
+
.resolves({ successful: { success: 'a' }, failed: ['failure'] }))
|
|
202
|
+
.command(['dev'])
|
|
203
|
+
.it('environment variables', ctx => {
|
|
204
|
+
(0, test_1.expect)(ctx.stdout).to.contain((0, styles_1.uncolorize)('Could not decrypt the environment variable failure.'));
|
|
205
|
+
(0, test_1.expect)(spawnStub.getCall(0).args.at(2).env.success).to.equal('a');
|
|
206
|
+
(0, test_1.expect)(spawnStub.getCall(0).args.at(2).env.failure).to.be.undefined;
|
|
207
|
+
});
|
|
188
208
|
});
|
|
@@ -6,13 +6,11 @@ const core_1 = require("@oclif/core");
|
|
|
6
6
|
const sinon = tslib_1.__importStar(require("sinon"));
|
|
7
7
|
const inquirer_1 = tslib_1.__importDefault(require("inquirer"));
|
|
8
8
|
const Configuration = tslib_1.__importStar(require("../../src/resources/configuration"));
|
|
9
|
-
const
|
|
9
|
+
const Oauth2Resource = tslib_1.__importStar(require("../../src/resources/oauth2"));
|
|
10
10
|
const IntegrationsPlatform = tslib_1.__importStar(require("../../src/services/integrationsPlatform"));
|
|
11
|
-
const
|
|
11
|
+
const DecryptionResource = tslib_1.__importStar(require("../../src/resources/decryption"));
|
|
12
12
|
const configurationTypes_1 = require("../../src/configurationTypes");
|
|
13
13
|
describe('oauth2', () => {
|
|
14
|
-
const INTEGRATION_NAME = 'myintegration';
|
|
15
|
-
const sandbox = sinon.createSandbox();
|
|
16
14
|
let getConfigurationsStub;
|
|
17
15
|
let writeTestAccountStub;
|
|
18
16
|
let performOAuth2FlowStub;
|
|
@@ -28,7 +26,7 @@ describe('oauth2', () => {
|
|
|
28
26
|
grantType: configurationTypes_1.GrantType.AUTHORIZATION_CODE,
|
|
29
27
|
};
|
|
30
28
|
const baseConfiguration = {
|
|
31
|
-
name:
|
|
29
|
+
name: 'myintegration',
|
|
32
30
|
authorizations: [
|
|
33
31
|
{
|
|
34
32
|
name: 'MyAuthorization',
|
|
@@ -43,19 +41,18 @@ describe('oauth2', () => {
|
|
|
43
41
|
refreshToken: 'refreshToken',
|
|
44
42
|
};
|
|
45
43
|
beforeEach(() => {
|
|
46
|
-
getConfigurationsStub =
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
getConfigurationsStub = sinon.stub(Configuration, 'getConfiguration').resolves(baseConfiguration);
|
|
45
|
+
sinon.spy(core_1.ux.action, 'start');
|
|
46
|
+
sinon.spy(core_1.ux.action, 'stop');
|
|
47
|
+
sinon.stub(inquirer_1.default, 'prompt').resolves({
|
|
50
48
|
oauth2Information: JSON.stringify(oauth2Information),
|
|
51
49
|
});
|
|
52
|
-
writeTestAccountStub =
|
|
53
|
-
performOAuth2FlowStub =
|
|
54
|
-
|
|
55
|
-
updateTokenStub = sandbox.stub(oauth2Service, 'updateToken').resolves(credentials);
|
|
50
|
+
writeTestAccountStub = sinon.stub(Configuration, 'writeTestAccount');
|
|
51
|
+
performOAuth2FlowStub = sinon.stub(Oauth2Resource, 'performOAuth2Flow').resolves(credentials);
|
|
52
|
+
updateTokenStub = sinon.stub(Oauth2Resource, 'updateToken').resolves(credentials);
|
|
56
53
|
});
|
|
57
54
|
afterEach(() => {
|
|
58
|
-
|
|
55
|
+
sinon.restore();
|
|
59
56
|
});
|
|
60
57
|
test_1.test
|
|
61
58
|
.stdout()
|
|
@@ -81,6 +78,7 @@ describe('oauth2', () => {
|
|
|
81
78
|
},
|
|
82
79
|
],
|
|
83
80
|
}))
|
|
81
|
+
.stub(DecryptionResource, 'decryptEntries', stub => stub.resolves({ successful: { ...oauth2Information, clientId: 'devClientID' }, failed: [] }))
|
|
84
82
|
.command(['oauth2', '--test-account', 'development'])
|
|
85
83
|
.it('prioritize development authorization', () => {
|
|
86
84
|
(0, test_1.expect)(performOAuth2FlowStub.getCalls().length).to.equal(1);
|
|
@@ -109,20 +107,6 @@ describe('oauth2', () => {
|
|
|
109
107
|
'development',
|
|
110
108
|
]);
|
|
111
109
|
});
|
|
112
|
-
test_1.test
|
|
113
|
-
.stdout()
|
|
114
|
-
.command(['oauth2', '--test-account', 'development'])
|
|
115
|
-
.it('performs the oauth flow when there is no test accounts and the auth information are setup', () => {
|
|
116
|
-
(0, test_1.expect)(performOAuth2FlowStub.getCalls().length).to.equal(1);
|
|
117
|
-
(0, test_1.expect)(updateTokenStub.getCalls().length).to.equal(0);
|
|
118
|
-
(0, test_1.expect)(writeTestAccountStub.getCall(0).args).to.deep.equal([
|
|
119
|
-
baseConfiguration,
|
|
120
|
-
'production',
|
|
121
|
-
undefined,
|
|
122
|
-
credentials,
|
|
123
|
-
'development',
|
|
124
|
-
]);
|
|
125
|
-
});
|
|
126
110
|
test_1.test
|
|
127
111
|
.stdout()
|
|
128
112
|
.do(() => getConfigurationsStub.returns({
|
|
@@ -131,6 +115,7 @@ describe('oauth2', () => {
|
|
|
131
115
|
development: credentials,
|
|
132
116
|
},
|
|
133
117
|
}))
|
|
118
|
+
.stub(DecryptionResource, 'decryptEntries', stub => stub.resolves({ successful: { ...oauth2Information }, failed: [] }))
|
|
134
119
|
.command(['oauth2', '--test-account', 'development', '--reauth'])
|
|
135
120
|
.it('performs the oauth flow when there is a test accounts, the auth information are setup and --reauth flag is present', () => {
|
|
136
121
|
(0, test_1.expect)(performOAuth2FlowStub.getCalls().length).to.equal(1);
|
|
@@ -156,6 +141,7 @@ describe('oauth2', () => {
|
|
|
156
141
|
development: { something: 'something' },
|
|
157
142
|
},
|
|
158
143
|
}))
|
|
144
|
+
.stub(DecryptionResource, 'decryptEntries', stub => stub.resolves({ successful: { ...oauth2Information }, failed: [] }))
|
|
159
145
|
.command(['oauth2', '--test-account', 'compliance'])
|
|
160
146
|
.it('performs the oauth flow when the requested test account is not setup', () => {
|
|
161
147
|
(0, test_1.expect)(performOAuth2FlowStub.getCalls().length).to.equal(1);
|
|
@@ -181,6 +167,7 @@ describe('oauth2', () => {
|
|
|
181
167
|
development: credentials,
|
|
182
168
|
},
|
|
183
169
|
}))
|
|
170
|
+
.stub(DecryptionResource, 'decryptEntries', stub => stub.resolves({ successful: { ...oauth2Information }, failed: [] }))
|
|
184
171
|
.command(['oauth2', '--test-account', 'development'])
|
|
185
172
|
.it('refresh the token when there is an existing test accounts and the auth information are setup', () => {
|
|
186
173
|
(0, test_1.expect)(performOAuth2FlowStub.getCalls().length).to.equal(0);
|
|
@@ -217,19 +204,19 @@ describe('oauth2', () => {
|
|
|
217
204
|
},
|
|
218
205
|
},
|
|
219
206
|
});
|
|
220
|
-
|
|
221
|
-
.stub(
|
|
207
|
+
sinon
|
|
208
|
+
.stub(DecryptionResource, 'decryptEntries')
|
|
222
209
|
.onFirstCall()
|
|
223
|
-
.resolves({
|
|
210
|
+
.resolves({ successful: { ...oauth2Information, clientSecret: 'devClientID' }, failed: [] })
|
|
224
211
|
.onSecondCall()
|
|
225
212
|
.resolves({
|
|
226
|
-
|
|
227
|
-
|
|
213
|
+
failed: [],
|
|
214
|
+
successful: {
|
|
228
215
|
accessToken: 'devAccessToken',
|
|
229
216
|
refreshToken: 'devRefreshToken',
|
|
230
217
|
},
|
|
231
218
|
});
|
|
232
|
-
|
|
219
|
+
sinon
|
|
233
220
|
.stub(IntegrationsPlatform, 'encryptData')
|
|
234
221
|
.onFirstCall()
|
|
235
222
|
.resolves({ encryptedData: `${Configuration.ENCRYPTION_PREFIX}encryptedAccessToken` })
|
|
@@ -9,7 +9,9 @@ const IntegrationsPlatformResource = tslib_1.__importStar(require("../../src/res
|
|
|
9
9
|
const ConfigurationResource = tslib_1.__importStar(require("../../src/resources/configuration"));
|
|
10
10
|
const IntegrationResource = tslib_1.__importStar(require("../../src/resources/integrations"));
|
|
11
11
|
const CredentialResource = tslib_1.__importStar(require("../../src/resources/credentials"));
|
|
12
|
+
const DecryptionResource = tslib_1.__importStar(require("../../src/resources/decryption"));
|
|
12
13
|
const errors_1 = require("../../src/errors");
|
|
14
|
+
const styles_1 = require("../helpers/styles");
|
|
13
15
|
describe('Test', () => {
|
|
14
16
|
const cliConfiguration = {
|
|
15
17
|
name: 'a',
|
|
@@ -17,6 +19,10 @@ describe('Test', () => {
|
|
|
17
19
|
secrets: {
|
|
18
20
|
secret: 'encryptedSecret',
|
|
19
21
|
},
|
|
22
|
+
environmentVariables: {
|
|
23
|
+
success: '',
|
|
24
|
+
failure: '',
|
|
25
|
+
},
|
|
20
26
|
testAccounts: {
|
|
21
27
|
compliance: {
|
|
22
28
|
accessToken: 'token',
|
|
@@ -209,4 +215,22 @@ describe('Test', () => {
|
|
|
209
215
|
(0, test_1.expect)(spawnStub.getCall(0).args.at(1)).to.include('--credential-payload={"from":"credential"}');
|
|
210
216
|
(0, test_1.expect)(spawnStub.getCall(0).args.at(1)).to.not.include('--read-only');
|
|
211
217
|
});
|
|
218
|
+
test_1.test
|
|
219
|
+
.stdout()
|
|
220
|
+
.stub(ConfigurationResource, 'getConfiguration', stub => stub.resolves(cliConfiguration))
|
|
221
|
+
.stub(IntegrationResource, 'validateIsIntegrationDirectory', stub => stub.returns(true))
|
|
222
|
+
.stub(CredentialResource, 'fetchCredential', stub => stub.resolves({ payload: { from: 'credential' } }))
|
|
223
|
+
.stub(DecryptionResource, 'decryptEntries', stub => stub
|
|
224
|
+
.onFirstCall()
|
|
225
|
+
.resolves({ successful: {}, failed: [] })
|
|
226
|
+
.onSecondCall()
|
|
227
|
+
.resolves({ successful: {}, failed: [] })
|
|
228
|
+
.onThirdCall()
|
|
229
|
+
.resolves({ successful: { success: 'a' }, failed: ['failure'] }))
|
|
230
|
+
.command(['test'])
|
|
231
|
+
.it('environment variables', ctx => {
|
|
232
|
+
(0, test_1.expect)(ctx.stdout).to.contain((0, styles_1.uncolorize)('Could not decrypt the environment variable failure.'));
|
|
233
|
+
(0, test_1.expect)(spawnStub.getCall(0).args.at(2).env.success).to.equal('a');
|
|
234
|
+
(0, test_1.expect)(spawnStub.getCall(0).args.at(2).env.failure).to.be.undefined;
|
|
235
|
+
});
|
|
212
236
|
});
|
package/dist/test/errors.test.js
CHANGED
|
@@ -80,7 +80,7 @@ describe('handleError', () => {
|
|
|
80
80
|
(0, strict_1.default)(handled);
|
|
81
81
|
});
|
|
82
82
|
it('handles EntryDecryptionError', () => {
|
|
83
|
-
const error = new errors_1.EntryDecryptionError('key', '
|
|
83
|
+
const error = new errors_1.EntryDecryptionError('key', 'staging');
|
|
84
84
|
const handled = (0, errors_1.handleError)(command, error);
|
|
85
85
|
(0, strict_1.default)(handled);
|
|
86
86
|
});
|
|
@@ -193,6 +193,36 @@ describe('configuration', () => {
|
|
|
193
193
|
await strict_1.default.rejects(Configuration.getConfiguration(globalConfiguration_1.Environment.Production), errors_1.ConfigurationInvalid);
|
|
194
194
|
});
|
|
195
195
|
});
|
|
196
|
+
describe('validates environment variables', () => {
|
|
197
|
+
it('valid', async () => {
|
|
198
|
+
await fs_1.default.promises.writeFile(Configuration.getConfigurationPath(), JSON.stringify({
|
|
199
|
+
name: 'foo',
|
|
200
|
+
environmentVariables: {
|
|
201
|
+
FOO: 'unito-secret-v1://bar',
|
|
202
|
+
},
|
|
203
|
+
}, null, 2));
|
|
204
|
+
const configuration = await Configuration.getConfiguration(globalConfiguration_1.Environment.Production);
|
|
205
|
+
strict_1.default.deepEqual(configuration.environmentVariables, { FOO: 'unito-secret-v1://bar' });
|
|
206
|
+
});
|
|
207
|
+
it('invalid - type', async () => {
|
|
208
|
+
await fs_1.default.promises.writeFile(Configuration.getConfigurationPath(), JSON.stringify({
|
|
209
|
+
name: 'foo',
|
|
210
|
+
environmentVariables: {
|
|
211
|
+
FOO: 123,
|
|
212
|
+
},
|
|
213
|
+
}, null, 2));
|
|
214
|
+
await strict_1.default.rejects(Configuration.getConfiguration(globalConfiguration_1.Environment.Production), errors_1.ConfigurationInvalid);
|
|
215
|
+
});
|
|
216
|
+
it('invalid - key pattern', async () => {
|
|
217
|
+
await fs_1.default.promises.writeFile(Configuration.getConfigurationPath(), JSON.stringify({
|
|
218
|
+
name: 'foo',
|
|
219
|
+
environmentVariables: {
|
|
220
|
+
foo: 'nope',
|
|
221
|
+
},
|
|
222
|
+
}, null, 2));
|
|
223
|
+
await strict_1.default.rejects(Configuration.getConfiguration(globalConfiguration_1.Environment.Production), errors_1.ConfigurationInvalid);
|
|
224
|
+
});
|
|
225
|
+
});
|
|
196
226
|
describe('validates test accounts - custom', () => {
|
|
197
227
|
it('valid test accounts', async () => {
|
|
198
228
|
await fs_1.default.promises.writeFile(Configuration.getConfigurationPath(), JSON.stringify({
|
|
@@ -40,8 +40,8 @@ describe('decryption helper', () => {
|
|
|
40
40
|
accessToken: 'developmentToken',
|
|
41
41
|
accessToken1: 'developmentToken1',
|
|
42
42
|
});
|
|
43
|
-
strict_1.default.deepEqual(decryptionResult.
|
|
44
|
-
strict_1.default.deepEqual(decryptionResult.
|
|
43
|
+
strict_1.default.deepEqual(decryptionResult.failed, []);
|
|
44
|
+
strict_1.default.deepEqual(decryptionResult.successful, {
|
|
45
45
|
accessToken1: 'developmentToken1',
|
|
46
46
|
accessToken: 'developmentToken',
|
|
47
47
|
});
|
|
@@ -51,8 +51,8 @@ describe('decryption helper', () => {
|
|
|
51
51
|
accessToken: 'token',
|
|
52
52
|
encryptedToken: `${configuration_1.ENCRYPTION_PREFIX}decrypt-me`,
|
|
53
53
|
});
|
|
54
|
-
strict_1.default.deepEqual(decryptionResult.
|
|
55
|
-
strict_1.default.deepEqual(decryptionResult.
|
|
54
|
+
strict_1.default.deepEqual(decryptionResult.failed, []);
|
|
55
|
+
strict_1.default.deepEqual(decryptionResult.successful, {
|
|
56
56
|
accessToken: 'token',
|
|
57
57
|
encryptedToken: `decrypted-me`,
|
|
58
58
|
});
|
|
@@ -62,16 +62,16 @@ describe('decryption helper', () => {
|
|
|
62
62
|
encryptedSecret1: `${configuration_1.ENCRYPTION_PREFIX}decrypt-me`,
|
|
63
63
|
encryptedSecret2: `${configuration_1.ENCRYPTION_PREFIX}decrypt-me`,
|
|
64
64
|
});
|
|
65
|
-
strict_1.default.deepEqual(decryptionResult.
|
|
66
|
-
strict_1.default.deepEqual(decryptionResult.
|
|
65
|
+
strict_1.default.deepEqual(decryptionResult.failed, []);
|
|
66
|
+
strict_1.default.deepEqual(decryptionResult.successful, {
|
|
67
67
|
encryptedSecret1: 'decrypted-me',
|
|
68
68
|
encryptedSecret2: 'decrypted-me',
|
|
69
69
|
});
|
|
70
70
|
});
|
|
71
71
|
it('support empty object', async () => {
|
|
72
72
|
const decryptionResult = await decryptionHelper.decryptEntries(configuration.name, GlobalConfiguration.Environment.Local, '/path/to/config', {});
|
|
73
|
-
strict_1.default.deepEqual(decryptionResult.
|
|
74
|
-
strict_1.default.deepEqual(decryptionResult.
|
|
73
|
+
strict_1.default.deepEqual(decryptionResult.failed, []);
|
|
74
|
+
strict_1.default.deepEqual(decryptionResult.successful, {});
|
|
75
75
|
});
|
|
76
76
|
});
|
|
77
77
|
});
|
|
@@ -44,6 +44,7 @@ describe('integrations platform', function () {
|
|
|
44
44
|
sinon.restore();
|
|
45
45
|
});
|
|
46
46
|
it('environment', function () {
|
|
47
|
+
IntegrationsPlatform.setEnvironment(globalConfiguration_1.Environment.Local);
|
|
47
48
|
strict_1.default.equal(integrations_platform_client_1.default.defaults.baseUrl, integrations_platform_client_1.default.servers.local);
|
|
48
49
|
IntegrationsPlatform.setEnvironment(globalConfiguration_1.Environment.Production);
|
|
49
50
|
strict_1.default.equal(integrations_platform_client_1.default.defaults.baseUrl, integrations_platform_client_1.default.servers.production);
|
package/oclif.manifest.json
CHANGED