Skip to content
This repository has been archived by the owner on Aug 16, 2024. It is now read-only.

Sonarqube filter params sdk 13.x #54

Merged
merged 23 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from 15 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
26 changes: 25 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
BASE_URL=
API_TOKEN=
ENABLE_FINDINGS_INGESTION=
ENABLE_FINDINGS_INGESTION=true/false

# INFO, MINOR -> LOW in API Version 2
# MAJOR -> MEDIUM in API Version 2
# CRITICAL BLOCKERS -> HIGH in API Version 2
# 0 or more values you can pass from given values
SEVERITIES=INFO,MINOR,MAJOR,CRITICAL,BLOCKER

# OPEN -> OPEN in API Version 2
# CONFIRMED -> CONFIRMED' in API Version 2
# REOPENED -> FALSE_POSITIVE' in API Version 2
# RESOLVED -> ACCEPTED' in API Version 2
# CLOSED -> FIXED in API Version 2
# 0 or more values you can pass from given values
STATUS=OPEN,CONFIRMED,REOPENED,RESOLVED,CLOSED

#createdInLast: optional
#To retrieve issues created during a time span before the current time (exclusive). Accepted units are 'y' for year, 'm' for month, 'w' for week and 'd' for day. If this parameter is set, createdAfter must not be set
# Example value: 1m2w (1 month 2 weeks)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change this name to FINDINGS_INGEST_SINCE_DAYS and make it a number where options are 90, 180, 275, 365 (days). Then you can convert those to the format sonarqube expects when you send the request. This way we are not attached to using their format in our config.
Github example:
image

CREATED_IN_LAST=10d # default value is 10 days

# CODE_SMELL -> MAINTAINABILITY in API Version 2
# BUG -> RELIABILITY in API Version 2
# VULNERABILITY: SECURITY in API Version 2
TYPES=CODE_SMELL,BUG,VULNERABILITY # 0 or more values you can pass from given values
6 changes: 3 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
strategy:
fail-fast: false
matrix:
node-version: [14.x]
node-version: [18.x]
os: [ubuntu-latest]

steps:
Expand Down Expand Up @@ -38,13 +38,13 @@ jobs:
strategy:
fail-fast: false
matrix:
node: [14]
node: [18]

steps:
- name: Setup Node
uses: actions/setup-node@v1
with:
node-version: 14.x
node-version: 18.x

- name: Check out repo
uses: actions/checkout@v2
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:14-alpine
FROM node:18-alpine

ENV JUPITERONE_INTEGRATION_DIR=/opt/jupiterone/integration

