Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions src/index.new.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,6 @@ describe('Core Index Tests', () => {
test('startSyncJob', () => {
expect(j1).toHaveProperty('startSyncJob');
});
test('uploadGraphObjectsForDeleteSyncJob', () => {
expect(j1).toHaveProperty('uploadGraphObjectsForDeleteSyncJob');
});
test('uploadGraphObjectsForSyncJob', () => {
expect(j1).toHaveProperty('uploadGraphObjectsForSyncJob');
});
Expand All @@ -103,9 +100,6 @@ describe('Core Index Tests', () => {
test('bulkUpload', () => {
expect(j1).toHaveProperty('bulkUpload');
});
test('bulkDelete', () => {
expect(j1).toHaveProperty('bulkDelete');
});

test('--api-base-url properly sets URLs', () => {
const jupiterOneCustomURLClient = new JupiterOneClient({
Expand Down Expand Up @@ -273,7 +267,7 @@ describe('Core Index Tests', () => {
const argumentOne = {
syncJobOptions: {
scope: 'an_example_scope',
syncMode: SyncJobModes.CREATE_OR_UPDATE,
syncMode: 'DIFF',
},
entities: [exampleEntity],
};
Expand All @@ -287,7 +281,7 @@ describe('Core Index Tests', () => {
const expectedArgument = {
source: SyncJobSources.API,
scope: 'an_example_scope',
syncMode: SyncJobModes.CREATE_OR_UPDATE,
syncMode: 'DIFF',
};

expect(j1.startSyncJob).toHaveBeenCalledWith(expectedArgument);
Expand Down
129 changes: 47 additions & 82 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@
import { networkRequest } from './networkRequest';

import {
Entity,
EntityForSync,
Relationship,
RelationshipForSync,
IntegrationDefinition,
ListIntegrationDefinitions,
Expand Down Expand Up @@ -74,8 +72,10 @@
nameForLogging?: string;
}) {
super(
`JupiterOne API error. Response not OK (requestName=${options.nameForLogging || '(none)'
}, status=${options.response.status}, url=${options.url}, method=${options.method
`JupiterOne API error. Response not OK (requestName=${
options.nameForLogging || '(none)'
}, status=${options.response.status}, url=${options.url}, method=${
options.method
}). Response: ${options.responseBody}`,
);
this.httpStatusCode = options.response.status;
Expand Down Expand Up @@ -111,7 +111,7 @@
{
maxAttempts: 5,
delay: 1000,
handleError(err, context, options) {

Check warning on line 114 in src/index.ts

View workflow job for this annotation

GitHub Actions / test

'options' is defined but never used

Check warning on line 114 in src/index.ts

View workflow job for this annotation

GitHub Actions / test

'options' is defined but never used
const possibleFetchError = err as Partial<FetchError>;
const { httpStatusCode } = possibleFetchError;
if (httpStatusCode !== undefined) {
Expand Down Expand Up @@ -163,7 +163,7 @@

export interface JupiterOneEntity {
entity: JupiterOneEntityMetadata;
properties: any;

Check warning on line 166 in src/index.ts

View workflow job for this annotation

GitHub Actions / test

Unexpected any. Specify a different type

Check warning on line 166 in src/index.ts

View workflow job for this annotation

GitHub Actions / test

Unexpected any. Specify a different type
}

export interface QueryResult {
Expand Down Expand Up @@ -252,7 +252,6 @@

export enum SyncJobModes {
DIFF = 'DIFF',
CREATE_OR_UPDATE = 'CREATE_OR_UPDATE',
}

export type SyncJobResponse = {
Expand Down Expand Up @@ -283,7 +282,7 @@
};

export class JupiterOneClient {
graphClient: ApolloClient<any>;

Check warning on line 285 in src/index.ts

View workflow job for this annotation

GitHub Actions / test

Unexpected any. Specify a different type

Check warning on line 285 in src/index.ts

View workflow job for this annotation

GitHub Actions / test

Unexpected any. Specify a different type
headers?: Record<string, string>;
account: string;
accessToken: string;
Expand Down Expand Up @@ -356,21 +355,20 @@
* this limits the looping to stop after at least {stopAfter} results are found
* @deprecated This property is no longer supported.
*/
stopAfter = Number.MAX_SAFE_INTEGER,

Check warning on line 358 in src/index.ts

View workflow job for this annotation

GitHub Actions / test

'stopAfter' is assigned a value but never used

Check warning on line 358 in src/index.ts

View workflow job for this annotation

GitHub Actions / test

'stopAfter' is assigned a value but never used
/** same as above, this gives more fine-grained control over the starting point of the query,
* since this method controls the `SKIP` clause in the query
* @deprecated This property is no longer supported.
*/
startPage = 0,

Check warning on line 363 in src/index.ts

View workflow job for this annotation

GitHub Actions / test

'startPage' is assigned a value but never used

Check warning on line 363 in src/index.ts

View workflow job for this annotation

GitHub Actions / test

'startPage' is assigned a value but never used
) {

let cursor: string;
let complete = false;
let results: any[] = [];

Check warning on line 367 in src/index.ts

View workflow job for this annotation

GitHub Actions / test

Unexpected any. Specify a different type

Check warning on line 367 in src/index.ts

View workflow job for this annotation

GitHub Actions / test

Unexpected any. Specify a different type

const limitCheck = j1ql.match(/limit (\d+)/i);

let progress: any;

Check warning on line 371 in src/index.ts

View workflow job for this annotation

GitHub Actions / test

Unexpected any. Specify a different type

Check warning on line 371 in src/index.ts

View workflow job for this annotation

GitHub Actions / test

Unexpected any. Specify a different type

do {
const res = await this.graphClient.query({
Expand All @@ -379,9 +377,9 @@
query: j1ql,
deferredResponse: 'FORCE',
flags: {
variableResultSize: true
variableResultSize: true,
},
cursor
cursor,
},
...options,
});
Expand All @@ -391,12 +389,13 @@

const deferredUrl = res.data.queryV1.url;
let status = JobStatus.IN_PROGRESS;
let statusFile: any;

Check warning on line 392 in src/index.ts

View workflow job for this annotation

GitHub Actions / test

Unexpected any. Specify a different type
const startTimeInMs = Date.now();
do {

Check warning on line 394 in src/index.ts

View workflow job for this annotation

GitHub Actions / test

Unexpected any. Specify a different type
if (Date.now() - startTimeInMs > QUERY_RESULTS_TIMEOUT) {
throw new Error(
`Exceeded request timeout of ${QUERY_RESULTS_TIMEOUT / 1000
`Exceeded request timeout of ${
QUERY_RESULTS_TIMEOUT / 1000
} seconds.`,
);
}
Expand All @@ -408,27 +407,31 @@
} while (status === JobStatus.IN_PROGRESS);

if (status === JobStatus.FAILED) {
throw new Error(`JupiterOne returned error(s) for query: '${statusFile.error}'`);
throw new Error(
`JupiterOne returned error(s) for query: '${statusFile.error}'`,
);
}

const result = statusFile.data;

if (showProgress && !limitCheck) {
if (results.length === 0) {
progress = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
progress = new cliProgress.SingleBar(
{},
cliProgress.Presets.shades_classic,
);
progress.start(Number(statusFile.totalCount), 0);
}
progress.update(results.length);
}

if (result) {
results = results.concat(result)
results = results.concat(result);
}

if (status === JobStatus.COMPLETED && (cursor == null || limitCheck)) {
complete = true;
}

} while (complete === false);
return results;
}
Expand Down Expand Up @@ -866,57 +869,44 @@
return validateSyncJobResponse(response);
}

async uploadGraphObjectsForDeleteSyncJob(options: {
syncJobId: string;
entities?: Entity[];
relationships?: Relationship[];
}): Promise<SyncJobResponse> {
const upload: GraphObjectDeletionPayload = {
deleteEntities: [],
deleteRelationships: [],
};
for (const e of options.entities || []) {
upload.deleteEntities.push({ _id: e?.['_id'] });
}

for (const r of options.relationships || []) {
upload.deleteRelationships.push({ _id: r?.['_id'] });
}

this.logger.trace(upload, 'Full upload of deletion sync job');
this.logger.info('uploading deletion sync job');
const headers = this.headers;
const response = await makeFetchRequest(
this.apiUrl +
`/persister/synchronization/jobs/${options.syncJobId}/upload`,
{
method: 'POST',
headers,
body: JSON.stringify(upload),
},
);
return validateSyncJobResponse(response);
}

async uploadGraphObjectsForSyncJob(options: {
syncJobId: string;
entities?: EntityForSync[];
relationships?: RelationshipForSync[];
}): Promise<SyncJobResponse> {
const { syncJobId, entities, relationships } = options;
const headers = this.headers;
const response = await makeFetchRequest(
this.apiUrl + `/persister/synchronization/jobs/${syncJobId}/upload`,
{
method: 'POST',
headers,
body: JSON.stringify({
entities,
relationships,
}),
},
);
return validateSyncJobResponse(response);
let response: SyncJobResponse | undefined = undefined;
if (entities.length) {
const entitiesResponse = await makeFetchRequest(
this.apiUrl + `/persister/synchronization/jobs/${syncJobId}/entities`,
{
method: 'POST',
headers,
body: JSON.stringify({
entities,
}),
},
);
response = await validateSyncJobResponse(entitiesResponse);
}

if (relationships.length) {
const relationshipsResponse = await makeFetchRequest(
this.apiUrl +
`/persister/synchronization/jobs/${syncJobId}/relationships`,
{
method: 'POST',
headers,
body: JSON.stringify({
relationships,
}),
},
);

response = await validateSyncJobResponse(relationshipsResponse);
}
return response;
}

async finalizeSyncJob(options: {
Expand Down Expand Up @@ -1031,29 +1021,4 @@
finalizeResult,
};
}

async bulkDelete(data: {
entities?: Entity[];
relationships?: Relationship[];
}): Promise<SyncJobResult | undefined> {
if (data.entities || data.relationships) {
const { job: syncJob } = await this.startSyncJob({
source: SyncJobSources.API,
syncMode: SyncJobModes.CREATE_OR_UPDATE,
});
const syncJobId = syncJob.id;
await this.uploadGraphObjectsForDeleteSyncJob({
syncJobId,
entities: data.entities,
relationships: data.relationships,
});
const finalizeResult = await this.finalizeSyncJob({ syncJobId });
return {
syncJobId,
finalizeResult,
};
} else {
this.logger.info('No entities or relationships to upload.');
}
}
}
Loading