diff --git a/plugins/reporters/web-app-template/src/App.css b/plugins/reporters/web-app-template/src/App.css index 68ab51da7a45e..7497283ab3971 100644 --- a/plugins/reporters/web-app-template/src/App.css +++ b/plugins/reporters/web-app-template/src/App.css @@ -64,9 +64,9 @@ /* === General === */ -/* Colors of exclude, error, hint and warning icons */ +/* Colors of exclude, error, hint and warning icons and texts */ .ort-error { - color: #f5222d; + color: #e53e3e; } .ort-excluded { diff --git a/plugins/reporters/web-app-template/src/components/IssuesTable.jsx b/plugins/reporters/web-app-template/src/components/IssuesTable.jsx index 3ad9d4c63078d..58eded708362d 100644 --- a/plugins/reporters/web-app-template/src/components/IssuesTable.jsx +++ b/plugins/reporters/web-app-template/src/components/IssuesTable.jsx @@ -23,14 +23,15 @@ import { } from 'react'; import { - ExclamationCircleOutlined, FileAddOutlined, - FileExcelOutlined, - InfoCircleOutlined, - IssuesCloseOutlined, - WarningOutlined + FileExcelOutlined } from '@ant-design/icons'; -import { Collapse, Table, Tooltip } from 'antd'; +import { + Collapse, + Table, + Tag, + Tooltip +} from 'antd'; import Markdown from 'markdown-to-jsx'; import PackageDetails from './PackageDetails'; @@ -40,6 +41,7 @@ import PackagePaths from './PackagePaths'; import PathExcludesTable from './PathExcludesTable'; import ResolutionTable from './ResolutionTable'; import ScopeExcludesTable from './ScopeExcludesTable'; +import SeverityTag from './SeverityTag'; import { getColumnSearchProps } from './Shared'; // Generates the HTML to display issues as a table @@ -74,7 +76,7 @@ const IssuesTable = ({ webAppOrtIssues = [], showExcludesColumn = true }) => { excludes: [], message: [], packageId: [], - rule: [], + source: [], severityIndex: [] }); @@ -155,59 +157,65 @@ const IssuesTable = ({ webAppOrtIssues = [], showExcludesColumn = true }) => { key: 'severityIndex', filters: [ { - text: 'Errors', + text: (), value: 0 }, { - text: 'Warnings', + text: (), value: 1 }, { - text: 'Hint', + text: (), value: 2 }, { - text: 'Resolved', - value: 3 + text: (Resolved), + value: 10 } ], filteredValue: filteredInfo.severityIndex || null, - onFilter: (value, record) => record.severityIndex === Number(value), + onFilter: (value, record) => record.severityIndex === Number(value) + || (record.severityIndex > 10 && Number(value) >= 10), render: (text, record) => ( record.isResolved ? ( - - - + 0 ? 's' : '' + }` + } + /> ) : ( { record.severity === 'ERROR' + && !record.isResolved && ( - ) } { record.severity === 'WARNING' + && !record.isResolved && ( - ) } { record.severity === 'HINT' + && !record.isResolved && ( - ) } @@ -216,7 +224,8 @@ const IssuesTable = ({ webAppOrtIssues = [], showExcludesColumn = true }) => { ), sorter: (a, b) => a.severityIndex - b.severityIndex, sortOrder: sortedInfo.field === 'severityIndex' && sortedInfo.order, - width: '5em' + title: 'Severity', + width: '8em' }); columns.push( @@ -238,17 +247,17 @@ const IssuesTable = ({ webAppOrtIssues = [], showExcludesColumn = true }) => { }, { dataIndex: 'source', - filteredValue: filteredInfo.rule || null, + filteredValue: filteredInfo.source || null, key: 'source', responsive: ['md'], - sorter: (a, b) => a.rule.localeCompare(b.rule), - sortOrder: sortedInfo.field === 'rule' && sortedInfo.order, + sorter: (a, b) => a.source.localeCompare(b.source), + sortOrder: sortedInfo.field === 'source' && sortedInfo.order, title: 'Source', width: '25%', ...getColumnSearchProps( 'source', - filteredInfo.rule, - (value) => setFilteredInfo({ ...filteredInfo, rule: value }) + filteredInfo.source, + (value) => setFilteredInfo({ ...filteredInfo, source: value }) ) }, { @@ -407,6 +416,7 @@ const IssuesTable = ({ webAppOrtIssues = [], showExcludesColumn = true }) => { current: pagination.current, hideOnSinglePage: true, onChange: handlePaginationChange, + pageSize: pagination.pageSize, pageSizeOptions: ['50', '100', '250', '500', '1000', '5000'], position: 'bottom', showQuickJumper: true, diff --git a/plugins/reporters/web-app-template/src/components/LicenseStatsTable.jsx b/plugins/reporters/web-app-template/src/components/LicenseStatsTable.jsx index 083c49627f304..5b789d1194bfe 100644 --- a/plugins/reporters/web-app-template/src/components/LicenseStatsTable.jsx +++ b/plugins/reporters/web-app-template/src/components/LicenseStatsTable.jsx @@ -29,7 +29,7 @@ const LicenseStatsTable = ({ emptyText, licenses, licenseStats }) => { /* === Table state handling === */ // State variable for displaying table in various pages - const [pagination, setPagination] = useState({ current: 1, pageSize: 100 }); + const [pagination, setPagination] = useState({ current: 1, pageSize: 50 }); // State variable for filtering the contents of table columns const filteredInfoDefault = { @@ -94,10 +94,10 @@ const LicenseStatsTable = ({ emptyText, licenses, licenseStats }) => { pagination={ { current: pagination.current, - defaultPageSize: 50, hideOnSinglePage: true, onChange: handlePaginationChange, position: 'bottom', + pageSize: pagination.pageSize, pageSizeOptions: ['50', '100', '250', '500', '1000', '5000'], showTotal: (total, range) => `${range[0]}-${range[1]} of ${total} results` } diff --git a/plugins/reporters/web-app-template/src/components/RuleViolationsTable.jsx b/plugins/reporters/web-app-template/src/components/RuleViolationsTable.jsx index a33f34514650f..97cebde51a0f7 100644 --- a/plugins/reporters/web-app-template/src/components/RuleViolationsTable.jsx +++ b/plugins/reporters/web-app-template/src/components/RuleViolationsTable.jsx @@ -23,16 +23,13 @@ import { } from 'react'; import { - ExclamationCircleOutlined, FileAddOutlined, - FileExcelOutlined, - InfoCircleOutlined, - IssuesCloseOutlined, - WarningOutlined + FileExcelOutlined } from '@ant-design/icons'; import { Collapse, Table, + Tag, Tooltip } from 'antd'; import Markdown from 'markdown-to-jsx'; @@ -44,6 +41,7 @@ import PackagePaths from './PackagePaths'; import PathExcludesTable from './PathExcludesTable'; import ResolutionTable from './ResolutionTable'; import ScopeExcludesTable from './ScopeExcludesTable'; +import SeverityTag from './SeverityTag'; import { getColumnSearchProps } from './Shared'; // Generates the HTML to display violations as a table @@ -57,7 +55,8 @@ const RuleViolationsTable = ({ webAppRuleViolations = [], showExcludesColumn = t isResolved: webAppRuleViolation.isResolved, key: webAppRuleViolation.key, message: webAppRuleViolation.message, - packageId: webAppRuleViolation.package.id, + packageId: webAppRuleViolation.package + ? webAppRuleViolation.package.id : '', rule: webAppRuleViolation.rule, severity: webAppRuleViolation.severity, severityIndex: webAppRuleViolation.severityIndex, @@ -159,59 +158,65 @@ const RuleViolationsTable = ({ webAppRuleViolations = [], showExcludesColumn = t key: 'severityIndex', filters: [ { - text: 'Errors', + text: (), value: 0 }, { - text: 'Warnings', + text: (), value: 1 }, { - text: 'Hint', + text: (), value: 2 }, { - text: 'Resolved', - value: 3 + text: (Resolved), + value: 10 } ], filteredValue: filteredInfo.severityIndex || null, - onFilter: (value, record) => record.severityIndex === Number(value), + onFilter: (value, record) => record.severityIndex === Number(value) + || (record.severityIndex > 10 && Number(value) >= 10), render: (text, record) => ( record.isResolved ? ( - - - + 0 ? 's' : '' + }` + } + /> ) : ( { record.severity === 'ERROR' + && !record.isResolved && ( - ) } { record.severity === 'WARNING' + && !record.isResolved && ( - ) } { record.severity === 'HINT' + && !record.isResolved && ( - ) } @@ -220,7 +225,8 @@ const RuleViolationsTable = ({ webAppRuleViolations = [], showExcludesColumn = t ), sorter: (a, b) => a.severityIndex - b.severityIndex, sortOrder: sortedInfo.field === 'severityIndex' && sortedInfo.order, - width: '5em' + title: 'Severity', + width: '8em' }); columns.push( diff --git a/plugins/reporters/web-app-template/src/components/SeverityTag.jsx b/plugins/reporters/web-app-template/src/components/SeverityTag.jsx new file mode 100644 index 0000000000000..5854add7ca22a --- /dev/null +++ b/plugins/reporters/web-app-template/src/components/SeverityTag.jsx @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2025 The ORT Project Authors (see ) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * License-Filename: LICENSE + */ + +import { + Tag, + Tooltip +} from 'antd'; + +const SeverityTag = ({ severity, isResolved = false, tooltipText = '' }) => { + const severityColors = { + error: '#e53e3e', + warning: '#f59e0b', + hint: '#84b6eb' + }; + + return isResolved + ? ( + + + + {`${severity.charAt(0).toUpperCase()}${severity.slice(1)}`} + + + + ) + : ( + + + {`${severity.charAt(0).toUpperCase()}${severity.slice(1)}`} + + ); +}; + +export default SeverityTag; diff --git a/plugins/reporters/web-app-template/src/components/VulnerabilitiesResolutionTable.jsx b/plugins/reporters/web-app-template/src/components/VulnerabilitiesResolutionTable.jsx new file mode 100644 index 0000000000000..0dc19c86e2432 --- /dev/null +++ b/plugins/reporters/web-app-template/src/components/VulnerabilitiesResolutionTable.jsx @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2025 The ORT Project Authors (see ) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * License-Filename: LICENSE + */ + +import { Table } from 'antd'; + +// Generates the HTML to display webAppVulnerabilityResolution(s) as a table +const VulnerabilitiesResolutionTable = ({ resolutions }) => { + const columns = [ + { + dataIndex: 'reason', + key: 'reason', + title: 'Reason' + }, + { + dataIndex: 'id', + key: 'id', + title: 'Id' + }, + { + dataIndex: 'comment', + key: 'comment', + textWrap: 'word-break', + title: 'Comment', + width: '50%' + } + ]; + + return ( + `${range[0]}-${range[1]} of ${total} results` + } + } + /> + ); +}; + +export default VulnerabilitiesResolutionTable; diff --git a/plugins/reporters/web-app-template/src/components/VulnerabilitiesTable.jsx b/plugins/reporters/web-app-template/src/components/VulnerabilitiesTable.jsx index a2c222194d422..58960289651e4 100644 --- a/plugins/reporters/web-app-template/src/components/VulnerabilitiesTable.jsx +++ b/plugins/reporters/web-app-template/src/components/VulnerabilitiesTable.jsx @@ -25,22 +25,23 @@ import { import { FileAddOutlined, FileExcelOutlined, - FileProtectOutlined, - IssuesCloseOutlined + FileProtectOutlined } from '@ant-design/icons'; import { Collapse, Table, + Tag, Tooltip } from 'antd'; import PackageDetails from './PackageDetails'; import PackagePaths from './PackagePaths'; import PathExcludesTable from './PathExcludesTable'; -import ResolutionTable from './ResolutionTable'; import ScopeExcludesTable from './ScopeExcludesTable'; import { getColumnSearchProps } from './Shared'; +import VulnerabilitiesResolutionTable from './VulnerabilitiesResolutionTable'; import VulnerabilityRatingTag from './VulnerabilityRatingTag'; +import VulnerabilityReferencesList from './VulnerabilityReferencesList'; // Generates the HTML to display vulnerabilities as a table const VulnerabilitiesTable = ({ webAppVulnerabilities = [], showExcludesColumn = true }) => { @@ -55,6 +56,11 @@ const VulnerabilitiesTable = ({ webAppVulnerabilities = [], showExcludesColumn = key: webAppVulnerability.key, packageId: webAppVulnerability.package.id, references: webAppVulnerability.references, + resolutionReasonsText: `Resolved with ${ + Array.from(webAppVulnerability.resolutionReasons).join(', ') + } resolution${ + webAppVulnerability.resolutionReasons.size > 0 ? 's' : '' + }`, severity: webAppVulnerability.severity, severityIndex: webAppVulnerability.severityIndex, webAppVulnerability @@ -126,17 +132,17 @@ const VulnerabilitiesTable = ({ webAppVulnerabilities = [], showExcludesColumn = if (webAppPackage) { return webAppPackage.isExcluded ? ( - - - - - + + + + + ) : ( - + ); } @@ -168,28 +174,73 @@ const VulnerabilitiesTable = ({ webAppVulnerabilities = [], showExcludesColumn = text: (), value: 3 }, - { - text: (), - value: 5 - }, { text: (), value: 4 + }, + { + text: (Resolved), + value: 10 } ], filteredValue: filteredInfo.severityIndex || null, - onFilter: (value, record) => record.severityIndex === Number(value), + onFilter: (value, record) => record.severityIndex === Number(value) + || (record.severityIndex > 10 && Number(value) >= 10), render: (text, record) => ( record.isResolved ? ( - - - + + { + record.severityIndex === 10 + && ( + + ) + } + { + record.severityIndex === 11 + && ( + + ) + } + { + record.severityIndex === 12 + && ( + + ) + } + { + record.severityIndex === 13 + && ( + + ) + } + { + record.severityIndex === 14 + && ( + + ) + } + ) : ( @@ -223,19 +274,13 @@ const VulnerabilitiesTable = ({ webAppVulnerabilities = [], showExcludesColumn = ) } - { - record.severityIndex === 5 - && ( - - ) - } ) ), sorter: (a, b) => a.severityIndex - b.severityIndex, sortOrder: sortedInfo.field === 'severityIndex' && sortedInfo.order, title: 'Severity', - width: '10em' + width: '8em' }); columns.push( @@ -335,9 +380,16 @@ const VulnerabilitiesTable = ({ webAppVulnerabilities = [], showExcludesColumn = expandedRowRender: (record) => { const webAppVulnerability = record.webAppVulnerability; const webAppPackage = webAppVulnerability.package; - let defaultActiveKey = record.isResolved - ? 'vulnerability-resolutions' - : ['vulnerability-package-details', 'vulnerability-package-paths']; + const defaultActiveKey = record.isResolved + ? [ + 'vulnerability-resolutions', + 'vulnerability-references' + ] + : [ + 'vulnerability-references', + 'vulnerability-package-details', + 'vulnerability-package-paths' + ]; return ( ) }); } + if (webAppVulnerability.hasReferences()) { + collapseItems.push({ + label: 'References', + key: 'vulnerability-references', + children: ( + + ) + }); + } + collapseItems.push({ label: 'Details', key: 'vulnerability-package-details', @@ -415,6 +479,7 @@ const VulnerabilitiesTable = ({ webAppVulnerabilities = [], showExcludesColumn = current: pagination.current, hideOnSinglePage: true, onChange: handlePaginationChange, + pageSize: pagination.pageSize, pageSizeOptions: ['50', '100', '250', '500', '1000', '5000'], position: 'bottom', showQuickJumper: true, diff --git a/plugins/reporters/web-app-template/src/components/VulnerabilityRatingTag.jsx b/plugins/reporters/web-app-template/src/components/VulnerabilityRatingTag.jsx index 17c2ebbfc47f3..3e4471f82650c 100644 --- a/plugins/reporters/web-app-template/src/components/VulnerabilityRatingTag.jsx +++ b/plugins/reporters/web-app-template/src/components/VulnerabilityRatingTag.jsx @@ -17,25 +17,42 @@ * License-Filename: LICENSE */ -import { Tag } from 'antd'; +import { + Tag, + Tooltip +} from 'antd'; -const VulnerabilityRatingTag = ({ severity }) => { +const VulnerabilityRatingTag = ({ severity, isResolved = false, tooltipText = '' }) => { const severityColors = { critical: '#e53e3e', high: '#dd6b20', low: '#f6e05e', medium: '#f59e0b', - none: '#808080', - resolved: '#b0c4de' + none: '#808080' }; - return ( - - {`${severity.charAt(0).toUpperCase()}${severity.slice(1)}`} - - ); + return isResolved + ? ( + + + + {`${severity.charAt(0).toUpperCase()}${severity.slice(1)}`} + + + + ) + : ( + + {`${severity.charAt(0).toUpperCase()}${severity.slice(1)}`} + + ); }; export default VulnerabilityRatingTag; diff --git a/plugins/reporters/web-app-template/src/components/VulnerabilityReferencesList.jsx b/plugins/reporters/web-app-template/src/components/VulnerabilityReferencesList.jsx new file mode 100644 index 0000000000000..22dcf90f1ed15 --- /dev/null +++ b/plugins/reporters/web-app-template/src/components/VulnerabilityReferencesList.jsx @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2025 The ORT Project Authors (see ) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * License-Filename: LICENSE + */ + +import { + useState +} from 'react'; + +import { + Descriptions, + List +} from 'antd'; + +const { Item } = Descriptions; + +// Generates the HTML to display references for a vulnerability as a list +const VulnerabilityReferencesList = ({ references = [] }) => { + // State variable for displaying list in various pages + const [pagination, setPagination] = useState({ current: 1, pageSize: 5 }); + + // Handle for list pagination changes + const handlePaginationChange = (page, pageSize) => { + setPagination({ current: page, pageSize }); + }; + + return ( + { + const { + url, + scoringSystem, + severity, + score, + vector + } = reference; + + return ( + + + { + !!scoringSystem + && ( + + {scoringSystem} + + ) + } + { + !!score + && ( + + {score} + + ) + } + { + !!severity + && ( + + {severity} + + ) + } + { + !!vector + && ( + + {vector} + + ) + } + { + !!url + && ( + + + {url} + + + ) + } + + + ); + }} + /> + ) +}; + +export default VulnerabilityReferencesList; diff --git a/plugins/reporters/web-app-template/src/models/VulnerabilityReference.js b/plugins/reporters/web-app-template/src/models/VulnerabilityReference.js index 8f73ae1661680..f051304766974 100644 --- a/plugins/reporters/web-app-template/src/models/VulnerabilityReference.js +++ b/plugins/reporters/web-app-template/src/models/VulnerabilityReference.js @@ -20,14 +20,22 @@ class VulnerabilityReference { #scoringSystem; + #score; + #severity; #severityIndex; #url; + #vector + constructor(obj) { if (obj instanceof Object) { + if (obj.score !== null) { + this.#score = obj.score; + } + if (obj.scoring_system !== null || obj.scoringSystem) { this.#scoringSystem = obj.scoring_system || obj.cscoringSystem; } @@ -56,9 +64,17 @@ class VulnerabilityReference { if (obj.url !== null) { this.#url = obj.url; } + + if (obj.vector !== null) { + this.#vector = obj.vector; + } } } + get score() { + return this.#score; + } + get scoringSystem() { return this.#scoringSystem; } @@ -74,6 +90,10 @@ class VulnerabilityReference { get url() { return this.#url; } + + get vector() { + return this.#vector; + } } export default VulnerabilityReference; diff --git a/plugins/reporters/web-app-template/src/models/WebAppOrtResult.js b/plugins/reporters/web-app-template/src/models/WebAppOrtResult.js index 260c41db008df..a7ee925549c15 100644 --- a/plugins/reporters/web-app-template/src/models/WebAppOrtResult.js +++ b/plugins/reporters/web-app-template/src/models/WebAppOrtResult.js @@ -33,6 +33,7 @@ import WebAppScope from './WebAppScope'; import WebAppScopeExclude from './WebAppScopeExclude'; import WebAppTreeNode from './WebAppTreeNode'; import WebAppVulnerability from './WebAppVulnerability'; +import WebAppVulnerabilityResolution from './WebAppVulnerabilityResolution'; class WebAppOrtResult { #concludedLicensePackages = []; @@ -328,7 +329,7 @@ class WebAppOrtResult { || obj.vulnerabilitiesResolutions; for (let i = 0, len = vulnerabilityResolutions.length; i < len; i++) { - this.#vulnerabilityResolutions.push(new WebAppResolution(vulnerabilityResolutions[i])); + this.#vulnerabilityResolutions.push(new WebAppVulnerabilityResolution(vulnerabilityResolutions[i])); } } diff --git a/plugins/reporters/web-app-template/src/models/WebAppRuleViolation.js b/plugins/reporters/web-app-template/src/models/WebAppRuleViolation.js index 3fffa4713d518..8aeca4edd9483 100644 --- a/plugins/reporters/web-app-template/src/models/WebAppRuleViolation.js +++ b/plugins/reporters/web-app-template/src/models/WebAppRuleViolation.js @@ -24,6 +24,8 @@ class WebAppRuleViolation { #howToFix; + #isResolved; + #license; #licenseIndex; @@ -38,6 +40,8 @@ class WebAppRuleViolation { #severity; + #severityIndex; + #resolutionIndexes = new Set(); #resolutionReasons; @@ -82,6 +86,20 @@ class WebAppRuleViolation { this.#severity = obj.severity; } + switch (this.#severity) { + case 'ERROR': + this.#severityIndex = 0; + break; + case 'WARNING': + this.#severityIndex = 1; + break; + case 'HINT': + this.#severityIndex = 3; + break; + default: + this.#severityIndex = 4; + } + if (obj.resolutions) { this.#resolutionIndexes = new Set(obj.resolutions); } @@ -104,6 +122,12 @@ class WebAppRuleViolation { } } + this.#isResolved = !!(this.#resolutionIndexes.size > 0); + + if (this.#isResolved) { + this.#severityIndex = this.#severityIndex + 10; + } + this.key = randomStringGenerator(20); } } @@ -113,7 +137,7 @@ class WebAppRuleViolation { } get isResolved() { - return this.#resolutionIndexes && this.#resolutionIndexes.size > 0; + return this.#isResolved; } get howToFix() { @@ -189,23 +213,7 @@ class WebAppRuleViolation { } get severityIndex() { - if (this.isResolved) { - return 3; - } - - if (this.#severity === 'ERROR') { - return 0; - } - - if (this.#severity === 'WARNING') { - return 1; - } - - if (this.#severity === 'HINT') { - return 2; - } - - return -1; + return this.#severityIndex; } hasHowToFix() { diff --git a/plugins/reporters/web-app-template/src/models/WebAppVulnerability.js b/plugins/reporters/web-app-template/src/models/WebAppVulnerability.js index 13159c5b6625f..f771857e1329d 100644 --- a/plugins/reporters/web-app-template/src/models/WebAppVulnerability.js +++ b/plugins/reporters/web-app-template/src/models/WebAppVulnerability.js @@ -26,6 +26,8 @@ class WebAppVulnerability { #id; + #isResolved; + #package; #packageIndex; @@ -69,6 +71,15 @@ class WebAppVulnerability { this.#resolutionIndexes = new Set(obj.resolutions); } + if (!this.#severityIndex) { + this.#severityIndex = 4; + this.#references.forEach((reference) => { + if (reference.severityIndex < this.#severityIndex) { + this.#severityIndex = reference.severityIndex; + } + }); + } + if (webAppOrtResult) { this.#webAppOrtResult = webAppOrtResult; @@ -78,6 +89,12 @@ class WebAppVulnerability { } } + this.#isResolved = !!(this.#resolutionIndexes.size > 0); + + if (this.#isResolved) { + this.#severityIndex += 10; + } + this.key = randomStringGenerator(20); } } @@ -91,11 +108,7 @@ class WebAppVulnerability { } get isResolved() { - if (this.#resolutionIndexes && this.#resolutionIndexes.size > 0) { - return true; - } - - return false; + return this.#isResolved; } get package() { @@ -147,17 +160,12 @@ class WebAppVulnerability { } get severityIndex() { - if (!this.#severityIndex) { - this.#severityIndex = 4; - this.#references.forEach((reference) => { - if (reference.severityIndex < this.#severityIndex) { - this.#severityIndex = reference.severityIndex; - } - }); - } - return this.#severityIndex; } + + hasReferences() { + return this.#references.length > 0; + } } export default WebAppVulnerability; diff --git a/plugins/reporters/web-app-template/src/models/WebAppVulnerabilityResolution.js b/plugins/reporters/web-app-template/src/models/WebAppVulnerabilityResolution.js new file mode 100644 index 0000000000000..014c4ea3341c5 --- /dev/null +++ b/plugins/reporters/web-app-template/src/models/WebAppVulnerabilityResolution.js @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2025 The ORT Project Authors (see ) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * License-Filename: LICENSE + */ + +import { randomStringGenerator } from '../utils'; + +class WebAppVulnerabilityResolution { + #_id; + + #comment; + + #id; + + #reason; + + constructor(obj) { + if (obj) { + if (Number.isInteger(obj._id)) { + this.#_id = obj._id; + } + + if (obj.comment) { + this.#comment = obj.comment; + } + + if (obj.id) { + this.#id = obj.id; + } + + if (obj.reason) { + this.#reason = obj.reason; + } + } + + this.key = randomStringGenerator(20); + } + + get _id() { + return this.#_id; + } + + get comment() { + return this.#comment; + } + + get id() { + return this.#id; + } + + get reason() { + return this.#reason; + } +} + +export default WebAppVulnerabilityResolution;