Add Notation UI for deployment security (#18952)

1. for #18927

Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
Shijun Sun 2023-07-19 18:22:11 +08:00 committed by GitHub
parent 970bdab936
commit 79e8c396bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 89 additions and 33 deletions

View File

@ -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>

View File

@ -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';

View File

@ -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;

View File

@ -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'">

View File

@ -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 = {

View File

@ -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

View File

@ -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
);
}

View File

@ -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());
}

View File

@ -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);
});
}
});

View File

@ -73,6 +73,7 @@ export const multipleFilter: Array<{
export enum AccessoryType {
COSIGN = 'signature.cosign',
NOTATION = 'signature.notation',
NYDUS = 'accelerator.nydus',
}

View File

@ -82,4 +82,5 @@ export enum HarborEvent {
DELETE_ACCESSORY = 'deleteAccessory',
COPY_DIGEST = 'copyDigest',
REFRESH_BANNER_MESSAGE = 'refreshBannerMessage',
RETRIEVED_ICON = 'retrievedIcon',
}

View File

@ -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": {

View File

@ -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": {

View File

@ -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": {

View File

@ -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": {

View File

@ -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": {

View File

@ -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": {

View File

@ -1685,7 +1685,7 @@
"ACCESSORIES": "附件",
"SUBJECT_ARTIFACT": "主体 Artifact",
"CO_SIGN": "Cosign",
"NOTARY": "Notary",
"NOTARY": "Notation",
"PLACEHOLDER": "未发现任何附件!"
},
"CLEARANCES": {

View File

@ -1677,7 +1677,7 @@
"ACCESSORIES": "附件",
"SUBJECT_ARTIFACT": "Subject Artifact",
"CO_SIGN": "Cosign",
"NOTARY": "Notary",
"NOTARY": "Notation",
"PLACEHOLDER": "找不到任何附件!"
},
"CLEARANCES": {