diff --git a/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/set-job/set-job.component.html b/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/set-job/set-job.component.html index 69f82e3f5..3a878c2b8 100644 --- a/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/set-job/set-job.component.html +++ b/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/set-job/set-job.component.html @@ -141,7 +141,7 @@ ) }"> {{ 'CLEARANCES.INCLUDED_OPERATIONS' | translate + >{{ 'CLEARANCES.INCLUDED_EVENT_TYPES' | translate }} {{ - 'CLEARANCES.INCLUDED_OPERATION_TOOLTIP' | translate + 'CLEARANCES.INCLUDED_EVENT_TYPE_TOOLTIP' | translate }} -
+
+ class="clr-checkbox-wrapper float-left" + *ngFor="let item of eventTypes"> -
+ *ngIf="!(selectedEventTypes?.length > 0)"> {{ - 'CLEARANCES.INCLUDED_OPERATION_ERROR' | translate + 'CLEARANCES.INCLUDED_EVENT_TYPE_ERROR' | translate }}
@@ -197,7 +195,7 @@ [disabled]=" disableGC || purgeForm.invalid || - !(selectedOperations?.length > 0) + !(selectedEventTypes?.length > 0) "> {{ 'CLEARANCES.PURGE_NOW' | translate }} @@ -210,7 +208,7 @@ [disabled]=" dryRunOnGoing || purgeForm.invalid || - !(selectedOperations?.length > 0) + !(selectedEventTypes?.length > 0) "> {{ 'TAG_RETENTION.WHAT_IF_RUN' | translate }} diff --git a/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/set-job/set-job.component.scss b/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/set-job/set-job.component.scss index f517614fd..47553f6b7 100644 --- a/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/set-job/set-job.component.scss +++ b/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/set-job/set-job.component.scss @@ -51,3 +51,8 @@ padding-left: .6rem; padding-right: .6rem; } + +.float-left { + float:left; + margin-right: 1rem; +} diff --git a/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/set-job/set-job.component.spec.ts b/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/set-job/set-job.component.spec.ts index bfb880944..bc97cdc39 100644 --- a/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/set-job/set-job.component.spec.ts +++ b/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/set-job/set-job.component.spec.ts @@ -2,16 +2,19 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ErrorHandler } from '../../../../../shared/units/error-handler'; import { CronScheduleComponent } from '../../../../../shared/components/cron-schedule'; import { CronTooltipComponent } from '../../../../../shared/components/cron-schedule'; -import { of } from 'rxjs'; +import { delay, of } from 'rxjs'; import { SharedTestingModule } from '../../../../../shared/shared.module'; import { SetJobComponent } from './set-job.component'; import { PurgeService } from 'ng-swagger-gen/services/purge.service'; import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { AuditlogService } from 'ng-swagger-gen/services'; +import { HttpHeaders, HttpResponse } from '@angular/common/http'; describe('GcComponent', () => { let component: SetJobComponent; let fixture: ComponentFixture; let purgeService: PurgeService; + let auditlogService: AuditlogService; let mockSchedule = []; const fakedErrorHandler = { error(error) { @@ -23,6 +26,29 @@ describe('GcComponent', () => { }; let spySchedule: jasmine.Spy; let spyGcNow: jasmine.Spy; + const mockedAuditLogs = [ + { + event_type: 'create_artifact', + }, + { + event_type: 'delete_artifact', + }, + { + event_type: 'pull_artifact', + }, + ]; + const fakedAuditlogService = { + listAuditLogEventTypesResponse() { + return of( + new HttpResponse({ + body: mockedAuditLogs, + headers: new HttpHeaders({ + 'x-total-count': '18', + }), + }) + ).pipe(delay(0)); + }, + }; beforeEach(() => { TestBed.configureTestingModule({ imports: [SharedTestingModule], @@ -31,7 +57,10 @@ describe('GcComponent', () => { CronScheduleComponent, CronTooltipComponent, ], - providers: [{ provide: ErrorHandler, useValue: fakedErrorHandler }], + providers: [ + { provide: ErrorHandler, useValue: fakedErrorHandler }, + { provide: AuditlogService, useValue: fakedAuditlogService }, + ], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); }); @@ -39,7 +68,7 @@ describe('GcComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(SetJobComponent); component = fixture.componentInstance; - + auditlogService = fixture.debugElement.injector.get(AuditlogService); purgeService = fixture.debugElement.injector.get(PurgeService); spySchedule = spyOn(purgeService, 'getPurgeSchedule').and.returnValues( of(mockSchedule as any) @@ -47,6 +76,7 @@ describe('GcComponent', () => { spyGcNow = spyOn(purgeService, 'createPurgeSchedule').and.returnValues( of(null) ); + component.selectedEventTypes = ['create_artifact']; fixture.detectChanges(); }); it('should create', () => { diff --git a/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/set-job/set-job.component.ts b/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/set-job/set-job.component.ts index 956463d99..d3d3234b8 100644 --- a/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/set-job/set-job.component.ts +++ b/src/portal/src/app/base/left-side-nav/clearing-job/audit-log-purge/set-job/set-job.component.ts @@ -10,13 +10,14 @@ import { ExecHistory } from '../../../../../../../ng-swagger-gen/models/exec-his import { JOB_STATUS, REFRESH_STATUS_TIME_DIFFERENCE, - RETENTION_OPERATIONS, - RETENTION_OPERATIONS_I18N_MAP, + RESOURCE_TYPES, RetentionTimeUnit, } from '../../clearing-job-interfact'; import { clone } from '../../../../../shared/units/utils'; import { PurgeHistoryComponent } from '../history/purge-history.component'; import { NgForm } from '@angular/forms'; +import { AuditlogService } from 'ng-swagger-gen/services'; +import { AuditLogEventType } from 'ng-swagger-gen/models'; const ONE_MINUTE: number = 60000; const ONE_DAY: number = 24; @@ -30,6 +31,7 @@ const MAX_RETENTION_DAYS: number = 10000; export class SetJobComponent implements OnInit, OnDestroy { originCron: OriginCron; disableGC: boolean = false; + loading: boolean = false; getLabelCurrent = 'CLEARANCES.SCHEDULE_TO_PURGE'; loadingGcStatus = false; @ViewChild(CronScheduleComponent) @@ -43,20 +45,23 @@ export class SetJobComponent implements OnInit, OnDestroy { retentionTime: number; retentionUnit: string = RetentionTimeUnit.DAYS; - operations: string[] = clone(RETENTION_OPERATIONS); - selectedOperations: string[] = clone(RETENTION_OPERATIONS); + + eventTypes: Record[] = []; + selectedEventTypes: string[] = clone([]); @ViewChild(PurgeHistoryComponent) purgeHistoryComponent: PurgeHistoryComponent; @ViewChild('purgeForm') purgeForm: NgForm; constructor( private purgeService: PurgeService, + private logService: AuditlogService, private errorHandler: ErrorHandler ) {} ngOnInit() { this.getCurrentSchedule(true); this.getStatus(); + this.initEventTypes(); } ngOnDestroy() { if (this.statusTimeout) { @@ -64,6 +69,43 @@ export class SetJobComponent implements OnInit, OnDestroy { this.statusTimeout = null; } } + + initEventTypes() { + this.loading = true; + this.logService + .listAuditLogEventTypesResponse() + .pipe(finalize(() => (this.loading = false))) + .subscribe( + response => { + const auditLogEventTypes = + response.body as AuditLogEventType[]; + this.eventTypes = [ + ...auditLogEventTypes + .filter(item => + RESOURCE_TYPES.includes(item.event_type) + ) + .map(event => ({ + label: + event.event_type.charAt(0).toUpperCase() + + event.event_type + .slice(1) + .replace(/_/g, ' '), + value: event.event_type, + id: event.event_type, + })), + { + label: 'Other events', + value: 'other', + id: 'other_events', + }, + ]; + }, + error => { + this.errorHandler.error(error); + } + ); + } + // get the latest non-dry-run execution to get the status getStatus() { this.loadingLastCompletedTime = true; @@ -122,11 +164,11 @@ export class SetJobComponent implements OnInit, OnDestroy { }; if (purgeHistory && purgeHistory.job_parameters) { const obj = JSON.parse(purgeHistory.job_parameters); - if (obj?.include_operations) { - this.selectedOperations = - obj?.include_operations?.split(','); + if (obj?.include_event_types) { + this.selectedEventTypes = + obj?.include_event_types?.split(','); } else { - this.selectedOperations = []; + this.selectedEventTypes = []; } if ( obj?.audit_retention_hour > ONE_DAY && @@ -140,7 +182,7 @@ export class SetJobComponent implements OnInit, OnDestroy { } } else { this.retentionTime = null; - this.selectedOperations = clone(RETENTION_OPERATIONS); + this.selectedEventTypes = clone([]); this.retentionUnit = RetentionTimeUnit.DAYS; } } else { @@ -165,7 +207,7 @@ export class SetJobComponent implements OnInit, OnDestroy { schedule: { parameters: { audit_retention_hour: +retentionTime, - include_operations: this.selectedOperations.join(','), + include_event_types: this.selectedEventTypes.join(','), dry_run: false, }, schedule: { @@ -195,7 +237,7 @@ export class SetJobComponent implements OnInit, OnDestroy { schedule: { parameters: { audit_retention_hour: +retentionTime, - include_operations: this.selectedOperations.join(','), + include_event_types: this.selectedEventTypes.join(','), dry_run: true, }, schedule: { @@ -231,8 +273,8 @@ export class SetJobComponent implements OnInit, OnDestroy { schedule: { parameters: { audit_retention_hour: +retentionTime, - include_operations: - this.selectedOperations.join(','), + include_event_types: + this.selectedEventTypes.join(','), dry_run: false, }, schedule: { @@ -259,8 +301,8 @@ export class SetJobComponent implements OnInit, OnDestroy { schedule: { parameters: { audit_retention_hour: +retentionTime, - include_operations: - this.selectedOperations.join(','), + include_event_types: + this.selectedEventTypes.join(','), dry_run: false, }, schedule: { @@ -283,21 +325,16 @@ export class SetJobComponent implements OnInit, OnDestroy { }); } } - hasOperation(operation: string): boolean { - return this.selectedOperations?.indexOf(operation) !== -1; + hasEventType(eventType: string): boolean { + return this.selectedEventTypes?.indexOf(eventType) !== -1; } - operationsToText(operation: string): string { - if (RETENTION_OPERATIONS_I18N_MAP[operation]) { - return RETENTION_OPERATIONS_I18N_MAP[operation]; - } - return operation; - } - setOperation(operation: string) { - if (this.selectedOperations.indexOf(operation) === -1) { - this.selectedOperations.push(operation); + + setEventType(eventType: string) { + if (this.selectedEventTypes.indexOf(eventType) === -1) { + this.selectedEventTypes.push(eventType); } else { - this.selectedOperations.splice( - this.selectedOperations.findIndex(item => item === operation), + this.selectedEventTypes.splice( + this.selectedEventTypes.findIndex(item => item === eventType), 1 ); } @@ -311,7 +348,7 @@ export class SetJobComponent implements OnInit, OnDestroy { return true; } return !( - this.purgeForm?.invalid || !(this.selectedOperations?.length > 0) + this.purgeForm?.invalid || !(this.selectedEventTypes?.length > 0) ); } isRetentionTimeValid() { diff --git a/src/portal/src/app/base/left-side-nav/clearing-job/clearing-job-interfact.ts b/src/portal/src/app/base/left-side-nav/clearing-job/clearing-job-interfact.ts index cf3a44f87..05cf4e410 100644 --- a/src/portal/src/app/base/left-side-nav/clearing-job/clearing-job-interfact.ts +++ b/src/portal/src/app/base/left-side-nav/clearing-job/clearing-job-interfact.ts @@ -3,12 +3,19 @@ export enum RetentionTimeUnit { DAYS = 'days', } -export const RETENTION_OPERATIONS = ['create', 'delete', 'pull']; +export const RESOURCE_TYPES = [ + 'create_artifact', + 'delete_artifact', + 'pull_artifact', +]; -export const RETENTION_OPERATIONS_I18N_MAP = { - pull: 'AUDIT_LOG.PULL', - create: 'AUDIT_LOG.CREATE', - delete: 'AUDIT_LOG.DELETE', +export const RESOURCE_TYPES_I18N_MAP = { + artifact: 'AUDIT_LOG.ARTIFACT', + user_login_logout: 'AUDIT_LOG.USER_LOGIN_LOGOUT', + user: 'AUDIT_LOG.USER', + project: 'AUDIT_LOG.PROJECT', + configuration: 'AUDIT_LOG.CONFIGURATION', + project_member: 'AUDIT_LOG.PROJECT_MEMBER', }; export const JOB_STATUS = { diff --git a/src/portal/src/app/base/left-side-nav/config/config.service.ts b/src/portal/src/app/base/left-side-nav/config/config.service.ts index 516eac239..54d6ab252 100644 --- a/src/portal/src/app/base/left-side-nav/config/config.service.ts +++ b/src/portal/src/app/base/left-side-nav/config/config.service.ts @@ -85,6 +85,10 @@ export class ConfigService { ); this._currentConfig.oidc_client_secret = new StringValueItem(fakePass, true); + if (!this._currentConfig.disabled_audit_log_event_types) { + this._currentConfig.disabled_audit_log_event_types = + new StringValueItem('', true); + } // Keep the original copy of the data this._originalConfig = clone(this._currentConfig); }, diff --git a/src/portal/src/app/base/left-side-nav/config/config.ts b/src/portal/src/app/base/left-side-nav/config/config.ts index a22110c59..90b52d8d7 100644 --- a/src/portal/src/app/base/left-side-nav/config/config.ts +++ b/src/portal/src/app/base/left-side-nav/config/config.ts @@ -112,6 +112,7 @@ export class Configuration { oidc_admin_group: StringValueItem; oidc_group_filter: StringValueItem; audit_log_forward_endpoint: StringValueItem; + disabled_audit_log_event_types: StringValueItem; skip_audit_log_database: BoolValueItem; session_timeout: NumberValueItem; scanner_skip_update_pulltime: BoolValueItem; @@ -189,6 +190,7 @@ export class Configuration { this.count_per_project = new NumberValueItem(-1, true); this.storage_per_project = new NumberValueItem(-1, true); this.audit_log_forward_endpoint = new StringValueItem('', true); + this.disabled_audit_log_event_types = new StringValueItem('', true); this.skip_audit_log_database = new BoolValueItem(false, true); this.session_timeout = new NumberValueItem(60, true); this.scanner_skip_update_pulltime = new BoolValueItem(false, true); diff --git a/src/portal/src/app/base/left-side-nav/config/system/system-settings.component.html b/src/portal/src/app/base/left-side-nav/config/system/system-settings.component.html index 485c31ec7..8cb79483d 100644 --- a/src/portal/src/app/base/left-side-nav/config/system/system-settings.component.html +++ b/src/portal/src/app/base/left-side-nav/config/system/system-settings.component.html @@ -315,6 +315,50 @@ !currentConfig?.audit_log_forward_endpoint?.editable " /> +
+ +
+ {{ 'CLEARANCES.AUDIT_LOG_EVENT_TYPE_EMPTY' | translate }} +
+
+
+ + +
+
+