@jupiterone/integration-sdk-cli 8.24.0 → 8.24.1
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/src/commands/collect.js +5 -5
- package/dist/src/commands/collect.js.map +1 -1
- package/dist/src/commands/diff.d.ts +1 -1
- package/dist/src/commands/diff.js +1 -0
- package/dist/src/commands/diff.js.map +1 -1
- package/dist/src/commands/generate-integration-graph-schema.js +1 -0
- package/dist/src/commands/generate-integration-graph-schema.js.map +1 -1
- package/dist/src/commands/options.d.ts +43 -18
- package/dist/src/commands/options.js +86 -38
- package/dist/src/commands/options.js.map +1 -1
- package/dist/src/commands/run.d.ts +2 -1
- package/dist/src/commands/run.js +21 -36
- package/dist/src/commands/run.js.map +1 -1
- package/dist/src/commands/sync.d.ts +2 -1
- package/dist/src/commands/sync.js +17 -33
- package/dist/src/commands/sync.js.map +1 -1
- package/dist/src/log.js +1 -0
- package/dist/src/log.js.map +1 -1
- package/dist/tsconfig.dist.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/src/__tests__/cli-run.test.ts +0 -83
- package/src/__tests__/cli-sync.test.ts +4 -78
- package/src/__tests__/options.test.ts +223 -0
- package/src/commands/collect.ts +7 -13
- package/src/commands/diff.ts +1 -0
- package/src/commands/generate-integration-graph-schema.ts +1 -0
- package/src/commands/options.ts +159 -42
- package/src/commands/run.ts +38 -75
- package/src/commands/sync.ts +35 -68
- package/src/log.ts +1 -0
|
@@ -64,16 +64,10 @@ test('uploads data to the synchronization api and displays the results', async (
|
|
|
64
64
|
});
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
test('
|
|
68
|
-
process.env.JUPITERONE_DEV = 'true';
|
|
69
|
-
|
|
67
|
+
test('skips finalization with skip-finalize', async () => {
|
|
70
68
|
const job = generateSynchronizationJob();
|
|
71
69
|
|
|
72
|
-
setupSynchronizerApi({
|
|
73
|
-
polly,
|
|
74
|
-
job,
|
|
75
|
-
baseUrl: 'https://api.dev.jupiterone.io',
|
|
76
|
-
});
|
|
70
|
+
setupSynchronizerApi({ polly, job, baseUrl: 'https://api.us.jupiterone.io' });
|
|
77
71
|
|
|
78
72
|
await createCli().parseAsync([
|
|
79
73
|
'node',
|
|
@@ -81,12 +75,13 @@ test('hits dev urls if JUPITERONE_DEV environment variable is set', async () =>
|
|
|
81
75
|
'sync',
|
|
82
76
|
'--integrationInstanceId',
|
|
83
77
|
'test',
|
|
78
|
+
'--skip-finalize',
|
|
84
79
|
]);
|
|
85
80
|
|
|
86
81
|
expect(log.displaySynchronizationResults).toHaveBeenCalledTimes(1);
|
|
87
82
|
expect(log.displaySynchronizationResults).toHaveBeenCalledWith({
|
|
88
83
|
...job,
|
|
89
|
-
status: SynchronizationJobStatus.
|
|
84
|
+
status: SynchronizationJobStatus.AWAITING_UPLOADS,
|
|
90
85
|
// We arrive at these numbers because of what
|
|
91
86
|
// was written to disk in the 'synchronization' project fixture
|
|
92
87
|
numEntitiesUploaded: 6,
|
|
@@ -123,72 +118,3 @@ test('does not publish events for source "api" since there is no integrationJobI
|
|
|
123
118
|
expect(eventsPublished).toBe(false);
|
|
124
119
|
expect(log.displaySynchronizationResults).toHaveBeenCalledTimes(1);
|
|
125
120
|
});
|
|
126
|
-
|
|
127
|
-
test('hits different url if --api-base-url is set', async () => {
|
|
128
|
-
const job = generateSynchronizationJob();
|
|
129
|
-
|
|
130
|
-
setupSynchronizerApi({
|
|
131
|
-
polly,
|
|
132
|
-
job,
|
|
133
|
-
baseUrl: 'https://api.TEST.jupiterone.io',
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
await createCli().parseAsync([
|
|
137
|
-
'node',
|
|
138
|
-
'j1-integration',
|
|
139
|
-
'sync',
|
|
140
|
-
'--integrationInstanceId',
|
|
141
|
-
'test',
|
|
142
|
-
'--api-base-url',
|
|
143
|
-
'https://api.TEST.jupiterone.io',
|
|
144
|
-
]);
|
|
145
|
-
|
|
146
|
-
expect(log.displaySynchronizationResults).toHaveBeenCalledTimes(1);
|
|
147
|
-
expect(log.displaySynchronizationResults).toHaveBeenCalledWith({
|
|
148
|
-
...job,
|
|
149
|
-
status: SynchronizationJobStatus.FINALIZE_PENDING,
|
|
150
|
-
// We arrive at these numbers because of what
|
|
151
|
-
// was written to disk in the 'synchronization' project fixture
|
|
152
|
-
numEntitiesUploaded: 6,
|
|
153
|
-
numRelationshipsUploaded: 3,
|
|
154
|
-
});
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
test('throws an error if --api-base-url is set with --development', async () => {
|
|
158
|
-
const job = generateSynchronizationJob();
|
|
159
|
-
|
|
160
|
-
setupSynchronizerApi({
|
|
161
|
-
polly,
|
|
162
|
-
job,
|
|
163
|
-
baseUrl: 'https://api.TEST.jupiterone.io',
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
await expect(
|
|
167
|
-
createCli().parseAsync([
|
|
168
|
-
'node',
|
|
169
|
-
'j1-integration',
|
|
170
|
-
'sync',
|
|
171
|
-
'--integrationInstanceId',
|
|
172
|
-
'test',
|
|
173
|
-
'--development',
|
|
174
|
-
'--api-base-url',
|
|
175
|
-
'https://api.TEST.jupiterone.io',
|
|
176
|
-
]),
|
|
177
|
-
).rejects.toThrow(
|
|
178
|
-
'Invalid configuration supplied. Cannot specify both --api-base-url and --development(-d) flags.',
|
|
179
|
-
);
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
test('throws if JUPITERONE_API_KEY is not set', async () => {
|
|
183
|
-
delete process.env.JUPITERONE_API_KEY;
|
|
184
|
-
|
|
185
|
-
await expect(
|
|
186
|
-
createCli().parseAsync([
|
|
187
|
-
'node',
|
|
188
|
-
'j1-integration',
|
|
189
|
-
'sync',
|
|
190
|
-
'--integrationInstanceId',
|
|
191
|
-
'test',
|
|
192
|
-
]),
|
|
193
|
-
).rejects.toThrow('JUPITERONE_API_KEY environment variable must be set');
|
|
194
|
-
});
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { createCommand } from 'commander';
|
|
2
|
+
import {
|
|
3
|
+
addApiClientOptionsToCommand,
|
|
4
|
+
addSyncOptionsToCommand,
|
|
5
|
+
ApiClientOptions,
|
|
6
|
+
getApiClientOptions,
|
|
7
|
+
SyncOptions,
|
|
8
|
+
validateApiClientOptions,
|
|
9
|
+
validateSyncOptions,
|
|
10
|
+
} from '../commands/options';
|
|
11
|
+
import {
|
|
12
|
+
DEFAULT_UPLOAD_BATCH_SIZE,
|
|
13
|
+
JUPITERONE_DEV_API_BASE_URL,
|
|
14
|
+
JUPITERONE_PROD_API_BASE_URL,
|
|
15
|
+
} from '@jupiterone/integration-sdk-runtime';
|
|
16
|
+
|
|
17
|
+
const syncOptions = (values?: Partial<SyncOptions>): SyncOptions => ({
|
|
18
|
+
source: 'integration-managed',
|
|
19
|
+
uploadBatchSize: DEFAULT_UPLOAD_BATCH_SIZE,
|
|
20
|
+
uploadRelationshipBatchSize: DEFAULT_UPLOAD_BATCH_SIZE,
|
|
21
|
+
skipFinalize: false,
|
|
22
|
+
...values,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const apiClientOptions = (
|
|
26
|
+
values?: Partial<ApiClientOptions>,
|
|
27
|
+
): ApiClientOptions => ({
|
|
28
|
+
apiBaseUrl: JUPITERONE_PROD_API_BASE_URL,
|
|
29
|
+
development: false,
|
|
30
|
+
...values,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('addSyncOptionsToCommand', () => {
|
|
34
|
+
test('default values', () => {
|
|
35
|
+
expect(
|
|
36
|
+
addSyncOptionsToCommand(createCommand())
|
|
37
|
+
.parse(['node', 'command'])
|
|
38
|
+
.opts<SyncOptions>(),
|
|
39
|
+
).toEqual(syncOptions());
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('--integrationInstanceId', () => {
|
|
43
|
+
expect(
|
|
44
|
+
addSyncOptionsToCommand(createCommand())
|
|
45
|
+
.parse(['node', 'command', '--integrationInstanceId', 'test'])
|
|
46
|
+
.opts(),
|
|
47
|
+
).toEqual(syncOptions({ integrationInstanceId: 'test' }));
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('--source', () => {
|
|
51
|
+
expect(
|
|
52
|
+
addSyncOptionsToCommand(createCommand())
|
|
53
|
+
.parse(['node', 'command', '--source', 'api'])
|
|
54
|
+
.opts(),
|
|
55
|
+
).toEqual(syncOptions({ source: 'api' }));
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('--source unknown', () => {
|
|
59
|
+
expect(() => {
|
|
60
|
+
addSyncOptionsToCommand(createCommand())
|
|
61
|
+
.parse(['node', 'command', '--source', 'unknown'])
|
|
62
|
+
.opts();
|
|
63
|
+
}).toThrowError(/must be/);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe('validateSyncOptions', () => {
|
|
68
|
+
test('valid', () => {
|
|
69
|
+
expect(() =>
|
|
70
|
+
validateSyncOptions(syncOptions({ integrationInstanceId: 'test' })),
|
|
71
|
+
).not.toThrow();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('source: api and integrationInstanceId', () => {
|
|
75
|
+
expect(() =>
|
|
76
|
+
validateSyncOptions(
|
|
77
|
+
syncOptions({ integrationInstanceId: 'test', source: 'api' }),
|
|
78
|
+
),
|
|
79
|
+
).toThrowError(/both --source api and --integrationInstanceId/);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('source: api without scope', () => {
|
|
83
|
+
expect(() =>
|
|
84
|
+
validateSyncOptions(syncOptions({ source: 'api' })),
|
|
85
|
+
).toThrowError(/--source api requires --scope/);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('defaults with no integrationInstanceId', () => {
|
|
89
|
+
expect(() => validateSyncOptions(syncOptions())).toThrowError(
|
|
90
|
+
/--integrationInstanceId or --source api/,
|
|
91
|
+
);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe('addApiClientOptionsToCommand', () => {
|
|
96
|
+
test('default values', () => {
|
|
97
|
+
expect(
|
|
98
|
+
addApiClientOptionsToCommand(createCommand())
|
|
99
|
+
.parse(['node', 'command'])
|
|
100
|
+
.opts<SyncOptions>(),
|
|
101
|
+
).toEqual(apiClientOptions());
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('--development with default --api-base-url', () => {
|
|
105
|
+
expect(
|
|
106
|
+
addApiClientOptionsToCommand(createCommand())
|
|
107
|
+
.parse(['node', 'command', '--development'])
|
|
108
|
+
.opts(),
|
|
109
|
+
).toEqual(
|
|
110
|
+
apiClientOptions({
|
|
111
|
+
development: true,
|
|
112
|
+
apiBaseUrl: JUPITERONE_PROD_API_BASE_URL,
|
|
113
|
+
}),
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe('validApiClientOptions', () => {
|
|
119
|
+
test('valid', () => {
|
|
120
|
+
expect(() => validateApiClientOptions(apiClientOptions())).not.toThrow();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test('--development with default --api-base-url', () => {
|
|
124
|
+
expect(() =>
|
|
125
|
+
validateApiClientOptions(
|
|
126
|
+
apiClientOptions({
|
|
127
|
+
development: true,
|
|
128
|
+
apiBaseUrl: JUPITERONE_PROD_API_BASE_URL,
|
|
129
|
+
}),
|
|
130
|
+
),
|
|
131
|
+
).not.toThrow();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test('--development with --api-base-url JUPITERONE_DEV_API_BASE_URL', () => {
|
|
135
|
+
expect(() =>
|
|
136
|
+
validateApiClientOptions(
|
|
137
|
+
apiClientOptions({
|
|
138
|
+
development: true,
|
|
139
|
+
apiBaseUrl: JUPITERONE_DEV_API_BASE_URL,
|
|
140
|
+
}),
|
|
141
|
+
),
|
|
142
|
+
).not.toThrow();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test('--development with --api-base-url', () => {
|
|
146
|
+
expect(() =>
|
|
147
|
+
validateApiClientOptions(
|
|
148
|
+
apiClientOptions({
|
|
149
|
+
development: true,
|
|
150
|
+
apiBaseUrl: 'https://example.com',
|
|
151
|
+
}),
|
|
152
|
+
),
|
|
153
|
+
).toThrow(/both --development and --api-base-url/);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('getApiClientOptions', () => {
|
|
158
|
+
beforeEach(() => {
|
|
159
|
+
process.env.JUPITERONE_ACCOUNT = 'test account';
|
|
160
|
+
process.env.JUPITERONE_API_KEY = 'test api key';
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
afterEach(() => {
|
|
164
|
+
delete process.env.JUPITERONE_ACCOUNT;
|
|
165
|
+
delete process.env.JUPITERONE_API_KEY;
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test('defaults with valid environment', () => {
|
|
169
|
+
expect(getApiClientOptions(apiClientOptions())).toEqual({
|
|
170
|
+
apiBaseUrl: JUPITERONE_PROD_API_BASE_URL,
|
|
171
|
+
accessToken: 'test api key',
|
|
172
|
+
account: 'test account',
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test('defaults with no JUPITERONE_API_KEY', () => {
|
|
177
|
+
delete process.env.JUPITERONE_API_KEY;
|
|
178
|
+
expect(() => getApiClientOptions(apiClientOptions())).toThrowError(
|
|
179
|
+
/JUPITERONE_API_KEY/,
|
|
180
|
+
);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test('defaults with no JUPITERONE_ACCOUNT', () => {
|
|
184
|
+
delete process.env.JUPITERONE_ACCOUNT;
|
|
185
|
+
expect(() => getApiClientOptions(apiClientOptions())).toThrowError(
|
|
186
|
+
/JUPITERONE_ACCOUNT/,
|
|
187
|
+
);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
test('--development', () => {
|
|
191
|
+
expect(
|
|
192
|
+
getApiClientOptions(apiClientOptions({ development: true })),
|
|
193
|
+
).toEqual({
|
|
194
|
+
apiBaseUrl: JUPITERONE_DEV_API_BASE_URL,
|
|
195
|
+
accessToken: 'test api key',
|
|
196
|
+
account: 'test account',
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test(`--api-base-url ${JUPITERONE_DEV_API_BASE_URL}`, () => {
|
|
201
|
+
expect(
|
|
202
|
+
getApiClientOptions(
|
|
203
|
+
apiClientOptions({ apiBaseUrl: JUPITERONE_DEV_API_BASE_URL }),
|
|
204
|
+
),
|
|
205
|
+
).toEqual({
|
|
206
|
+
apiBaseUrl: JUPITERONE_DEV_API_BASE_URL,
|
|
207
|
+
accessToken: 'test api key',
|
|
208
|
+
account: 'test account',
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
test(`--api-base-url ${JUPITERONE_PROD_API_BASE_URL}`, () => {
|
|
213
|
+
expect(
|
|
214
|
+
getApiClientOptions(
|
|
215
|
+
apiClientOptions({ apiBaseUrl: JUPITERONE_PROD_API_BASE_URL }),
|
|
216
|
+
),
|
|
217
|
+
).toEqual({
|
|
218
|
+
apiBaseUrl: JUPITERONE_PROD_API_BASE_URL,
|
|
219
|
+
accessToken: 'test api key',
|
|
220
|
+
account: 'test account',
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
});
|
package/src/commands/collect.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
|
|
12
12
|
import { loadConfig } from '../config';
|
|
13
13
|
import * as log from '../log';
|
|
14
|
+
import { addPathOptionsToCommand, configureRuntimeFilesystem } from './options';
|
|
14
15
|
|
|
15
16
|
// coercion function to collect multiple values for a flag
|
|
16
17
|
const collector = (value: string, arr: string[]) => {
|
|
@@ -19,13 +20,11 @@ const collector = (value: string, arr: string[]) => {
|
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
export function collect() {
|
|
22
|
-
|
|
23
|
+
const command = createCommand('collect');
|
|
24
|
+
addPathOptionsToCommand(command);
|
|
25
|
+
|
|
26
|
+
return command
|
|
23
27
|
.description('collect data and store entities and relationships to disk')
|
|
24
|
-
.option(
|
|
25
|
-
'-p, --project-path <directory>',
|
|
26
|
-
'path to integration project directory',
|
|
27
|
-
process.cwd(),
|
|
28
|
-
)
|
|
29
28
|
.option(
|
|
30
29
|
'-s, --step <steps>',
|
|
31
30
|
'step(s) to run, comma separated. Utilizes available caches to speed up dependent steps.',
|
|
@@ -42,6 +41,8 @@ export function collect() {
|
|
|
42
41
|
)
|
|
43
42
|
.option('-V, --disable-schema-validation', 'disable schema validation')
|
|
44
43
|
.action(async (options) => {
|
|
44
|
+
configureRuntimeFilesystem(options);
|
|
45
|
+
|
|
45
46
|
if (!options.cache && options.step.length === 0) {
|
|
46
47
|
throw new Error(
|
|
47
48
|
'Invalid option: Option --no-cache requires option --step to also be specified.',
|
|
@@ -53,13 +54,6 @@ export function collect() {
|
|
|
53
54
|
);
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
// Point `fileSystem.ts` functions to expected location relative to
|
|
57
|
-
// integration project path.
|
|
58
|
-
process.env.JUPITERONE_INTEGRATION_STORAGE_DIRECTORY = path.resolve(
|
|
59
|
-
options.projectPath,
|
|
60
|
-
'.j1-integration',
|
|
61
|
-
);
|
|
62
|
-
|
|
63
57
|
if (options.step.length > 0 && options.cache && !options.cachePath) {
|
|
64
58
|
// Step option was used, cache is wanted, and no cache path was provided
|
|
65
59
|
// therefore, copy .j1-integration into .j1-integration-cache
|
package/src/commands/diff.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { IntegrationInvocationConfigLoadError, loadConfig } from '../config';
|
|
|
12
12
|
import { promises as fs } from 'fs';
|
|
13
13
|
import * as log from '../log';
|
|
14
14
|
|
|
15
|
+
/* eslint-disable no-console */
|
|
15
16
|
export function generateIntegrationGraphSchemaCommand() {
|
|
16
17
|
return createCommand('generate-integration-graph-schema')
|
|
17
18
|
.description(
|
package/src/commands/options.ts
CHANGED
|
@@ -1,51 +1,97 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_UPLOAD_BATCH_SIZE,
|
|
3
|
+
getAccountFromEnvironment,
|
|
4
|
+
getApiKeyFromEnvironment,
|
|
5
|
+
JUPITERONE_DEV_API_BASE_URL,
|
|
6
|
+
JUPITERONE_PROD_API_BASE_URL,
|
|
7
|
+
} from '@jupiterone/integration-sdk-runtime';
|
|
8
|
+
import { Command, OptionValues } from 'commander';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
|
|
11
|
+
export interface PathOptions {
|
|
12
|
+
projectPath: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function addPathOptionsToCommand(command: Command): Command {
|
|
16
|
+
return command.option(
|
|
17
|
+
'-p, --project-path <directory>',
|
|
18
|
+
'path to integration project directory',
|
|
19
|
+
process.cwd(),
|
|
20
|
+
);
|
|
21
|
+
}
|
|
2
22
|
|
|
3
23
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* - --development - use the development API
|
|
7
|
-
*
|
|
8
|
-
* @throws Error if both --api-base-url and --development are specified
|
|
24
|
+
* Configure the filesystem interaction code to function against `${options.projectPath}/.j1-integration by setting the
|
|
25
|
+
* global `process.env.JUPITERONE_INTEGRATION_STORAGE_DIRECTORY` variable.
|
|
9
26
|
*/
|
|
10
|
-
export function
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
'Invalid configuration supplied. Cannot specify both --api-base-url and --development(-d) flags.',
|
|
16
|
-
);
|
|
17
|
-
}
|
|
18
|
-
apiBaseUrl = options.apiBaseUrl;
|
|
19
|
-
} else {
|
|
20
|
-
apiBaseUrl = getApiBaseUrl({
|
|
21
|
-
dev: options.development,
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
return apiBaseUrl;
|
|
27
|
+
export function configureRuntimeFilesystem(options: PathOptions): void {
|
|
28
|
+
process.env.JUPITERONE_INTEGRATION_STORAGE_DIRECTORY = path.resolve(
|
|
29
|
+
options.projectPath,
|
|
30
|
+
'.j1-integration',
|
|
31
|
+
);
|
|
25
32
|
}
|
|
26
33
|
|
|
27
|
-
interface
|
|
34
|
+
export interface SyncOptions {
|
|
28
35
|
source: 'integration-managed' | 'integration-external' | 'api';
|
|
29
|
-
scope?: string;
|
|
30
|
-
integrationInstanceId?: string;
|
|
36
|
+
scope?: string | undefined;
|
|
37
|
+
integrationInstanceId?: string | undefined;
|
|
38
|
+
uploadBatchSize: number;
|
|
39
|
+
uploadRelationshipBatchSize: number;
|
|
40
|
+
skipFinalize: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function addSyncOptionsToCommand(command: Command): Command {
|
|
44
|
+
return command
|
|
45
|
+
.option(
|
|
46
|
+
'-i, --integrationInstanceId <id>',
|
|
47
|
+
'_integrationInstanceId assigned to uploaded entities and relationships',
|
|
48
|
+
)
|
|
49
|
+
.option(
|
|
50
|
+
'--source <integration-managed|integration-external|api>',
|
|
51
|
+
'specify synchronization job source value',
|
|
52
|
+
(value: string) => {
|
|
53
|
+
if (
|
|
54
|
+
value !== 'integration-managed' &&
|
|
55
|
+
value !== 'integration-external' &&
|
|
56
|
+
value !== 'api'
|
|
57
|
+
) {
|
|
58
|
+
throw new Error(
|
|
59
|
+
`--source must be one of "integration-managed", "integration-external", or "api"`,
|
|
60
|
+
);
|
|
61
|
+
} else {
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
'integration-managed',
|
|
66
|
+
)
|
|
67
|
+
.option('--scope <anystring>', 'specify synchronization job scope value')
|
|
68
|
+
.option(
|
|
69
|
+
'-u, --upload-batch-size <number>',
|
|
70
|
+
'specify number of entities and relationships per upload batch',
|
|
71
|
+
(value, _previous: Number) => Number(value),
|
|
72
|
+
DEFAULT_UPLOAD_BATCH_SIZE,
|
|
73
|
+
)
|
|
74
|
+
.option(
|
|
75
|
+
'-ur, --upload-relationship-batch-size <number>',
|
|
76
|
+
'specify number of relationships per upload batch, overrides --upload-batch-size',
|
|
77
|
+
(value, _previous: Number) => Number(value),
|
|
78
|
+
DEFAULT_UPLOAD_BATCH_SIZE,
|
|
79
|
+
)
|
|
80
|
+
.option(
|
|
81
|
+
'--skip-finalize',
|
|
82
|
+
'skip synchronization finalization to leave job open for additional uploads',
|
|
83
|
+
false,
|
|
84
|
+
);
|
|
31
85
|
}
|
|
32
86
|
|
|
33
87
|
/**
|
|
34
|
-
*
|
|
35
|
-
* - --source - a specific source to use
|
|
36
|
-
* - --scope - a specific scope to use, required when --source is "api"
|
|
37
|
-
* - --integrationInstanceId - a specific integrationInstanceId to use, required when --source is not "api"
|
|
88
|
+
* Validates options for the synchronization job.
|
|
38
89
|
*
|
|
39
|
-
* @throws Error if --source is "api" and --scope is not specified
|
|
40
|
-
* @throws Error if --source is "api" and --integrationInstanceId is specified
|
|
41
|
-
* @throws Error if one of --integrationInstanceId or --source is not specified
|
|
90
|
+
* @throws {Error} if --source is "api" and --scope is not specified
|
|
91
|
+
* @throws {Error} if --source is "api" and --integrationInstanceId is specified
|
|
92
|
+
* @throws {Error} if one of --integrationInstanceId or --source is not specified
|
|
42
93
|
*/
|
|
43
|
-
export function
|
|
44
|
-
options: any,
|
|
45
|
-
): SynchronizationJobSourceOptions {
|
|
46
|
-
const synchronizeOptions: SynchronizationJobSourceOptions = {
|
|
47
|
-
source: options.source,
|
|
48
|
-
};
|
|
94
|
+
export function validateSyncOptions(options: SyncOptions): SyncOptions {
|
|
49
95
|
if (options.source === 'api') {
|
|
50
96
|
if (options.integrationInstanceId)
|
|
51
97
|
throw new Error(
|
|
@@ -55,19 +101,90 @@ export function getSynchronizationJobSourceOptions(
|
|
|
55
101
|
throw new Error(
|
|
56
102
|
'Invalid configuration supplied. --source api requires --scope flag.',
|
|
57
103
|
);
|
|
58
|
-
synchronizeOptions.scope = options.scope;
|
|
59
104
|
} else if (
|
|
60
105
|
!['integration-managed', 'integration-external'].includes(options.source)
|
|
61
106
|
) {
|
|
62
107
|
throw new Error(
|
|
63
108
|
`Invalid configuration supplied. --source must be one of: integration-managed, integration-external, api. Received: ${options.source}.`,
|
|
64
109
|
);
|
|
65
|
-
} else if (options.integrationInstanceId) {
|
|
66
|
-
synchronizeOptions.integrationInstanceId = options.integrationInstanceId;
|
|
67
|
-
} else {
|
|
110
|
+
} else if (!options.integrationInstanceId) {
|
|
68
111
|
throw new Error(
|
|
69
112
|
'Invalid configuration supplied. --integrationInstanceId or --source api and --scope required.',
|
|
70
113
|
);
|
|
71
114
|
}
|
|
72
|
-
return
|
|
115
|
+
return options;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Returns an object containing only `SyncOptions` properties. This helps to ensure other properties of `OptionValues` are not passed to the `SynchronizationJob`.
|
|
120
|
+
*/
|
|
121
|
+
export function getSyncOptions(options: OptionValues): SyncOptions {
|
|
122
|
+
return {
|
|
123
|
+
source: options.source,
|
|
124
|
+
scope: options.scope,
|
|
125
|
+
integrationInstanceId: options.integrationInstanceId,
|
|
126
|
+
uploadBatchSize: options.uploadBatchSize,
|
|
127
|
+
uploadRelationshipBatchSize: options.uploadRelationshipBatchSize,
|
|
128
|
+
skipFinalize: options.skipFinalize,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface ApiClientOptions {
|
|
133
|
+
development: boolean;
|
|
134
|
+
apiBaseUrl: string;
|
|
135
|
+
apiKey?: string;
|
|
136
|
+
account?: string;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function addApiClientOptionsToCommand(command: Command): Command {
|
|
140
|
+
return command
|
|
141
|
+
.option(
|
|
142
|
+
'--api-base-url <url>',
|
|
143
|
+
'specify synchronization API base URL',
|
|
144
|
+
JUPITERONE_PROD_API_BASE_URL,
|
|
145
|
+
)
|
|
146
|
+
.option(
|
|
147
|
+
'-d, --development',
|
|
148
|
+
'"true" to target apps.dev.jupiterone.io (JUPITERONE_DEV environment variable)',
|
|
149
|
+
!!process.env.JUPITERONE_DEV,
|
|
150
|
+
)
|
|
151
|
+
.option(
|
|
152
|
+
'--account <account>',
|
|
153
|
+
'JupiterOne account ID (JUPITERONE_ACCOUNT environment variable)',
|
|
154
|
+
process.env.JUPITERONE_ACCOUNT,
|
|
155
|
+
)
|
|
156
|
+
.option(
|
|
157
|
+
'--api-key <key>',
|
|
158
|
+
'JupiterOne API key (JUPITERONE_API_KEY environment variable)',
|
|
159
|
+
process.env.JUPITERONE_API_KEY?.replace(/./, '*'),
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function validateApiClientOptions(options: ApiClientOptions) {
|
|
164
|
+
if (
|
|
165
|
+
options.development &&
|
|
166
|
+
![JUPITERONE_PROD_API_BASE_URL, JUPITERONE_DEV_API_BASE_URL].includes(
|
|
167
|
+
options.apiBaseUrl,
|
|
168
|
+
)
|
|
169
|
+
) {
|
|
170
|
+
throw new Error(
|
|
171
|
+
`Invalid configuration supplied. Cannot specify both --development and --api-base-url flags.`,
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Builds a set of options for the 'createApiClient' function.
|
|
178
|
+
*
|
|
179
|
+
* @throws IntegrationApiKeyRequiredError
|
|
180
|
+
* @throws IntegrationAccountRequiredError
|
|
181
|
+
*/
|
|
182
|
+
export function getApiClientOptions(options: ApiClientOptions) {
|
|
183
|
+
return {
|
|
184
|
+
apiBaseUrl: options.development
|
|
185
|
+
? JUPITERONE_DEV_API_BASE_URL
|
|
186
|
+
: options.apiBaseUrl,
|
|
187
|
+
accessToken: options.apiKey || getApiKeyFromEnvironment(),
|
|
188
|
+
account: options.account || getAccountFromEnvironment(),
|
|
189
|
+
};
|
|
73
190
|
}
|