@jupiterone/integration-sdk-cli 8.4.0 → 8.4.3
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/document.js.map +1 -1
- package/dist/src/commands/neo4j.js +4 -2
- package/dist/src/commands/neo4j.js.map +1 -1
- package/dist/src/commands/visualize-types.js +1 -1
- package/dist/src/commands/visualize-types.js.map +1 -1
- package/dist/src/config.js +2 -1
- package/dist/src/config.js.map +1 -1
- package/dist/src/neo4j/neo4jGraphStore.js +25 -9
- package/dist/src/neo4j/neo4jGraphStore.js.map +1 -1
- package/dist/src/neo4j/uploadToNeo4j.js.map +1 -1
- package/dist/src/neo4j/wipeNeo4j.js.map +1 -1
- package/dist/src/visualization/generateVisualization.js +2 -2
- package/dist/src/visualization/generateVisualization.js.map +1 -1
- package/dist/src/visualization/retrieveIntegrationData.js.map +1 -1
- package/dist/src/visualization/utils.d.ts +1 -1
- package/dist/src/visualization/utils.js.map +1 -1
- package/dist/tsconfig.dist.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/commands/document.ts +10 -9
- package/src/commands/neo4j.ts +16 -10
- package/src/commands/visualize-types.ts +7 -9
- package/src/config.ts +2 -1
- package/src/neo4j/README.md +15 -18
- package/src/neo4j/__tests__/neo4jGraphStore.test.ts +55 -53
- package/src/neo4j/__tests__/neo4jUtilities.test.ts +27 -9
- package/src/neo4j/index.ts +1 -1
- package/src/neo4j/neo4jGraphStore.ts +64 -29
- package/src/neo4j/uploadToNeo4j.ts +5 -2
- package/src/neo4j/wipeNeo4j.ts +15 -11
- package/src/visualization/__tests__/createMappedRelationshipNodesAndEdges.test.ts +35 -49
- package/src/visualization/generateVisualization.ts +7 -12
- package/src/visualization/retrieveIntegrationData.ts +3 -5
- package/src/visualization/types/IntegrationData.ts +5 -1
- package/src/visualization/utils.ts +7 -4
- package/tsconfig.dist.json +1 -3
- package/tsconfig.json +1 -3
package/src/neo4j/README.md
CHANGED
|
@@ -2,16 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
## Installation
|
|
4
4
|
|
|
5
|
-
This command assumes you have three additional values stored in your
|
|
6
|
-
|
|
7
|
-
NEO4J_URI
|
|
8
|
-
NEO4J_USER
|
|
9
|
-
NEO4J_PASSWORD
|
|
5
|
+
This command assumes you have three additional values stored in your local .env
|
|
6
|
+
file: NEO4J_URI NEO4J_USER NEO4J_PASSWORD
|
|
10
7
|
|
|
11
|
-
This can be used for uploading to local or remote Neo4j databases.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
This can be used for uploading to local or remote Neo4j databases. If SSL is
|
|
9
|
+
needed for a remote connection, specify `bolt+s` or `bolt+ssc` in the URI. For
|
|
10
|
+
easy access to a local Neo4j instance, you can launch one via a Neo4j provided
|
|
11
|
+
Docker image with the command:
|
|
15
12
|
|
|
16
13
|
```
|
|
17
14
|
docker run \
|
|
@@ -25,18 +22,18 @@ docker run \
|
|
|
25
22
|
neo4j:latest
|
|
26
23
|
```
|
|
27
24
|
|
|
28
|
-
If you would like to use a different username and password, the NEO4J_AUTH
|
|
29
|
-
|
|
25
|
+
If you would like to use a different username and password, the NEO4J_AUTH value
|
|
26
|
+
can be modified to whatever username/password you prefer.
|
|
30
27
|
|
|
31
|
-
NOTE:
|
|
32
|
-
|
|
28
|
+
NOTE: Future updates are planned to streamline this without removing the option
|
|
29
|
+
of pushing to an external Neo4j database.
|
|
33
30
|
|
|
34
31
|
## Usage
|
|
35
32
|
|
|
36
33
|
Data is still collected in the same way as before with a call to `yarn start`.
|
|
37
34
|
|
|
38
|
-
Once data has been collected, you can run `j1-integration neo4j push`.
|
|
39
|
-
push data to the Neo4j server listed in the NEO4J_URI .env parameter.
|
|
40
|
-
|
|
41
|
-
http://localhost:7474.
|
|
42
|
-
|
|
35
|
+
Once data has been collected, you can run `j1-integration neo4j push`. This will
|
|
36
|
+
push data to the Neo4j server listed in the NEO4J_URI .env parameter. If running
|
|
37
|
+
locally, you can then access data in the Neo4j database by visiting
|
|
38
|
+
http://localhost:7474. Alternatively, you can download the full Neo4j Desktop
|
|
39
|
+
application at https://neo4j.com/download/.
|
|
@@ -1,63 +1,66 @@
|
|
|
1
|
-
import {
|
|
2
|
-
mockDriver,
|
|
3
|
-
mockSessionFromQuerySet,
|
|
4
|
-
QuerySpec
|
|
5
|
-
} from 'neo-forgery';
|
|
1
|
+
import { mockDriver, mockSessionFromQuerySet, QuerySpec } from 'neo-forgery';
|
|
6
2
|
import * as neo4j from 'neo4j-driver';
|
|
7
3
|
import { Neo4jGraphStore } from '../neo4jGraphStore';
|
|
8
4
|
import { Entity, Relationship } from '@jupiterone/integration-sdk-core';
|
|
9
5
|
|
|
10
6
|
const testInstanceID = 'testInstanceID';
|
|
11
|
-
const testEntityData: Entity[] = [
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
7
|
+
const testEntityData: Entity[] = [
|
|
8
|
+
{
|
|
9
|
+
_type: 'testType',
|
|
10
|
+
_class: 'testClass',
|
|
11
|
+
_key: 'testKey',
|
|
12
|
+
},
|
|
13
|
+
];
|
|
14
|
+
const testRelationshipData: Relationship[] = [
|
|
15
|
+
{
|
|
16
|
+
_fromEntityKey: 'testKey1',
|
|
17
|
+
_toEntityKey: 'testKey2',
|
|
18
|
+
_type: 'testRelType',
|
|
19
|
+
_key: 'relKey',
|
|
20
|
+
_class: 'testRelationshipClass',
|
|
21
|
+
},
|
|
22
|
+
];
|
|
23
|
+
const constraintCall =
|
|
24
|
+
'CREATE CONSTRAINT unique_testType IF NOT EXISTS ON (n:testType) ASSERT n._key IS UNIQUE;';
|
|
24
25
|
const addEntityCall = `MERGE (n:testType {_key: 'testKey', _integrationInstanceID: '${testInstanceID}'}) SET n._type = 'testType', n._class = 'testClass';`;
|
|
25
26
|
const addRelationshipCall = `
|
|
26
27
|
MATCH (start {_key: 'testKey1', _integrationInstanceID: '${testInstanceID}'})
|
|
27
28
|
MATCH (end {_key: 'testKey2', _integrationInstanceID: '${testInstanceID}'})
|
|
28
|
-
MERGE (start)-[relationship:testRelType]->(end)
|
|
29
|
+
MERGE (start)-[relationship:testRelType]->(end);`;
|
|
29
30
|
const wipeByIDCall = `MATCH (n {_integrationInstanceID: '${testInstanceID}'}) DETACH DELETE n`;
|
|
30
31
|
const wipeAllCall = 'MATCH (n) DETACH DELETE n';
|
|
31
|
-
const querySet: QuerySpec[] = [
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
},
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
},
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
},
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
},
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
32
|
+
const querySet: QuerySpec[] = [
|
|
33
|
+
{
|
|
34
|
+
name: 'addConstraint',
|
|
35
|
+
query: constraintCall,
|
|
36
|
+
params: undefined,
|
|
37
|
+
output: { records: [] },
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'addEntity',
|
|
41
|
+
query: addEntityCall,
|
|
42
|
+
params: undefined,
|
|
43
|
+
output: { records: [] },
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: 'addRelationship',
|
|
47
|
+
query: addRelationshipCall,
|
|
48
|
+
params: undefined,
|
|
49
|
+
output: { records: [] },
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'wipeByID',
|
|
53
|
+
query: wipeByIDCall,
|
|
54
|
+
params: undefined,
|
|
55
|
+
output: { records: [] },
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: 'wipeAll',
|
|
59
|
+
query: wipeAllCall,
|
|
60
|
+
params: undefined,
|
|
61
|
+
output: { records: [] },
|
|
62
|
+
},
|
|
63
|
+
];
|
|
61
64
|
|
|
62
65
|
describe('#neo4jGraphStore', () => {
|
|
63
66
|
const mockDriverResp = mockDriver();
|
|
@@ -88,12 +91,11 @@ describe('#neo4jGraphStore', () => {
|
|
|
88
91
|
});
|
|
89
92
|
|
|
90
93
|
test('should generate call to create a Relationship', () => {
|
|
91
|
-
|
|
92
|
-
|
|
94
|
+
expect(async () => await store.addRelationships(testRelationshipData))
|
|
95
|
+
.toReturn;
|
|
93
96
|
});
|
|
94
97
|
|
|
95
98
|
test('should generate call to wipe by ID', () => {
|
|
96
99
|
expect(async () => await store.wipeInstanceIdData()).toReturn;
|
|
97
100
|
});
|
|
98
|
-
|
|
99
|
-
});
|
|
101
|
+
});
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
startsWithNumeric,
|
|
3
|
+
sanitizePropertyName,
|
|
4
|
+
sanitizeValue,
|
|
5
|
+
buildPropertyParameters,
|
|
6
|
+
} from '../neo4jUtilities';
|
|
3
7
|
|
|
4
8
|
describe('#neo4jUtilities', () => {
|
|
5
9
|
test('should return true for string starting with a numeric', () => {
|
|
@@ -11,15 +15,29 @@ describe('#neo4jUtilities', () => {
|
|
|
11
15
|
expect(testTrailingNumeric).toEqual(false);
|
|
12
16
|
});
|
|
13
17
|
test('should sanitize property name properly', () => {
|
|
14
|
-
const testSanitize: string = sanitizePropertyName(
|
|
15
|
-
|
|
18
|
+
const testSanitize: string = sanitizePropertyName(
|
|
19
|
+
`1a!b@c#d$e%f^g&h*i(j)k-l=m+n\\o|p'q"r;s:t/u?v.w,x>y<z\`1~2\t3\n4[5]6{7}8 90`,
|
|
20
|
+
);
|
|
21
|
+
expect(testSanitize).toEqual(
|
|
22
|
+
'n1a_b_c_d_e_f_g_h_i_j_k_l_m_n_o_p_q_r_s_t_u_v_w_x_y_z_1_2_3_4_5_6_7_8_90',
|
|
23
|
+
);
|
|
16
24
|
});
|
|
17
25
|
test('should sanitize value properly', () => {
|
|
18
|
-
const testSanitize: string = sanitizeValue(
|
|
19
|
-
|
|
26
|
+
const testSanitize: string = sanitizeValue(
|
|
27
|
+
'1a!b@c#d$e%f^g&h*i(j)k-l=m+n\\o|p\'q"r;s:t/u?v.w,x>y<z`1~2\t3\n4[5]6{7}8 90',
|
|
28
|
+
);
|
|
29
|
+
expect(testSanitize).toEqual(
|
|
30
|
+
'1a!b@c#d$e%f^g&h*i(j)k-l=m+n\\o|p\'q\\"r;s:t/u?v.w,x>y<z`1~2\t3\n4[5]6{7}8 90',
|
|
31
|
+
);
|
|
20
32
|
});
|
|
21
33
|
test('should build property string correctly including sanitization', () => {
|
|
22
|
-
const testPropResults: Object = buildPropertyParameters({
|
|
23
|
-
|
|
34
|
+
const testPropResults: Object = buildPropertyParameters({
|
|
35
|
+
test: '123',
|
|
36
|
+
'1sanitize1hi&$abc d': '1h"i&$abc d',
|
|
37
|
+
});
|
|
38
|
+
expect(testPropResults).toEqual({
|
|
39
|
+
test: '123',
|
|
40
|
+
n1sanitize1hi__abc_d: '1h\\"i&$abc d',
|
|
41
|
+
});
|
|
24
42
|
});
|
|
25
|
-
});
|
|
43
|
+
});
|
package/src/neo4j/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export * from './uploadToNeo4j';
|
|
2
|
-
export * from './wipeNeo4j';
|
|
2
|
+
export * from './wipeNeo4j';
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { Entity, Relationship } from '@jupiterone/integration-sdk-core';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
sanitizeValue,
|
|
4
|
+
buildPropertyParameters,
|
|
5
|
+
sanitizePropertyName,
|
|
6
|
+
} from './neo4jUtilities';
|
|
3
7
|
|
|
4
8
|
import * as neo4j from 'neo4j-driver';
|
|
5
9
|
|
|
@@ -7,8 +11,8 @@ export interface Neo4jGraphObjectStoreParams {
|
|
|
7
11
|
uri: string;
|
|
8
12
|
username: string;
|
|
9
13
|
password: string;
|
|
10
|
-
integrationInstanceID: string
|
|
11
|
-
session?: neo4j.Session
|
|
14
|
+
integrationInstanceID: string;
|
|
15
|
+
session?: neo4j.Session;
|
|
12
16
|
}
|
|
13
17
|
|
|
14
18
|
export class Neo4jGraphStore {
|
|
@@ -19,10 +23,9 @@ export class Neo4jGraphStore {
|
|
|
19
23
|
private integrationInstanceID: string;
|
|
20
24
|
|
|
21
25
|
constructor(params: Neo4jGraphObjectStoreParams) {
|
|
22
|
-
if(params.session) {
|
|
26
|
+
if (params.session) {
|
|
23
27
|
this.persistedSession = params.session;
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
28
|
+
} else {
|
|
26
29
|
this.neo4jDriver = neo4j.driver(
|
|
27
30
|
params.uri,
|
|
28
31
|
neo4j.auth.basic(params.username, params.password),
|
|
@@ -31,12 +34,14 @@ export class Neo4jGraphStore {
|
|
|
31
34
|
this.integrationInstanceID = params.integrationInstanceID;
|
|
32
35
|
}
|
|
33
36
|
|
|
34
|
-
private async runCypherCommand(
|
|
35
|
-
|
|
37
|
+
private async runCypherCommand(
|
|
38
|
+
cypherCommand: string,
|
|
39
|
+
cypherParameters?: any,
|
|
40
|
+
): Promise<neo4j.Result> {
|
|
41
|
+
if (this.persistedSession) {
|
|
36
42
|
const result = await this.persistedSession.run(cypherCommand);
|
|
37
43
|
return result;
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
44
|
+
} else {
|
|
40
45
|
const session = this.neo4jDriver.session({
|
|
41
46
|
database: this.databaseName,
|
|
42
47
|
defaultAccessMode: neo4j.session.WRITE,
|
|
@@ -50,24 +55,37 @@ export class Neo4jGraphStore {
|
|
|
50
55
|
async addEntities(newEntities: Entity[]) {
|
|
51
56
|
const nodeAlias: string = 'entityNode';
|
|
52
57
|
for (const entity of newEntities) {
|
|
53
|
-
|
|
54
|
-
|
|
58
|
+
let classLabels = '';
|
|
59
|
+
if (entity._class) {
|
|
60
|
+
if (typeof entity._class === 'string') {
|
|
61
|
+
classLabels += `:${sanitizePropertyName(entity._class)}`;
|
|
62
|
+
} else {
|
|
63
|
+
for (const className of entity._class) {
|
|
64
|
+
classLabels += `:${sanitizePropertyName(className)}`;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// I believe we currently can't use parameters for node labels, hence the use of string
|
|
69
|
+
// interpolation in the below commands.
|
|
70
|
+
// Add index if not already in types. This will optimize future
|
|
71
|
+
// MATCH/MERGE calls.
|
|
55
72
|
if (!this.typeList.has(entity._type)) {
|
|
56
73
|
await this.runCypherCommand(
|
|
57
74
|
`CREATE INDEX index_${entity._type} IF NOT EXISTS FOR (n:${entity._type}) ON (n._key, n._integrationInstanceID);`,
|
|
58
75
|
);
|
|
59
76
|
this.typeList.add(entity._type);
|
|
60
77
|
}
|
|
78
|
+
const sanitizedType = sanitizePropertyName(entity._type);
|
|
61
79
|
const propertyParameters = buildPropertyParameters(entity);
|
|
62
80
|
const finalKeyValue = sanitizeValue(entity._key.toString());
|
|
63
81
|
const buildCommand = `
|
|
64
82
|
MERGE (${nodeAlias} {_key: $finalKeyValue, _integrationInstanceID: $integrationInstanceID})
|
|
65
83
|
SET ${nodeAlias} += $propertyParameters
|
|
66
|
-
SET ${nodeAlias}:${
|
|
84
|
+
SET ${nodeAlias}:${sanitizedType}${classLabels};`;
|
|
67
85
|
await this.runCypherCommand(buildCommand, {
|
|
68
|
-
propertyParameters: propertyParameters,
|
|
69
|
-
finalKeyValue: finalKeyValue,
|
|
70
|
-
integrationInstanceID: this.integrationInstanceID
|
|
86
|
+
propertyParameters: propertyParameters,
|
|
87
|
+
finalKeyValue: finalKeyValue,
|
|
88
|
+
integrationInstanceID: this.integrationInstanceID,
|
|
71
89
|
});
|
|
72
90
|
}
|
|
73
91
|
}
|
|
@@ -84,43 +102,60 @@ export class Neo4jGraphStore {
|
|
|
84
102
|
if (relationship._fromEntityKey) {
|
|
85
103
|
startEntityKey = sanitizeValue(relationship._fromEntityKey.toString());
|
|
86
104
|
}
|
|
87
|
-
if(relationship._toEntityKey) {
|
|
105
|
+
if (relationship._toEntityKey) {
|
|
88
106
|
endEntityKey = sanitizeValue(relationship._toEntityKey.toString());
|
|
89
107
|
}
|
|
90
108
|
|
|
91
|
-
if(relationship._mapping) {
|
|
92
|
-
|
|
109
|
+
if (relationship._mapping) {
|
|
110
|
+
//Mapped Relationship
|
|
111
|
+
if (relationship._mapping['skipTargetCreation'] === false) {
|
|
93
112
|
//Create target entity first
|
|
94
113
|
const tempEntity: Entity = {
|
|
95
114
|
_class: relationship._mapping['targetEntity']._class,
|
|
96
115
|
//TODO, I think this key is wrong, but not sure what else to use
|
|
97
|
-
_key:
|
|
116
|
+
_key: sanitizeValue(
|
|
117
|
+
relationship._key.replace(
|
|
118
|
+
relationship._mapping['sourceEntityKey'],
|
|
119
|
+
'',
|
|
120
|
+
),
|
|
121
|
+
),
|
|
98
122
|
_type: relationship._mapping['targetEntity']._type,
|
|
99
|
-
}
|
|
123
|
+
};
|
|
100
124
|
await this.addEntities([tempEntity]);
|
|
101
125
|
}
|
|
102
|
-
startEntityKey = sanitizeValue(
|
|
126
|
+
startEntityKey = sanitizeValue(
|
|
127
|
+
relationship._mapping['sourceEntityKey'],
|
|
128
|
+
);
|
|
103
129
|
// TODO, see above. This key might also be an issue for the same reason
|
|
104
|
-
endEntityKey = sanitizeValue(
|
|
130
|
+
endEntityKey = sanitizeValue(
|
|
131
|
+
relationship._key.replace(
|
|
132
|
+
relationship._mapping['sourceEntityKey'],
|
|
133
|
+
'',
|
|
134
|
+
),
|
|
135
|
+
);
|
|
105
136
|
}
|
|
106
137
|
|
|
138
|
+
const sanitizedRelationshipClass = sanitizePropertyName(
|
|
139
|
+
relationship._class,
|
|
140
|
+
);
|
|
141
|
+
|
|
107
142
|
const buildCommand = `
|
|
108
143
|
MERGE (start {_key: $startEntityKey, _integrationInstanceID: $integrationInstanceID})
|
|
109
144
|
MERGE (end {_key: $endEntityKey, _integrationInstanceID: $integrationInstanceID})
|
|
110
|
-
MERGE (start)-[${relationshipAlias}:${
|
|
145
|
+
MERGE (start)-[${relationshipAlias}:${sanitizedRelationshipClass}]->(end)
|
|
111
146
|
SET ${relationshipAlias} += $propertyParameters;`;
|
|
112
147
|
await this.runCypherCommand(buildCommand, {
|
|
113
|
-
propertyParameters: propertyParameters,
|
|
114
|
-
startEntityKey: startEntityKey,
|
|
148
|
+
propertyParameters: propertyParameters,
|
|
149
|
+
startEntityKey: startEntityKey,
|
|
115
150
|
endEntityKey: endEntityKey,
|
|
116
|
-
integrationInstanceID: this.integrationInstanceID
|
|
151
|
+
integrationInstanceID: this.integrationInstanceID,
|
|
117
152
|
});
|
|
118
153
|
}
|
|
119
154
|
}
|
|
120
155
|
|
|
121
156
|
// TODO, if we get to very large databases we could reach a size where
|
|
122
|
-
// one or both both of the below wipe commands can't be easily executed
|
|
123
|
-
// in memory. At that time, we should consider requiring/using the APOC
|
|
157
|
+
// one or both both of the below wipe commands can't be easily executed
|
|
158
|
+
// in memory. At that time, we should consider requiring/using the APOC
|
|
124
159
|
// library so we can use apoc.periodic.iterate. Leaving out for now,
|
|
125
160
|
// since that would further complicate the Neo4j database setup.
|
|
126
161
|
async wipeInstanceIdData() {
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { Neo4jGraphStore } from './neo4jGraphStore';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
iterateParsedGraphFiles,
|
|
4
|
+
isDirectoryPresent,
|
|
5
|
+
} from '@jupiterone/integration-sdk-runtime';
|
|
3
6
|
import { FlushedGraphObjectData } from '@jupiterone/integration-sdk-runtime/src/storage/types';
|
|
4
7
|
|
|
5
8
|
type UploadToNeo4jParams = {
|
|
@@ -44,4 +47,4 @@ export async function uploadToNeo4j({
|
|
|
44
47
|
} finally {
|
|
45
48
|
await store.close();
|
|
46
49
|
}
|
|
47
|
-
}
|
|
50
|
+
}
|
package/src/neo4j/wipeNeo4j.ts
CHANGED
|
@@ -5,15 +5,17 @@ type WipeNeo4jParams = {
|
|
|
5
5
|
neo4jUri?: string;
|
|
6
6
|
neo4jUser?: string;
|
|
7
7
|
neo4jPassword?: string;
|
|
8
|
-
}
|
|
8
|
+
};
|
|
9
9
|
export async function wipeNeo4jByID({
|
|
10
10
|
integrationInstanceID,
|
|
11
11
|
neo4jUri = process.env.NEO4J_URI,
|
|
12
|
-
neo4jUser = process.env.
|
|
13
|
-
neo4jPassword = process.env.
|
|
12
|
+
neo4jUser = process.env.NEO4J_USER,
|
|
13
|
+
neo4jPassword = process.env.NEO4J_PASSWORD,
|
|
14
14
|
}: WipeNeo4jParams) {
|
|
15
|
-
if(!neo4jUri || !neo4jUser || !neo4jPassword) {
|
|
16
|
-
throw new Error(
|
|
15
|
+
if (!neo4jUri || !neo4jUser || !neo4jPassword) {
|
|
16
|
+
throw new Error(
|
|
17
|
+
'ERROR: must provide login information in function call or include NEO4J_URI, NEO4J_USER, and NEO4J_PASSWORD files in your .env file!',
|
|
18
|
+
);
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
const store = new Neo4jGraphStore({
|
|
@@ -33,15 +35,17 @@ type WipeAllNeo4jParams = {
|
|
|
33
35
|
neo4jUri?: string;
|
|
34
36
|
neo4jUser?: string;
|
|
35
37
|
neo4jPassword?: string;
|
|
36
|
-
}
|
|
38
|
+
};
|
|
37
39
|
|
|
38
40
|
export async function wipeAllNeo4j({
|
|
39
41
|
neo4jUri = process.env.NEO4J_URI,
|
|
40
|
-
neo4jUser = process.env.
|
|
41
|
-
neo4jPassword = process.env.
|
|
42
|
+
neo4jUser = process.env.NEO4J_USER,
|
|
43
|
+
neo4jPassword = process.env.NEO4J_PASSWORD,
|
|
42
44
|
}: WipeAllNeo4jParams) {
|
|
43
|
-
if(!neo4jUri || !neo4jUser || !neo4jPassword) {
|
|
44
|
-
throw new Error(
|
|
45
|
+
if (!neo4jUri || !neo4jUser || !neo4jPassword) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
'ERROR: must provide login information in function call or include NEO4J_URI, NEO4J_USER, and NEO4J_PASSWORD files in your .env file!',
|
|
48
|
+
);
|
|
45
49
|
}
|
|
46
50
|
|
|
47
51
|
const store = new Neo4jGraphStore({
|
|
@@ -55,4 +59,4 @@ export async function wipeAllNeo4j({
|
|
|
55
59
|
} finally {
|
|
56
60
|
await store.close();
|
|
57
61
|
}
|
|
58
|
-
}
|
|
62
|
+
}
|
|
@@ -42,13 +42,11 @@ describe('#createMappedRelationshipNodesAndEdges', () => {
|
|
|
42
42
|
},
|
|
43
43
|
];
|
|
44
44
|
|
|
45
|
-
const {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
explicitEntities,
|
|
51
|
-
});
|
|
45
|
+
const { mappedRelationshipEdges, mappedRelationshipNodes } =
|
|
46
|
+
createMappedRelationshipNodesAndEdges({
|
|
47
|
+
mappedRelationships,
|
|
48
|
+
explicitEntities,
|
|
49
|
+
});
|
|
52
50
|
|
|
53
51
|
expect(mappedRelationshipEdges).toEqual([
|
|
54
52
|
{
|
|
@@ -71,13 +69,11 @@ describe('#createMappedRelationshipNodesAndEdges', () => {
|
|
|
71
69
|
},
|
|
72
70
|
];
|
|
73
71
|
|
|
74
|
-
const {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
explicitEntities,
|
|
80
|
-
});
|
|
72
|
+
const { mappedRelationshipEdges, mappedRelationshipNodes } =
|
|
73
|
+
createMappedRelationshipNodesAndEdges({
|
|
74
|
+
mappedRelationships,
|
|
75
|
+
explicitEntities,
|
|
76
|
+
});
|
|
81
77
|
|
|
82
78
|
expect(mappedRelationshipEdges).toEqual([
|
|
83
79
|
{
|
|
@@ -110,13 +106,11 @@ describe('#createMappedRelationshipNodesAndEdges', () => {
|
|
|
110
106
|
},
|
|
111
107
|
];
|
|
112
108
|
|
|
113
|
-
const {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
explicitEntities,
|
|
119
|
-
});
|
|
109
|
+
const { mappedRelationshipEdges, mappedRelationshipNodes } =
|
|
110
|
+
createMappedRelationshipNodesAndEdges({
|
|
111
|
+
mappedRelationships,
|
|
112
|
+
explicitEntities,
|
|
113
|
+
});
|
|
120
114
|
|
|
121
115
|
expect(mappedRelationshipEdges).toEqual([
|
|
122
116
|
{
|
|
@@ -184,13 +178,11 @@ describe('#createMappedRelationshipNodesAndEdges', () => {
|
|
|
184
178
|
},
|
|
185
179
|
];
|
|
186
180
|
|
|
187
|
-
const {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
explicitEntities,
|
|
193
|
-
});
|
|
181
|
+
const { mappedRelationshipEdges, mappedRelationshipNodes } =
|
|
182
|
+
createMappedRelationshipNodesAndEdges({
|
|
183
|
+
mappedRelationships,
|
|
184
|
+
explicitEntities,
|
|
185
|
+
});
|
|
194
186
|
|
|
195
187
|
expect(mappedRelationshipEdges).toEqual([
|
|
196
188
|
{
|
|
@@ -264,13 +256,11 @@ describe('#createMappedRelationshipNodesAndEdges', () => {
|
|
|
264
256
|
},
|
|
265
257
|
];
|
|
266
258
|
|
|
267
|
-
const {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
explicitEntities,
|
|
273
|
-
});
|
|
259
|
+
const { mappedRelationshipEdges, mappedRelationshipNodes } =
|
|
260
|
+
createMappedRelationshipNodesAndEdges({
|
|
261
|
+
mappedRelationships,
|
|
262
|
+
explicitEntities,
|
|
263
|
+
});
|
|
274
264
|
|
|
275
265
|
expect(mappedRelationshipEdges).toEqual([
|
|
276
266
|
{
|
|
@@ -328,13 +318,11 @@ describe('#createMappedRelationshipNodesAndEdges', () => {
|
|
|
328
318
|
},
|
|
329
319
|
];
|
|
330
320
|
|
|
331
|
-
const {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
explicitEntities,
|
|
337
|
-
});
|
|
321
|
+
const { mappedRelationshipEdges, mappedRelationshipNodes } =
|
|
322
|
+
createMappedRelationshipNodesAndEdges({
|
|
323
|
+
mappedRelationships,
|
|
324
|
+
explicitEntities,
|
|
325
|
+
});
|
|
338
326
|
|
|
339
327
|
expect(mappedRelationshipEdges).toEqual([
|
|
340
328
|
{
|
|
@@ -389,13 +377,11 @@ describe('#createMappedRelationshipNodesAndEdges', () => {
|
|
|
389
377
|
},
|
|
390
378
|
];
|
|
391
379
|
|
|
392
|
-
const {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
explicitEntities,
|
|
398
|
-
});
|
|
380
|
+
const { mappedRelationshipEdges, mappedRelationshipNodes } =
|
|
381
|
+
createMappedRelationshipNodesAndEdges({
|
|
382
|
+
mappedRelationships,
|
|
383
|
+
explicitEntities,
|
|
384
|
+
});
|
|
399
385
|
|
|
400
386
|
expect(mappedRelationshipEdges).toEqual([
|
|
401
387
|
{
|
|
@@ -28,11 +28,8 @@ export async function generateVisualization(
|
|
|
28
28
|
log.warn(`Unable to find any files under path: ${graphDataPath}`);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
const {
|
|
32
|
-
|
|
33
|
-
relationships,
|
|
34
|
-
mappedRelationships,
|
|
35
|
-
} = await retrieveIntegrationData(entitiesAndRelationshipPaths);
|
|
31
|
+
const { entities, relationships, mappedRelationships } =
|
|
32
|
+
await retrieveIntegrationData(entitiesAndRelationshipPaths);
|
|
36
33
|
|
|
37
34
|
const nodeDataSets = entities.map((entity) => ({
|
|
38
35
|
id: getNodeIdFromEntity(entity, []),
|
|
@@ -47,13 +44,11 @@ export async function generateVisualization(
|
|
|
47
44
|
}),
|
|
48
45
|
);
|
|
49
46
|
|
|
50
|
-
const {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
explicitEntities: entities,
|
|
56
|
-
});
|
|
47
|
+
const { mappedRelationshipEdges, mappedRelationshipNodes } =
|
|
48
|
+
createMappedRelationshipNodesAndEdges({
|
|
49
|
+
mappedRelationships,
|
|
50
|
+
explicitEntities: entities,
|
|
51
|
+
});
|
|
57
52
|
|
|
58
53
|
await writeFileToPath({
|
|
59
54
|
path: visualizationOutputPath,
|
|
@@ -18,11 +18,9 @@ export async function retrieveIntegrationData(
|
|
|
18
18
|
const mappedRelationships: MappedRelationship[] = [];
|
|
19
19
|
|
|
20
20
|
const entitiesAndRelationships = await Promise.all(
|
|
21
|
-
entitiesAndRelationshipPaths.map(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
},
|
|
25
|
-
),
|
|
21
|
+
entitiesAndRelationshipPaths.map(async (path): Promise<any> => {
|
|
22
|
+
return await readJsonFromPath<any>(path);
|
|
23
|
+
}),
|
|
26
24
|
);
|
|
27
25
|
|
|
28
26
|
for (const item of entitiesAndRelationships) {
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Entity,
|
|
3
|
+
ExplicitRelationship,
|
|
4
|
+
MappedRelationship,
|
|
5
|
+
} from '@jupiterone/integration-sdk-core';
|
|
2
6
|
|
|
3
7
|
export interface IntegrationData {
|
|
4
8
|
entities: Entity[];
|