123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 |
- /*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
- import { compact, isArray, uniq } from 'lodash';
- import { getUsers } from '../../api/users';
- import { formatMeasure } from '../../helpers/measures';
- import {
- cleanQuery,
- parseAsArray,
- parseAsBoolean,
- parseAsDate,
- parseAsString,
- queriesEqual,
- serializeDateShort,
- serializeString,
- serializeStringArray,
- } from '../../helpers/query';
- import { get, save } from '../../helpers/storage';
- import { isDefined } from '../../helpers/types';
- import {
- CleanCodeAttributeCategory,
- Facet,
- RawFacet,
- SoftwareImpactSeverity,
- SoftwareQuality,
- } from '../../types/issues';
- import { MetricType } from '../../types/metrics';
- import { SecurityStandard } from '../../types/security';
- import { Dict, Issue, Paging, RawQuery } from '../../types/types';
- import { RestUser } from '../../types/users';
-
- const OWASP_ASVS_4_0 = 'owaspAsvs-4.0';
-
- export interface Query {
- assigned: boolean;
- assignees: string[];
- author: string[];
- cleanCodeAttributeCategories: CleanCodeAttributeCategory[];
- codeVariants: string[];
- createdAfter: Date | undefined;
- createdAt: string;
- createdBefore: Date | undefined;
- createdInLast: string;
- cwe: string[];
- directories: string[];
- files: string[];
- impactSeverities: SoftwareImpactSeverity[];
- impactSoftwareQualities: SoftwareQuality[];
- issues: string[];
- languages: string[];
- owaspTop10: string[];
- 'owaspTop10-2021': string[];
- 'pciDss-3.2': string[];
- 'pciDss-4.0': string[];
- [OWASP_ASVS_4_0]: string[];
- owaspAsvsLevel: string;
- projects: string[];
- resolutions: string[];
- resolved: boolean;
- rules: string[];
- scopes: string[];
- severities: string[];
- inNewCodePeriod: boolean;
- sonarsourceSecurity: string[];
- sort: string;
- statuses: string[];
- tags: string[];
- types: string[];
- }
-
- export const STANDARDS = 'standards';
-
- // allow sorting by CREATION_DATE only
- const parseAsSort = (sort: string) => (sort === 'CREATION_DATE' ? 'CREATION_DATE' : '');
- const ISSUES_DEFAULT = 'sonarqube.issues.default';
-
- export function parseQuery(query: RawQuery): Query {
- return {
- assigned: parseAsBoolean(query.assigned),
- assignees: parseAsArray(query.assignees, parseAsString),
- author: isArray(query.author) ? query.author : [query.author].filter(isDefined),
- cleanCodeAttributeCategories: parseAsArray<CleanCodeAttributeCategory>(
- query.cleanCodeAttributeCategories,
- parseAsString
- ),
- createdAfter: parseAsDate(query.createdAfter),
- createdAt: parseAsString(query.createdAt),
- createdBefore: parseAsDate(query.createdBefore),
- createdInLast: parseAsString(query.createdInLast),
- cwe: parseAsArray(query.cwe, parseAsString),
- directories: parseAsArray(query.directories, parseAsString),
- files: parseAsArray(query.files, parseAsString),
- impactSeverities: parseImpactSeverityQuery(query.impactSeverities, query.severities),
- impactSoftwareQualities: parseAsArray<SoftwareQuality>(
- query.impactSoftwareQualities,
- parseAsString
- ),
- inNewCodePeriod: parseAsBoolean(query.inNewCodePeriod, false),
- issues: parseAsArray(query.issues, parseAsString),
- languages: parseAsArray(query.languages, parseAsString),
- owaspTop10: parseAsArray(query.owaspTop10, parseAsString),
- 'owaspTop10-2021': parseAsArray(query['owaspTop10-2021'], parseAsString),
- 'pciDss-3.2': parseAsArray(query['pciDss-3.2'], parseAsString),
- 'pciDss-4.0': parseAsArray(query['pciDss-4.0'], parseAsString),
- [OWASP_ASVS_4_0]: parseAsArray(query[OWASP_ASVS_4_0], parseAsString),
- owaspAsvsLevel: parseAsString(query['owaspAsvsLevel']),
- projects: parseAsArray(query.projects, parseAsString),
- resolutions: parseAsArray(query.resolutions, parseAsString),
- resolved: parseAsBoolean(query.resolved),
- rules: parseAsArray(query.rules, parseAsString),
- scopes: parseAsArray(query.scopes, parseAsString),
- severities: [],
- sonarsourceSecurity: parseAsArray(query.sonarsourceSecurity, parseAsString),
- sort: parseAsSort(query.s),
- statuses: parseAsArray(query.statuses, parseAsString),
- tags: parseAsArray(query.tags, parseAsString),
- types: parseAsArray(query.types, parseAsString),
- codeVariants: parseAsArray(query.codeVariants, parseAsString),
- };
- }
-
- function parseImpactSeverityQuery(
- newSeverities: string,
- oldSeverities?: string
- ): SoftwareImpactSeverity[] {
- const OLD_TO_NEW_MAPPER = {
- BLOCKER: SoftwareImpactSeverity.High,
- CRITICAL: SoftwareImpactSeverity.High,
- MAJOR: SoftwareImpactSeverity.Medium,
- MINOR: SoftwareImpactSeverity.Low,
- INFO: SoftwareImpactSeverity.Low,
- };
-
- // Merging new and old severities includes mapping for old to new
- return compact(
- uniq([
- ...parseAsArray<SoftwareImpactSeverity>(newSeverities, parseAsString),
- ...parseAsArray(oldSeverities, parseAsString).map(
- (oldSeverity: string) => OLD_TO_NEW_MAPPER[oldSeverity as keyof typeof OLD_TO_NEW_MAPPER]
- ),
- ])
- );
- }
-
- export function getOpen(query: RawQuery): string | undefined {
- return query.open;
- }
-
- export function getOpenIssue(props: { location: { query: RawQuery } }, issues: Issue[]) {
- const open = getOpen(props.location.query);
- return open ? issues.find((issue) => issue.key === open) : undefined;
- }
-
- export const areMyIssuesSelected = (query: RawQuery) => query.myIssues === 'true';
-
- export function serializeQuery(query: Query): RawQuery {
- const filter = {
- assigned: query.assigned ? undefined : 'false',
- assignees: serializeStringArray(query.assignees),
- author: query.author,
- cleanCodeAttributeCategories: serializeStringArray(query.cleanCodeAttributeCategories),
- createdAfter: serializeDateShort(query.createdAfter),
- createdAt: serializeString(query.createdAt),
- createdBefore: serializeDateShort(query.createdBefore),
- createdInLast: serializeString(query.createdInLast),
- cwe: serializeStringArray(query.cwe),
- directories: serializeStringArray(query.directories),
- files: serializeStringArray(query.files),
- issues: serializeStringArray(query.issues),
- languages: serializeStringArray(query.languages),
- owaspTop10: serializeStringArray(query.owaspTop10),
- 'owaspTop10-2021': serializeStringArray(query['owaspTop10-2021']),
- 'pciDss-3.2': serializeStringArray(query['pciDss-3.2']),
- 'pciDss-4.0': serializeStringArray(query['pciDss-4.0']),
- [OWASP_ASVS_4_0]: serializeStringArray(query[OWASP_ASVS_4_0]),
- owaspAsvsLevel: serializeString(query['owaspAsvsLevel']),
- projects: serializeStringArray(query.projects),
- resolutions: serializeStringArray(query.resolutions),
- resolved: query.resolved ? undefined : 'false',
- rules: serializeStringArray(query.rules),
- s: serializeString(query.sort),
- scopes: serializeStringArray(query.scopes),
- severities: undefined,
- impactSeverities: serializeStringArray(query.impactSeverities),
- impactSoftwareQualities: serializeStringArray(query.impactSoftwareQualities),
- inNewCodePeriod: query.inNewCodePeriod ? 'true' : undefined,
- sonarsourceSecurity: serializeStringArray(query.sonarsourceSecurity),
- statuses: serializeStringArray(query.statuses),
- tags: serializeStringArray(query.tags),
- types: serializeStringArray(query.types),
- codeVariants: serializeStringArray(query.codeVariants),
- };
-
- return cleanQuery(filter);
- }
-
- export const areQueriesEqual = (a: RawQuery, b: RawQuery) =>
- queriesEqual(parseQuery(a), parseQuery(b));
-
- export function parseFacets(facets?: RawFacet[]): Dict<Facet> {
- if (!facets) {
- return {};
- }
-
- const result: Dict<Facet> = {};
- facets.forEach((facet) => {
- const values: Facet = {};
- facet.values.forEach((value) => {
- values[value.val] = value.count;
- });
- result[facet.property] = values;
- });
- return result;
- }
-
- export function formatFacetStat(stat: number | undefined) {
- return stat && formatMeasure(stat, MetricType.ShortInteger);
- }
-
- export const searchAssignees = (
- query: string,
- page = 1
- ): Promise<{ paging: Paging; results: RestUser[] }> => {
- return getUsers<RestUser>({ pageIndex: page, q: query }).then(({ page, users }) => ({
- paging: page,
- results: users,
- }));
- };
-
- const LOCALSTORAGE_MY = 'my';
- const LOCALSTORAGE_ALL = 'all';
-
- export const isMySet = () => {
- return get(ISSUES_DEFAULT) === LOCALSTORAGE_MY;
- };
-
- export const saveMyIssues = (myIssues: boolean) =>
- save(ISSUES_DEFAULT, myIssues ? LOCALSTORAGE_MY : LOCALSTORAGE_ALL);
-
- export function getLocations(
- {
- flows,
- secondaryLocations,
- flowsWithType,
- }: Pick<Issue, 'flows' | 'secondaryLocations' | 'flowsWithType'>,
- selectedFlowIndex: number | undefined
- ) {
- if (secondaryLocations.length > 0) {
- return secondaryLocations;
- } else if (selectedFlowIndex !== undefined) {
- return flows[selectedFlowIndex] || flowsWithType[selectedFlowIndex]?.locations || [];
- }
- return [];
- }
-
- export function getSelectedLocation(
- issue: Pick<Issue, 'flows' | 'secondaryLocations' | 'flowsWithType'>,
- selectedFlowIndex: number | undefined,
- selectedLocationIndex: number | undefined
- ) {
- const locations = getLocations(issue, selectedFlowIndex);
- if (
- selectedLocationIndex !== undefined &&
- selectedLocationIndex >= 0 &&
- locations.length >= selectedLocationIndex
- ) {
- return locations[selectedLocationIndex];
- }
- return undefined;
- }
-
- export function allLocationsEmpty(
- issue: Pick<Issue, 'flows' | 'secondaryLocations' | 'flowsWithType'>,
- selectedFlowIndex: number | undefined
- ) {
- return getLocations(issue, selectedFlowIndex).every((location) => !location.msg);
- }
-
- export function shouldOpenStandardsFacet(
- openFacets: Dict<boolean>,
- query: Partial<Query>
- ): boolean {
- return (
- openFacets[STANDARDS] ||
- isFilteredBySecurityIssueTypes(query) ||
- isOneStandardChildFacetOpen(openFacets, query)
- );
- }
-
- export function shouldOpenStandardsChildFacet(
- openFacets: Dict<boolean>,
- query: Partial<Query>,
- standardType:
- | SecurityStandard.CWE
- | SecurityStandard.OWASP_TOP10
- | SecurityStandard.OWASP_TOP10_2021
- | SecurityStandard.SONARSOURCE
- ): boolean {
- const filter = query[standardType];
- return (
- openFacets[STANDARDS] !== false &&
- (openFacets[standardType] ||
- (standardType !== SecurityStandard.CWE && filter !== undefined && filter.length > 0))
- );
- }
-
- export function shouldOpenSonarSourceSecurityFacet(
- openFacets: Dict<boolean>,
- query: Partial<Query>
- ): boolean {
- // Open it by default if the parent is open, and no other standard is open.
- return (
- shouldOpenStandardsChildFacet(openFacets, query, SecurityStandard.SONARSOURCE) ||
- (shouldOpenStandardsFacet(openFacets, query) && !isOneStandardChildFacetOpen(openFacets, query))
- );
- }
-
- function isFilteredBySecurityIssueTypes(query: Partial<Query>): boolean {
- return query.types !== undefined && query.types.includes('VULNERABILITY');
- }
-
- function isOneStandardChildFacetOpen(openFacets: Dict<boolean>, query: Partial<Query>): boolean {
- return [SecurityStandard.OWASP_TOP10, SecurityStandard.CWE, SecurityStandard.SONARSOURCE].some(
- (
- standardType:
- | SecurityStandard.CWE
- | SecurityStandard.OWASP_TOP10
- | SecurityStandard.OWASP_TOP10_2021
- | SecurityStandard.SONARSOURCE
- ) => shouldOpenStandardsChildFacet(openFacets, query, standardType)
- );
- }
|