Compare commits

...

5 Commits

Author SHA1 Message Date
stonezdj(Daojun Zhang) c7e5a3d691
Merge f10b060eef into 9471f5d5a6 2024-04-26 20:30:58 +08:00
Shengwen YU 9471f5d5a6
fix: update total permission count to 59 (#20352)
Signed-off-by: Shengwen Yu <yshengwen@vmware.com>
2024-04-26 08:21:27 +00:00
Lichao Xue dee73a44f3
Fix UI bugs (#20364)
Signed-off-by: xuelichao <xuel@vmware.com>
2024-04-26 06:56:23 +00:00
Shengwen YU c791b39a26
fix: add stop_scan_payload when call stop scan api (#20353)
Signed-off-by: Shengwen Yu <yshengwen@vmware.com>
2024-04-26 06:13:00 +00:00
stonezdj f10b060eef Add scan type in webhook event
fixes #20331

Signed-off-by: stonezdj <stone.zhang@broadcom.com>
2024-04-25 17:37:51 +08:00
30 changed files with 147 additions and 92 deletions

View File

@ -104,6 +104,7 @@ func constructScanImagePayload(ctx context.Context, event *event.ScanImageEvent,
RepoFullName: event.Artifact.Repository,
RepoType: repoType,
},
ScanType: event.ScanType,
},
Operator: event.Operator,
}
@ -138,17 +139,29 @@ func constructScanImagePayload(ctx context.Context, event *event.ScanImageEvent,
time.Sleep(500 * time.Millisecond)
}
// Add scan overview
summaries, err := scan.DefaultController.GetSummary(ctx, art, []string{v1.MimeTypeNativeReport, v1.MimeTypeGenericVulnerabilityReport})
if err != nil {
return nil, errors.Wrap(err, "construct scan payload")
scanSummaries := map[string]interface{}{}
if event.ScanType == v1.ScanTypeVulnerability {
scanSummaries, err = scan.DefaultController.GetSummary(ctx, art, []string{v1.MimeTypeNativeReport, v1.MimeTypeGenericVulnerabilityReport})
if err != nil {
return nil, errors.Wrap(err, "construct scan payload")
}
}
sbomOverview := map[string]interface{}{}
if event.ScanType == v1.ScanTypeSbom {
sbomOverview, err = scan.DefaultController.GetSummary(ctx, art, []string{v1.MimeTypeSBOMReport})
if err != nil {
return nil, errors.Wrap(err, "construct scan payload")
}
}
// Add scan overview and sbom overview
resource := &model.Resource{
Tag: event.Artifact.Tag,
Digest: event.Artifact.Digest,
ResourceURL: resURL,
ScanOverview: summaries,
ScanOverview: scanSummaries,
SBOMOverview: sbomOverview,
}
payload.EventData.Resources = append(payload.EventData.Resources, resource)

View File

@ -27,6 +27,7 @@ import (
// ScanImageMetaData defines meta data of image scanning event
type ScanImageMetaData struct {
Artifact *v1.Artifact
ScanType string
Status string
Operator string
}
@ -55,6 +56,7 @@ func (si *ScanImageMetaData) Resolve(evt *event.Event) error {
Artifact: si.Artifact,
OccurAt: time.Now(),
Operator: si.Operator,
ScanType: si.ScanType,
}
evt.Topic = topic

View File

@ -289,6 +289,7 @@ func (d *DeleteTagEvent) String() string {
// ScanImageEvent is scanning image related event data to publish
type ScanImageEvent struct {
EventType string
ScanType string
Artifact *v1.Artifact
OccurAt time.Time
Operator string

View File

@ -120,6 +120,13 @@ func scanTaskStatusChange(ctx context.Context, taskID int64, status string) (err
if operator, ok := exec.ExtraAttrs["operator"].(string); ok {
e.Operator = operator
}
// extract ScanType if exist in ExtraAttrs
if c, ok := exec.ExtraAttrs["enabled_capabilities"].(map[string]interface{}); ok {
if Type, ok := c["type"].(string); ok {
e.ScanType = Type
}
}
// fire event
notification.AddEvent(ctx, e)
}

View File

@ -42,6 +42,7 @@ type EventData struct {
Repository *Repository `json:"repository,omitempty"`
Replication *model.Replication `json:"replication,omitempty"`
Retention *model.Retention `json:"retention,omitempty"`
ScanType string `json:"scan_type,omitempty"`
Custom map[string]string `json:"custom_attributes,omitempty"`
}
@ -51,6 +52,7 @@ type Resource struct {
Tag string `json:"tag,omitempty"`
ResourceURL string `json:"resource_url,omitempty"`
ScanOverview map[string]interface{} `json:"scan_overview,omitempty"`
SBOMOverview map[string]interface{} `json:"sbom_overview,omitempty"`
}
// Repository info of notification event

View File

@ -78,6 +78,7 @@ export const ACTION_RESOURCE_I18N_MAP = {
log: 'ROBOT_ACCOUNT.LOG',
'notification-policy': 'ROBOT_ACCOUNT.NOTIFICATION_POLICY',
quota: 'ROBOT_ACCOUNT.QUOTA',
sbom: 'ROBOT_ACCOUNT.SBOM',
};
export function convertKey(key: string) {

View File

@ -13,10 +13,13 @@
[clrIfActive]="currentTabLinkId === 'vulnerability'">
<clr-tab-content id="vulnerability-content">
<hbr-artifact-vulnerabilities
*ngIf="currentTabLinkId === 'vulnerability'"
[artifact]="artifact"
[projectName]="projectName"
[projectId]="projectId"
[repoName]="repoName"
[scanBtnState]="getScanBtnState()"
[hasEnabledScanner]="hasEnabledScanner()"
[digest]="digest"
[vulnerabilitiesLink]="
getVulnerability()
@ -24,16 +27,18 @@
</clr-tab-content>
</ng-template>
</clr-tab>
<clr-tab *ngIf="getSbom()">
<clr-tab *ngIf="hasScannerSupportSBOM()">
<button clrTabLink id="sbom" (click)="actionTab('sbom')">
{{ 'REPOSITORY.SBOM' | translate }}
</button>
<ng-template [clrIfActive]="currentTabLinkId === 'sbom'">
<clr-tab-content id="sbom-content">
<hbr-artifact-sbom
*ngIf="currentTabLinkId === 'sbom'"
[artifact]="artifact"
[projectName]="projectName"
[projectId]="projectId"
[hasScannerSupportSBOM]="hasScannerSupportSBOM()"
[repoName]="repoName"
[sbomDigest]="sbomDigest"></hbr-artifact-sbom>
</clr-tab-content>
@ -50,6 +55,7 @@
[clrIfActive]="currentTabLinkId === 'build-history'">
<clr-tab-content>
<hbr-artifact-build-history
*ngIf="currentTabLinkId === 'build-history'"
[buildHistoryLink]="
getBuildHistory()
"></hbr-artifact-build-history>
@ -67,6 +73,7 @@
[clrIfActive]="currentTabLinkId === 'summary-link'">
<clr-tab-content id="summary-content">
<hbr-artifact-summary
*ngIf="currentTabLinkId === 'summary-link'"
[summaryLink]="getSummary()"></hbr-artifact-summary>
</clr-tab-content>
</ng-template>
@ -81,6 +88,7 @@
<ng-template [clrIfActive]="currentTabLinkId === 'depend-link'">
<clr-tab-content id="depend-content">
<hbr-artifact-dependencies
*ngIf="currentTabLinkId === 'depend-link'"
[dependenciesLink]="
getDependencies()
"></hbr-artifact-dependencies>
@ -97,6 +105,7 @@
<ng-template [clrIfActive]="currentTabLinkId === 'value-link'">
<clr-tab-content id="value-content">
<hbr-artifact-values
*ngIf="currentTabLinkId === 'value-link'"
[valuesLink]="getValues()"></hbr-artifact-values>
</clr-tab-content>
</ng-template>

View File

@ -4,6 +4,8 @@ import { AdditionLinks } from '../../../../../../../ng-swagger-gen/models/additi
import { CURRENT_BASE_HREF } from '../../../../../shared/units/utils';
import { SharedTestingModule } from '../../../../../shared/shared.module';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ArtifactListPageService } from '../artifact-list-page/artifact-list-page.service';
import { ClrLoadingState } from '@clr/angular';
describe('ArtifactAdditionsComponent', () => {
const mockedAdditionLinks: AdditionLinks = {
@ -12,6 +14,18 @@ describe('ArtifactAdditionsComponent', () => {
href: CURRENT_BASE_HREF + '/test',
},
};
const mockedArtifactListPageService = {
hasScannerSupportSBOM(): boolean {
return true;
},
hasEnabledScanner(): boolean {
return true;
},
getScanBtnState(): ClrLoadingState {
return ClrLoadingState.SUCCESS;
},
init() {},
};
let component: ArtifactAdditionsComponent;
let fixture: ComponentFixture<ArtifactAdditionsComponent>;
@ -20,6 +34,12 @@ describe('ArtifactAdditionsComponent', () => {
imports: [SharedTestingModule],
declarations: [ArtifactAdditionsComponent],
schemas: [NO_ERRORS_SCHEMA],
providers: [
{
provide: ArtifactListPageService,
useValue: mockedArtifactListPageService,
},
],
}).compileComponents();
});
@ -27,6 +47,7 @@ describe('ArtifactAdditionsComponent', () => {
fixture = TestBed.createComponent(ArtifactAdditionsComponent);
component = fixture.componentInstance;
component.additionLinks = mockedAdditionLinks;
component.tab = 'vulnerability';
fixture.detectChanges();
});

View File

@ -10,7 +10,8 @@ import { ADDITIONS } from './models';
import { AdditionLinks } from '../../../../../../../ng-swagger-gen/models/addition-links';
import { AdditionLink } from '../../../../../../../ng-swagger-gen/models/addition-link';
import { Artifact } from '../../../../../../../ng-swagger-gen/models/artifact';
import { ClrTabs } from '@clr/angular';
import { ClrLoadingState, ClrTabs } from '@clr/angular';
import { ArtifactListPageService } from '../artifact-list-page/artifact-list-page.service';
@Component({
selector: 'artifact-additions',
@ -32,14 +33,21 @@ export class ArtifactAdditionsComponent implements AfterViewChecked, OnInit {
@Input()
tab: string;
@Input() currentTabLinkId: string = 'vulnerability';
@Input() currentTabLinkId: string = '';
activeTab: string = null;
@ViewChild('additionsTab') tabs: ClrTabs;
constructor(private ref: ChangeDetectorRef) {}
constructor(
private ref: ChangeDetectorRef,
private artifactListPageService: ArtifactListPageService
) {}
ngOnInit(): void {
this.activeTab = this.tab;
if (!this.activeTab) {
this.currentTabLinkId = 'vulnerability';
}
this.artifactListPageService.init(this.projectId);
}
ngAfterViewChecked() {
@ -50,6 +58,10 @@ export class ArtifactAdditionsComponent implements AfterViewChecked, OnInit {
this.ref.detectChanges();
}
hasScannerSupportSBOM(): boolean {
return this.artifactListPageService.hasScannerSupportSBOM();
}
getVulnerability(): AdditionLink {
if (
this.additionLinks &&
@ -59,12 +71,7 @@ export class ArtifactAdditionsComponent implements AfterViewChecked, OnInit {
}
return null;
}
getSbom(): AdditionLink {
if (this.additionLinks && this.additionLinks[ADDITIONS.SBOMS]) {
return this.additionLinks[ADDITIONS.SBOMS];
}
return {};
}
getBuildHistory(): AdditionLink {
if (this.additionLinks && this.additionLinks[ADDITIONS.BUILD_HISTORY]) {
return this.additionLinks[ADDITIONS.BUILD_HISTORY];
@ -93,4 +100,12 @@ export class ArtifactAdditionsComponent implements AfterViewChecked, OnInit {
actionTab(tab: string): void {
this.currentTabLinkId = tab;
}
getScanBtnState(): ClrLoadingState {
return this.artifactListPageService.getScanBtnState();
}
hasEnabledScanner(): boolean {
return this.artifactListPageService.hasEnabledScanner();
}
}

View File

@ -32,12 +32,18 @@
</div>
</div>
</clr-dg-action-bar>
<clr-dg-column [clrDgField]="'package'" class="package-medium">{{
'SBOM.GRID.COLUMN_PACKAGE' | translate
}}</clr-dg-column>
<clr-dg-column [clrDgField]="'version'" class="version-medium">{{
'SBOM.GRID.COLUMN_VERSION' | translate
}}</clr-dg-column>
<clr-dg-column
[clrDgSortBy]="'name'"
[clrDgField]="'name'"
class="package-medium"
>{{ 'SBOM.GRID.COLUMN_PACKAGE' | translate }}</clr-dg-column
>
<clr-dg-column
[clrDgSortBy]="'versionInfo'"
[clrDgField]="'versionInfo'"
class="version-medium"
>{{ 'SBOM.GRID.COLUMN_VERSION' | translate }}</clr-dg-column
>
<clr-dg-column>{{
'SBOM.GRID.COLUMN_LICENSE' | translate
}}</clr-dg-column>

View File

@ -10,7 +10,6 @@ import {
} from '@ngx-translate/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { UserPermissionService } from '../../../../../../shared/services';
import { AdditionLink } from '../../../../../../../../ng-swagger-gen/models/addition-link';
import { ErrorHandler } from '../../../../../../shared/units/error-handler';
import { SessionService } from '../../../../../../shared/services/session.service';
import { SessionUser } from '../../../../../../shared/entities/session-user';

View File

@ -1,13 +1,6 @@
import {
AfterViewInit,
Component,
Input,
OnDestroy,
OnInit,
} from '@angular/core';
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { ClrDatagridStateInterface, ClrLoadingState } from '@clr/angular';
import { finalize } from 'rxjs/operators';
import { AdditionLink } from '../../../../../../../../ng-swagger-gen/models/addition-link';
import {
ScannerVo,
UserPermissionService,
@ -30,7 +23,6 @@ import {
HarborEvent,
} from '../../../../../../services/event-service/event.service';
import { severityText } from '../../../../../left-side-nav/interrogation-services/vulnerability-database/security-hub.interface';
import { AppConfigService } from 'src/app/services/app-config.service';
import {
ArtifactSbom,
@ -38,8 +30,7 @@ import {
getArtifactSbom,
} from '../../artifact';
import { ArtifactService } from 'ng-swagger-gen/services';
import { ScanTypes } from 'src/app/shared/entities/shared.const';
import { ArtifactListPageService } from '../../artifact-list-page/artifact-list-page.service';
import { ScanTypes } from '../../../../../../shared/entities/shared.const';
@Component({
selector: 'hbr-artifact-sbom',
@ -56,13 +47,12 @@ export class ArtifactSbomComponent implements OnInit, OnDestroy {
@Input()
sbomDigest: string;
@Input() artifact: Artifact;
@Input() hasScannerSupportSBOM: boolean = false;
artifactSbom: ArtifactSbom;
loading: boolean = false;
hasScannerSupportSBOM: boolean = false;
downloadSbomBtnState: ClrLoadingState = ClrLoadingState.DEFAULT;
hasSbomPermission: boolean = false;
hasShowLoading: boolean = false;
sub: Subscription;
hasViewInitWithDelay: boolean = false;
@ -73,16 +63,13 @@ export class ArtifactSbomComponent implements OnInit, OnDestroy {
readonly severityText = severityText;
constructor(
private errorHandler: ErrorHandler,
private appConfigService: AppConfigService,
private artifactService: ArtifactService,
private artifactListPageService: ArtifactListPageService,
private userPermissionService: UserPermissionService,
private eventService: EventService,
private session: SessionService
) {}
ngOnInit() {
this.artifactListPageService.init(this.projectId);
this.getSbom();
this.getSbomPermission();
if (!this.sub) {
@ -222,8 +209,6 @@ export class ArtifactSbomComponent implements OnInit, OnDestroy {
}
canDownloadSbom(): boolean {
this.hasScannerSupportSBOM =
this.artifactListPageService.hasScannerSupportSBOM();
return (
this.hasScannerSupportSBOM &&
//this.hasSbomPermission &&
@ -234,7 +219,12 @@ export class ArtifactSbomComponent implements OnInit, OnDestroy {
}
artifactSbomPackages(): ArtifactSbomPackageItem[] {
return this.artifactSbom?.sbomPackage?.packages ?? [];
return (
this.artifactSbom?.sbomPackage?.packages?.filter(
item =>
item?.name || item?.versionInfo || item?.licenseConcluded
) ?? []
);
}
load(state: ClrDatagridStateInterface) {

View File

@ -50,14 +50,13 @@ export class ArtifactVulnerabilitiesComponent implements OnInit, OnDestroy {
@Input()
digest: string;
@Input() artifact: Artifact;
@Input() scanBtnState: ClrLoadingState = ClrLoadingState.DEFAULT;
@Input() hasEnabledScanner: boolean = false;
scan_overview: any;
scanner: ScannerVo;
projectScanner: ScannerVo;
scanningResults: VulnerabilityItem[] = [];
loading: boolean = false;
hasEnabledScanner: boolean = false;
scanBtnState: ClrLoadingState = ClrLoadingState.DEFAULT;
severitySort: ClrDatagridComparatorInterface<VulnerabilityItem>;
cvssSort: ClrDatagridComparatorInterface<VulnerabilityItem>;
hasScanningPermission: boolean = false;
@ -112,7 +111,6 @@ export class ArtifactVulnerabilitiesComponent implements OnInit, OnDestroy {
ngOnInit() {
this.getVulnerabilities();
this.getScanningPermission();
this.getProjectScanner();
if (!this.sub) {
this.sub = this.eventService.subscribe(
HarborEvent.UPDATE_VULNERABILITY_INFO,
@ -203,30 +201,6 @@ export class ArtifactVulnerabilitiesComponent implements OnInit, OnDestroy {
);
}
getProjectScanner(): void {
this.hasEnabledScanner = false;
this.scanBtnState = ClrLoadingState.LOADING;
this.scanningService.getProjectScanner(this.projectId).subscribe(
response => {
if (
response &&
'{}' !== JSON.stringify(response) &&
!response.disabled &&
response.health === 'healthy'
) {
this.scanBtnState = ClrLoadingState.SUCCESS;
this.hasEnabledScanner = true;
} else {
this.scanBtnState = ClrLoadingState.ERROR;
}
this.projectScanner = response;
},
error => {
this.scanBtnState = ClrLoadingState.ERROR;
}
);
}
getLevel(v: VulnerabilityItem): number {
if (v && v.severity && SEVERITY_LEVEL_MAP[v.severity]) {
return SEVERITY_LEVEL_MAP[v.severity];

View File

@ -65,10 +65,6 @@
class="action-dropdown"
clrPosition="bottom-left"
*clrIfOpen>
<div
class="dropdown-divider"
role="separator"
aria-hidden="true"></div>
<button
clrDropdownItem
id="stop-scan"

View File

@ -1099,7 +1099,7 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
res?.filter(
item =>
item.type === AccessoryType.SBOM
)?.[0]?.digest ?? null;
)?.[0]?.digest ?? undefined;
}
},
error: err => {

View File

@ -76,7 +76,7 @@ export enum AccessoryType {
COSIGN = 'signature.cosign',
NOTATION = 'signature.notation',
NYDUS = 'accelerator.nydus',
SBOM = 'harbor.sbom',
SBOM = 'sbom.harbor',
}
export enum ArtifactType {

View File

@ -68,9 +68,7 @@ export class SbomTipHistogramComponent {
}
get noSbom(): boolean {
return (
this.sbomSummary.scan_status === SBOM_SCAN_STATUS.NOT_GENERATED_SBOM
);
return this.sbomDigest === undefined || this.sbomDigest === '';
}
isThemeLight() {

View File

@ -142,7 +142,16 @@ export const errorHandler = function (error: any): string {
}
// Not a standard error return Basically not used cover unknown error
try {
return JSON.parse(error.error).message;
const jsonError = JSON.parse(error.error);
if (jsonError.errors && jsonError.errors instanceof Array) {
return (
jsonError.errors?.map(error => error.message) ?? [
'UNKNOWN_ERROR',
]
).join(',');
} else {
return JSON.parse(error.error).message;
}
} catch (err) {}
// Not a standard error return Basically not used cover unknown error
if (typeof error.error === 'string') {

View File

@ -406,6 +406,7 @@
"REPOSITORY": "Repository",
"ARTIFACT": "Artifact",
"SCAN": "Scan",
"SBOM": "SBOM",
"TAG": "Tag",
"ACCESSORY": "Accessory",
"ARTIFACT_ADDITION": "Artifact Addition",
@ -1061,7 +1062,7 @@
"GENERATE": "Generate SBOM",
"DOWNLOAD": "Download SBOM",
"Details": "SBOM details",
"STOP": "Stop SBOM",
"STOP": "Stop Generate SBOM",
"TRIGGER_STOP_SUCCESS": "Trigger stopping SBOM generation successfully"
},
"VULNERABILITY": {

View File

@ -406,6 +406,7 @@
"REPOSITORY": "Repository",
"ARTIFACT": "Artifact",
"SCAN": "Scan",
"SBOM": "SBOM",
"TAG": "Tag",
"ACCESSORY": "Accessory",
"ARTIFACT_ADDITION": "Artifact Addition",
@ -1062,7 +1063,7 @@
"GENERATE": "Generate SBOM ",
"DOWNLOAD": "Download SBOM",
"Details": "SBOM details",
"STOP": "Stop SBOM",
"STOP": "Stop Generate SBOM",
"TRIGGER_STOP_SUCCESS": "Trigger stopping SBOM generation successfully"
},
"VULNERABILITY": {

View File

@ -407,6 +407,7 @@
"REPOSITORY": "Repository",
"ARTIFACT": "Artifact",
"SCAN": "Scan",
"SBOM": "SBOM",
"TAG": "Tag",
"ACCESSORY": "Accessory",
"ARTIFACT_ADDITION": "Artifact Addition",
@ -1060,7 +1061,7 @@
"GENERATE": "Generate SBOM",
"DOWNLOAD": "Download SBOM",
"Details": "SBOM details",
"STOP": "Stop SBOM",
"STOP": "Stop Generate SBOM",
"TRIGGER_STOP_SUCCESS": "Trigger stopping SBOM generation successfully"
},
"VULNERABILITY": {

View File

@ -406,6 +406,7 @@
"REPOSITORY": "Dépôt",
"ARTIFACT": "Artefact",
"SCAN": "Scan",
"SBOM": "SBOM",
"TAG": "Tag",
"ACCESSORY": "Accessoire",
"ARTIFACT_ADDITION": "Artefact Addition",
@ -1060,7 +1061,7 @@
"GENERATE": "Generate SBOM",
"DOWNLOAD": "Download SBOM",
"Details": "SBOM details",
"STOP": "Stop SBOM",
"STOP": "Stop Generate SBOM",
"TRIGGER_STOP_SUCCESS": "Trigger stopping SBOM generation successfully"
},
"VULNERABILITY": {

View File

@ -403,6 +403,7 @@
"REPOSITORY": "저장소",
"ARTIFACT": "아티팩트",
"SCAN": "스캔",
"SBOM": "SBOM",
"TAG": "태그",
"ACCESSORY": "액세서리",
"ARTIFACT_ADDITION": "아티팩트 추가",
@ -1059,7 +1060,7 @@
"GENERATE": "Generate SBOM",
"DOWNLOAD": "Download SBOM",
"Details": "SBOM details",
"STOP": "Stop SBOM",
"STOP": "Stop Generate SBOM",
"TRIGGER_STOP_SUCCESS": "Trigger stopping SBOM generation successfully"
},
"VULNERABILITY": {

View File

@ -404,6 +404,7 @@
"REPOSITORY": "Repository",
"ARTIFACT": "Artifact",
"SCAN": "Scan",
"SBOM": "SBOM",
"TAG": "Tag",
"ACCESSORY": "Accessory",
"ARTIFACT_ADDITION": "Artifact Addition",
@ -1058,7 +1059,7 @@
"GENERATE": "Generate SBOM",
"DOWNLOAD": "Download SBOM",
"Details": "SBOM details",
"STOP": "Stop SBOM",
"STOP": "Stop Generate SBOM",
"TRIGGER_STOP_SUCCESS": "Trigger stopping SBOM generation successfully"
},
"VULNERABILITY": {

View File

@ -406,6 +406,7 @@
"REPOSITORY": "Repository",
"ARTIFACT": "Artifact",
"SCAN": "Scan",
"SBOM": "SBOM",
"TAG": "Tag",
"ACCESSORY": "Accessory",
"ARTIFACT_ADDITION": "Artifact Addition",
@ -1061,7 +1062,7 @@
"GENERATE": "Generate SBOM",
"DOWNLOAD": "Download SBOM",
"Details": "SBOM details",
"STOP": "Stop SBOM",
"STOP": "Stop Generate SBOM",
"TRIGGER_STOP_SUCCESS": "Trigger stopping SBOM generation successfully"
},
"VULNERABILITY": {

View File

@ -405,6 +405,7 @@
"REPOSITORY": "仓库",
"ARTIFACT": "Artifact",
"SCAN": "扫描",
"SBOM": "SBOM",
"TAG": "Tag",
"ACCESSORY": "附件",
"ARTIFACT_ADDITION": "Artifact 额外信息",
@ -1059,7 +1060,7 @@
"GENERATE": "Generate SBOM",
"DOWNLOAD": "Download SBOM",
"Details": "SBOM details",
"STOP": "Stop SBOM",
"STOP": "Stop Generate SBOM",
"TRIGGER_STOP_SUCCESS": "Trigger stopping SBOM generation successfully"
},
"VULNERABILITY": {

View File

@ -405,6 +405,7 @@
"REPOSITORY": "Repository",
"ARTIFACT": "Artifact",
"SCAN": "Scan",
"SBOM": "SBOM",
"TAG": "Tag",
"ACCESSORY": "Accessory",
"ARTIFACT_ADDITION": "Artifact Addition",
@ -1058,7 +1059,7 @@
"GENERATE": "Generate SBOM",
"DOWNLOAD": "Download SBOM",
"Details": "SBOM details",
"STOP": "Stop SBOM",
"STOP": "Stop Generate SBOM",
"TRIGGER_STOP_SUCCESS": "Trigger stopping SBOM generation successfully"
},
"VULNERABILITY": {

View File

@ -89,8 +89,11 @@ copy_artifact = Permission("{}/projects/{}/repositories/target_repo/artifacts?fr
delete_artifact = Permission("{}/projects/{}/repositories/target_repo/artifacts/{}".format(harbor_base_url, project_name, source_artifact_tag), "DELETE", 200)
# 6. Resource scan actions: ['read', 'create', 'stop']
stop_scan_payload = {
"scan_type": "vulnerability"
}
create_scan = Permission("{}/projects/{}/repositories/{}/artifacts/{}/scan".format(harbor_base_url, project_name, source_artifact_name, source_artifact_tag), "POST", 202)
stop_scan = Permission("{}/projects/{}/repositories/{}/artifacts/{}/scan/stop".format(harbor_base_url, project_name, source_artifact_name, source_artifact_tag), "POST", 202)
stop_scan = Permission("{}/projects/{}/repositories/{}/artifacts/{}/scan/stop".format(harbor_base_url, project_name, source_artifact_name, source_artifact_tag), "POST", 202, stop_scan_payload)
read_scan = Permission("{}/projects/{}/repositories/{}/artifacts/{}/scan/83be44fd-1234-5678-b49f-4b6d6e8f5730/log".format(harbor_base_url, project_name, source_artifact_name, source_artifact_tag), "get", 404)
# 7. Resource tag actions: ['list', 'create', 'delete']

View File

@ -24,8 +24,8 @@ Create A Project Robot Account
${permission_count}= Create Dictionary
${total}= Set Variable 0
IF '${first_resource}' == 'all'
Set To Dictionary ${permission_count} all=56
${total}= Set Variable 56
Set To Dictionary ${permission_count} all=59
${total}= Set Variable 59
Retry Element Click //span[text()='Select all']
ELSE
FOR ${item} IN @{resources}

View File

@ -745,7 +745,7 @@ Test Case - System Robot Account
${robot_account_name} ${token}= Create A System Robot Account sys2${d} days days=2 description=For testing cover_all_project_resources=${true}
Push image ${ip} '${robot_account_name}' ${token} project${d} hello-world:latest
Retry Wait Element Visible //clr-dg-row[.//clr-dg-cell[contains(.,'${robot_account_name}')] and .//clr-icon[contains(@class, 'color-green')] and .//span[text()='All projects with'] and .//button[text()=' 56 PERMISSION(S) '] and .//span[contains(.,'1d 23h')] and .//clr-dg-cell[text()='For testing'] and .//clr-dg-cell//span[text()=' None ']]
Retry Wait Element Visible //clr-dg-row[.//clr-dg-cell[contains(.,'${robot_account_name}')] and .//clr-icon[contains(@class, 'color-green')] and .//span[text()='All projects with'] and .//button[text()=' 59 PERMISSION(S) '] and .//span[contains(.,'1d 23h')] and .//clr-dg-cell[text()='For testing'] and .//clr-dg-cell//span[text()=' None ']]
Retry Action Keyword Check System Robot Account API Permission ${robot_account_name} ${token} ${HARBOR_ADMIN} ${HARBOR_PASSWORD} all 1
Retry Action Keyword Check Project Robot Account API Permission ${robot_account_name} ${token} ${HARBOR_ADMIN} ${HARBOR_PASSWORD} ${project_id} ${project_name} hello-world latest all
Close Browser