@jupiterone/integration-sdk-cli 8.23.1 → 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 +50 -0
- package/dist/src/commands/options.js +109 -0
- package/dist/src/commands/options.js.map +1 -0
- package/dist/src/commands/run.d.ts +2 -1
- package/dist/src/commands/run.js +28 -43
- package/dist/src/commands/run.js.map +1 -1
- package/dist/src/commands/sync.d.ts +2 -1
- package/dist/src/commands/sync.js +18 -42
- 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 +33 -51
- package/src/__tests__/cli-sync.test.ts +18 -62
- package/src/__tests__/options.test.ts +223 -0
- package/src/__tests__/util/synchronization.ts +17 -3
- 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 +190 -0
- package/src/commands/run.ts +47 -74
- package/src/commands/sync.ts +38 -70
- package/src/log.ts +1 -0
package/src/commands/run.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createCommand } from 'commander';
|
|
1
|
+
import { Command, createCommand, OptionValues } from 'commander';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
|
|
4
4
|
import { Metric } from '@jupiterone/integration-sdk-core';
|
|
@@ -11,84 +11,48 @@ import {
|
|
|
11
11
|
executeIntegrationInstance,
|
|
12
12
|
FileSystemGraphObjectStore,
|
|
13
13
|
finalizeSynchronization,
|
|
14
|
-
getAccountFromEnvironment,
|
|
15
|
-
getApiBaseUrl,
|
|
16
|
-
getApiKeyFromEnvironment,
|
|
17
14
|
initiateSynchronization,
|
|
15
|
+
synchronizationStatus,
|
|
18
16
|
} from '@jupiterone/integration-sdk-runtime';
|
|
19
17
|
import { createPersisterApiStepGraphObjectDataUploader } from '@jupiterone/integration-sdk-runtime/dist/src/execution/uploader';
|
|
20
18
|
|
|
21
19
|
import { loadConfig } from '../config';
|
|
22
20
|
import * as log from '../log';
|
|
21
|
+
import {
|
|
22
|
+
addApiClientOptionsToCommand,
|
|
23
|
+
addPathOptionsToCommand,
|
|
24
|
+
addSyncOptionsToCommand,
|
|
25
|
+
configureRuntimeFilesystem,
|
|
26
|
+
getApiClientOptions,
|
|
27
|
+
getSyncOptions,
|
|
28
|
+
validateApiClientOptions,
|
|
29
|
+
validateSyncOptions,
|
|
30
|
+
} from './options';
|
|
23
31
|
|
|
24
32
|
const DEFAULT_UPLOAD_CONCURRENCY = 5;
|
|
25
33
|
|
|
26
|
-
export function run() {
|
|
27
|
-
|
|
28
|
-
.description('collect and sync to upload entities and relationships')
|
|
29
|
-
.requiredOption(
|
|
30
|
-
'-i, --integrationInstanceId <id>',
|
|
31
|
-
'_integrationInstanceId assigned to uploaded entities and relationships',
|
|
32
|
-
)
|
|
33
|
-
.option(
|
|
34
|
-
'-p, --project-path <directory>',
|
|
35
|
-
'path to integration project directory',
|
|
36
|
-
process.cwd(),
|
|
37
|
-
)
|
|
38
|
-
.option(
|
|
39
|
-
'-d, --development',
|
|
40
|
-
'"true" to target apps.dev.jupiterone.io',
|
|
41
|
-
!!process.env.JUPITERONE_DEV,
|
|
42
|
-
)
|
|
43
|
-
.option('--api-base-url <url>', 'API base URL used during run operation.')
|
|
44
|
-
.option('-V, --disable-schema-validation', 'disable schema validation')
|
|
45
|
-
.option(
|
|
46
|
-
'-u, --upload-batch-size <number>',
|
|
47
|
-
'specify number of items per batch for upload (default 250)',
|
|
48
|
-
)
|
|
49
|
-
.option(
|
|
50
|
-
'-ur, --upload-relationship-batch-size <number>',
|
|
51
|
-
'specify number of relationships per batch for upload (default 250)',
|
|
52
|
-
)
|
|
53
|
-
.action(async (options) => {
|
|
54
|
-
const projectPath = path.resolve(options.projectPath);
|
|
55
|
-
// Point `fileSystem.ts` functions to expected location relative to
|
|
56
|
-
// integration project path.
|
|
57
|
-
process.env.JUPITERONE_INTEGRATION_STORAGE_DIRECTORY = path.resolve(
|
|
58
|
-
projectPath,
|
|
59
|
-
'.j1-integration',
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
log.debug('Loading API Key from JUPITERONE_API_KEY environment variable');
|
|
63
|
-
const accessToken = getApiKeyFromEnvironment();
|
|
34
|
+
export function run(): Command {
|
|
35
|
+
const command = createCommand('run');
|
|
64
36
|
|
|
65
|
-
|
|
66
|
-
|
|
37
|
+
addPathOptionsToCommand(command);
|
|
38
|
+
addApiClientOptionsToCommand(command);
|
|
39
|
+
addSyncOptionsToCommand(command);
|
|
67
40
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
apiBaseUrl = options.apiBaseUrl;
|
|
76
|
-
} else {
|
|
77
|
-
apiBaseUrl = getApiBaseUrl({
|
|
78
|
-
dev: options.development,
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
log.debug(`Configuring client to access "${apiBaseUrl}"`);
|
|
41
|
+
return command
|
|
42
|
+
.description('collect and sync to upload entities and relationships')
|
|
43
|
+
.option('-V, --disable-schema-validation', 'disable schema validation')
|
|
44
|
+
.action(async (options: OptionValues, actionCommand: Command) => {
|
|
45
|
+
configureRuntimeFilesystem(actionCommand.opts());
|
|
46
|
+
validateApiClientOptions(actionCommand.opts());
|
|
47
|
+
validateSyncOptions(actionCommand.opts());
|
|
82
48
|
|
|
83
49
|
const startTime = Date.now();
|
|
84
50
|
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
account
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const { integrationInstanceId } = options;
|
|
51
|
+
const clientApiOptions = getApiClientOptions(actionCommand.opts());
|
|
52
|
+
const apiClient = createApiClient(clientApiOptions);
|
|
53
|
+
log.debug(
|
|
54
|
+
`Configured JupiterOne API client. (apiBaseUrl: '${clientApiOptions.apiBaseUrl}', account: ${clientApiOptions.account})`,
|
|
55
|
+
);
|
|
92
56
|
|
|
93
57
|
let logger = createIntegrationLogger({
|
|
94
58
|
name: 'local',
|
|
@@ -98,7 +62,7 @@ export function run() {
|
|
|
98
62
|
const synchronizationContext = await initiateSynchronization({
|
|
99
63
|
logger,
|
|
100
64
|
apiClient,
|
|
101
|
-
|
|
65
|
+
...getSyncOptions(actionCommand.opts()),
|
|
102
66
|
});
|
|
103
67
|
|
|
104
68
|
logger = synchronizationContext.logger;
|
|
@@ -112,7 +76,9 @@ export function run() {
|
|
|
112
76
|
.on('event', (event) => eventPublishingQueue.enqueue(event))
|
|
113
77
|
.on('metric', (metric) => metrics.push(metric));
|
|
114
78
|
|
|
115
|
-
const invocationConfig = await loadConfig(
|
|
79
|
+
const invocationConfig = await loadConfig(
|
|
80
|
+
path.resolve(options.projectPath, 'src'),
|
|
81
|
+
);
|
|
116
82
|
|
|
117
83
|
const graphObjectStore = new FileSystemGraphObjectStore({
|
|
118
84
|
prettifyFiles: true,
|
|
@@ -127,7 +93,7 @@ export function run() {
|
|
|
127
93
|
invocationConfig,
|
|
128
94
|
{
|
|
129
95
|
current: {
|
|
130
|
-
startedOn:
|
|
96
|
+
startedOn: synchronizationContext.job.startTimestamp,
|
|
131
97
|
},
|
|
132
98
|
},
|
|
133
99
|
{
|
|
@@ -150,12 +116,19 @@ export function run() {
|
|
|
150
116
|
|
|
151
117
|
log.displayExecutionResults(executionResults);
|
|
152
118
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
119
|
+
if (options.skipFinalize) {
|
|
120
|
+
log.info(
|
|
121
|
+
'Skipping synchronization finalization. Job will remain in "AWAITING_UPLOADS" state.',
|
|
122
|
+
);
|
|
123
|
+
const jobStatus = await synchronizationStatus(synchronizationContext);
|
|
124
|
+
log.displaySynchronizationResults(jobStatus);
|
|
125
|
+
} else {
|
|
126
|
+
const synchronizationResult = await finalizeSynchronization({
|
|
127
|
+
...synchronizationContext,
|
|
128
|
+
partialDatasets: executionResults.metadata.partialDatasets,
|
|
129
|
+
});
|
|
130
|
+
log.displaySynchronizationResults(synchronizationResult);
|
|
131
|
+
}
|
|
159
132
|
} catch (err) {
|
|
160
133
|
await eventPublishingQueue.onIdle();
|
|
161
134
|
if (!logger.isHandledError(err)) {
|
package/src/commands/sync.ts
CHANGED
|
@@ -1,92 +1,60 @@
|
|
|
1
|
-
import { createCommand } from 'commander';
|
|
2
|
-
import path from 'path';
|
|
1
|
+
import { Command, createCommand, OptionValues } from 'commander';
|
|
3
2
|
|
|
4
3
|
import {
|
|
5
4
|
createApiClient,
|
|
6
5
|
createIntegrationLogger,
|
|
7
|
-
getAccountFromEnvironment,
|
|
8
|
-
getApiBaseUrl,
|
|
9
|
-
getApiKeyFromEnvironment,
|
|
10
6
|
synchronizeCollectedData,
|
|
11
7
|
} from '@jupiterone/integration-sdk-runtime';
|
|
12
8
|
|
|
13
9
|
import * as log from '../log';
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
import {
|
|
11
|
+
addApiClientOptionsToCommand,
|
|
12
|
+
addPathOptionsToCommand,
|
|
13
|
+
addSyncOptionsToCommand,
|
|
14
|
+
configureRuntimeFilesystem,
|
|
15
|
+
getApiClientOptions,
|
|
16
|
+
getSyncOptions,
|
|
17
|
+
validateApiClientOptions,
|
|
18
|
+
validateSyncOptions,
|
|
19
|
+
} from './options';
|
|
20
|
+
|
|
21
|
+
export function sync(): Command {
|
|
22
|
+
const command = createCommand('sync');
|
|
23
|
+
|
|
24
|
+
addPathOptionsToCommand(command);
|
|
25
|
+
addApiClientOptionsToCommand(command);
|
|
26
|
+
addSyncOptionsToCommand(command);
|
|
27
|
+
|
|
28
|
+
return command
|
|
17
29
|
.description(
|
|
18
30
|
'sync collected data with JupiterOne, requires JUPITERONE_API_KEY, JUPITERONE_ACCOUNT',
|
|
19
31
|
)
|
|
20
|
-
.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
.option(
|
|
30
|
-
'-d, --development',
|
|
31
|
-
'"true" to target apps.dev.jupiterone.io',
|
|
32
|
-
!!process.env.JUPITERONE_DEV,
|
|
33
|
-
)
|
|
34
|
-
.option('--api-base-url <url>', 'API base URL used during sync operation.')
|
|
35
|
-
.option(
|
|
36
|
-
'-u, --upload-batch-size <number>',
|
|
37
|
-
'specify number of items per batch for upload (default 250)',
|
|
38
|
-
)
|
|
39
|
-
.option(
|
|
40
|
-
'-ur, --upload-relationship-batch-size <number>',
|
|
41
|
-
'specify number of relationships per batch for upload (default 250)',
|
|
42
|
-
)
|
|
43
|
-
.action(async (options) => {
|
|
44
|
-
// Point `fileSystem.ts` functions to expected location relative to
|
|
45
|
-
// integration project path.
|
|
46
|
-
process.env.JUPITERONE_INTEGRATION_STORAGE_DIRECTORY = path.resolve(
|
|
47
|
-
options.projectPath,
|
|
48
|
-
'.j1-integration',
|
|
32
|
+
.action(async (options: OptionValues, actionCommand: Command) => {
|
|
33
|
+
configureRuntimeFilesystem(actionCommand.opts());
|
|
34
|
+
validateApiClientOptions(actionCommand.opts());
|
|
35
|
+
validateSyncOptions(actionCommand.opts());
|
|
36
|
+
|
|
37
|
+
const clientApiOptions = getApiClientOptions(actionCommand.opts());
|
|
38
|
+
const apiClient = createApiClient(clientApiOptions);
|
|
39
|
+
log.debug(
|
|
40
|
+
`Configured JupiterOne API client. (apiBaseUrl: '${clientApiOptions.apiBaseUrl}', account: ${clientApiOptions.account})`,
|
|
49
41
|
);
|
|
50
42
|
|
|
51
|
-
log.debug('Loading API Key from JUPITERONE_API_KEY environment variable');
|
|
52
|
-
const accessToken = getApiKeyFromEnvironment();
|
|
53
|
-
|
|
54
|
-
log.debug('Loading account from JUPITERONE_ACCOUNT environment variable');
|
|
55
|
-
const account = getAccountFromEnvironment();
|
|
56
|
-
|
|
57
|
-
let apiBaseUrl: string;
|
|
58
|
-
if (options.apiBaseUrl) {
|
|
59
|
-
if (options.development) {
|
|
60
|
-
throw new Error(
|
|
61
|
-
'Invalid configuration supplied. Cannot specify both --api-base-url and --development(-d) flags.',
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
apiBaseUrl = options.apiBaseUrl;
|
|
65
|
-
} else {
|
|
66
|
-
apiBaseUrl = getApiBaseUrl({
|
|
67
|
-
dev: options.development,
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
log.debug(`Configuring client to access "${apiBaseUrl}"`);
|
|
71
|
-
|
|
72
|
-
const apiClient = createApiClient({
|
|
73
|
-
apiBaseUrl,
|
|
74
|
-
account,
|
|
75
|
-
accessToken,
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
const { integrationInstanceId } = options;
|
|
79
|
-
|
|
80
43
|
const logger = createIntegrationLogger({
|
|
81
44
|
name: 'local',
|
|
82
45
|
pretty: true,
|
|
83
46
|
});
|
|
47
|
+
|
|
48
|
+
const syncOptions = getSyncOptions(actionCommand.opts());
|
|
49
|
+
if (syncOptions.skipFinalize)
|
|
50
|
+
log.info(
|
|
51
|
+
'Skipping synchronization finalization. Job will remain in "AWAITING_UPLOADS" state.',
|
|
52
|
+
);
|
|
53
|
+
|
|
84
54
|
const job = await synchronizeCollectedData({
|
|
85
|
-
logger: logger.child(
|
|
55
|
+
logger: logger.child(syncOptions),
|
|
86
56
|
apiClient,
|
|
87
|
-
|
|
88
|
-
uploadBatchSize: options.uploadBatchSize,
|
|
89
|
-
uploadRelationshipBatchSize: options.uploadRelationshipBatchSize,
|
|
57
|
+
...syncOptions,
|
|
90
58
|
});
|
|
91
59
|
|
|
92
60
|
log.displaySynchronizationResults(job);
|