Expand Down
11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,14 @@
"prepack": "yarn build"
},
"peerDependencies": {
"@jupiterone/integration-sdk-core": "^8.30.0"
"@jupiterone/integration-sdk-core": "^13.1.0"
},
"devDependencies": {
"@jupiterone/integration-sdk-core": "^8.30.0",
"@jupiterone/integration-sdk-dev-tools": "^8.30.0",
"@jupiterone/integration-sdk-testing": "^8.30.0",
"@types/node-fetch": "^2.5.10"
"@jupiterone/integration-sdk-core": "^13.1.0",
"@jupiterone/integration-sdk-dev-tools": "^13.1.0",
"@jupiterone/integration-sdk-testing": "^13.1.0",
"@types/node": "^22.0.2",
"@types/node-fetch": "^2.6.11"
},
"dependencies": {
"node-fetch": "^2.6.1"
Expand Down
15 changes: 9 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ import { integrationSteps } from './steps';
import { SonarqubeIntegrationConfig } from './types';
import validateInvocation from './validateInvocation';
import getStepStartStates from './getStepStartStates';
import { ingestionConfig } from './ingestionConfig';

export const invocationConfig: IntegrationInvocationConfig<SonarqubeIntegrationConfig> = {
instanceConfigFields,
validateInvocation,
getStepStartStates,
integrationSteps,
};
export const invocationConfig: IntegrationInvocationConfig<SonarqubeIntegrationConfig> =
{
instanceConfigFields,
validateInvocation,
getStepStartStates,
integrationSteps,
ingestionConfig,
};
30 changes: 30 additions & 0 deletions src/ingestionConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { IntegrationIngestionConfigFieldMap } from '@jupiterone/integration-sdk-core';
import { INGESTION_SOURCE_IDS } from './steps/constants';

export const ingestionConfig: IntegrationIngestionConfigFieldMap = {
[INGESTION_SOURCE_IDS.ACCOUNT]: {
title: 'Account',
description: 'SonarQube Accounts',
defaultsToDisabled: false,
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ingestion source is not required, in general without account the rest of the steps wouldn't run, and we don't fetch anything so it's ok to always have it

[INGESTION_SOURCE_IDS.FINDINGS]: {
title: 'Users',
description: 'SonarQube Issues',
defaultsToDisabled: false,
},
[INGESTION_SOURCE_IDS.USERS]: {
title: 'Users',
description: 'SonarQube Users',
defaultsToDisabled: false,
},
[INGESTION_SOURCE_IDS.PROJECT]: {
title: 'Projects',
description: 'SonarQube Projects',
defaultsToDisabled: false,
},
[INGESTION_SOURCE_IDS.USER_GROUPS]: {
title: 'User Groups',
description: 'SonarQube Groups',
defaultsToDisabled: false,
},
};
20 changes: 20 additions & 0 deletions src/instanceConfigFields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,26 @@ const instanceConfigFields: IntegrationInstanceConfigFieldMap = {
mask: false,
optional: true,
},
severities: {
type: 'string',
mask: false,
optional: true,
},
status: {
type: 'string',
mask: false,
optional: true,
},
createdInLast: {
type: 'string',
mask: false,
optional: true,
},
types: {
type: 'string',
mask: false,
optional: true,
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
severities: {
type: 'string',
mask: false,
optional: true,
},
status: {
type: 'string',
mask: false,
optional: true,
},
createdInLast: {
type: 'string',
mask: false,
optional: true,
},
types: {
type: 'string',
mask: false,
optional: true,
},
findingSeverities: {
type: 'string',
mask: false,
optional: true,
},
findingStatus: {
type: 'string',
mask: false,
optional: true,
},
findingsIngestSinceDays: {
type: 'string',
mask: false,
optional: true,
},
findingTypes: {
type: 'string',
mask: false,
optional: true,
},

};

export default instanceConfigFields;
26 changes: 19 additions & 7 deletions src/provider/SonarqubeClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ export class SonarqubeClient {
}

async fetchSystemInfo() {
return this.makeSingularRequest('/system/info') as Promise<
SonarqubeSystemInfo
>;
return this.makeSingularRequest(
'/system/info',
) as Promise<SonarqubeSystemInfo>;
}

async iterateProjects(
Expand Down Expand Up @@ -161,9 +161,9 @@ export class SonarqubeClient {
}

async fetchAuthenticationValidate(): Promise<ValidationResponse> {
return this.makeSingularRequest('/authentication/validate') as Promise<
ValidationResponse
>;
return this.makeSingularRequest(
'/authentication/validate',
) as Promise<ValidationResponse>;
}

private async makeRequest(
Expand Down Expand Up @@ -242,10 +242,22 @@ export class SonarqubeClient {

const paginationQueryParms = PaginationQueryParams[endpointVersion];

const sanitizedParams: Record<string, string> = {};
if (params) {
Object.keys(params).forEach((key) => {
const value = params[key];
if (value !== undefined) {
sanitizedParams[key] = Array.isArray(value)
? value.join(',')
: value;
}
});
}

const searchParams = new URLSearchParams({
[paginationQueryParms.pageIndex]: String(page),
[paginationQueryParms.pageSize]: String(ITEMS_PER_PAGE),
...params,
...sanitizedParams,
});

const parametizedEndpoint = `${endpoint}?${searchParams.toString()}`;
Expand Down
1 change: 1 addition & 0 deletions src/steps/account/converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export function createAccountEntity(
_class: Entities.ACCOUNT._class,
id,
name,
vendor: 'SonarSource'
},
},
});
Expand Down
8 changes: 7 additions & 1 deletion src/steps/account/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ import {
IntegrationStepExecutionContext,
} from '@jupiterone/integration-sdk-core';

import { ACCOUNT_ENTITY_KEY, Entities, Steps } from '../constants';
import {
ACCOUNT_ENTITY_KEY,
Entities,
INGESTION_SOURCE_IDS,
Steps,
} from '../constants';
import { createAccountEntity } from './converter';
import { SonarqubeIntegrationConfig } from '../../types';

Expand All @@ -19,6 +24,7 @@ export const accountSteps: IntegrationStep<SonarqubeIntegrationConfig>[] = [
{
id: Steps.ACCOUNT,
name: 'Fetch Account',
ingestionSourceId: INGESTION_SOURCE_IDS.ACCOUNT,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this

entities: [Entities.ACCOUNT],
executionHandler: fetchAccount,
relationships: [],
Expand Down
40 changes: 40 additions & 0 deletions src/steps/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,46 @@ import { RelationshipClass } from '@jupiterone/integration-sdk-core';

export const ACCOUNT_ENTITY_KEY = 'sonarqube:account';

export const FINDINGS_SEVERITIES = {
INFO: 'LOW',
MINOR: 'LOW',
MAJOR: 'MEDIUM',
CRITICAL: 'HIGH',
BLOCKER: 'HIGH',
};

export const V1_SEVERITIES_VALUES = [
'INFO',
'MINOR',
'MAJOR',
'CRITICAL',
'BLOCKER',
];
export const V2_SEVERITIES_VALUES = ['LOW', 'MEDIUM', 'HIGH'];
export const DEFAULT_CREATED_IN_LAST = '10d';

export const FINDING_STATUSES = {
OPEN: 'OPEN',
CONFIRMED: 'CONFIRMED',
REOPENED: 'FALSE_POSITIVE',
RESOLVED: 'ACCEPTED',
CLOSED: 'FIXED',
};

export const FINDING_TYPES = {
CODE_SMELL: 'MAINTAINABILITY',
BUG: 'RELIABILITY',
VULNERABILITY: 'SECURITY',
};

export const INGESTION_SOURCE_IDS = {
ACCOUNT: 'accounts',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this one

PROJECT: 'projects',
USERS: 'users',
USER_GROUPS: 'user-groups',
FINDINGS: 'findings',
};

export const Steps = {
ACCOUNT: 'fetch-account',
PROJECTS: 'fetch-projects',
Expand Down
Loading
Loading