@jupiterone/integration-sdk-cli 9.5.0 → 9.6.2
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/generate.d.ts +1 -0
- package/dist/src/commands/generate.js +29 -0
- package/dist/src/commands/generate.js.map +1 -0
- package/dist/src/commands/index.d.ts +1 -0
- package/dist/src/commands/index.js +1 -0
- package/dist/src/commands/index.js.map +1 -1
- package/dist/src/generator/actions.d.ts +4 -0
- package/dist/src/generator/actions.js +38 -0
- package/dist/src/generator/actions.js.map +1 -0
- package/dist/src/generator/configFieldsFlow.d.ts +7 -0
- package/dist/src/generator/configFieldsFlow.js +53 -0
- package/dist/src/generator/configFieldsFlow.js.map +1 -0
- package/dist/src/generator/entitiesFlow.d.ts +7 -0
- package/dist/src/generator/entitiesFlow.js +175 -0
- package/dist/src/generator/entitiesFlow.js.map +1 -0
- package/dist/src/generator/helpers.d.ts +2 -0
- package/dist/src/generator/helpers.js +9 -0
- package/dist/src/generator/helpers.js.map +1 -0
- package/dist/src/generator/newIntegration.d.ts +1 -0
- package/dist/src/generator/newIntegration.js +124 -0
- package/dist/src/generator/newIntegration.js.map +1 -0
- package/dist/src/generator/relationshipsFlow.d.ts +7 -0
- package/dist/src/generator/relationshipsFlow.js +65 -0
- package/dist/src/generator/relationshipsFlow.js.map +1 -0
- package/dist/src/generator/stepTemplate/index.ts.hbs +24 -0
- package/dist/src/generator/stepsFlow.d.ts +10 -0
- package/dist/src/generator/stepsFlow.js +94 -0
- package/dist/src/generator/stepsFlow.js.map +1 -0
- package/dist/src/generator/template/.env.example.hbs +3 -0
- package/dist/src/generator/template/.eslintignore.hbs +1 -0
- package/dist/src/generator/template/.eslintrc.hbs +6 -0
- package/dist/src/generator/template/.github/pull_request_template.md.hbs +17 -0
- package/dist/src/generator/template/.github/workflows/build.yml.hbs +53 -0
- package/dist/src/generator/template/.github/workflows/codeql-analysis.yml.hbs +69 -0
- package/dist/src/generator/template/.github/workflows/integration-deployment.yml.hbs +36 -0
- package/dist/src/generator/template/.github/workflows/peril.yml.hbs +90 -0
- package/dist/src/generator/template/.github/workflows/questions.yml.hbs +40 -0
- package/dist/src/generator/template/.gitignore.hbs +8 -0
- package/dist/src/generator/template/.node-version.hbs +1 -0
- package/dist/src/generator/template/.prettierignore.hbs +5 -0
- package/dist/src/generator/template/CHANGELOG.md.hbs +9 -0
- package/dist/src/generator/template/CODEOWNERS.hbs +3 -0
- package/dist/src/generator/template/Dockerfile.hbs +25 -0
- package/dist/src/generator/template/LICENSE.hbs +373 -0
- package/dist/src/generator/template/README.md.hbs +114 -0
- package/dist/src/generator/template/docs/development.md.hbs +28 -0
- package/dist/src/generator/template/docs/jupiterone.md.hbs +1 -0
- package/dist/src/generator/template/husky.config.js.hbs +1 -0
- package/dist/src/generator/template/jest.config.js.hbs +1 -0
- package/dist/src/generator/template/jupiterone/questions/questions.yaml.hbs +16 -0
- package/dist/src/generator/template/lint-staged.config.js.hbs +1 -0
- package/dist/src/generator/template/package.json.hbs +63 -0
- package/dist/src/generator/template/prettier.config.js.hbs +1 -0
- package/dist/src/generator/template/scripts/execute.sh.hbs +7 -0
- package/dist/src/generator/template/src/client.ts.hbs +23 -0
- package/dist/src/generator/template/src/config.ts.hbs +39 -0
- package/dist/src/generator/template/src/index.ts.hbs +14 -0
- package/dist/src/generator/template/src/steps/constants.ts.hbs +34 -0
- package/dist/src/generator/template/src/steps/index.ts.hbs +7 -0
- package/dist/src/generator/template/src/validateInvocation.ts.hbs +23 -0
- package/dist/src/generator/template/test/README.md.hbs +4 -0
- package/dist/src/generator/template/test/config.ts.hbs +30 -0
- package/dist/src/generator/template/test/recording.ts.hbs +74 -0
- package/dist/src/generator/template/tsconfig.dist.json.hbs +13 -0
- package/dist/src/generator/template/tsconfig.json.hbs +7 -0
- package/dist/src/generator/util.d.ts +9 -0
- package/dist/src/generator/util.js +35 -0
- package/dist/src/generator/util.js.map +1 -0
- package/dist/src/index.js +2 -1
- package/dist/src/index.js.map +1 -1
- package/dist/tsconfig.dist.tsbuildinfo +1 -1
- package/package.json +12 -6
- package/src/commands/generate.ts +28 -0
- package/src/commands/index.ts +1 -0
- package/src/generator/actions.ts +37 -0
- package/src/generator/configFieldsFlow.ts +60 -0
- package/src/generator/entitiesFlow.ts +185 -0
- package/src/generator/helpers.ts +6 -0
- package/src/generator/newIntegration.ts +137 -0
- package/src/generator/relationshipsFlow.ts +73 -0
- package/src/generator/stepTemplate/index.ts.hbs +24 -0
- package/src/generator/stepsFlow.ts +123 -0
- package/src/generator/template/.env.example.hbs +3 -0
- package/src/generator/template/.eslintignore.hbs +1 -0
- package/src/generator/template/.eslintrc.hbs +6 -0
- package/src/generator/template/.github/pull_request_template.md.hbs +17 -0
- package/src/generator/template/.github/workflows/build.yml.hbs +53 -0
- package/src/generator/template/.github/workflows/codeql-analysis.yml.hbs +69 -0
- package/src/generator/template/.github/workflows/integration-deployment.yml.hbs +36 -0
- package/src/generator/template/.github/workflows/peril.yml.hbs +90 -0
- package/src/generator/template/.github/workflows/questions.yml.hbs +40 -0
- package/src/generator/template/.gitignore.hbs +8 -0
- package/src/generator/template/.node-version.hbs +1 -0
- package/src/generator/template/.prettierignore.hbs +5 -0
- package/src/generator/template/CHANGELOG.md.hbs +9 -0
- package/src/generator/template/CODEOWNERS.hbs +3 -0
- package/src/generator/template/Dockerfile.hbs +25 -0
- package/src/generator/template/LICENSE.hbs +373 -0
- package/src/generator/template/README.md.hbs +114 -0
- package/src/generator/template/docs/development.md.hbs +28 -0
- package/src/generator/template/docs/jupiterone.md.hbs +1 -0
- package/src/generator/template/husky.config.js.hbs +1 -0
- package/src/generator/template/jest.config.js.hbs +1 -0
- package/src/generator/template/jupiterone/questions/questions.yaml.hbs +16 -0
- package/src/generator/template/lint-staged.config.js.hbs +1 -0
- package/src/generator/template/package.json.hbs +63 -0
- package/src/generator/template/prettier.config.js.hbs +1 -0
- package/src/generator/template/scripts/execute.sh.hbs +7 -0
- package/src/generator/template/src/client.ts.hbs +23 -0
- package/src/generator/template/src/config.ts.hbs +39 -0
- package/src/generator/template/src/index.ts.hbs +14 -0
- package/src/generator/template/src/steps/constants.ts.hbs +34 -0
- package/src/generator/template/src/steps/index.ts.hbs +7 -0
- package/src/generator/template/src/validateInvocation.ts.hbs +23 -0
- package/src/generator/template/test/README.md.hbs +4 -0
- package/src/generator/template/test/config.ts.hbs +30 -0
- package/src/generator/template/test/recording.ts.hbs +74 -0
- package/src/generator/template/tsconfig.dist.json.hbs +13 -0
- package/src/generator/template/tsconfig.json.hbs +7 -0
- package/src/generator/util.ts +39 -0
- package/src/index.ts +3 -1
- package/tsconfig.dist.json +3 -1
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IntegrationExecutionContext,
|
|
3
|
+
{{#if configFields}}IntegrationValidationError,{{/if}}
|
|
4
|
+
IntegrationInstanceConfigFieldMap,
|
|
5
|
+
IntegrationInstanceConfig,
|
|
6
|
+
} from '@jupiterone/integration-sdk-core';
|
|
7
|
+
import { createAPIClient } from './client';
|
|
8
|
+
|
|
9
|
+
export const instanceConfigFields: IntegrationInstanceConfigFieldMap = {
|
|
10
|
+
{{#each configFields}}
|
|
11
|
+
{{camelCase field}}: {
|
|
12
|
+
type: '{{type}}',
|
|
13
|
+
mask: {{mask}}
|
|
14
|
+
},
|
|
15
|
+
{{/each}}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export interface IntegrationConfig extends IntegrationInstanceConfig {
|
|
19
|
+
{{#each configFields}}
|
|
20
|
+
{{camelCase field}}: {{ type }};
|
|
21
|
+
{{/each}}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function validateInvocation(
|
|
25
|
+
context: IntegrationExecutionContext<IntegrationConfig>,
|
|
26
|
+
) {
|
|
27
|
+
const { config } = context.instance;
|
|
28
|
+
|
|
29
|
+
{{#if configFields}}
|
|
30
|
+
if ({{#each configFields}}!config.{{camelCase field}}{{#unless @last}}||{{/unless}}{{/each}}) {
|
|
31
|
+
throw new IntegrationValidationError(
|
|
32
|
+
'Config requires all of {{#each configFields}}{{camelCase field}}{{#unless @last}},{{/unless}}{{/each}}',
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
{{/if}}
|
|
36
|
+
|
|
37
|
+
const apiClient = createAPIClient(config);
|
|
38
|
+
await apiClient.verifyAuthentication();
|
|
39
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { IntegrationInvocationConfig } from '@jupiterone/integration-sdk-core';
|
|
2
|
+
import { integrationSteps } from './steps';
|
|
3
|
+
import {
|
|
4
|
+
validateInvocation,
|
|
5
|
+
IntegrationConfig,
|
|
6
|
+
instanceConfigFields,
|
|
7
|
+
} from './config';
|
|
8
|
+
|
|
9
|
+
export const invocationConfig: IntegrationInvocationConfig<IntegrationConfig> =
|
|
10
|
+
{
|
|
11
|
+
instanceConfigFields,
|
|
12
|
+
validateInvocation,
|
|
13
|
+
integrationSteps,
|
|
14
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import {
|
|
2
|
+
{{#if relationships}}RelationshipClass,{{/if}}
|
|
3
|
+
StepEntityMetadata,
|
|
4
|
+
StepRelationshipMetadata,
|
|
5
|
+
} from '@jupiterone/integration-sdk-core';
|
|
6
|
+
|
|
7
|
+
export const Steps: Record<{{#unless steps}}string{{/unless}}{{#each steps}}'{{constantCase name}}'{{#unless @last}}|{{/unless}}{{/each}}, string> = {
|
|
8
|
+
{{#each steps}}
|
|
9
|
+
{{constantCase name}}: '{{kebabCase name}}',
|
|
10
|
+
{{/each}}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const Entities: Record<{{#unless entities}}string{{/unless}}{{#each entities}}'{{constantCase resourceName}}'{{#unless @last}}|{{/unless}}{{/each}}
|
|
14
|
+
, StepEntityMetadata > = {
|
|
15
|
+
{{#each entities}}
|
|
16
|
+
{{constantCase resourceName}}: {
|
|
17
|
+
resourceName: '{{resourceName}}',
|
|
18
|
+
_type: '{{_type}}',
|
|
19
|
+
_class: [{{#each _class}}'{{this}}'{{#unless @last}},{{/unless}}{{/each}}],
|
|
20
|
+
},
|
|
21
|
+
{{/each}}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const Relationships: Record<{{#unless relationships}}string{{/unless}}{{#each relationships}}'{{constantCase (generateRelationshipName this)}}'{{#unless @last}}|{{/unless}}{{/each}},
|
|
25
|
+
StepRelationshipMetadata> = {
|
|
26
|
+
{{#each relationships}}
|
|
27
|
+
{{constantCase (generateRelationshipName this)}}: {
|
|
28
|
+
sourceType: Entities.{{ constantCase from.resourceName }}._type,
|
|
29
|
+
targetType: Entities.{{ constantCase to.resourceName }}._type,
|
|
30
|
+
_type: '{{snakeCase (generateRelationshipType this)}}',
|
|
31
|
+
_class: RelationshipClass.{{_class}},
|
|
32
|
+
},
|
|
33
|
+
{{/each}}
|
|
34
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Recording } from '@jupiterone/integration-sdk-testing';
|
|
2
|
+
|
|
3
|
+
describe('#validateInvocation', () => {
|
|
4
|
+
let recording: Recording;
|
|
5
|
+
|
|
6
|
+
afterEach(async () => {
|
|
7
|
+
if (recording) {
|
|
8
|
+
await recording.stop();
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test.todo('requires valid config', async () => {
|
|
13
|
+
// TODO
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test.todo('successfully validates invocation', async () => {
|
|
17
|
+
// TODO
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('fails validating invocation', () => {
|
|
21
|
+
// TODO
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { IntegrationInvocationConfig } from '@jupiterone/integration-sdk-core';
|
|
2
|
+
import { StepTestConfig } from '@jupiterone/integration-sdk-testing';
|
|
3
|
+
import * as dotenv from 'dotenv';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import { invocationConfig } from '../src';
|
|
6
|
+
import { IntegrationConfig } from '../src/config';
|
|
7
|
+
|
|
8
|
+
if (process.env.LOAD_ENV) {
|
|
9
|
+
dotenv.config({
|
|
10
|
+
path: path.join(__dirname, '../.env'),
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
{{#each configField}}
|
|
15
|
+
const DEFAULT_{{constantCase field}} = '';
|
|
16
|
+
{{/each}}
|
|
17
|
+
|
|
18
|
+
export const integrationConfig: IntegrationConfig = {
|
|
19
|
+
{{#each configField}}
|
|
20
|
+
{{camelCase field}}: process.env.{{constantCase field}} || DEFAULT_{{constantCase field}}
|
|
21
|
+
{{/each}}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export function buildStepTestConfigForStep(stepId: string): StepTestConfig {
|
|
25
|
+
return {
|
|
26
|
+
stepId,
|
|
27
|
+
instanceConfig: integrationConfig,
|
|
28
|
+
invocationConfig: invocationConfig as IntegrationInvocationConfig,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {
|
|
2
|
+
setupRecording,
|
|
3
|
+
Recording,
|
|
4
|
+
SetupRecordingInput,
|
|
5
|
+
mutations,
|
|
6
|
+
} from '@jupiterone/integration-sdk-testing';
|
|
7
|
+
|
|
8
|
+
export { Recording };
|
|
9
|
+
|
|
10
|
+
export function setupProjectRecording(
|
|
11
|
+
input: Omit<SetupRecordingInput, 'mutateEntry'>,
|
|
12
|
+
): Recording {
|
|
13
|
+
return setupRecording({
|
|
14
|
+
...input,
|
|
15
|
+
redactedRequestHeaders: ['Authorization'],
|
|
16
|
+
redactedResponseHeaders: ['set-cookie'],
|
|
17
|
+
mutateEntry: mutations.unzipGzippedRecordingEntry,
|
|
18
|
+
/*mutateEntry: (entry) => {
|
|
19
|
+
redact(entry);
|
|
20
|
+
},*/
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// a more sophisticated redaction example below:
|
|
25
|
+
|
|
26
|
+
/*
|
|
27
|
+
function getRedactedOAuthResponse() {
|
|
28
|
+
return {
|
|
29
|
+
access_token: '[REDACTED]',
|
|
30
|
+
expires_in: 9999,
|
|
31
|
+
token_type: 'Bearer',
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function redact(entry): void {
|
|
36
|
+
if (entry.request.postData) {
|
|
37
|
+
entry.request.postData.text = '[REDACTED]';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!entry.response.content.text) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
//let's unzip the entry so we can modify it
|
|
45
|
+
mutations.unzipGzippedRecordingEntry(entry);
|
|
46
|
+
|
|
47
|
+
//we can just get rid of all response content if this was the token call
|
|
48
|
+
const requestUrl = entry.request.url;
|
|
49
|
+
if (requestUrl.match(/oauth\/token/)) {
|
|
50
|
+
entry.response.content.text = JSON.stringify(getRedactedOAuthResponse());
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
//if it wasn't a token call, parse the response text, removing any carriage returns or newlines
|
|
55
|
+
const responseText = entry.response.content.text;
|
|
56
|
+
const parsedResponseText = JSON.parse(responseText.replace(/\r?\n|\r/g, ''));
|
|
57
|
+
|
|
58
|
+
//now we can modify the returned object as desired
|
|
59
|
+
//in this example, if the return text is an array of objects that have the 'tenant' property...
|
|
60
|
+
if (parsedResponseText[0]?.tenant) {
|
|
61
|
+
for (let i = 0; i < parsedResponseText.length; i++) {
|
|
62
|
+
parsedResponseText[i].client_secret = '[REDACTED]';
|
|
63
|
+
parsedResponseText[i].jwt_configuration = '[REDACTED]';
|
|
64
|
+
parsedResponseText[i].signing_keys = '[REDACTED]';
|
|
65
|
+
parsedResponseText[i].encryption_key = '[REDACTED]';
|
|
66
|
+
parsedResponseText[i].addons = '[REDACTED]';
|
|
67
|
+
parsedResponseText[i].client_metadata = '[REDACTED]';
|
|
68
|
+
parsedResponseText[i].mobile = '[REDACTED]';
|
|
69
|
+
parsedResponseText[i].native_social_login = '[REDACTED]';
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
entry.response.content.text = JSON.stringify(parsedResponseText);
|
|
74
|
+
} */
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"include": ["src", "package.json"],
|
|
4
|
+
"exclude": [
|
|
5
|
+
"dist",
|
|
6
|
+
"**/*.test.ts",
|
|
7
|
+
"**/*.test.js",
|
|
8
|
+
"**/*/__tests__/**/*.ts",
|
|
9
|
+
"**/*/__tests__/**/*.js",
|
|
10
|
+
"**/*/__mocks__/**/*.ts",
|
|
11
|
+
"**/*/__mocks__/**/*.js"
|
|
12
|
+
]
|
|
13
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Entity } from './entitiesFlow';
|
|
2
|
+
|
|
3
|
+
async function askRepeatedly<T>(
|
|
4
|
+
inquirer,
|
|
5
|
+
cb: () => Promise<void>,
|
|
6
|
+
): Promise<void> {
|
|
7
|
+
let again = false;
|
|
8
|
+
do {
|
|
9
|
+
await cb();
|
|
10
|
+
again = await askAgain(inquirer);
|
|
11
|
+
} while (again);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function generateChoicesFromEntities(entities) {
|
|
15
|
+
const choices: { name: string; value: Entity }[] = [];
|
|
16
|
+
for (const entity of entities) {
|
|
17
|
+
choices.push({
|
|
18
|
+
name: entity._type,
|
|
19
|
+
value: entity,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return choices;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function confirmPrompt(inquiurer, message) {
|
|
26
|
+
return (
|
|
27
|
+
await inquiurer.prompt({
|
|
28
|
+
type: 'confirm',
|
|
29
|
+
name: 'value',
|
|
30
|
+
message,
|
|
31
|
+
})
|
|
32
|
+
).value;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function askAgain(inquirer) {
|
|
36
|
+
return await confirmPrompt(inquirer, 'Add another?');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export { askAgain, askRepeatedly, confirmPrompt, generateChoicesFromEntities };
|
package/src/index.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
generateIntegrationGraphSchemaCommand,
|
|
15
15
|
generateIngestionSourcesConfigCommand,
|
|
16
16
|
troubleshootLocalExecution,
|
|
17
|
+
generate,
|
|
17
18
|
} from './commands';
|
|
18
19
|
|
|
19
20
|
export function createCli() {
|
|
@@ -30,5 +31,6 @@ export function createCli() {
|
|
|
30
31
|
.addCommand(visualizeDependencies())
|
|
31
32
|
.addCommand(generateIntegrationGraphSchemaCommand())
|
|
32
33
|
.addCommand(generateIngestionSourcesConfigCommand())
|
|
33
|
-
.addCommand(troubleshootLocalExecution())
|
|
34
|
+
.addCommand(troubleshootLocalExecution())
|
|
35
|
+
.addCommand(generate());
|
|
34
36
|
}
|