add ui for project level policy

This commit is contained in:
Deng, Qian 2017-10-24 12:56:23 +08:00
parent 367f447991
commit 69ffd7117c
25 changed files with 557 additions and 18 deletions

View File

@ -47,6 +47,7 @@ func initRouters() {
beego.Router("/harbor/projects/:id/replications", &controllers.IndexController{})
beego.Router("/harbor/projects/:id/members", &controllers.IndexController{})
beego.Router("/harbor/projects/:id/logs", &controllers.IndexController{})
beego.Router("/harbor/projects/:id/configs", &controllers.IndexController{})
beego.Router("/harbor/tags/:id/*", &controllers.IndexController{})
beego.Router("/harbor/users", &controllers.IndexController{})

View File

@ -24,6 +24,7 @@ import { VULNERABILITY_DIRECTIVES } from './vulnerability-scanning/index';
import { PUSH_IMAGE_BUTTON_DIRECTIVES } from './push-image/index';
import { CONFIGURATION_DIRECTIVES } from './config/index';
import { JOB_LOG_VIEWER_DIRECTIVES } from './job-log-viewer/index';
import { PROJECT_POLICY_CONFIG_DIRECTIVES } from './project-policy-config/index';
import {
SystemInfoService,
@ -43,7 +44,9 @@ import {
ConfigurationService,
ConfigurationDefaultService,
JobLogService,
JobLogDefaultService
JobLogDefaultService,
ProjectService,
ProjectDefaultService,
} from './service/index';
import {
ErrorHandler,
@ -68,6 +71,7 @@ export const DefaultServiceConfig: IServiceConfig = {
replicationRuleEndpoint: "/api/policies/replication",
replicationJobEndpoint: "/api/jobs/replication",
vulnerabilityScanningBaseEndpoint: "/api/repositories",
projectPolicyEndpoint: "/api/projects/configs",
enablei18Support: false,
defaultLang: DEFAULT_LANG,
langCookieKey: DEFAULT_LANG_COOKIE_KEY,
@ -118,7 +122,10 @@ export interface HarborModuleConfig {
configService?: Provider,
//Service implementation for job log
jobLogService?: Provider
jobLogService?: Provider,
//Service implementation for project policy
projectPolicyService?: Provider,
}
/**
@ -162,7 +169,8 @@ export function initConfig(translateInitializer: TranslateServiceInitializer, co
VULNERABILITY_DIRECTIVES,
PUSH_IMAGE_BUTTON_DIRECTIVES,
CONFIGURATION_DIRECTIVES,
JOB_LOG_VIEWER_DIRECTIVES
JOB_LOG_VIEWER_DIRECTIVES,
PROJECT_POLICY_CONFIG_DIRECTIVES
],
exports: [
LOG_DIRECTIVES,
@ -183,7 +191,8 @@ export function initConfig(translateInitializer: TranslateServiceInitializer, co
PUSH_IMAGE_BUTTON_DIRECTIVES,
CONFIGURATION_DIRECTIVES,
JOB_LOG_VIEWER_DIRECTIVES,
TranslateModule
TranslateModule,
PROJECT_POLICY_CONFIG_DIRECTIVES
],
providers: []
})
@ -204,6 +213,7 @@ export class HarborLibraryModule {
config.scanningService || { provide: ScanningResultService, useClass: ScanningResultDefaultService },
config.configService || { provide: ConfigurationService, useClass: ConfigurationDefaultService },
config.jobLogService || { provide: JobLogService, useClass: JobLogDefaultService },
config.projectPolicyService || { provide: ProjectService, useClass: ProjectDefaultService },
//Do initializing
TranslateServiceInitializer,
{
@ -232,6 +242,7 @@ export class HarborLibraryModule {
config.scanningService || { provide: ScanningResultService, useClass: ScanningResultDefaultService },
config.configService || { provide: ConfigurationService, useClass: ConfigurationDefaultService },
config.jobLogService || { provide: JobLogService, useClass: JobLogDefaultService },
config.projectPolicyService || { provide: ProjectService, useClass: ProjectDefaultService },
ChannelService
]
};

View File

@ -17,4 +17,5 @@ export * from './push-image/index';
export * from './third-party/index';
export * from './config/index';
export * from './job-log-viewer/index';
export * from './channel/index';
export * from './channel/index';
export * from './project-policy-config/index';

View File

@ -0,0 +1,8 @@
import { Type } from '@angular/core';
import { ProjectPolicyConfigComponent } from './project-policy-config.component';
export * from './project-policy-config.component'
export const PROJECT_POLICY_CONFIG_DIRECTIVES: Type<any>[] = [
ProjectPolicyConfigComponent
];

View File

@ -0,0 +1,9 @@
export const PROJECT_POLICY_CONFIG_STYLE = `#severity-blk div
{
display: inline-block;
}
.select {
width: 120px;
}
`;

View File

@ -0,0 +1,51 @@
export const PROJECT_POLICY_CONFIG_TEMPLATE = `
<form #projectPolicyForm="ngForm">
<section class="form-block">
<div class="form-group">
<label for="projectPolicyForm">{{ 'PROJECT_CONFIG.REGISTRY' | translate }}</label>
<div class="form-content">
<clr-checkbox [(ngModel)]="projectPolicy.Public" name="public"
[clrDisabled]="!hasProjectAdminRole">{{ 'PROJECT_CONFIG.PUBLIC_TOGGLE' | translate }}</clr-checkbox>
<div>
<label> {{ 'PROJECT_CONFIG.PUBLIC_POLICY' | translate }} </label>
</div>
</div>
</div>
<div class="form-group">
<label for="projectPolicyForm">{{ 'PROJECT_CONFIG.SECURITY' | translate }}</label>
<div class="form-content">
<div>
<clr-checkbox [(ngModel)]="projectPolicy.ContentTrust" name="content-trust"
[clrDisabled]="!hasProjectAdminRole">{{ 'PROJECT_CONFIG.CONTENT_TRUST_TOGGLE' | translate }}</clr-checkbox>
<div class="chk-explain"><label> {{ 'PROJECT_CONFIG.CONTENT_TRUST_POLCIY' | translate }} </label></div>
</div>
<div>
<clr-checkbox [(ngModel)]="projectPolicy.PreventVulImg" name="prevent-vulenrability-image" [clrDisabled]="!hasProjectAdminRole">{{ 'PROJECT_CONFIG.PREVENT_VULNERABLE_TOGGLE' | translate }}</clr-checkbox>
<div class="chk-explain">
<label>
<div id="severity-blk">
<div>{{ 'PROJECT_CONFIG.PREVENT_VULNERABLE_1' | translate }}</div>
<div class="select">
<select id="severity" name="severity" [(ngModel)]="projectPolicy.PreventVulImgServerity" [disabled]="!projectPolicy.PreventVulImg">
<option *ngFor='let s of severityOptions' [ngValue]="s.severity">{{ s.severityLevel | translate | uppercase }}</option>
</select>
</div>
<div> {{ 'PROJECT_CONFIG.PREVENT_VULNERABLE_2' | translate }} </div>
</div>
</label>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="projectPolicyForm">{{ 'PROJECT_CONFIG.SCAN' | translate }}</label>
<div class="form-content">
<clr-checkbox [(ngModel)]="projectPolicy.ScanImgOnPush" name="scan-image-on-push" [clrDisabled]="!hasProjectAdminRole">{{ 'PROJECT_CONFIG.AUTOSCAN_TOGGLE' | translate }}</clr-checkbox>
<div class="chk-explain"><label> {{ 'PROJECT_CONFIG.AUTOSCAN_POLICY' | translate }}</label></div>
</div>
</div>
<button type="button" class="btn btn-primary" (click)="save()" [disabled]="!isValid() || !hasChanges() || !hasProjectAdminRole">{{'BUTTON.SAVE' | translate}}</button>
<button type="button" class="btn btn-outline" (click)="cancel()" [disabled]="!isValid() || !hasChanges() || !hasProjectAdminRole">{{'BUTTON.CANCEL' | translate}}</button>
<confirmation-dialog #cfgConfirmationDialog (confirmAction)="confirmCancel($event)"></confirmation-dialog>
</section>
</form>`;

View File

@ -0,0 +1,45 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ErrorHandler } from '../error-handler/error-handler';
import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation-dialog.component';
import { ProjectPolicyConfigComponent } from './project-policy-config.component';
import { SharedModule } from '../shared/shared.module';
import { ProjectService, ProjectDefaultService} from '../service/project.service';
import { SERVICE_CONFIG, IServiceConfig} from '../service.config';
describe('ProjectPolicyConfigComponent', () => {
let component: ProjectPolicyConfigComponent;
let fixture: ComponentFixture<ProjectPolicyConfigComponent>;
let config: IServiceConfig = {
projectPolicyEndpoint: '/api/projects/testing/:id/'
};
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [SharedModule],
declarations: [
ProjectPolicyConfigComponent,
ConfirmationDialogComponent,
ConfirmationDialogComponent,
],
providers: [
ErrorHandler,
{ provide: SERVICE_CONFIG, useValue: config },
{ provide: ProjectService, useClass: ProjectDefaultService }
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ProjectPolicyConfigComponent);
component = fixture.componentInstance;
component.projectId = 1;
component.hasProjectAdminRole = true;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,155 @@
import { Component, Input, OnInit, ViewChild } from '@angular/core';
import { PROJECT_POLICY_CONFIG_TEMPLATE } from './project-policy-config.component.html';
import { PROJECT_POLICY_CONFIG_STYLE } from './project-policy-config.component.css';
import { toPromise, compareValue, clone } from '../utils';
import { ProjectService } from '../service/project.service';
import { ErrorHandler } from '../error-handler/error-handler';
import { State } from 'clarity-angular';
import { ConfirmationState, ConfirmationTargets, ConfirmationButtons } from '../shared/shared.const';
import { ConfirmationMessage } from '../confirmation-dialog/confirmation-message';
import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation-dialog.component';
import { ConfirmationAcknowledgement } from '../confirmation-dialog/confirmation-state-message';
import { TranslateService } from '@ngx-translate/core';
import { Project } from './project';
export class ProjectPolicy {
Public: boolean;
ContentTrust: boolean;
PreventVulImg: boolean;
PreventVulImgServerity: string;
ScanImgOnPush: boolean;
constructor() {
this.Public = false;
this.ContentTrust = false;
this.PreventVulImg = false;
this.PreventVulImgServerity = 'low';
this.ScanImgOnPush = false;
}
initByProject(pro: Project) {
this.Public = pro.metadata.public === 'true' ? true : false;
this.ContentTrust = pro.metadata.enable_content_trust === 'true' ? true : false;
this.PreventVulImg = pro.metadata.prevent_vul === 'true' ? true : false;
if (pro.metadata.severity) { this.PreventVulImgServerity = pro.metadata.severity; };
this.ScanImgOnPush = pro.metadata.auto_scan === 'true' ? true : false;
};
}
@Component({
selector: 'hbr-project-policy-config',
template: PROJECT_POLICY_CONFIG_TEMPLATE,
styles: [PROJECT_POLICY_CONFIG_STYLE]
})
export class ProjectPolicyConfigComponent implements OnInit {
onGoing = false;
@Input() projectId: number;
@Input() projectName = 'unknown';
@Input() hasSignedIn: boolean;
@Input() hasProjectAdminRole: boolean;
@ViewChild('cfgConfirmationDialog') confirmationDlg: ConfirmationDialogComponent;
orgProjectPolicy = new ProjectPolicy();
projectPolicy = new ProjectPolicy();
severityOptions = [
{severity: 'high', severityLevel: 'VULNERABILITY.SEVERITY.HIGH'},
{severity: 'medium', severityLevel: 'VULNERABILITY.SEVERITY.MEDIUM'},
{severity: 'low', severityLevel: 'VULNERABILITY.SEVERITY.LOW'},
{severity: 'negligible', severityLevel: 'VULNERABILITY.SEVERITY.NEGLIGIBLE'},
];
constructor(
private errorHandler: ErrorHandler,
private translate: TranslateService,
private projectService: ProjectService,
) {}
ngOnInit(): void {
if (!this.projectId) {
this.errorHandler.error('Project ID cannot be unset.');
return;
}
this.retrieve();
}
retrieve(state?: State): any {
toPromise<Project>(this.projectService.
getProject(this.projectId))
.then(
response => {
this.orgProjectPolicy.initByProject(response);
this.projectPolicy.initByProject(response);
},
error => this.errorHandler.error(error)
);
}
updateProjectPolicy(projectId: string|number, pp: ProjectPolicy) {
this.projectService.updateProjectPolicy(projectId, pp);
}
refresh() {
this.retrieve();
}
isValid() {
let flag = false;
if (!this.projectPolicy.PreventVulImg || this.severityOptions.some(x => x.severity === this.projectPolicy.PreventVulImgServerity)) {
flag = true;
}
return flag;
}
hasChanges() {
return compareValue(this.orgProjectPolicy, this.projectPolicy)
}
save() {
if (!this.hasChanges()) {
return;
}
this.onGoing = true;
toPromise<any>(this.projectService.updateProjectPolicy(this.projectId, this.projectPolicy))
.then(() => {
this.onGoing = false;
this.translate.get('CONFIG.SAVE_SUCCESS').subscribe((res: string) => {
this.errorHandler.info(res);
});
this.refresh();
})
.catch(error => {
console.log(error);
this.onGoing = false;
this.errorHandler.error(error);
});
}
cancel(): void {
let msg = new ConfirmationMessage(
'CONFIG.CONFIRM_TITLE',
'CONFIG.CONFIRM_SUMMARY',
'',
{},
ConfirmationTargets.CONFIG
);
this.confirmationDlg.open(msg);
}
reset(): void {
this.projectPolicy = clone(this.orgProjectPolicy);
}
confirmCancel(ack: ConfirmationAcknowledgement): void {
if (ack && ack.source === ConfirmationTargets.CONFIG &&
ack.state === ConfirmationState.CONFIRMED) {
this.reset();
}
}
}

View File

@ -0,0 +1,30 @@
export class Project {
project_id: number;
owner_id: number;
name: string;
creation_time: Date;
creation_time_str: string;
deleted: number;
owner_name: string;
togglable: boolean;
update_time: Date;
current_user_role_id: number;
repo_count: number;
has_project_admin_role: boolean;
is_member: boolean;
role_name: string;
metadata: {
public: string | boolean;
enable_content_trust: string | boolean;
prevent_vul: string | boolean;
severity: string;
auto_scan: string | boolean;
};
constructor () {
this.metadata.public = false;
this.metadata.enable_content_trust = false;
this.metadata.prevent_vul = false;
this.metadata.severity = 'low';
this.metadata.auto_scan = false;
}
}

View File

@ -80,6 +80,14 @@ export interface IServiceConfig {
*/
vulnerabilityScanningBaseEndpoint?: string;
/**
* The base endpoint of the service used to handle project policy.
*
* @type {string}
* @memberOf IServiceConfig
*/
projectPolicyEndpoint?: string;
/**
* To determine whether or not to enable the i18 multiple languages supporting.
*

View File

@ -8,4 +8,5 @@ export * from './tag.service';
export * from './RequestQueryParams';
export * from './scanning.service';
export * from './configuration.service';
export * from './job-log.service';
export * from './job-log.service';
export * from './project.service';

View File

@ -242,4 +242,4 @@ export interface TagClickEvent {
project_id: string | number;
repository_name: string;
tag_name: string;
}
}

View File

@ -0,0 +1,85 @@
import { Observable } from 'rxjs/Observable';
import { Injectable, Inject } from '@angular/core';
import 'rxjs/add/observable/of';
import { Http, Headers, RequestOptions } from '@angular/http';
import { SERVICE_CONFIG, IServiceConfig } from '../service.config';
import { Project } from '../project-policy-config/project';
import { ProjectPolicy } from '../project-policy-config/project-policy-config.component';
/**
* Define the service methods to handle the Prject related things.
*
* @export
* @abstract
* @class ProjectService
*/
export abstract class ProjectService {
/**
* Get Infomations of a specific Project.
*
* @abstract
* @param {string|number} [projectId]
* @returns {(Observable<Project> | Promise<Project> | Project)}
*
* @memberOf ProjectService
*/
abstract getProject(projectId: number | string): Observable<Project> | Promise<Project> | Project;
/**
* Update the specified project.
*
* @abstract
* @param {(number | string)} projectId
* @param {ProjectPolicy} projectPolicy
* @returns {(Observable<any> | Promise<any> | any)}
*
* @memberOf EndpointService
*/
abstract updateProjectPolicy(projectId: number | string, projectPolicy: ProjectPolicy): Observable<any> | Promise<any> | any;
}
/**
* Implement default service for project.
*
* @export
* @class ProjectDefaultService
* @extends {ProjectService}
*/
@Injectable()
export class ProjectDefaultService extends ProjectService {
headers = new Headers({'Content-type': 'application/json'});
options = new RequestOptions({'headers': this.headers});
constructor(
private http: Http,
@Inject(SERVICE_CONFIG) private config: IServiceConfig
) {
super();
}
public getProject(projectId: number | string): Observable<Project> | Promise<Project> | Project {
if (!projectId) {
return Promise.reject('Bad argument');
}
return this.http
.get(`/api/projects/${projectId}`)
.map(response => response.json())
.catch(error => Observable.throw(error));
}
public updateProjectPolicy(projectId: number | string, projectPolicy: ProjectPolicy): any {
return this.http
.put(`/api/projects/${projectId}`, { 'metadata': {
'public': projectPolicy.Public ? 'true' : 'false',
'enable_content_trust': projectPolicy.ContentTrust ? 'true' : 'false',
'prevent_vul': projectPolicy.PreventVulImg ? 'true' : 'false',
'severity': projectPolicy.PreventVulImgServerity,
'auto_scan': projectPolicy.ScanImgOnPush ? 'true' : 'false'
} }, this.options)
.map(response => response.status)
.catch(error => Observable.throw(error));
}
}

View File

@ -31,7 +31,7 @@
"clarity-icons": "^0.9.8",
"clarity-ui": "^0.9.8",
"core-js": "^2.4.1",
"harbor-ui": "0.4.85",
"harbor-ui": "0.4.91",
"intl": "^1.2.5",
"mutationobserver-shim": "^0.3.2",
"ngx-cookie": "^1.0.0",

View File

@ -24,6 +24,7 @@ import { ConfigurationModule } from './config/config.module';
import { TranslateService } from "@ngx-translate/core";
import { AppConfigService } from './app-config.service';
import {SkinableConfig} from "./skinable-config.service";
import { ProjectConfigComponent } from './project/project-config/project-config.component';
export function initConfig(configService: AppConfigService, skinableService: SkinableConfig) {
return () => {
@ -39,6 +40,7 @@ export function getCurrentLanguage(translateService: TranslateService) {
@NgModule({
declarations: [
AppComponent,
ProjectConfigComponent,
],
imports: [
SharedModule,
@ -49,10 +51,10 @@ export function getCurrentLanguage(translateService: TranslateService) {
],
providers: [
AppConfigService,
SkinableConfig,
{
provide: APP_INITIALIZER,
useFactory: initConfig,
SkinableConfig,
{
provide: APP_INITIALIZER,
useFactory: initConfig,
deps: [ AppConfigService, SkinableConfig],
multi: true
},

View File

@ -31,6 +31,7 @@ import { TagRepositoryComponent } from './repository/tag-repository/tag-reposito
import { ReplicationPageComponent } from './replication/replication-page.component';
import { MemberComponent } from './project/member/member.component';
import { AuditLogComponent } from './log/audit-log.component';
import { ProjectConfigComponent } from './project/project-config/project-config.component'
import { ProjectRoutingResolver } from './project/project-routing-resolver.service';
import { SystemAdminGuard } from './shared/route/system-admin-activate.service';
@ -133,6 +134,10 @@ const harborRoutes: Routes = [
{
path: 'logs',
component: AuditLogComponent
},
{
path: 'configs',
component: ProjectConfigComponent
}
]
},

View File

@ -0,0 +1,5 @@
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12" style="top: 8px;">
<hbr-project-policy-config [projectId]="projectId" [projectName]="projectName" [hasSignedIn]="hasSignedIn" [hasProjectAdminRole]="hasProjectAdminRole"></hbr-project-policy-config>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ProjectConfigComponent } from './project-config.component';
describe('ProjectConfigPageComponent', () => {
let component: ProjectConfigComponent;
let fixture: ComponentFixture<ProjectConfigComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ProjectConfigComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ProjectConfigComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,49 @@
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
//
// 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
//
// http://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.
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { SessionService } from '../../shared/session.service';
import { SessionUser } from '../../shared/session-user';
import { Project } from '../project';
@Component({
selector: 'app-project-config',
templateUrl: './project-config.component.html',
styleUrls: ['./project-config.component.css']
})
export class ProjectConfigComponent implements OnInit {
projectId: number;
projectName: string;
currentUser: SessionUser;
hasSignedIn: boolean;
hasProjectAdminRole: boolean;
constructor(
private route: ActivatedRoute,
private router: Router,
private session: SessionService) {}
ngOnInit() {
this.projectId = +this.route.snapshot.parent.params['id'];
this.currentUser = this.session.getCurrentUser();
this.hasSignedIn = this.session.getCurrentUser() !== null;
let resolverData = this.route.snapshot.parent.data;
if (resolverData) {
let pro: Project = <Project>resolverData['projectResolver'];
this.hasProjectAdminRole = pro.has_project_admin_role;
this.projectName = pro.name;
}
}
}

View File

@ -16,6 +16,9 @@
<li class="nav-item" *ngIf="isSessionValid && isSystemAdmin">
<a class="nav-link" routerLink="replications" routerLinkActive="active">{{'PROJECT_DETAIL.REPLICATION' | translate}}</a>
</li>
<li class="nav-item" *ngIf="isSessionValid && isSystemAdmin">
<a class="nav-link" routerLink="configs" routerLinkActive="active">{{'PROJECT_DETAIL.CONFIG' | translate}}</a>
</li>
</ul>
</nav>
<router-outlet></router-outlet>

View File

@ -23,14 +23,14 @@ import { RoleMapping } from '../../shared/shared.const';
@Component({
selector: 'project-detail',
templateUrl: "project-detail.component.html",
templateUrl: 'project-detail.component.html',
styleUrls: [ 'project-detail.component.css' ]
})
export class ProjectDetailComponent {
hasSignedIn: boolean;
currentProject: Project;
isMember: boolean;
roleName: string;
@ -41,7 +41,7 @@ export class ProjectDetailComponent {
private projectService: ProjectService) {
this.hasSignedIn = this.sessionService.getCurrentUser() !== null;
this.route.data.subscribe(data=>{
this.route.data.subscribe(data => {
this.currentProject = <Project>data['projectResolver'];
this.isMember = this.currentProject.is_member;
this.roleName = RoleMapping[this.currentProject.role_name];

View File

@ -161,7 +161,22 @@
"REPLICATION": "Replication",
"USERS": "Members",
"LOGS": "Logs",
"PROJECTS": "Projects"
"PROJECTS": "Projects",
"CONFIG": "Configuration"
},
"PROJECT_CONFIG": {
"REGISTRY": "Project registry",
"PUBLIC_TOGGLE": "Public",
"PUBLIC_POLICY": "Making a project registry public will make all repositories accessible to everyone.",
"SECURITY": "Deployment security",
"CONTENT_TRUST_TOGGLE": "Enable content trust",
"CONTENT_TRUST_POLCIY": "Only allow verified images to be deployed.",
"PREVENT_VULNERABLE_TOGGLE": "Prevent vulnerable images from running.",
"PREVENT_VULNERABLE_1": "Prevent images with vulnerability serverity of",
"PREVENT_VULNERABLE_2": "and above from being deployed.",
"SCAN": "Vulnerability scanning",
"AUTOSCAN_TOGGLE": "Automatically scan images on push",
"AUTOSCAN_POLICY": "Automatically scan images when they are pushed to the project registry."
},
"MEMBER": {
"NEW_MEMBER": "New Member",

View File

@ -161,7 +161,22 @@
"REPLICATION": "Replicación",
"USERS": "Miembros",
"LOGS": "Logs",
"PROJECTS": "Proyectos"
"PROJECTS": "Proyectos",
"CONFIG": "Configuración"
},
"PROJECT_CONFIG": {
"REGISTRY": "Registro de proyectos",
"PUBLIC_TOGGLE": "Público",
"PUBLIC_POLICY": "Hacer público un registro de proyecto hará que todos los repositorios sean accesibles para todos.",
"SECURITY": "Seguridad de despliegue",
"CONTENT_TRUST_TOGGLE": "Habilitar la confianza de contenido",
"CONTENT_TRUST_POLCIY": "Solo permita la implementación de imágenes verificadas.",
"PREVENT_VULNERABLE_TOGGLE": "Evitar que se ejecuten imágenes vulnerables.",
"PREVENT_VULNERABLE_1": "Impedir imágenes con la gravedad de la vulnerabilidad de",
"PREVENT_VULNERABLE_2": "y más arriba de ser desplegado.",
"SCAN": "Escaneo de vulnerabilidad",
"AUTOSCAN_TOGGLE": "Escanee automáticamente las imágenes al instante",
"AUTOSCAN_POLICY": "Escanee automáticamente las imágenes cuando son enviadas al registro del proyecto."
},
"MEMBER": {
"NEW_MEMBER": "Nuevo miembro",

View File

@ -161,7 +161,22 @@
"REPLICATION": "复制",
"USERS": "成员",
"LOGS": "日志",
"PROJECTS": "项目"
"PROJECTS": "项目",
"CONFIG": "配置管理"
},
"PROJECT_CONFIG": {
"REGISTRY": "项目仓库",
"PUBLIC_TOGGLE": "公开",
"PUBLIC_POLICY": "此项目的仓库对所有访客公开。",
"SECURITY": "部署安全",
"CONTENT_TRUST_TOGGLE": "内容信任",
"CONTENT_TRUST_POLCIY": "仅允许部署通过认证的镜像。",
"PREVENT_VULNERABLE_TOGGLE": "阻止潜在漏洞镜像",
"PREVENT_VULNERABLE_1": "阻止危害级别",
"PREVENT_VULNERABLE_2": "以上的镜像运行。",
"SCAN": "漏洞扫描",
"AUTOSCAN_TOGGLE": "自动扫描镜像",
"AUTOSCAN_POLICY": "当镜像上传后,自动进行扫描"
},
"MEMBER": {
"NEW_MEMBER": "新建成员",