mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-22 02:05:41 +01:00
Update security hub ui (#19062)
1. Fixes #19010 2. Fixes #19011 3. Fixes #19012 4. Fixes #19015 5. Fixes #19025 6. Fixes #19026 7. Fixes #19034 8. Fixes #19037 Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
parent
d93f24a4dc
commit
854e0295d1
@ -29,7 +29,7 @@
|
||||
'VULNERABILITY.GRID.COLUMN_SEVERITY' | translate
|
||||
}}</clr-dg-column>
|
||||
<clr-dg-column class="min-width">{{
|
||||
'VULNERABILITY.PACKAGE' | translate
|
||||
'VULNERABILITY.GRID.COLUMN_PACKAGE' | translate
|
||||
}}</clr-dg-column>
|
||||
<clr-dg-column>{{
|
||||
'VULNERABILITY.GRID.COLUMN_VERSION' | translate
|
||||
@ -42,12 +42,17 @@
|
||||
</clr-dg-placeholder>
|
||||
<clr-dg-row *ngFor="let c of vul" [clrDgItem]="c">
|
||||
<clr-dg-cell class="min-width">
|
||||
<span *ngIf="!c?.links || c?.links?.length === 0">{{
|
||||
c.cve_id
|
||||
}}</span>
|
||||
<span
|
||||
*ngIf="
|
||||
!c?.links ||
|
||||
c?.links?.length === 0 ||
|
||||
(c?.links?.length === 1 && !c?.links[0])
|
||||
"
|
||||
>{{ c.cve_id }}</span
|
||||
>
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
*ngIf="c?.links && c?.links.length === 1"
|
||||
*ngIf="c?.links && c?.links.length === 1 && c?.links[0]"
|
||||
href="{{ c?.links[0] }}"
|
||||
target="_blank"
|
||||
>{{ c.cve_id }}</a
|
||||
|
@ -10,12 +10,12 @@ import {
|
||||
import { finalize } from 'rxjs/operators';
|
||||
import { VulnerabilityItem } from '../../../../../../ng-swagger-gen/models/vulnerability-item';
|
||||
import {
|
||||
getDigestLink,
|
||||
getRepoLink,
|
||||
OptionType,
|
||||
SearchEventData,
|
||||
severityText,
|
||||
VUL_ID,
|
||||
getDigestLink,
|
||||
getRepoLink,
|
||||
} from './security-hub.interface';
|
||||
import { ProjectService } from '../../../../../../ng-swagger-gen/services/project.service';
|
||||
import { VulnerabilityFilterComponent } from './vulnerability-filter/vulnerability-filter.component';
|
||||
@ -96,14 +96,17 @@ export class SecurityHubComponent {
|
||||
search(res: SearchEventData) {
|
||||
if (res?.projectId) {
|
||||
this.projectService
|
||||
.getProject({
|
||||
projectNameOrId: res.projectId,
|
||||
.listProjects({
|
||||
name: res.projectId,
|
||||
page: 1,
|
||||
pageSize: 1,
|
||||
withDetail: false,
|
||||
})
|
||||
.subscribe({
|
||||
next: project => {
|
||||
if (project?.project_id) {
|
||||
next: projects => {
|
||||
if (projects?.length) {
|
||||
res.normal.push(
|
||||
`${OptionType.PROJECT_ID}=${project?.project_id}`
|
||||
`${OptionType.PROJECT_ID}=${projects[0]?.project_id}`
|
||||
);
|
||||
this.clrDgRefresh(this.state, res?.normal);
|
||||
} else {
|
||||
@ -112,7 +115,8 @@ export class SecurityHubComponent {
|
||||
}
|
||||
},
|
||||
error: err => {
|
||||
this.messageHandler.error(err);
|
||||
res.normal.push(`${OptionType.PROJECT_ID}=0`);
|
||||
this.clrDgRefresh(this.state, res?.normal);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
@ -157,12 +161,30 @@ export class SecurityHubComponent {
|
||||
|
||||
searchCVE(cveId: string) {
|
||||
this.vulnerabilityFilterComponent.selectedOptions = [OptionType.CVE_ID];
|
||||
this.vulnerabilityFilterComponent.candidates = [
|
||||
OptionType.SEVERITY,
|
||||
OptionType.CVSS3,
|
||||
OptionType.PROJECT_ID,
|
||||
OptionType.REPO,
|
||||
OptionType.PACKAGE,
|
||||
OptionType.TAG,
|
||||
];
|
||||
this.vulnerabilityFilterComponent.valueMap = {};
|
||||
this.vulnerabilityFilterComponent.valueMap[OptionType.CVE_ID] = cveId;
|
||||
this.currentPage = 1;
|
||||
this.clrDgRefresh(this.state, [`${OptionType.CVE_ID}=${cveId}`]);
|
||||
}
|
||||
searchRepo(repoName: string) {
|
||||
this.vulnerabilityFilterComponent.selectedOptions = [OptionType.REPO];
|
||||
this.vulnerabilityFilterComponent.candidates = [
|
||||
OptionType.CVE_ID,
|
||||
OptionType.SEVERITY,
|
||||
OptionType.CVSS3,
|
||||
OptionType.PROJECT_ID,
|
||||
OptionType.PACKAGE,
|
||||
OptionType.TAG,
|
||||
];
|
||||
this.vulnerabilityFilterComponent.valueMap = {};
|
||||
this.vulnerabilityFilterComponent.valueMap[OptionType.REPO] = repoName;
|
||||
this.currentPage = 1;
|
||||
this.clrDgRefresh(this.state, [`${OptionType.REPO}=${repoName}`]);
|
||||
|
@ -29,7 +29,7 @@ export const OptionType_I18n_Map = {
|
||||
[OptionType.SEVERITY]: 'VULNERABILITY.GRID.COLUMN_SEVERITY',
|
||||
[OptionType.CVSS3]: 'VULNERABILITY.GRID.CVSS3',
|
||||
[OptionType.REPO]: 'SECURITY_HUB.REPO_NAME',
|
||||
[OptionType.PACKAGE]: 'VULNERABILITY.PACKAGE',
|
||||
[OptionType.PACKAGE]: 'VULNERABILITY.GRID.COLUMN_PACKAGE',
|
||||
[OptionType.TAG]: 'REPLICATION.TAG',
|
||||
[OptionType.PROJECT_ID]: 'SECURITY_HUB.OPTION_PROJECT_ID_NAME',
|
||||
};
|
||||
|
@ -56,7 +56,7 @@ export class SingleBarComponent implements OnChanges {
|
||||
enabled: true,
|
||||
distance: -8,
|
||||
style: {
|
||||
fontSize: 8,
|
||||
fontSize: '8px',
|
||||
fontWeight: 1,
|
||||
},
|
||||
pointFormat: '{point.y}',
|
||||
|
@ -97,7 +97,7 @@ export class VulnerabilityFilterComponent {
|
||||
item === OptionType.PROJECT_ID &&
|
||||
this.valueMap[OptionType.PROJECT_ID]
|
||||
) {
|
||||
result.projectId = this.valueMap[OptionType.PROJECT_ID];
|
||||
result.projectId = this.valueMap[OptionType.PROJECT_ID]?.trim();
|
||||
} else if (item === OptionType.SEVERITY) {
|
||||
if (this.severity) {
|
||||
result.normal.push(
|
||||
@ -108,12 +108,12 @@ export class VulnerabilityFilterComponent {
|
||||
if (this.startScore || this.endScore) {
|
||||
result.normal.push(
|
||||
`${OptionType.CVSS3}=[${
|
||||
this.startScore ? this.startScore : '0.0'
|
||||
}~${this.endScore ? this.endScore : '10.0'}]`
|
||||
this.startScore ? this.startScore?.trim() : '0.0'
|
||||
}~${this.endScore ? this.endScore?.trim() : '10.0'}]`
|
||||
);
|
||||
}
|
||||
} else if (this.valueMap[item]) {
|
||||
result.normal.push(`${item}=${this.valueMap[item]}`);
|
||||
result.normal.push(`${item}=${this.valueMap[item]?.trim()}`);
|
||||
}
|
||||
});
|
||||
this.search.emit(result);
|
||||
|
@ -116,16 +116,18 @@
|
||||
<div
|
||||
class="clr-row row"
|
||||
*ngFor="let item of securitySummary?.dangerous_artifacts">
|
||||
<div class="clr-col ellipsis">
|
||||
<div class="clr-col">
|
||||
<a
|
||||
class="search"
|
||||
href="javascript:void(0)"
|
||||
appScrollAnchor="{{ vulId }}"
|
||||
(click)="searchRepoClick(item?.repository_name)"
|
||||
title="{{ item.repository_name }}"
|
||||
><clr-icon shape="search"></clr-icon
|
||||
>{{ item.repository_name }}</a
|
||||
>
|
||||
title="{{ item.repository_name }}">
|
||||
<span class="ellipsis">
|
||||
<clr-icon shape="search"></clr-icon
|
||||
>{{ item.repository_name }}
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="clr-col" title="{{ item?.digest }}">
|
||||
<a
|
||||
@ -137,8 +139,10 @@
|
||||
item.digest
|
||||
)
|
||||
"
|
||||
>{{ item?.digest?.slice(0, 15) }}</a
|
||||
>
|
||||
><span class="ellipsis">{{
|
||||
item?.digest?.slice(0, 15)
|
||||
}}</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="clr-col">
|
||||
<div class="single-bar-container">
|
||||
@ -163,7 +167,7 @@
|
||||
{{ 'VULNERABILITY.GRID.CVSS3' | translate }}
|
||||
</div>
|
||||
<div class="clr-col-4 column">
|
||||
{{ 'VULNERABILITY.PACKAGE' | translate }}
|
||||
{{ 'VULNERABILITY.GRID.COLUMN_PACKAGE' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -171,16 +175,18 @@
|
||||
<div
|
||||
class="clr-row row"
|
||||
*ngFor="let item of securitySummary?.dangerous_cves">
|
||||
<div class="clr-col-4 ellipsis">
|
||||
<div class="clr-col-4">
|
||||
<a
|
||||
class="search"
|
||||
href="javascript:void(0)"
|
||||
appScrollAnchor="{{ vulId }}"
|
||||
(click)="searchCVEClick(item?.cve_id)"
|
||||
title="{{ item.cve_id }}"
|
||||
><clr-icon shape="search"></clr-icon
|
||||
>{{ item.cve_id }}</a
|
||||
>
|
||||
title="{{ item.cve_id }}">
|
||||
<span class="ellipsis">
|
||||
<clr-icon shape="search"></clr-icon
|
||||
>{{ item.cve_id }}
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="clr-col-2">
|
||||
<ng-container [ngSwitch]="item.severity">
|
||||
|
@ -113,6 +113,7 @@ export class VulnerabilitySummaryComponent implements OnInit, OnDestroy {
|
||||
enabled: false,
|
||||
},
|
||||
showInLegend: true,
|
||||
borderWidth: 0,
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { throwError as observableThrowError, Observable, of } from 'rxjs';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
import { catchError, share } from 'rxjs/operators';
|
||||
import { Project } from '../../base/project/project-config/project-policy-config/project';
|
||||
import { ProjectPolicy } from '../../base/project/project-config/project-policy-config/project-policy-config.component';
|
||||
import {
|
||||
@ -10,6 +10,7 @@ import {
|
||||
buildHttpRequestOptionsWithObserveResponse,
|
||||
CURRENT_BASE_HREF,
|
||||
} from '../units/utils';
|
||||
import { CacheObservable } from '../units/cache-util';
|
||||
|
||||
/**
|
||||
* Define the service methods to handle the Project related things.
|
||||
@ -87,18 +88,26 @@ export abstract class ProjectService {
|
||||
*/
|
||||
@Injectable()
|
||||
export class ProjectDefaultService extends ProjectService {
|
||||
// to avoid multiple requests for one navigating action
|
||||
private _sharedProjectObservableMap: {
|
||||
[key: number | string]: Observable<Project>;
|
||||
} = {};
|
||||
constructor(private http: HttpClient) {
|
||||
super();
|
||||
}
|
||||
|
||||
@CacheObservable({ maxAge: 1000 * 60 })
|
||||
public getProject(projectId: number | string): Observable<Project> {
|
||||
if (!projectId) {
|
||||
return observableThrowError('Bad argument');
|
||||
}
|
||||
let baseUrl: string = CURRENT_BASE_HREF + '/projects';
|
||||
return this.http
|
||||
if (this._sharedProjectObservableMap[projectId]) {
|
||||
return this._sharedProjectObservableMap[projectId];
|
||||
}
|
||||
this._sharedProjectObservableMap[projectId] = this.http
|
||||
.get<Project>(`${baseUrl}/${projectId}`, HTTP_GET_OPTIONS)
|
||||
.pipe(catchError(error => observableThrowError(error)));
|
||||
.pipe(share());
|
||||
return this._sharedProjectObservableMap[projectId];
|
||||
}
|
||||
|
||||
public updateProjectPolicy(
|
||||
|
@ -1886,7 +1886,7 @@
|
||||
"CVE": "CVEs",
|
||||
"FILTER_BY": "Filter by",
|
||||
"OPTION_ALL": "All",
|
||||
"OPTION_PROJECT_ID_NAME": "Project id or name",
|
||||
"OPTION_PROJECT_ID_NAME": "Project Name",
|
||||
"SEARCH": "SEARCH",
|
||||
"REPO_NAME": "Repository Name",
|
||||
"TOOLTIP": "All filters except CVSS3 only support exact matches",
|
||||
|
@ -1887,7 +1887,7 @@
|
||||
"CVE": "CVEs",
|
||||
"FILTER_BY": "Filter by",
|
||||
"OPTION_ALL": "All",
|
||||
"OPTION_PROJECT_ID_NAME": "Project Id or Name",
|
||||
"OPTION_PROJECT_ID_NAME": "Project Name",
|
||||
"SEARCH": "SEARCH",
|
||||
"REPO_NAME": "Repository Name",
|
||||
"TOOLTIP": "All filters except CVSS3 only support exact matches",
|
||||
|
@ -1883,7 +1883,7 @@
|
||||
"CVE": "CVEs",
|
||||
"FILTER_BY": "Filter by",
|
||||
"OPTION_ALL": "All",
|
||||
"OPTION_PROJECT_ID_NAME": "Project id or name",
|
||||
"OPTION_PROJECT_ID_NAME": "Project Name",
|
||||
"SEARCH": "SEARCH",
|
||||
"REPO_NAME": "Repository Name",
|
||||
"TOOLTIP": "All filters except CVSS3 only support exact matches",
|
||||
|
@ -1853,7 +1853,7 @@
|
||||
"CVE": "CVEs",
|
||||
"FILTER_BY": "Filter by",
|
||||
"OPTION_ALL": "All",
|
||||
"OPTION_PROJECT_ID_NAME": "Project id or name",
|
||||
"OPTION_PROJECT_ID_NAME": "Project Name",
|
||||
"SEARCH": "SEARCH",
|
||||
"REPO_NAME": "Repository Name",
|
||||
"TOOLTIP": "All filters except CVSS3 only support exact matches",
|
||||
|
@ -1883,7 +1883,7 @@
|
||||
"CVE": "CVEs",
|
||||
"FILTER_BY": "Filter by",
|
||||
"OPTION_ALL": "All",
|
||||
"OPTION_PROJECT_ID_NAME": "Project id or name",
|
||||
"OPTION_PROJECT_ID_NAME": "Project Name",
|
||||
"SEARCH": "SEARCH",
|
||||
"REPO_NAME": "Repository Name",
|
||||
"TOOLTIP": "All filters except CVSS3 only support exact matches",
|
||||
|
@ -1886,7 +1886,7 @@
|
||||
"CVE": "CVEs",
|
||||
"FILTER_BY": "Filter by",
|
||||
"OPTION_ALL": "All",
|
||||
"OPTION_PROJECT_ID_NAME": "Project id or name",
|
||||
"OPTION_PROJECT_ID_NAME": "Project Name",
|
||||
"SEARCH": "SEARCH",
|
||||
"REPO_NAME": "Repository Name",
|
||||
"TOOLTIP": "All filters except CVSS3 only support exact matches",
|
||||
|
@ -1883,7 +1883,7 @@
|
||||
"CVE": "CVEs",
|
||||
"FILTER_BY": "过滤条件",
|
||||
"OPTION_ALL": "全部",
|
||||
"OPTION_PROJECT_ID_NAME": "项目 ID 或 名称",
|
||||
"OPTION_PROJECT_ID_NAME": "项目名称",
|
||||
"SEARCH": "搜索",
|
||||
"REPO_NAME": "仓库名称",
|
||||
"TOOLTIP": "CVSS3 除外的所有过滤项只支持精确匹配",
|
||||
|
@ -1875,7 +1875,7 @@
|
||||
"CVE": "CVEs",
|
||||
"FILTER_BY": "Filter by",
|
||||
"OPTION_ALL": "All",
|
||||
"OPTION_PROJECT_ID_NAME": "Project id or name",
|
||||
"OPTION_PROJECT_ID_NAME": "Project Name",
|
||||
"SEARCH": "SEARCH",
|
||||
"REPO_NAME": "Repository Name",
|
||||
"TOOLTIP": "All filters except CVSS3 only support exact matches",
|
||||
|
Loading…
Reference in New Issue
Block a user