@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.
@@ -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
- return createCommand('run')
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
- log.debug('Loading account from JUPITERONE_ACCOUNT environment variable');
66
- const account = getAccountFromEnvironment();
37
+ addPathOptionsToCommand(command);
38
+ addApiClientOptionsToCommand(command);
39
+ addSyncOptionsToCommand(command);
67
40
 
68
- let apiBaseUrl: string;
69
- if (options.apiBaseUrl) {
70
- if (options.development) {
71
- throw new Error(
72
- 'Invalid configuration supplied. Cannot specify both --api-base-url and --development(-d) flags.',
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 apiClient = createApiClient({
86
- apiBaseUrl,
87
- accessToken,
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
- integrationInstanceId,
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(path.join(projectPath, 'src'));
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: startTime,
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
- const synchronizationResult = await finalizeSynchronization({
154
- ...synchronizationContext,
155
- partialDatasets: executionResults.metadata.partialDatasets,
156
- });
157
-
158
- log.displaySynchronizationResults(synchronizationResult);
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)) {
@@ -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
- export function sync() {
16
- return createCommand('sync')
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
- .requiredOption(
21
- '-i, --integrationInstanceId <id>',
22
- '_integrationInstanceId assigned to uploaded entities and relationships',
23
- )
24
- .option(
25
- '-p, --project-path <directory>',
26
- 'path to integration project directory',
27
- process.cwd(),
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({ integrationInstanceId }),
55
+ logger: logger.child(syncOptions),
86
56
  apiClient,
87
- integrationInstanceId,
88
- uploadBatchSize: options.uploadBatchSize,
89
- uploadRelationshipBatchSize: options.uploadRelationshipBatchSize,
57
+ ...syncOptions,
90
58
  });
91
59
 
92
60
  log.displaySynchronizationResults(job);
package/src/log.ts CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  Metric,
12
12
  } from '@jupiterone/integration-sdk-core';
13
13
 
14
+ /* eslint-disable no-console */
14
15
  export function debug(msg: string) {
15
16
  console.log(`${chalk.gray(msg)}`);
16
17
  }