| 'reporters'
| 'resolutions'
| 'rules'
- | 'sansTop25'
| 'severities'
| 'statuses'
| 'tags'
query,
SecurityStandard.OWASP_TOP10_2021
),
- sansTop25: shouldOpenStandardsChildFacet({}, query, SecurityStandard.SANS_TOP25),
sonarsourceSecurity: shouldOpenSonarSourceSecurityFacet({}, query),
standards: shouldOpenStandardsFacet({}, query),
types: true,
fetchingCwe={false}
fetchingOwaspTop10={false}
fetchingOwaspTop10-2021={false}
- fetchingSansTop25={false}
fetchingSonarSourceSecurity={false}
onChange={props.onFilterChange}
onToggle={props.onFacetToggle}
owaspTop10-2021Open={!!props.openFacets['owaspTop10-2021']}
owaspTop10-2021Stats={props.facets && props.facets['owaspTop10-2021']}
query={props.query}
- sansTop25={props.query.sansTop25}
- sansTop25Open={!!props.openFacets.sansTop25}
- sansTop25Stats={props.facets && props.facets.sansTop25}
sonarsourceSecurity={props.query.sonarsourceSecurity}
sonarsourceSecurityOpen={!!props.openFacets.sonarsourceSecurity}
sonarsourceSecurityStats={props.facets && props.facets.sonarsourceSecurity}
"profile": undefined,
"repositories": [],
"ruleKey": undefined,
- "sansTop25": [],
"searchQuery": undefined,
"severities": [],
"sonarsourceSecurity": [],
"profile": undefined,
"repositories": [],
"ruleKey": undefined,
- "sansTop25": [],
"searchQuery": undefined,
"severities": [],
"sonarsourceSecurity": [],
"languages": true,
"owaspTop10": false,
"owaspTop10-2021": false,
- "sansTop25": false,
"sonarsourceSecurity": false,
"standards": false,
"types": true,
"profile": undefined,
"repositories": [],
"ruleKey": undefined,
- "sansTop25": [],
"searchQuery": undefined,
"severities": [],
"sonarsourceSecurity": [],
"profile": undefined,
"repositories": [],
"ruleKey": undefined,
- "sansTop25": [],
"searchQuery": undefined,
"severities": [],
"sonarsourceSecurity": [],
fetchingCwe={false}
fetchingOwaspTop10={false}
fetchingOwaspTop10-2021={false}
- fetchingSansTop25={false}
fetchingSonarSourceSecurity={false}
onChange={[MockFunction]}
onToggle={[MockFunction]}
owaspTop10-2021Open={false}
owaspTop10Open={false}
query={{}}
- sansTop25Open={false}
sonarsourceSecurityOpen={false}
/>
<injectIntl(AvailableSinceFacet)
profile: string | undefined;
repositories: string[];
ruleKey: string | undefined;
- sansTop25: string[];
searchQuery: string | undefined;
severities: string[];
sonarsourceSecurity: string[];
profile: parseAsOptionalString(query.qprofile),
repositories: parseAsArray(query.repositories, parseAsString),
ruleKey: parseAsOptionalString(query.rule_key),
- sansTop25: parseAsArray(query.sansTop25, parseAsString),
searchQuery: parseAsOptionalString(query.q),
severities: parseAsArray(query.severities, parseAsString),
sonarsourceSecurity: parseAsArray(query.sonarsourceSecurity, parseAsString),
qprofile: serializeString(query.profile),
repositories: serializeStringArray(query.repositories),
rule_key: serializeString(query.ruleKey),
- sansTop25: serializeStringArray(query.sansTop25),
severities: serializeStringArray(query.severities),
sonarsourceSecurity: serializeStringArray(query.sonarsourceSecurity),
statuses: serializeStringArray(query.statuses),
'owaspTop10',
'owaspTop10-2021',
'repositories',
- 'sansTop25',
'severities',
'sonarsourceSecurity',
'standard',
resolved: true,
rules: ['a', 'b'],
sort: 'rules',
- sansTop25: ['a', 'b'],
scopes: ['a', 'b'],
severities: ['a', 'b'],
inNewCodePeriod: true,
resolutions: 'a,b',
rules: 'a,b',
s: 'rules',
- sansTop25: 'a,b',
scopes: 'a,b',
severities: 'a,b',
inNewCodePeriod: 'true',
expect(
shouldOpenStandardsChildFacet({ owaspTop10: true }, {}, SecurityStandard.OWASP_TOP10)
).toBe(true);
- expect(
- shouldOpenStandardsChildFacet({ sansTop25: true }, {}, SecurityStandard.SANS_TOP25)
- ).toBe(true);
expect(
shouldOpenStandardsChildFacet(
- { sansTop25: true },
+ { cwe: true },
{ owaspTop10: ['A1'] },
SecurityStandard.OWASP_TOP10
)
)
).toBe(true);
expect(
- shouldOpenStandardsChildFacet(
- {},
- { sansTop25: ['insecure-interactions'] },
- SecurityStandard.SANS_TOP25
- )
+ shouldOpenStandardsChildFacet({}, { owaspTop10: ['A1'] }, SecurityStandard.OWASP_TOP10)
).toBe(true);
expect(
shouldOpenStandardsChildFacet(
{},
- { sansTop25: ['insecure-interactions'], sonarsourceSecurity: ['sql-injection'] },
+ { owaspTop10: ['A1'], sonarsourceSecurity: ['sql-injection'] },
SecurityStandard.SONARSOURCE
)
).toBe(true);
expect(
shouldOpenStandardsChildFacet({ standards: true }, {}, SecurityStandard.OWASP_TOP10)
).toBe(false);
+ expect(shouldOpenStandardsChildFacet({ cwe: true }, {}, SecurityStandard.OWASP_TOP10)).toBe(
+ false
+ );
expect(
- shouldOpenStandardsChildFacet({ sansTop25: true }, {}, SecurityStandard.OWASP_TOP10)
- ).toBe(false);
- expect(
- shouldOpenStandardsChildFacet({}, { types: ['VULNERABILITY'] }, SecurityStandard.SANS_TOP25)
+ shouldOpenStandardsChildFacet({}, { types: ['VULNERABILITY'] }, SecurityStandard.OWASP_TOP10)
).toBe(false);
expect(
shouldOpenStandardsChildFacet(
{},
- { sansTop25: ['insecure-interactions'], sonarsourceSecurity: ['sql-injection'] },
- SecurityStandard.OWASP_TOP10
+ { owaspTop10: ['A1'], sonarsourceSecurity: ['sql-injection'] },
+ SecurityStandard.OWASP_TOP10_2021
)
).toBe(false);
});
it('should NOT open sonarsourceSecurity facet', () => {
expect(shouldOpenSonarSourceSecurityFacet({ standards: false }, {})).toBe(false);
expect(shouldOpenSonarSourceSecurityFacet({ owaspTop10: true }, {})).toBe(false);
- expect(shouldOpenSonarSourceSecurityFacet({ standards: true, sansTop25: true }, {})).toBe(
- false
- );
+ expect(shouldOpenSonarSourceSecurityFacet({ standards: true, cwe: true }, {})).toBe(false);
});
});
query,
SecurityStandard.OWASP_TOP10_2021
),
- sansTop25: shouldOpenStandardsChildFacet({}, query, SecurityStandard.SANS_TOP25),
severities: true,
sonarsourceSecurity: shouldOpenSonarSourceSecurityFacet({}, query),
standards: shouldOpenStandardsFacet({}, query),
fetchingCwe={this.props.loadingFacets.cwe === true}
fetchingOwaspTop10={this.props.loadingFacets.owaspTop10 === true}
fetchingOwaspTop10-2021={this.props.loadingFacets['owaspTop10-2021'] === true}
- fetchingSansTop25={this.props.loadingFacets.sansTop25 === true}
fetchingSonarSourceSecurity={this.props.loadingFacets.sonarsourceSecurity === true}
loadSearchResultCount={this.props.loadSearchResultCount}
onChange={this.props.onFilterChange}
owaspTop10-2021Open={!!openFacets['owaspTop10-2021']}
owaspTop10-2021Stats={facets['owaspTop10-2021']}
query={query}
- sansTop25={query.sansTop25}
- sansTop25Open={!!openFacets.sansTop25}
- sansTop25Stats={facets.sansTop25}
sonarsourceSecurity={query.sonarsourceSecurity}
sonarsourceSecurityOpen={!!openFacets.sonarsourceSecurity}
sonarsourceSecurityStats={facets.sonarsourceSecurity}
renderCWECategory,
renderOwaspTop102021Category,
renderOwaspTop10Category,
- renderSansTop25Category,
renderSonarSourceSecurityCategory,
} from '../../../helpers/security-standard';
import { Facet } from '../../../types/issues';
fetchingCwe: boolean;
fetchingOwaspTop10: boolean;
'fetchingOwaspTop10-2021': boolean;
- fetchingSansTop25: boolean;
fetchingSonarSourceSecurity: boolean;
loadSearchResultCount?: (property: string, changes: Partial<Query>) => Promise<Facet>;
onChange: (changes: Partial<Query>) => void;
'owaspTop10-2021Open': boolean;
'owaspTop10-2021Stats': Dict<number> | undefined;
query: Partial<Query>;
- sansTop25: string[];
- sansTop25Open: boolean;
- sansTop25Stats: Dict<number> | undefined;
sonarsourceSecurity: string[];
sonarsourceSecurityOpen: boolean;
sonarsourceSecurityStats: Dict<number> | undefined;
| 'owaspTop10-2021Stats'
| 'owaspTop10Stats'
| 'cweStats'
- | 'sansTop25Stats'
| 'sonarsourceSecurityStats';
-type ValuesProp = 'owaspTop10-2021' | 'owaspTop10' | 'sansTop25' | 'sonarsourceSecurity' | 'cwe';
+type ValuesProp = 'owaspTop10-2021' | 'owaspTop10' | 'sonarsourceSecurity' | 'cwe';
const INITIAL_FACET_COUNT = 15;
export default class StandardFacet extends React.PureComponent<Props, State> {
standards: {
owaspTop10: {},
'owaspTop10-2021': {},
- sansTop25: {},
cwe: {},
sonarsourceSecurity: {},
'pciDss-3.2': {},
this.props.owaspTop10.length > 0 ||
this.props['owaspTop10-2021'].length > 0 ||
this.props.cwe.length > 0 ||
- this.props.sansTop25.length > 0 ||
this.props.sonarsourceSecurity.length > 0
) {
this.loadStandards();
({
'owaspTop10-2021': owaspTop102021,
owaspTop10,
- sansTop25,
cwe,
sonarsourceSecurity,
'pciDss-3.2': pciDss3_2,
standards: {
'owaspTop10-2021': owaspTop102021,
owaspTop10,
- sansTop25,
cwe,
sonarsourceSecurity,
'pciDss-3.2': pciDss3_2,
...this.props['owaspTop10-2021'].map((item) =>
renderOwaspTop102021Category(this.state.standards, item, true)
),
- ...this.props.sansTop25.map((item) =>
- renderSansTop25Category(this.state.standards, item, true)
- ),
...this.props.cwe.map((item) => renderCWECategory(this.state.standards, item)),
];
};
this.props.onToggle('owaspTop10-2021');
};
- handleSansTop25HeaderClick = () => {
- this.props.onToggle('sansTop25');
- };
-
handleSonarSourceSecurityHeaderClick = () => {
this.props.onToggle('sonarsourceSecurity');
};
[this.property]: [],
owaspTop10: [],
'owaspTop10-2021': [],
- sansTop25: [],
cwe: [],
sonarsourceSecurity: [],
});
this.handleItemClick(SecurityStandard.OWASP_TOP10_2021, itemValue, multiple);
};
- handleSansTop25ItemClick = (itemValue: string, multiple: boolean) => {
- this.handleItemClick(SecurityStandard.SANS_TOP25, itemValue, multiple);
- };
-
handleSonarSourceSecurityItemClick = (itemValue: string, multiple: boolean) => {
this.handleItemClick(SecurityStandard.SONARSOURCE, itemValue, multiple);
};
);
}
- renderSansTop25List() {
- return this.renderList(
- 'sansTop25Stats',
- SecurityStandard.SANS_TOP25,
- renderSansTop25Category,
- this.handleSansTop25ItemClick
- );
- }
-
renderSonarSourceSecurityList() {
const stats = this.props.sonarsourceSecurityStats;
const values = this.props.sonarsourceSecurity;
return this.renderHint('owaspTop10-2021Stats', SecurityStandard.OWASP_TOP10_2021);
}
- renderSansTop25Hint() {
- return this.renderHint('sansTop25Stats', SecurityStandard.SANS_TOP25);
- }
-
renderSonarSourceSecurityHint() {
return this.renderHint('sonarsourceSecurityStats', SecurityStandard.SONARSOURCE);
}
</>
)}
</FacetBox>
- <FacetBox className="is-inner" property={SecurityStandard.SANS_TOP25}>
- <FacetHeader
- fetching={this.props.fetchingSansTop25}
- name={translate('issues.facet.sansTop25')}
- onClick={this.handleSansTop25HeaderClick}
- open={this.props.sansTop25Open}
- values={this.props.sansTop25.map((item) =>
- renderSansTop25Category(this.state.standards, item)
- )}
- />
- {this.props.sansTop25Open && (
- <>
- {this.renderSansTop25List()}
- {this.renderSansTop25Hint()}
- </>
- )}
- </FacetBox>
<ListStyleFacet<string>
className="is-inner"
facetHeader={translate('issues.facet.cwe')}
title: 'Broken Authentication',
},
},
- sansTop25: {
- 'insecure-interaction': {
- title: 'Insecure Interaction Between Components',
- },
- },
cwe: {
unknown: {
title: 'No CWE associated',
cwe: [],
owaspTop10: [],
'owaspTop10-2021': [],
- sansTop25: [],
sonarsourceSecurity: [],
standards: [],
});
owaspTop10: ['a3'],
owaspTop10Open: true,
owaspTop10Stats: { a1: 15, a3: 5 },
- sansTop25: ['risky-resource'],
- sansTop25Open: true,
- sansTop25Stats: { foo: 12, 'risky-resource': 10 },
sonarsourceSecurity: ['sql-injection'],
sonarsourceSecurityOpen: true,
sonarsourceSecurityStats: { 'sql-injection': 12 },
it('should render empty sub-facet', () => {
expect(
- shallowRender({ open: true, sansTop25: [], sansTop25Open: true, sansTop25Stats: {} }).find(
- 'FacetBox[property="sansTop25"]'
- )
+ shallowRender({
+ open: true,
+ 'owaspTop10-2021': [],
+ 'owaspTop10-2021Open': true,
+ 'owaspTop10-2021Stats': {},
+ }).find('FacetBox[property="owaspTop10-2021"]')
).toMatchSnapshot();
});
owaspTop10: ['a3'],
owaspTop10Open: true,
owaspTop10Stats: { a1: 15, a3: 5 },
- sansTop25: ['risky-resource'],
- sansTop25Open: true,
- sansTop25Stats: { foo: 12, 'risky-resource': 10 },
sonarsourceSecurity: ['command-injection'],
sonarsourceSecurityOpen: true,
sonarsourceSecurityStats: { 'sql-injection': 10 },
selectAndCheck('owaspTop10', 'a1');
selectAndCheck('owaspTop10', 'a1', true, ['a1', 'a3']);
- selectAndCheck('sansTop25', 'foo');
selectAndCheck('sonarsourceSecurity', 'sql-injection');
function selectAndCheck(facet: string, value: string, multiple = false, expectedValue = [value]) {
const wrapper = shallowRender({ onToggle, open: true });
click(wrapper.find('FacetBox[property="owaspTop10"]').children('FacetHeader'));
expect(onToggle).toHaveBeenLastCalledWith('owaspTop10');
- click(wrapper.find('FacetBox[property="sansTop25"]').children('FacetHeader'));
- expect(onToggle).toHaveBeenLastCalledWith('sansTop25');
click(wrapper.find('FacetBox[property="sonarsourceSecurity"]').children('FacetHeader'));
expect(onToggle).toHaveBeenLastCalledWith('sonarsourceSecurity');
});
open: true,
owaspTop10: ['a1', 'a3'],
'owaspTop10-2021': ['a1', 'a2'],
- sansTop25: ['risky-resource', 'foo'],
cwe: ['42', '1111', 'unknown'],
sonarsourceSecurity: ['sql-injection', 'others'],
});
'OWASP A3',
'OWASP A1 - a1 title',
'OWASP A2',
- 'SANS Risky Resource Management',
- 'SANS foo',
'CWE-42 - cwe-42 title',
'CWE-1111',
'Unknown CWE',
]);
checkValues('owaspTop10', ['A1 - a1 title', 'A3']);
checkValues('owaspTop10-2021', ['A1 - a1 title', 'A2']);
- checkValues('sansTop25', ['Risky Resource Management', 'foo']);
checkValues('sonarsourceSecurity', ['SQL Injection', 'Others']);
function checkValues(property: string, values: string[]) {
fetchingCwe={false}
fetchingOwaspTop10={false}
fetchingOwaspTop10-2021={false}
- fetchingSansTop25={false}
fetchingSonarSourceSecurity={false}
loadSearchResultCount={jest.fn()}
onChange={jest.fn()}
owaspTop10-2021Open={false}
owaspTop10-2021Stats={{}}
query={{} as Query}
- sansTop25={[]}
- sansTop25Open={false}
- sansTop25Stats={{}}
sonarsourceSecurity={[]}
sonarsourceSecurityOpen={false}
sonarsourceSecurityStats={{}}
standards: {
owaspTop10: { a1: { title: 'a1 title' } },
'owaspTop10-2021': { a1: { title: 'a1 title' } },
- sansTop25: { 'risky-resource': { title: 'Risky Resource Management' } },
cwe: { 42: { title: 'cwe-42 title' }, unknown: { title: 'Unknown CWE' } },
sonarsourceSecurity: {
'sql-injection': { title: 'SQL Injection' },
exports[`should render empty sub-facet 1`] = `
<FacetBox
className="is-inner"
- property="sansTop25"
+ property="owaspTop10-2021"
>
<FacetHeader
fetching={false}
- name="issues.facet.sansTop25"
+ name="issues.facet.owaspTop10_2021"
onClick={[Function]}
open={true}
values={[]}
[
"SONAR SQL Injection",
"OWASP A3",
- "SANS Risky Resource Management",
"CWE-42 - cwe-42 title",
]
}
values={1}
/>
</FacetBox>
- <FacetBox
- className="is-inner"
- property="sansTop25"
- >
- <FacetHeader
- fetching={false}
- name="issues.facet.sansTop25"
- onClick={[Function]}
- open={true}
- values={
- [
- "Risky Resource Management",
- ]
- }
- />
- <FacetItemsList>
- <FacetItem
- active={false}
- halfWidth={false}
- key="foo"
- loading={false}
- name="foo"
- onClick={[Function]}
- stat="12"
- tooltip="foo"
- value="foo"
- />
- <FacetItem
- active={true}
- halfWidth={false}
- key="risky-resource"
- loading={false}
- name="Risky Resource Management"
- onClick={[Function]}
- stat="10"
- tooltip="Risky Resource Management"
- value="risky-resource"
- />
- </FacetItemsList>
- <MultipleSelectionHint
- options={2}
- values={1}
- />
- </FacetBox>
<ListStyleFacet
className="is-inner"
facetHeader="issues.facet.cwe"
resolutions: string[];
resolved: boolean;
rules: string[];
- sansTop25: string[];
scopes: string[];
severities: string[];
inNewCodePeriod: boolean;
resolutions: parseAsArray(query.resolutions, parseAsString),
resolved: parseAsBoolean(query.resolved),
rules: parseAsArray(query.rules, parseAsString),
- sansTop25: parseAsArray(query.sansTop25, parseAsString),
scopes: parseAsArray(query.scopes, parseAsString),
severities: parseAsArray(query.severities, parseAsString),
sonarsourceSecurity: parseAsArray(query.sonarsourceSecurity, parseAsString),
resolved: query.resolved ? undefined : 'false',
rules: serializeStringArray(query.rules),
s: serializeString(query.sort),
- sansTop25: serializeStringArray(query.sansTop25),
scopes: serializeStringArray(query.scopes),
severities: serializeStringArray(query.severities),
inNewCodePeriod: query.inNewCodePeriod ? 'true' : undefined,
| SecurityStandard.CWE
| SecurityStandard.OWASP_TOP10
| SecurityStandard.OWASP_TOP10_2021
- | SecurityStandard.SANS_TOP25
| SecurityStandard.SONARSOURCE
): boolean {
const filter = query[standardType];
}
function isOneStandardChildFacetOpen(openFacets: Dict<boolean>, query: Partial<Query>): boolean {
- return [
- SecurityStandard.OWASP_TOP10,
- SecurityStandard.SANS_TOP25,
- SecurityStandard.CWE,
- SecurityStandard.SONARSOURCE,
- ].some(
+ return [SecurityStandard.OWASP_TOP10, SecurityStandard.CWE, SecurityStandard.SONARSOURCE].some(
(
standardType:
| SecurityStandard.CWE
| SecurityStandard.OWASP_TOP10
| SecurityStandard.OWASP_TOP10_2021
- | SecurityStandard.SANS_TOP25
| SecurityStandard.SONARSOURCE
) => shouldOpenStandardsChildFacet(openFacets, query, standardType)
);
standards: {
[SecurityStandard.OWASP_TOP10]: {},
[SecurityStandard.OWASP_TOP10_2021]: {},
- [SecurityStandard.SANS_TOP25]: {},
[SecurityStandard.SONARSOURCE]: {},
[SecurityStandard.CWE]: {},
[SecurityStandard.PCI_DSS_3_2]: {},
renderOwaspTop10Category,
renderPciDss32Category,
renderPciDss40Category,
- renderSansTop25Category,
renderSonarSourceSecurityCategory,
} from '../../helpers/security-standard';
import { SecurityStandard } from '../../types/security';
SecurityStandard.SONARSOURCE,
SecurityStandard.OWASP_TOP10,
SecurityStandard.OWASP_TOP10_2021,
- SecurityStandard.SANS_TOP25,
SecurityStandard.CWE,
SecurityStandard.PCI_DSS_3_2,
SecurityStandard.PCI_DSS_4_0,
export const SECURITY_STANDARD_RENDERER = {
[SecurityStandard.OWASP_TOP10]: renderOwaspTop10Category,
[SecurityStandard.OWASP_TOP10_2021]: renderOwaspTop102021Category,
- [SecurityStandard.SANS_TOP25]: renderSansTop25Category,
[SecurityStandard.SONARSOURCE]: renderSonarSourceSecurityCategory,
[SecurityStandard.CWE]: renderCWECategory,
[SecurityStandard.PCI_DSS_3_2]: renderPciDss32Category,
renderOwaspTop10Category,
renderPciDss32Category,
renderPciDss40Category,
- renderSansTop25Category,
renderSonarSourceSecurityCategory,
} from '../security-standard';
},
owaspTop10: {},
'owaspTop10-2021': {},
- sansTop25: {},
sonarsourceSecurity: {},
'pciDss-3.2': {},
'pciDss-4.0': {},
},
},
'owaspTop10-2021': {},
- sansTop25: {},
sonarsourceSecurity: {},
'pciDss-3.2': {},
'pciDss-4.0': {},
title: 'Injection',
},
},
- sansTop25: {},
sonarsourceSecurity: {},
'pciDss-3.2': {},
'pciDss-4.0': {},
cwe: {},
owaspTop10: {},
'owaspTop10-2021': {},
- sansTop25: {},
sonarsourceSecurity: {},
'pciDss-3.2': {
'1': {
cwe: {},
owaspTop10: {},
'owaspTop10-2021': {},
- sansTop25: {},
sonarsourceSecurity: {},
'pciDss-3.2': {},
'pciDss-4.0': {
cwe: {},
owaspTop10: {},
'owaspTop10-2021': {},
- sansTop25: {},
sonarsourceSecurity: {},
'pciDss-3.2': {},
'pciDss-4.0': {},
});
});
-describe('renderSansTop25Category', () => {
- const standards: Standards = {
- cwe: {},
- owaspTop10: {},
- 'owaspTop10-2021': {},
- sansTop25: {
- 'insecure-interaction': {
- title: 'Insecure Interaction Between Components',
- },
- },
- sonarsourceSecurity: {},
- 'pciDss-3.2': {},
- 'pciDss-4.0': {},
- 'owaspAsvs-4.0': {},
- };
- it('should render sans categories correctly', () => {
- expect(renderSansTop25Category(standards, 'insecure-interaction')).toEqual(
- 'Insecure Interaction Between Components'
- );
- expect(renderSansTop25Category(standards, 'insecure-interaction', true)).toEqual(
- 'SANS Insecure Interaction Between Components'
- );
- expect(renderSansTop25Category(standards, 'unknown')).toEqual('unknown');
- expect(renderSansTop25Category(standards, 'unknown', true)).toEqual('SANS unknown');
- });
-});
-
describe('renderSonarSourceSecurityCategory', () => {
const standards: Standards = {
cwe: {},
owaspTop10: {},
'owaspTop10-2021': {},
- sansTop25: {},
sonarsourceSecurity: {
xss: {
title: 'Cross-Site Scripting (XSS)',
[SecurityStandard.OWASP_TOP10_2021]: 'a1',
[SecurityStandard.CWE]: '213',
[SecurityStandard.OWASP_TOP10]: 'a1',
- [SecurityStandard.SANS_TOP25]: 'insecure-interaction',
[SecurityStandard.SONARSOURCE]: 'command-injection',
[SecurityStandard.PCI_DSS_3_2]: '4.2',
[SecurityStandard.PCI_DSS_4_0]: '4.1',
[SecurityStandard.OWASP_TOP10_2021]: 'a1',
[SecurityStandard.OWASP_TOP10]: 'a1',
[SecurityStandard.SONARSOURCE]: 'command-injection',
- [SecurityStandard.SANS_TOP25]: 'insecure-interaction',
[SecurityStandard.CWE]: '213',
[SecurityStandard.PCI_DSS_3_2]: '4.2',
[SecurityStandard.PCI_DSS_4_0]: '4.1',
title: 'Sensitive Data Exposure',
},
},
- sansTop25: {
- 'insecure-interaction': {
- title: 'Insecure Interaction Between Components',
- },
- 'risky-resource': {
- title: 'Risky Resource Management',
- },
- 'porous-defenses': {
- title: 'Porous Defenses',
- },
- },
sonarsourceSecurity: {
'buffer-overflow': {
title: 'Buffer Overflow',
return addPrefix(`${category.toUpperCase()} - ${record.title}`, 'OWASP', withPrefix);
}
-export function renderSansTop25Category(
- standards: Standards,
- category: string,
- withPrefix = false
-): string {
- const record = standards.sansTop25[category];
- return addPrefix(record ? record.title : category, 'SANS', withPrefix);
-}
-
export function renderSonarSourceSecurityCategory(
standards: Standards,
category: string,
"description": "Insufficient logging and monitoring, coupled with missing or ineffective integration with incident response, allows attackers to further attack systems, maintain persistence, pivot to more systems, and tamper, extract, or destroy data. Most breach studies show time to detect a breach is over 200 days, typically detected by external parties rather than internal processes or monitoring."
}
},
- "sansTop25": {
- "insecure-interaction": {
- "title": "Insecure Interaction Between Components",
- "description": "These weaknesses are related to insecure ways in which data is sent and received between separate components, modules, programs, processes, threads, or systems."
- },
- "risky-resource": {
- "title": "Risky Resource Management",
- "description": "The weaknesses in this category are related to ways in which software does not properly manage the creation, usage, transfer, or destruction of important system resources."
- },
- "porous-defenses": {
- "title": "Porous Defenses",
- "description": "The weaknesses in this category are related to defensive techniques that are often misused, abused, or just plain ignored."
- }
- },
"cwe": {
"5": {
"title": "J2EE Misconfiguration: Data Transmission Without Encryption",
"level": "2"
}
}
-}
\ No newline at end of file
+}
SecurityStandard.OWASP_TOP10_2021,
SecurityStandard.OWASP_TOP10,
SecurityStandard.SONARSOURCE,
- SecurityStandard.SANS_TOP25,
SecurityStandard.CWE,
SecurityStandard.PCI_DSS_3_2,
SecurityStandard.PCI_DSS_4_0,
repositories?: string;
rule_key?: string;
s?: string;
- sansTop25?: string;
severities?: string;
sonarsourceSecurity?: string;
statuses?: string;
export enum SecurityStandard {
OWASP_TOP10_2021 = 'owaspTop10-2021',
OWASP_TOP10 = 'owaspTop10',
- SANS_TOP25 = 'sansTop25',
SONARSOURCE = 'sonarsourceSecurity',
CWE = 'cwe',
PCI_DSS_3_2 = 'pciDss-3.2',
import static org.sonar.server.security.SecurityReviewRating.computeRating;
import static org.sonar.server.security.SecurityStandards.CWES_BY_CWE_TOP_25;
import static org.sonar.server.security.SecurityStandards.OWASP_ASVS_40_REQUIREMENTS_BY_LEVEL;
-import static org.sonar.server.security.SecurityStandards.SANS_TOP_25_INSECURE_INTERACTION;
-import static org.sonar.server.security.SecurityStandards.SANS_TOP_25_POROUS_DEFENSES;
-import static org.sonar.server.security.SecurityStandards.SANS_TOP_25_RISKY_RESOURCE;
import static org.sonar.server.view.index.ViewIndexDefinition.TYPE_VIEW;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.FACET_MODE_EFFORT;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ASSIGNEES;
.collect(MoreCollectors.toList(projectUuids.size()));
}
- /**
- * @deprecated SansTop25 report is outdated and will be removed in future versions
- */
- @Deprecated
- public List<SecurityStandardCategoryStatistics> getSansTop25Report(String projectUuid, boolean isViewOrApp, boolean includeCwe) {
- SearchSourceBuilder request = prepareNonClosedVulnerabilitiesAndHotspotSearch(projectUuid, isViewOrApp);
- Stream.of(SANS_TOP_25_INSECURE_INTERACTION, SANS_TOP_25_RISKY_RESOURCE, SANS_TOP_25_POROUS_DEFENSES)
- .forEach(sansCategory -> request.aggregation(newSecurityReportSubAggregations(
- AggregationBuilders.filter(sansCategory, boolQuery().filter(termQuery(FIELD_ISSUE_SANS_TOP_25, sansCategory))),
- includeCwe,
- SecurityStandards.CWES_BY_SANS_TOP_25.get(sansCategory))));
- return search(request, includeCwe, null);
- }
-
public List<SecurityStandardCategoryStatistics> getCweTop25Reports(String projectUuid, boolean isViewOrApp) {
SearchSourceBuilder request = prepareNonClosedVulnerabilitiesAndHotspotSearch(projectUuid, isViewOrApp);
CWES_BY_CWE_TOP_25.keySet()
import static org.sonar.api.server.rule.RulesDefinition.PciDssVersion;
import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
import static org.sonar.server.issue.IssueDocTesting.newDoc;
-import static org.sonar.server.security.SecurityStandards.SANS_TOP_25_INSECURE_INTERACTION;
-import static org.sonar.server.security.SecurityStandards.SANS_TOP_25_POROUS_DEFENSES;
-import static org.sonar.server.security.SecurityStandards.SANS_TOP_25_RISKY_RESOURCE;
import static org.sonar.server.security.SecurityStandards.UNKNOWN_STANDARD;
public class IssueIndexSecurityReportsTest extends IssueIndexTestCommon {
return owaspTop10Report;
}
- @Test
- public void getSansTop25Report_aggregation() {
- ComponentDto project = newPrivateProjectDto();
- indexIssues(
- newDoc("openvul1", project).setSansTop25(asList(SANS_TOP_25_INSECURE_INTERACTION, SANS_TOP_25_RISKY_RESOURCE)).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_OPEN)
- .setSeverity(Severity.MAJOR),
- newDoc("openvul2", project).setSansTop25(asList(SANS_TOP_25_RISKY_RESOURCE, SANS_TOP_25_POROUS_DEFENSES)).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_REOPENED)
- .setSeverity(Severity.MINOR),
- newDoc("notopenvul", project).setSansTop25(asList(SANS_TOP_25_RISKY_RESOURCE, SANS_TOP_25_POROUS_DEFENSES)).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_CLOSED)
- .setResolution(Issue.RESOLUTION_FIXED)
- .setSeverity(Severity.BLOCKER),
- newDoc("notsansvul", project).setSansTop25(singletonList(UNKNOWN_STANDARD)).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_OPEN).setSeverity(Severity.CRITICAL),
- newDoc("toreviewhotspot1", project).setSansTop25(asList(SANS_TOP_25_INSECURE_INTERACTION, SANS_TOP_25_RISKY_RESOURCE)).setType(RuleType.SECURITY_HOTSPOT)
- .setStatus(Issue.STATUS_TO_REVIEW),
- newDoc("toreviewhotspot2", project).setSansTop25(asList(SANS_TOP_25_RISKY_RESOURCE, SANS_TOP_25_POROUS_DEFENSES)).setType(RuleType.SECURITY_HOTSPOT)
- .setStatus(Issue.STATUS_TO_REVIEW),
- newDoc("inReviewHotspot", project).setSansTop25(List.of(SANS_TOP_25_RISKY_RESOURCE)).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_IN_REVIEW),
- newDoc("reviewedHotspot", project).setSansTop25(List.of(SANS_TOP_25_RISKY_RESOURCE)).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED)
- .setResolution(Issue.RESOLUTION_FIXED),
- newDoc("notowasphotspot", project).setSansTop25(singletonList(UNKNOWN_STANDARD)).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW));
-
- List<SecurityStandardCategoryStatistics> sansTop25Report = underTest.getSansTop25Report(project.uuid(), false, false);
- assertThat(sansTop25Report)
- .extracting(SecurityStandardCategoryStatistics::getCategory, SecurityStandardCategoryStatistics::getVulnerabilities,
- SecurityStandardCategoryStatistics::getVulnerabilityRating, SecurityStandardCategoryStatistics::getToReviewSecurityHotspots,
- SecurityStandardCategoryStatistics::getReviewedSecurityHotspots, SecurityStandardCategoryStatistics::getSecurityReviewRating)
- .containsExactlyInAnyOrder(
- tuple(SANS_TOP_25_INSECURE_INTERACTION, 1L /* openvul1 */, OptionalInt.of(3)/* MAJOR = C */, 1L /* toreviewhotspot1 */, 0L, 5),
- tuple(SANS_TOP_25_RISKY_RESOURCE, 2L /* openvul1,openvul2 */, OptionalInt.of(3)/* MAJOR = C */, 2L/* toreviewhotspot1,toreviewhotspot2 */,
- 1L /* reviewedHotspot */, 4),
- tuple(SANS_TOP_25_POROUS_DEFENSES, 1L /* openvul2 */, OptionalInt.of(2)/* MINOR = B */, 1L/* openhotspot2 */, 0L, 5));
-
- assertThat(sansTop25Report).allMatch(category -> category.getChildren().isEmpty());
- }
-
- @Test
- public void getSansTop25Report_aggregation_on_portfolio() {
- ComponentDto portfolio1 = db.components().insertPrivateApplication();
- ComponentDto portfolio2 = db.components().insertPrivateApplication();
- ComponentDto project1 = db.components().insertPrivateProject();
- ComponentDto project2 = db.components().insertPrivateProject();
-
- indexIssues(
- newDoc("openvul1", project1).setSansTop25(asList(SANS_TOP_25_INSECURE_INTERACTION, SANS_TOP_25_RISKY_RESOURCE)).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_OPEN)
- .setSeverity(Severity.MAJOR),
- newDoc("openvul2", project2).setSansTop25(asList(SANS_TOP_25_RISKY_RESOURCE, SANS_TOP_25_POROUS_DEFENSES)).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_REOPENED)
- .setSeverity(Severity.MINOR),
- newDoc("notopenvul", project1).setSansTop25(asList(SANS_TOP_25_RISKY_RESOURCE, SANS_TOP_25_POROUS_DEFENSES)).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_CLOSED)
- .setResolution(Issue.RESOLUTION_FIXED)
- .setSeverity(Severity.BLOCKER),
- newDoc("notsansvul", project2).setSansTop25(singletonList(UNKNOWN_STANDARD)).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_OPEN).setSeverity(Severity.CRITICAL),
- newDoc("toreviewhotspot1", project1).setSansTop25(asList(SANS_TOP_25_INSECURE_INTERACTION, SANS_TOP_25_RISKY_RESOURCE)).setType(RuleType.SECURITY_HOTSPOT)
- .setStatus(Issue.STATUS_TO_REVIEW),
- newDoc("toreviewhotspot2", project2).setSansTop25(asList(SANS_TOP_25_RISKY_RESOURCE, SANS_TOP_25_POROUS_DEFENSES)).setType(RuleType.SECURITY_HOTSPOT)
- .setStatus(Issue.STATUS_TO_REVIEW),
- newDoc("reviewedHotspot", project2).setSansTop25(List.of(SANS_TOP_25_RISKY_RESOURCE)).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED)
- .setResolution(Issue.RESOLUTION_FIXED),
- newDoc("notowasphotspot", project1).setSansTop25(singletonList(UNKNOWN_STANDARD)).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW));
-
- indexView(portfolio1.uuid(), singletonList(project1.uuid()));
- indexView(portfolio2.uuid(), singletonList(project2.uuid()));
-
- List<SecurityStandardCategoryStatistics> sansTop25Report = underTest.getSansTop25Report(portfolio1.uuid(), true, false);
- assertThat(sansTop25Report)
- .extracting(SecurityStandardCategoryStatistics::getCategory, SecurityStandardCategoryStatistics::getVulnerabilities,
- SecurityStandardCategoryStatistics::getVulnerabilityRating, SecurityStandardCategoryStatistics::getToReviewSecurityHotspots,
- SecurityStandardCategoryStatistics::getReviewedSecurityHotspots, SecurityStandardCategoryStatistics::getSecurityReviewRating)
- .containsExactlyInAnyOrder(
- tuple(SANS_TOP_25_INSECURE_INTERACTION, 1L /* openvul1 */, OptionalInt.of(3)/* MAJOR = C */, 1L /* toreviewhotspot1 */, 0L, 5),
- tuple(SANS_TOP_25_RISKY_RESOURCE, 1L /* openvul1 */, OptionalInt.of(3)/* MAJOR = C */, 1L/* toreviewhotspot1 */, 0L, 5),
- tuple(SANS_TOP_25_POROUS_DEFENSES, 0L, OptionalInt.empty(), 0L, 0L, 1));
-
- assertThat(sansTop25Report).allMatch(category -> category.getChildren().isEmpty());
- }
-
@Test
public void getPciDssReport_aggregation_on_portfolio() {
ComponentDto portfolio1 = db.components().insertPrivateApplication();
issues.facet.standards=Security Category
issues.facet.owaspTop10=OWASP Top 10 2017
issues.facet.owaspTop10_2021=OWASP Top 10 2021
-issues.facet.sansTop25=SANS Top 25
issues.facet.sonarsourceSecurity=SonarSource
issues.facet.cwe=CWE
issues.facet.sonarsource.show_more=Show more SonarSource categories