mirror of
https://github.com/goharbor/harbor.git
synced 2024-06-26 06:45:12 +02:00
Add Notation UI for deployment security (#18952)
1. for #18927 Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
parent
970bdab936
commit
79e8c396bf
|
@ -32,6 +32,18 @@
|
|||
'ACCESSORY.CO_SIGN' | translate
|
||||
}}</label>
|
||||
</clr-checkbox-wrapper>
|
||||
<clr-checkbox-wrapper>
|
||||
<input
|
||||
id="content-trust"
|
||||
type="checkbox"
|
||||
clrCheckbox
|
||||
[(ngModel)]="projectPolicy.ContentTrust"
|
||||
name="content-trust"
|
||||
[disabled]="!hasChangeConfigRole" />
|
||||
<label for="content-trust">{{
|
||||
'ACCESSORY.NOTARY' | translate
|
||||
}}</label>
|
||||
</clr-checkbox-wrapper>
|
||||
<clr-control-helper class="config-subtext">
|
||||
{{ 'PROJECT_CONFIG.CONTENT_TRUST_POLCIY' | translate }}
|
||||
</clr-control-helper>
|
||||
|
|
|
@ -44,6 +44,7 @@ export class ProjectPolicy {
|
|||
|
||||
initByProject(pro: Project) {
|
||||
this.Public = pro.metadata.public === 'true';
|
||||
this.ContentTrust = pro.metadata.enable_content_trust === 'true';
|
||||
this.ContentTrustCosign =
|
||||
pro.metadata.enable_content_trust_cosign === 'true';
|
||||
this.PreventVulImg = pro.metadata.prevent_vul === 'true';
|
||||
|
|
|
@ -14,6 +14,7 @@ export class Project {
|
|||
role_name?: string;
|
||||
metadata?: {
|
||||
public: string | boolean;
|
||||
enable_content_trust?: string | boolean;
|
||||
enable_content_trust_cosign?: string | boolean;
|
||||
prevent_vul: string | boolean;
|
||||
severity: string;
|
||||
|
|
|
@ -160,7 +160,7 @@
|
|||
</clr-dg-column>
|
||||
<clr-dg-column class="co-signed-column">
|
||||
<ng-template [clrDgHideableColumn]="{ hidden: hiddenArray[3] }">
|
||||
{{ 'ACCESSORY.CO_SIGNED' | translate }}
|
||||
{{ 'REPOSITORY.SIGNED' | translate }}
|
||||
</ng-template>
|
||||
</clr-dg-column>
|
||||
<clr-dg-column [clrDgSortBy]="'size'">
|
||||
|
|
|
@ -25,7 +25,7 @@ import { ClrLoadingState } from '@clr/angular';
|
|||
import { Accessory } from 'ng-swagger-gen/models/accessory';
|
||||
import { ArtifactModule } from '../../../artifact.module';
|
||||
|
||||
describe('ArtifactListTabComponent (inline template)', () => {
|
||||
describe('ArtifactListTabComponent', () => {
|
||||
let comp: ArtifactListTabComponent;
|
||||
let fixture: ComponentFixture<ArtifactListTabComponent>;
|
||||
const mockActivatedRoute = {
|
||||
|
|
|
@ -932,33 +932,45 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
checkCosignAsync(artifacts: ArtifactFront[]) {
|
||||
if (artifacts && artifacts.length) {
|
||||
artifacts.forEach(item => {
|
||||
item.coSigned = CHECKING;
|
||||
const listTagParams: NewArtifactService.ListAccessoriesParams =
|
||||
{
|
||||
projectName: this.projectName,
|
||||
repositoryName: dbEncodeURIComponent(this.repoName),
|
||||
reference: item.digest,
|
||||
q: encodeURIComponent(`type=${AccessoryType.COSIGN}`),
|
||||
page: 1,
|
||||
pageSize: ACCESSORY_PAGE_SIZE,
|
||||
};
|
||||
this.newArtifactService
|
||||
.listAccessories(listTagParams)
|
||||
.subscribe(
|
||||
res => {
|
||||
if (res?.length) {
|
||||
if (artifacts) {
|
||||
if (artifacts.length) {
|
||||
artifacts.forEach(item => {
|
||||
item.coSigned = CHECKING;
|
||||
const listTagParams: NewArtifactService.ListAccessoriesParams =
|
||||
{
|
||||
projectName: this.projectName,
|
||||
repositoryName: dbEncodeURIComponent(this.repoName),
|
||||
reference: item.digest,
|
||||
page: 1,
|
||||
pageSize: ACCESSORY_PAGE_SIZE,
|
||||
};
|
||||
listTagParams.q = encodeURIComponent(
|
||||
`type=${AccessoryType.COSIGN}`
|
||||
);
|
||||
const cosignParam = listTagParams;
|
||||
listTagParams.q = encodeURIComponent(
|
||||
`type=${AccessoryType.NOTATION}`
|
||||
);
|
||||
forkJoin([
|
||||
this.newArtifactService.listAccessories(cosignParam),
|
||||
this.newArtifactService.listAccessories(listTagParams),
|
||||
]).subscribe({
|
||||
next: res => {
|
||||
if (
|
||||
res?.length &&
|
||||
(res[0]?.length || res[1]?.length)
|
||||
) {
|
||||
item.coSigned = TRUE;
|
||||
} else {
|
||||
item.coSigned = FALSE;
|
||||
}
|
||||
},
|
||||
err => {
|
||||
error: err => {
|
||||
item.coSigned = FALSE;
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// return true if all selected rows are in "running" state
|
||||
|
|
|
@ -102,6 +102,7 @@ export class PullCommandComponent {
|
|||
artifact?.type === ArtifactType.CHART ||
|
||||
artifact?.type === ArtifactType.CNAB) &&
|
||||
this.accessoryType !== AccessoryType.COSIGN &&
|
||||
this.accessoryType !== AccessoryType.NOTATION &&
|
||||
this.accessoryType !== AccessoryType.NYDUS
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import {
|
|||
ChangeDetectorRef,
|
||||
Component,
|
||||
Input,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
import {
|
||||
|
@ -31,6 +32,7 @@ import {
|
|||
EventService,
|
||||
HarborEvent,
|
||||
} from '../../../../../../../../services/event-service/event.service';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
export const ACCESSORY_PAGE_SIZE: number = 5;
|
||||
|
||||
|
@ -40,7 +42,9 @@ export const ACCESSORY_PAGE_SIZE: number = 5;
|
|||
styleUrls: ['./sub-accessories.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush, // use OnPush Strategy to avoid ExpressionChangedAfterItHasBeenCheckedError
|
||||
})
|
||||
export class SubAccessoriesComponent implements OnInit, AfterViewInit {
|
||||
export class SubAccessoriesComponent
|
||||
implements OnInit, AfterViewInit, OnDestroy
|
||||
{
|
||||
@Input()
|
||||
projectName: string;
|
||||
@Input()
|
||||
|
@ -56,6 +60,7 @@ export class SubAccessoriesComponent implements OnInit, AfterViewInit {
|
|||
page: number = 1;
|
||||
displayedAccessories: AccessoryFront[] = [];
|
||||
loading: boolean = false;
|
||||
iconSub: Subscription;
|
||||
constructor(
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private router: Router,
|
||||
|
@ -71,8 +76,24 @@ export class SubAccessoriesComponent implements OnInit, AfterViewInit {
|
|||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
if (!this.iconSub) {
|
||||
this.iconSub = this.event.subscribe(
|
||||
HarborEvent.RETRIEVED_ICON,
|
||||
() => {
|
||||
this.cdf.detectChanges();
|
||||
}
|
||||
);
|
||||
}
|
||||
this.displayedAccessories = clone(this.accessories);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
if (this.iconSub) {
|
||||
this.iconSub.unsubscribe();
|
||||
this.iconSub = null;
|
||||
}
|
||||
}
|
||||
|
||||
size(size: number) {
|
||||
return formatSize(size.toString());
|
||||
}
|
||||
|
|
|
@ -6,6 +6,10 @@ import { IconService } from '../../../../../../ng-swagger-gen/services/icon.serv
|
|||
import { share } from 'rxjs/operators';
|
||||
import { Icon } from 'ng-swagger-gen/models/icon';
|
||||
import { Accessory } from '../../../../../../ng-swagger-gen/models/accessory';
|
||||
import {
|
||||
EventService,
|
||||
HarborEvent,
|
||||
} from '../../../../services/event-service/event.service';
|
||||
|
||||
/**
|
||||
* Define the service methods to handle the repository tag related things.
|
||||
|
@ -28,7 +32,8 @@ export class ArtifactDefaultService extends ArtifactService {
|
|||
private _sharedIconObservableMap: { [key: string]: Observable<Icon> } = {};
|
||||
constructor(
|
||||
private iconService: IconService,
|
||||
private domSanitizer: DomSanitizer
|
||||
private domSanitizer: DomSanitizer,
|
||||
private event: EventService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
@ -57,6 +62,7 @@ export class ArtifactDefaultService extends ArtifactService {
|
|||
`data:${res['content-type']};charset=utf-8;base64,${res.content}`
|
||||
)
|
||||
);
|
||||
this.event.publish(HarborEvent.RETRIEVED_ICON);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -73,6 +73,7 @@ export const multipleFilter: Array<{
|
|||
|
||||
export enum AccessoryType {
|
||||
COSIGN = 'signature.cosign',
|
||||
NOTATION = 'signature.notation',
|
||||
NYDUS = 'accelerator.nydus',
|
||||
}
|
||||
|
||||
|
|
|
@ -82,4 +82,5 @@ export enum HarborEvent {
|
|||
DELETE_ACCESSORY = 'deleteAccessory',
|
||||
COPY_DIGEST = 'copyDigest',
|
||||
REFRESH_BANNER_MESSAGE = 'refreshBannerMessage',
|
||||
RETRIEVED_ICON = 'retrievedIcon',
|
||||
}
|
||||
|
|
|
@ -1688,7 +1688,7 @@
|
|||
"ACCESSORIES": "Anhänge",
|
||||
"SUBJECT_ARTIFACT": "Subjekt Artefakt",
|
||||
"CO_SIGN": "Cosign",
|
||||
"NOTARY": "Notary",
|
||||
"NOTARY": "Notation",
|
||||
"PLACEHOLDER": "Es konnten keine Anhänge gefunden werden!"
|
||||
},
|
||||
"CLEARANCES": {
|
||||
|
|
|
@ -1689,7 +1689,7 @@
|
|||
"ACCESSORIES": "Accessories",
|
||||
"SUBJECT_ARTIFACT": "Subject Artifact",
|
||||
"CO_SIGN": "Cosign",
|
||||
"NOTARY": "Notary",
|
||||
"NOTARY": "Notation",
|
||||
"PLACEHOLDER": "We couldn't find any accessories!"
|
||||
},
|
||||
"CLEARANCES": {
|
||||
|
|
|
@ -1685,7 +1685,7 @@
|
|||
"ACCESSORIES": "Accessories",
|
||||
"SUBJECT_ARTIFACT": "Subject Artifact",
|
||||
"CO_SIGN": "Cosign",
|
||||
"NOTARY": "Notary",
|
||||
"NOTARY": "Notation",
|
||||
"PLACEHOLDER": "We couldn't find any accessories!"
|
||||
},
|
||||
"CLEARANCES": {
|
||||
|
|
|
@ -1655,7 +1655,7 @@
|
|||
"ACCESSORIES": "Accessoires",
|
||||
"SUBJECT_ARTIFACT": "Sujet de l'artefact",
|
||||
"CO_SIGN": "Cosign",
|
||||
"NOTARY": "Notary",
|
||||
"NOTARY": "Notation",
|
||||
"PLACEHOLDER": "Nous n'avons trouvé aucun accessoire !"
|
||||
},
|
||||
"CLEARANCES": {
|
||||
|
|
|
@ -1685,7 +1685,7 @@
|
|||
"ACCESSORIES": "Accessories",
|
||||
"SUBJECT_ARTIFACT": "Subject Artifact",
|
||||
"CO_SIGN": "Cosign",
|
||||
"NOTARY": "Notary",
|
||||
"NOTARY": "Notation",
|
||||
"PLACEHOLDER": "We couldn't find any accessories!"
|
||||
},
|
||||
"CLEARANCES": {
|
||||
|
|
|
@ -1688,7 +1688,7 @@
|
|||
"ACCESSORIES": "Accessories",
|
||||
"SUBJECT_ARTIFACT": "Subject Artifact",
|
||||
"CO_SIGN": "Cosign",
|
||||
"NOTARY": "Notary",
|
||||
"NOTARY": "Notation",
|
||||
"PLACEHOLDER": "We couldn't find any accessories!"
|
||||
},
|
||||
"CLEARANCES": {
|
||||
|
|
|
@ -1685,7 +1685,7 @@
|
|||
"ACCESSORIES": "附件",
|
||||
"SUBJECT_ARTIFACT": "主体 Artifact",
|
||||
"CO_SIGN": "Cosign",
|
||||
"NOTARY": "Notary",
|
||||
"NOTARY": "Notation",
|
||||
"PLACEHOLDER": "未发现任何附件!"
|
||||
},
|
||||
"CLEARANCES": {
|
||||
|
|
|
@ -1677,7 +1677,7 @@
|
|||
"ACCESSORIES": "附件",
|
||||
"SUBJECT_ARTIFACT": "Subject Artifact",
|
||||
"CO_SIGN": "Cosign",
|
||||
"NOTARY": "Notary",
|
||||
"NOTARY": "Notation",
|
||||
"PLACEHOLDER": "找不到任何附件!"
|
||||
},
|
||||
"CLEARANCES": {
|
||||
|
|
Loading…
Reference in New Issue
Block a user