From 9e4fa27b92d5a7b3b3c0346d4d10c4b5e28849bb Mon Sep 17 00:00:00 2001 From: Marcel Haag Date: Tue, 4 Apr 2023 15:44:01 +0200 Subject: [PATCH] feat: As an user I want to add the pentest status of a project --- .../objective-header.component.html | 1 + .../objective-header.component.spec.ts | 2 + .../objective-header.component.ts | 13 +- .../objective-overview.module.ts | 54 ++--- .../pentest-comments.component.spec.ts | 2 + .../pentest-content.component.spec.ts | 2 + .../pentest-findings.component.spec.ts | 2 + .../pentest-info.component.spec.ts | 2 + .../pentest-header.component.spec.ts | 2 + .../project-overview.component.html | 194 +++++++++++------- .../project-overview.component.scss | 160 ++++++++++----- .../project-overview.component.ts | 81 +++++++- .../project-overview.module.ts | 20 +- .../project/project.component.spec.ts | 3 +- .../src/assets/i18n/de-DE.json | 21 ++ .../src/assets/i18n/en-US.json | 21 ++ .../src/shared/models/project.model.ts | 17 ++ .../src/shared/models/state.enum.ts | 40 ++++ .../comment-dialog.component.spec.ts | 2 + .../export-report-dialog.component.spec.ts | 2 + .../finding-dialog.component.spec.ts | 8 +- .../project-dialog.component.html | 12 ++ .../project-dialog.component.scss | 20 +- .../project-dialog.component.spec.ts | 29 ++- .../project-dialog.component.ts | 60 +++++- .../project-dialog/project-dialog.module.ts | 27 +-- .../service/project-dialog.service.ts | 21 +- .../services/api/project.service.spec.ts | 4 + .../report-state-tag.component.html | 29 +++ .../report-state-tag.component.spec.ts | 45 ++++ .../report-state-tag.component.ts | 29 +++ .../report-state-tag.module.ts | 22 ++ .../severity-tag/severity-tag.module.ts | 6 +- .../com/securityc4po/api/project/Project.kt | 6 + .../securityc4po/api/project/ProjectEntity.kt | 1 + .../com/securityc4po/api/project/State.kt | 19 ++ .../PentestControllerDocumentationTest.kt | 2 + .../api/pentest/PentestControllerIntTest.kt | 2 + .../CommentControllerDocumentationTest.kt | 2 + .../comment/CommentControllerIntTest.kt | 2 + .../FindingControllerDocumentationTest.kt | 2 + .../finding/FindingControllerIntTest.kt | 2 + .../ProjectControllerDocumentationTest.kt | 14 ++ .../api/project/ProjectControllerIntTest.kt | 7 + .../test/resources/collections/projects.json | 15 +- 45 files changed, 823 insertions(+), 204 deletions(-) create mode 100644 security-c4po-angular/src/shared/models/state.enum.ts create mode 100644 security-c4po-angular/src/shared/widgets/report-state-tag/report-state-tag.component.html create mode 100644 security-c4po-angular/src/shared/widgets/report-state-tag/report-state-tag.component.spec.ts create mode 100644 security-c4po-angular/src/shared/widgets/report-state-tag/report-state-tag.component.ts create mode 100644 security-c4po-angular/src/shared/widgets/report-state-tag/report-state-tag.module.ts create mode 100644 security-c4po-api/src/main/kotlin/com/securityc4po/api/project/State.kt diff --git a/security-c4po-angular/src/app/objective-overview/objective-header/objective-header.component.html b/security-c4po-angular/src/app/objective-overview/objective-header/objective-header.component.html index d4cec49..3c8a36c 100644 --- a/security-c4po-angular/src/app/objective-overview/objective-header/objective-header.component.html +++ b/security-c4po-angular/src/app/objective-overview/objective-header/objective-header.component.html @@ -9,6 +9,7 @@ +

{{selectedProject$.getValue().title}}

diff --git a/security-c4po-angular/src/app/objective-overview/objective-header/objective-header.component.spec.ts b/security-c4po-angular/src/app/objective-overview/objective-header/objective-header.component.spec.ts index 40cde6d..e3d01c1 100644 --- a/security-c4po-angular/src/app/objective-overview/objective-header/objective-header.component.spec.ts +++ b/security-c4po-angular/src/app/objective-overview/objective-header/objective-header.component.spec.ts @@ -24,6 +24,7 @@ import {Category} from '@shared/models/category.model'; import {PentestStatus} from '@shared/models/pentest-status.model'; import {ExportReportDialogService} from '@shared/modules/export-report-dialog/service/export-report-dialog.service'; import {ExportReportDialogServiceMock} from '@shared/modules/export-report-dialog/service/export-report-dialog.service.mock'; +import {ReportState} from '@shared/models/state.enum'; const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = { selectedProject: { @@ -33,6 +34,7 @@ const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = { createdAt: new Date('2019-01-10T09:00:00'), tester: 'Novatester', summary: '', + state: ReportState.NEW, testingProgress: 0, createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110' }, diff --git a/security-c4po-angular/src/app/objective-overview/objective-header/objective-header.component.ts b/security-c4po-angular/src/app/objective-overview/objective-header/objective-header.component.ts index b8ca420..973acd9 100644 --- a/security-c4po-angular/src/app/objective-overview/objective-header/objective-header.component.ts +++ b/security-c4po-angular/src/app/objective-overview/objective-header/objective-header.component.ts @@ -75,21 +75,16 @@ export class ObjectiveHeaderComponent implements OnInit { closeOnBackdropClick: false } ).pipe( - filter(value => !!value), - mergeMap((value: ProjectDialogBody) => this.projectService.updateProject(this.selectedProject$.getValue().id, value)), untilDestroyed(this) ).subscribe({ - next: (project: Project) => { + next: (project) => { this.store.dispatch(new InitProjectState( project, [], [] - )).pipe(untilDestroyed(this)).subscribe(); - this.notificationService.showPopup('project.popup.update.success', PopupType.SUCCESS); - }, - error: error => { - console.error(error); - this.notificationService.showPopup('project.popup.update.failed', PopupType.FAILURE); + )).pipe( + untilDestroyed(this) + ).subscribe(); } }); } diff --git a/security-c4po-angular/src/app/objective-overview/objective-overview.module.ts b/security-c4po-angular/src/app/objective-overview/objective-overview.module.ts index 1528af1..817fc97 100644 --- a/security-c4po-angular/src/app/objective-overview/objective-overview.module.ts +++ b/security-c4po-angular/src/app/objective-overview/objective-overview.module.ts @@ -25,6 +25,7 @@ import {ObjectiveOverviewRoutingModule} from './objective-overview-routing.modul import {ExportReportDialogModule} from '@shared/modules/export-report-dialog/export-report-dialog.module'; import {ProjectDialogModule} from '@shared/modules/project-dialog/project-dialog.module'; import {CommentWidgetModule} from '@shared/widgets/comment-widget/comment-widget.module'; +import {ReportStateTagModule} from '@shared/widgets/report-state-tag/report-state-tag.module'; @NgModule({ declarations: [ @@ -32,32 +33,33 @@ import {CommentWidgetModule} from '@shared/widgets/comment-widget/comment-widget ObjectiveCategoriesComponent, ObjectiveTableComponent, ], - imports: [ - CommonModule, - CommonAppModule, - NbLayoutModule, - NbCardModule, - NbButtonModule, - // nbTooltip crashes app right now if used in component, - // workaround: use title in html for now - NbTooltipModule, - NbTreeGridModule, - TranslateModule, - StatusTagModule, - RouterModule, - FormsModule, - NbListModule, - FontAwesomeModule, - FlexLayoutModule, - NbActionsModule, - ExportReportDialogModule, - ProjectDialogModule, - ObjectiveOverviewRoutingModule, - // Table Widgets - FindigWidgetModule, - CommentWidgetModule, - NbMenuModule - ], + imports: [ + CommonModule, + CommonAppModule, + NbLayoutModule, + NbCardModule, + NbButtonModule, + // nbTooltip crashes app right now if used in component, + // workaround: use title in html for now + NbTooltipModule, + NbTreeGridModule, + TranslateModule, + StatusTagModule, + RouterModule, + FormsModule, + NbListModule, + FontAwesomeModule, + FlexLayoutModule, + NbActionsModule, + ExportReportDialogModule, + ProjectDialogModule, + ObjectiveOverviewRoutingModule, + // Table Widgets + FindigWidgetModule, + CommentWidgetModule, + NbMenuModule, + ReportStateTagModule + ], exports: [ ObjectiveHeaderComponent, ObjectiveCategoriesComponent, diff --git a/security-c4po-angular/src/app/pentest/pentest-content/pentest-comments/pentest-comments.component.spec.ts b/security-c4po-angular/src/app/pentest/pentest-content/pentest-comments/pentest-comments.component.spec.ts index 25703f0..93011d3 100644 --- a/security-c4po-angular/src/app/pentest/pentest-content/pentest-comments/pentest-comments.component.spec.ts +++ b/security-c4po-angular/src/app/pentest/pentest-content/pentest-comments/pentest-comments.component.spec.ts @@ -22,6 +22,7 @@ import {DialogService} from '@shared/services/dialog-service/dialog.service'; import {DialogServiceMock} from '@shared/services/dialog-service/dialog.service.mock'; import {CommentDialogService} from '@shared/modules/comment-dialog/service/comment-dialog.service'; import {CommentDialogServiceMock} from '@shared/modules/comment-dialog/service/comment-dialog.service.mock'; +import {ReportState} from '@shared/models/state.enum'; const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = { selectedProject: { @@ -31,6 +32,7 @@ const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = { createdAt: new Date('2019-01-10T09:00:00'), tester: 'Novatester', summary: '', + state: ReportState.NEW, testingProgress: 0, createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110' }, diff --git a/security-c4po-angular/src/app/pentest/pentest-content/pentest-content.component.spec.ts b/security-c4po-angular/src/app/pentest/pentest-content/pentest-content.component.spec.ts index 399092e..1529afe 100644 --- a/security-c4po-angular/src/app/pentest/pentest-content/pentest-content.component.spec.ts +++ b/security-c4po-angular/src/app/pentest/pentest-content/pentest-content.component.spec.ts @@ -13,6 +13,7 @@ import {Category} from '@shared/models/category.model'; import {PentestStatus} from '@shared/models/pentest-status.model'; import {NotificationService} from '@shared/services/toaster-service/notification.service'; import {NotificationServiceMock} from '@shared/services/toaster-service/notification.service.mock'; +import {ReportState} from '@shared/models/state.enum'; const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = { selectedProject: { @@ -22,6 +23,7 @@ const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = { createdAt: new Date('2019-01-10T09:00:00'), tester: 'Novatester', summary: '', + state: ReportState.NEW, testingProgress: 0, createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110' }, diff --git a/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.spec.ts b/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.spec.ts index a923dd0..c5613b4 100644 --- a/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.spec.ts +++ b/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.spec.ts @@ -22,6 +22,7 @@ import {FindingDialogService} from '@shared/modules/finding-dialog/service/findi import {FindingDialogServiceMock} from '@shared/modules/finding-dialog/service/finding-dialog.service.mock'; import {DialogService} from '@shared/services/dialog-service/dialog.service'; import {DialogServiceMock} from '@shared/services/dialog-service/dialog.service.mock'; +import {ReportState} from '@shared/models/state.enum'; const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = { selectedProject: { @@ -31,6 +32,7 @@ const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = { createdAt: new Date('2019-01-10T09:00:00'), tester: 'Novatester', summary: '', + state: ReportState.NEW, testingProgress: 0, createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110' }, diff --git a/security-c4po-angular/src/app/pentest/pentest-content/pentest-info/pentest-info.component.spec.ts b/security-c4po-angular/src/app/pentest/pentest-content/pentest-info/pentest-info.component.spec.ts index 68cf90f..0e8ccc0 100644 --- a/security-c4po-angular/src/app/pentest/pentest-content/pentest-info/pentest-info.component.spec.ts +++ b/security-c4po-angular/src/app/pentest/pentest-content/pentest-info/pentest-info.component.spec.ts @@ -13,6 +13,7 @@ import {NgxsModule, Store} from '@ngxs/store'; import {PROJECT_STATE_NAME, ProjectState, ProjectStateModel} from '@shared/stores/project-state/project-state'; import {Category} from '@shared/models/category.model'; import {PentestStatus} from '@shared/models/pentest-status.model'; +import {ReportState} from '@shared/models/state.enum'; const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = { selectedProject: { @@ -22,6 +23,7 @@ const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = { createdAt: new Date('2019-01-10T09:00:00'), tester: 'Novatester', summary: '', + state: ReportState.NEW, testingProgress: 0, createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110' }, diff --git a/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.spec.ts b/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.spec.ts index 3bea60c..08162e3 100644 --- a/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.spec.ts +++ b/security-c4po-angular/src/app/pentest/pentest-header/pentest-header.component.spec.ts @@ -13,6 +13,7 @@ import {Category} from '@shared/models/category.model'; import {PentestStatus} from '@shared/models/pentest-status.model'; import {NotificationService} from '@shared/services/toaster-service/notification.service'; import {NotificationServiceMock} from '@shared/services/toaster-service/notification.service.mock'; +import {ReportState} from '@shared/models/state.enum'; const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = { selectedProject: { @@ -22,6 +23,7 @@ const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = { createdAt: new Date('2019-01-10T09:00:00'), tester: 'Novatester', summary: '', + state: ReportState.NEW, testingProgress: 0, createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110' }, diff --git a/security-c4po-angular/src/app/project-overview/project-overview.component.html b/security-c4po-angular/src/app/project-overview/project-overview.component.html index be1d742..befa390 100644 --- a/security-c4po-angular/src/app/project-overview/project-overview.component.html +++ b/security-c4po-angular/src/app/project-overview/project-overview.component.html @@ -1,87 +1,131 @@ -
-
- - -

{{project?.title}}

-
- -

- {{'project.client' | translate}}: -

- +
+ + + +
+ +
+ + +
+ + + + +
+ + +
+ +
+ +
+
+
+ + +
+
+ + +
+

{{project?.title}}

+ +
+
+ +

+ {{'project.client' | translate}}: +

+ {{project?.client}} -

- {{'project.tester' | translate}}: -

- +

+ {{'project.tester' | translate}}: +

+ {{project?.tester}} -

- {{'project.createdAt' | translate}}: -

- +

+ {{'project.createdAt' | translate}}: +

+ {{project?.createdAt | dateTimeFormat}} -
- -
-
- - - - {{'popup.info' | translate}} {{'global.no.progress' | translate}} - -
+ + +
+
+ + + + {{'popup.info' | translate}} {{'global.no.progress' | translate}} + +
- - + + +
+
+
-
-
-
-
+
+ +
+

+ {{'project.overview.no.projects' | translate}} +

+
+ + -
-

- {{'project.overview.no.projects' | translate}} -

+ +
- -
- -
- - diff --git a/security-c4po-angular/src/app/project-overview/project-overview.component.scss b/security-c4po-angular/src/app/project-overview/project-overview.component.scss index 0fae7c5..7fa0d50 100644 --- a/security-c4po-angular/src/app/project-overview/project-overview.component.scss +++ b/security-c4po-angular/src/app/project-overview/project-overview.component.scss @@ -1,62 +1,118 @@ @import '../../assets/@theme/styles/themes'; +@import '../../assets/@theme/styles/variables'; -.project-card { - max-width: 22rem; - width: 22rem; - min-width: 20rem; - max-height: 100%; - height: 100%; - min-height: 100%; +.pentest-overview { + width: 100vw; + height: 80vh; + // ToDo: Disable and fix scrolling + overflow: hidden; - .project-header { - max-height: 8rem; - height: 8rem; - min-height: 6rem; + .pentest-overview-header { + width: 100vw; + + .header-filer { + + .project-filter-input { + width: 24rem; + + .search-prefix-icon { + color:nb-theme(color-info-default); + } + } + + .state-dialog { + margin-left: auto; + margin-right: 0; + + .states { + width: 14rem !important; + } + } + + .reset-filter-btn { + .btn-icon { + padding-right: 0.5rem; + } + } + } + + .header-project-button { + position: fixed; + right: 1.5rem; + + .add-project-button { + // align-content: flex-end; + margin: 6rem 2rem 6rem 0; + + .btn-icon { + padding-right: 0.5rem; + } + } + } } - .project-subheader { - font-size: 1.25rem; - font-weight: bold; - } + .pentest-overview-column { + width: 100vw; - .project-paragraph { - font-size: 1.15rem; - font-style: italic; - } + .project-card { + max-width: 22rem; + width: 22rem; + min-width: 20rem; + max-height: 100%; + height: 100%; + min-height: 100%; - .project-progress { - max-width: 65%; - width: 65%; - min-width: 65%; - } + .project-header { + max-height: 8rem; + height: 8rem; + min-height: 6rem; - .project-button { - height: 1.425rem; + .header-title { + width: 12.5rem; + } + + .state-tag { + width: 1rem; + } + } + + .project-subheader { + font-size: 1.25rem; + font-weight: bold; + } + + .project-paragraph { + font-size: 1.15rem; + font-style: italic; + } + + .project-progress { + max-width: 65%; + width: 65%; + min-width: 65%; + } + + .project-button { + height: 1.425rem; + } + } + + .project-card:hover { + background-color: nb-theme(color-basic-transparent-focus); + // Increases element size on hover + // Decreases usability which is why it is commented out + /* + margin-top: +0.625rem; + transform: scale(1.025); + */ + } + + .project-link:hover { + cursor: pointer !important; + } + .error-text { + font-size: 1.25rem; + font-weight: bold; + } } } - -.project-card:hover { - background-color: nb-theme(color-basic-transparent-focus); - // Increases element size on hover - // Decreases usability which is why it is commented out - /* - margin-top: +0.625rem; - transform: scale(1.025); - */ -} - -.project-link:hover { - cursor: pointer !important; -} - -.add-project-button { - margin: 6rem 2rem 6rem 0; - .new-project-icon { - padding-right: 0.5rem; - } -} - -.error-text { - font-size: 1.25rem; - font-weight: bold; -} diff --git a/security-c4po-angular/src/app/project-overview/project-overview.component.ts b/security-c4po-angular/src/app/project-overview/project-overview.component.ts index c30b800..44c1834 100644 --- a/security-c4po-angular/src/app/project-overview/project-overview.component.ts +++ b/security-c4po-angular/src/app/project-overview/project-overview.component.ts @@ -5,7 +5,7 @@ import {BehaviorSubject, Observable} from 'rxjs'; import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy'; import {ProjectService} from '@shared/services/api/project.service'; import {NotificationService, PopupType} from '@shared/services/toaster-service/notification.service'; -import {filter, tap} from 'rxjs/operators'; +import {filter, startWith, tap} from 'rxjs/operators'; import {DialogService} from '@shared/services/dialog-service/dialog.service'; import {ProjectDialogComponent} from '@shared/modules/project-dialog/project-dialog.component'; import {ProjectDialogService} from '@shared/modules/project-dialog/service/project-dialog.service'; @@ -13,6 +13,8 @@ import {Router} from '@angular/router'; import {Route} from '@shared/models/route.enum'; import {InitProjectState} from '@shared/stores/project-state/project-state.actions'; import {Store} from '@ngxs/store'; +import {ReportState} from '@shared/models/state.enum'; +import {FormControl} from '@angular/forms'; @UntilDestroy() @Component({ @@ -26,6 +28,11 @@ export class ProjectOverviewComponent implements OnInit { loading$: BehaviorSubject = new BehaviorSubject(true); projects$: BehaviorSubject = new BehaviorSubject([]); + allProjects$: BehaviorSubject = new BehaviorSubject([]); + + // Search + projectSearch: FormControl; + protected filter$: Observable; constructor( private readonly notificationService: NotificationService, @@ -38,6 +45,9 @@ export class ProjectOverviewComponent implements OnInit { ngOnInit(): void { this.loadProjects(); + // Setup Search + this.projectSearch = new FormControl({value: '', disabled: !this.allProjects$.getValue()}); + this.setFilterObserverForProjects(); } loadProjects(): void { @@ -49,6 +59,7 @@ export class ProjectOverviewComponent implements OnInit { .subscribe({ next: (projects: Project[]) => { this.projects$.next(projects); + this.allProjects$.next(projects); this.loading$.next(false); }, error: err => { @@ -156,6 +167,74 @@ export class ProjectOverviewComponent implements OnInit { return this.loading$.asObservable(); } + /** + * HTML only + * @return the correct nb-accent for current report state of the project + */ + getProjectAccentFillStatus(value: any): string { + let reportStateFillStatus; + const statusValue = typeof value !== 'number' ? ReportState[value] : value; + // Check for correct accent color of status + switch (statusValue) { + case 6: + case 7: { + reportStateFillStatus = 'success'; + break; + } + case 0: { + reportStateFillStatus = 'info'; + break; + } + case 8: + case 9: + case 11: + case 12: { + reportStateFillStatus = 'warning'; + break; + } + case 1: + case 10: { + reportStateFillStatus = 'danger'; + break; + } + default: { + reportStateFillStatus = 'control'; + break; + } + } + return reportStateFillStatus; + } + + onClickResetFilter(): void { + this.projectSearch.reset(''); + this.projects$.next(this.allProjects$.getValue()); + } + + private setFilterObserverForProjects(): void { + this.filter$ = this.projectSearch.valueChanges.pipe(startWith('')); + this.filter$.subscribe( + (filterString: string) => { + if (filterString.length === 0) { + this.projects$.next(this.allProjects$.getValue()); + } else { + const matchingProjects: Project[] = []; + this.allProjects$.getValue().forEach(project => { + // Project attributes that the user can filter through + if ( + project.title.toLowerCase().includes(filterString.toLowerCase()) + || project.client.toLowerCase().includes(filterString.toLowerCase()) + || project.tester.toLowerCase().includes(filterString.toLowerCase()) + || project.state.toString().toLowerCase().includes(filterString.toLowerCase()) + ) { + matchingProjects.push(project); + } + }); + this.projects$.next(matchingProjects); + } + } + ); + } + private deleteProject(project: Project): void { this.projectService.deleteProjectById(project.id).pipe( untilDestroyed(this) diff --git a/security-c4po-angular/src/app/project-overview/project-overview.module.ts b/security-c4po-angular/src/app/project-overview/project-overview.module.ts index c30838a..5b0106d 100644 --- a/security-c4po-angular/src/app/project-overview/project-overview.module.ts +++ b/security-c4po-angular/src/app/project-overview/project-overview.module.ts @@ -2,7 +2,15 @@ import {NgModule} from '@angular/core'; import {CommonModule} from '@angular/common'; import {ProjectOverviewComponent} from './project-overview.component'; import {ProjectOverviewRoutingModule} from './project-overview-routing.module'; -import {NbButtonModule, NbCardModule, NbProgressBarModule} from '@nebular/theme'; +import { + NbButtonModule, + NbCardModule, + NbFormFieldModule, + NbInputModule, + NbLayoutModule, + NbProgressBarModule, + NbSelectModule +} from '@nebular/theme'; import {FlexLayoutModule} from '@angular/flex-layout'; import {FontAwesomeModule} from '@fortawesome/angular-fontawesome'; import {TranslateModule} from '@ngx-translate/core'; @@ -12,6 +20,8 @@ import {CommonAppModule} from '../common-app.module'; import {ConfirmDialogModule} from '@shared/modules/confirm-dialog/confirm-dialog.module'; import {SecurityConfirmDialogModule} from '@shared/modules/security-confirm-dialog/security-confirm-dialog.module'; import {RouterModule} from '@angular/router'; +import {ReportStateTagModule} from '@shared/widgets/report-state-tag/report-state-tag.module'; +import {ReactiveFormsModule} from '@angular/forms'; @NgModule({ declarations: [ @@ -34,7 +44,13 @@ import {RouterModule} from '@angular/router'; TranslateModule, ProjectDialogModule, ConfirmDialogModule, - SecurityConfirmDialogModule + ReportStateTagModule, + SecurityConfirmDialogModule, + NbLayoutModule, + NbInputModule, + NbFormFieldModule, + ReactiveFormsModule, + NbSelectModule ] }) export class ProjectOverviewModule { diff --git a/security-c4po-angular/src/app/project-overview/project/project.component.spec.ts b/security-c4po-angular/src/app/project-overview/project/project.component.spec.ts index 081765b..6f237b5 100644 --- a/security-c4po-angular/src/app/project-overview/project/project.component.spec.ts +++ b/security-c4po-angular/src/app/project-overview/project/project.component.spec.ts @@ -8,7 +8,6 @@ import {HttpLoaderFactory} from '../../common-app.module'; import {HttpClient, HttpClientModule} from '@angular/common/http'; import {RouterTestingModule} from '@angular/router/testing'; import {NgxsModule, Store} from '@ngxs/store'; -import {SessionState} from '@shared/stores/session-state/session-state'; import {HttpClientTestingModule} from '@angular/common/http/testing'; import {NbCardModule, NbDialogRef, NbLayoutModule} from '@nebular/theme'; import {KeycloakService} from 'keycloak-angular'; @@ -27,6 +26,7 @@ import {PentestStatus} from '@shared/models/pentest-status.model'; import {createSpyObj} from '@shared/modules/finding-dialog/finding-dialog.component.spec'; import {ExportReportDialogService} from '@shared/modules/export-report-dialog/service/export-report-dialog.service'; import {ExportReportDialogServiceMock} from '@shared/modules/export-report-dialog/service/export-report-dialog.service.mock'; +import {ReportState} from '@shared/models/state.enum'; const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = { selectedProject: { @@ -36,6 +36,7 @@ const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = { createdAt: new Date('2019-01-10T09:00:00'), tester: 'Novatester', summary: '', + state: ReportState.NEW, testingProgress: 0, createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110' }, diff --git a/security-c4po-angular/src/assets/i18n/de-DE.json b/security-c4po-angular/src/assets/i18n/de-DE.json index cd3dfeb..e887b71 100644 --- a/security-c4po-angular/src/assets/i18n/de-DE.json +++ b/security-c4po-angular/src/assets/i18n/de-DE.json @@ -52,6 +52,21 @@ "failed": "Benutzername oder Passwort falsch", "unauthorized": "Benutzer nicht gefunden. Bitte registrieren und erneut versuchen" }, + "state": { + "new": "Neu", + "needs_more_info": "Benötigt mehr Informationen", + "pre_submission": "Voranmeldung", + "pending": "Pending", + "triaged": "Ausstehend", + "retesting": "Erneutes Testen", + "resolved": "Aufgeklärt", + "informative": "Informatif", + "duplicate": "Duplikat", + "not_applicable": "Unzutreffend", + "spam": "Spam", + "out_of_scope": "Außerhalb Anwendungsbereich", + "accepted_risk": "Akzeptiertes Risiko" + }, "report": { "dialog": { "header": "Penetrationstestbereicht exportieren", @@ -69,17 +84,22 @@ "title.label": "Projekt Titel", "client.label": "Name des Auftraggebers", "tester.label": "Name des Pentester", + "state.label": "Penteststatus", "summary.label": "Zusammenfassung", "summary.placeholder": "Sollte eine Zusammenfassung, einen Ansatz, einen Umfang und eine Bewertungsübersicht sowie allgemeine Empfehlungen enthalten", "title": "Titel", "client": "Klient", "tester": "Tester", + "state": "Penteststatus", "summary": "Zusammenfassung", "createdAt": "Erstellt am", "overview": { "add.project": "Projekt hinzufügen", "no.projects": "Keine Projekte verfügbar" }, + "filter": { + "placeholder": "Projekt suchen" + }, "create": { "header": "Neues Projekt erstellen" }, @@ -96,6 +116,7 @@ "titleRequired": "Titel ist erforderlich.", "clientRequired": "Klient ist erforderlich.", "testerRequired": "Tester ist erforderlich.", + "stateRequired": "Status ist erforderlich.", "summaryRequired": "Zusammenfassung ist erforderlich." }, "popup": { diff --git a/security-c4po-angular/src/assets/i18n/en-US.json b/security-c4po-angular/src/assets/i18n/en-US.json index 5491102..c588327 100644 --- a/security-c4po-angular/src/assets/i18n/en-US.json +++ b/security-c4po-angular/src/assets/i18n/en-US.json @@ -52,6 +52,21 @@ "failed": "Wrong username or password", "unauthorized": "User not found. Please register and try again" }, + "state": { + "new": "New", + "needs_more_info": "Needs More Info", + "pre_submission": "Pre-submission", + "pending": "Pending", + "triaged": "Triaged", + "retesting": "Retesting", + "resolved": "Resolved", + "informative": "Informative", + "duplicate": "Duplicate", + "not_applicable": "Not Applicable", + "spam": "Spam", + "out_of_scope": "Out Of Scope", + "accepted_risk": "Accepted Risk" + }, "report": { "dialog": { "header": "Export Penetrationtest Report", @@ -69,17 +84,22 @@ "title.label": "Project Title", "client.label": "Name of Client", "tester.label": "Name of Pentester", + "state.label": "State of Pentest", "summary.label": "Summary", "summary.placeholder": "Should include Executive Summary, Approach, Scope and Assessment Overview as well as General Recommendations", "title": "Title", "client": "Client", "tester": "Tester", + "state": "State of Pentest", "summary": "Summary", "createdAt": "Created at", "overview": { "add.project": "Add Project", "no.projects": "No projects available" }, + "filter": { + "placeholder": "Search for project" + }, "create": { "header": "Create New Project" }, @@ -96,6 +116,7 @@ "titleRequired": "Title is required.", "clientRequired": "Client is required.", "testerRequired": "Tester is required.", + "stateRequired": "State is required.", "summaryRequired": "Summary is required." }, "popup": { diff --git a/security-c4po-angular/src/shared/models/project.model.ts b/security-c4po-angular/src/shared/models/project.model.ts index 80a865f..a05fec9 100644 --- a/security-c4po-angular/src/shared/models/project.model.ts +++ b/security-c4po-angular/src/shared/models/project.model.ts @@ -1,4 +1,5 @@ import {PentestStatus} from '@shared/models/pentest-status.model'; +import {ReportState} from '@shared/models/state.enum'; export class Project { id: string; @@ -7,6 +8,7 @@ export class Project { createdAt: Date; tester: string; summary: string; + state: ReportState; projectPentests?: Array; testingProgress?: number; createdBy: string; @@ -16,6 +18,7 @@ export class Project { title: string, createdAt: Date, tester: string, + state: ReportState, projectPentests?: Array, testingProgress?: number, summary?: string, @@ -28,14 +31,28 @@ export class Project { this.projectPentests = projectPentests; this.testingProgress = testingProgress; this.summary = summary; + this.state = state; this.createdBy = createdBy; } } +export function transformProjectToRequestBody(project: ProjectDialogBody | Project): ProjectDialogBody { + const transformedProject = { + ...project, + title: project.title, + client: project.client, + tester: project.tester, + state: typeof project.state === 'number' ? ReportState[project.state] : project.state, + summary: project.summary, + } as unknown as ProjectDialogBody; + return transformedProject; +} + export interface ProjectDialogBody { title: string; client: string; tester: string; + state: ReportState; summary: string; } diff --git a/security-c4po-angular/src/shared/models/state.enum.ts b/security-c4po-angular/src/shared/models/state.enum.ts new file mode 100644 index 0000000..5c979e7 --- /dev/null +++ b/security-c4po-angular/src/shared/models/state.enum.ts @@ -0,0 +1,40 @@ +export enum ReportState { + NEW, + NEEDS_MORE_INFO, + // Report states depending on customer feedback + PRE_SUBMISSION, + PENDING, + TRIAGED, + RETESTING, + // Report states for closed submissions + RESOLVED, + INFORMATIVE, + DUPLICATE, + NOT_APPLICABLE, + SPAM, + OUT_OF_SCOPE, + ACCEPTED_RISK +} + +export const reportStateTexts: Array = [ + {value: ReportState.NEW, translationText: 'state.new'}, + {value: ReportState.NEEDS_MORE_INFO, translationText: 'state.needs_more_info'}, + // Report states depending on customer feedback + {value: ReportState.PRE_SUBMISSION, translationText: 'state.pre_submission'}, + {value: ReportState.PENDING, translationText: 'state.pending'}, + {value: ReportState.TRIAGED, translationText: 'state.triaged'}, + {value: ReportState.RETESTING, translationText: 'state.retesting'}, + // Report states for closed submissions + {value: ReportState.RESOLVED, translationText: 'state.resolved'}, + {value: ReportState.INFORMATIVE, translationText: 'state.informative'}, + {value: ReportState.DUPLICATE, translationText: 'state.duplicate'}, + {value: ReportState.NOT_APPLICABLE, translationText: 'state.not_applicable'}, + {value: ReportState.SPAM, translationText: 'state.spam'}, + {value: ReportState.OUT_OF_SCOPE, translationText: 'state.out_of_scope'}, + {value: ReportState.ACCEPTED_RISK, translationText: 'state.accepted_risk'} +]; + +export interface ReportStateText { + value: ReportState; + translationText: string; +} diff --git a/security-c4po-angular/src/shared/modules/comment-dialog/comment-dialog.component.spec.ts b/security-c4po-angular/src/shared/modules/comment-dialog/comment-dialog.component.spec.ts index b185913..7bdbd98 100644 --- a/security-c4po-angular/src/shared/modules/comment-dialog/comment-dialog.component.spec.ts +++ b/security-c4po-angular/src/shared/modules/comment-dialog/comment-dialog.component.spec.ts @@ -32,6 +32,7 @@ import Mock = jest.Mock; import {Finding} from '@shared/models/finding.model'; import {Severity} from '@shared/models/severity.enum'; import {Comment} from '@shared/models/comment.model'; +import {ReportState} from '@shared/models/state.enum'; const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = { selectedProject: { @@ -41,6 +42,7 @@ const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = { createdAt: new Date('2019-01-10T09:00:00'), tester: 'Novatester', summary: '', + state: ReportState.NEW, testingProgress: 0, createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110' }, diff --git a/security-c4po-angular/src/shared/modules/export-report-dialog/export-report-dialog.component.spec.ts b/security-c4po-angular/src/shared/modules/export-report-dialog/export-report-dialog.component.spec.ts index aebeda0..424fee3 100644 --- a/security-c4po-angular/src/shared/modules/export-report-dialog/export-report-dialog.component.spec.ts +++ b/security-c4po-angular/src/shared/modules/export-report-dialog/export-report-dialog.component.spec.ts @@ -28,6 +28,7 @@ import {Project, ProjectPentests} from '@shared/models/project.model'; import {PentestStatus} from '@shared/models/pentest-status.model'; import {ObjectiveChartModule} from '@shared/modules/objective-chart/objective-chart.module'; import {FontAwesomeModule} from '@fortawesome/angular-fontawesome'; +import {ReportState} from '@shared/models/state.enum'; describe('ExportReportDialogComponent', () => { let component: ExportReportDialogComponent; @@ -102,6 +103,7 @@ const mockProject: Project = { createdAt: new Date('2019-01-10T09:00:00'), tester: 'Novatester', summary: '', + state: ReportState.NEW, projectPentests: mockedPentests, testingProgress: 0, createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110' diff --git a/security-c4po-angular/src/shared/modules/finding-dialog/finding-dialog.component.spec.ts b/security-c4po-angular/src/shared/modules/finding-dialog/finding-dialog.component.spec.ts index bd6c95e..df6bf2e 100644 --- a/security-c4po-angular/src/shared/modules/finding-dialog/finding-dialog.component.spec.ts +++ b/security-c4po-angular/src/shared/modules/finding-dialog/finding-dialog.component.spec.ts @@ -30,6 +30,7 @@ import {Category} from '@shared/models/category.model'; import {PentestStatus} from '@shared/models/pentest-status.model'; import {PROJECT_STATE_NAME, ProjectState, ProjectStateModel} from '@shared/stores/project-state/project-state'; import {NgxsModule, Store} from '@ngxs/store'; +import {ReportState} from '@shared/models/state.enum'; const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = { selectedProject: { @@ -39,6 +40,7 @@ const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = { createdAt: new Date('2019-01-10T09:00:00'), tester: 'Novatester', summary: '', + state: ReportState.NEW, testingProgress: 0, createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110' }, @@ -97,13 +99,13 @@ describe('FindingDialogComponent', () => { {provide: NotificationService, useValue: new NotificationServiceMock()}, {provide: DialogService, useClass: DialogServiceMock}, {provide: NbDialogRef, useValue: dialogSpy}, - {provide: NB_DIALOG_CONFIG, useValue: mockedCommentDialogData} + {provide: NB_DIALOG_CONFIG, useValue: mockedFindingDialogData} ] }).compileComponents(); }); beforeEach(() => { - TestBed.overrideProvider(NB_DIALOG_CONFIG, {useValue: mockedCommentDialogData}); + TestBed.overrideProvider(NB_DIALOG_CONFIG, {useValue: mockedFindingDialogData}); fixture = TestBed.createComponent(FindingDialogComponent); store = TestBed.inject(Store); store.reset({ @@ -138,7 +140,7 @@ export const mockFinding: Finding = { mitigation: 'Mitigation Test' }; -export const mockedCommentDialogData = { +export const mockedFindingDialogData = { form: { findingTitle: { fieldName: 'findingTitle', diff --git a/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.component.html b/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.component.html index 818c189..45b7ab6 100644 --- a/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.component.html +++ b/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.component.html @@ -1,6 +1,18 @@ {{ dialogData?.options[0].headerLabelKey | translate }} + +
+ + + {{ reportState.translationText | translate }} + + +
{ let component: ProjectDialogComponent; @@ -43,6 +45,7 @@ describe('ProjectDialogComponent', () => { NbButtonModule, FlexLayoutModule, NbInputModule, + NbSelectModule, NbFormFieldModule, ReactiveFormsModule, BrowserAnimationsModule, @@ -70,7 +73,8 @@ describe('ProjectDialogComponent', () => { TestBed.overrideProvider(NB_DIALOG_CONFIG, {useValue: mockedProjectDialogData}); fixture = TestBed.createComponent(ProjectDialogComponent); component = fixture.componentInstance; - fixture.detectChanges(); + // ToDo: fix detectChanges() when controlsConfig is defined + // fixture.detectChanges(); }); it('should create', () => { @@ -91,7 +95,8 @@ export const mockProject: Project = { title: 'Test Project', client: 'Testclient', tester: 'Testpentester', - summary: '', + summary: 'Test', + state: ReportState.NEW, createdAt: new Date(), testingProgress: 0, createdBy: 'UID-11-12-13' @@ -137,13 +142,27 @@ export const mockedProjectDialogData = { errors: [ {errorCode: 'required', translationKey: 'project.validationMessage.testerRequired'} ] - } + }, + pentestState: { + fieldName: 'pentestState', + type: 'state-select', + labelKey: 'project.state.label', + placeholder: 'project.state', + controlsConfig: [ + {value: mockProject ? mockProject.state : ReportState.NEW, disabled: false}, + [Validators.required] + ], + errors: [ + {errorCode: 'required', translationKey: 'project.validationMessage.stateRequired'} + ] + }, }, options: [ { headerLabelKey: 'project.edit.header', buttonKey: 'global.action.update', - accentColor: 'warning' + accentColor: 'warning', + additionalData: mockProject }, ] }; diff --git a/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.component.ts b/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.component.ts index a017b61..ffa9bac 100644 --- a/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.component.ts +++ b/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.component.ts @@ -7,6 +7,9 @@ import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy'; import {DialogService} from '@shared/services/dialog-service/dialog.service'; import {ProjectService} from '@shared/services/api/project.service'; import {NotificationService, PopupType} from '@shared/services/toaster-service/notification.service'; +import * as FA from '@fortawesome/free-solid-svg-icons'; +import {ReportState, reportStateTexts} from '@shared/models/state.enum'; +import {Project, transformProjectToRequestBody} from '@shared/models/project.model'; @UntilDestroy() @Component({ @@ -21,6 +24,11 @@ export class ProjectDialogComponent implements OnInit { dialogData: GenericDialogData; + // HTML only + readonly fa = FA; + state: ReportState = ReportState.NEW; + readonly reportStateTexts = reportStateTexts; + constructor( @Inject(NB_DIALOG_CONFIG) private data: GenericDialogData, private fb: FormBuilder, @@ -63,6 +71,43 @@ export class ProjectDialogComponent implements OnInit { return this.projectFormGroup.valid && this.projectDataChanged(); } + /** + * HTML only + * @return the correct nb-status for current report state of the project + */ + getReportStateFillStatus(value: number): string { + let reportStateFillStatus; + switch (value) { + case 6: + case 7: { + reportStateFillStatus = 'success'; + break; + } + case 0: + { + reportStateFillStatus = 'info'; + break; + } + case 8: + case 9: + case 11: + case 12: { + reportStateFillStatus = 'warning'; + break; + } + case 1: + case 10: { + reportStateFillStatus = 'danger'; + break; + } + default: { + reportStateFillStatus = 'basic'; + break; + } + } + return reportStateFillStatus; + } + /** * @return true if project data is different from initial value */ @@ -98,9 +143,12 @@ export class ProjectDialogComponent implements OnInit { title: value.projectTitle, client: value.projectClient, tester: value.projectTester, + state: this.formArray[4].controlsConfig[0].value, summary: value.projectSummary }; - this.projectService.saveProject(dialogRes).pipe( + this.projectService.saveProject( + transformProjectToRequestBody(dialogRes) + ).pipe( untilDestroyed(this) ).subscribe( { @@ -122,15 +170,19 @@ export class ProjectDialogComponent implements OnInit { title: value.projectTitle, client: value.projectClient, tester: value.projectTester, + state: this.formArray[4].controlsConfig[0].value, summary: value.projectSummary }; - this.projectService.updateProject(this.dialogData.options[0].additionalData.id, dialogRes).pipe( + this.projectService.updateProject( + this.dialogData.options[0].additionalData.id, + transformProjectToRequestBody(dialogRes) + ).pipe( untilDestroyed(this) ).subscribe( { - next: () => { + next: (project: Project) => { this.notificationService.showPopup('project.popup.update.success', PopupType.SUCCESS); - this.dialogRef.close(); + this.dialogRef.close(project); }, error: err => { console.error(err); diff --git a/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.module.ts b/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.module.ts index 72cef0f..3f9dd1b 100644 --- a/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.module.ts +++ b/security-c4po-angular/src/shared/modules/project-dialog/project-dialog.module.ts @@ -1,7 +1,7 @@ import {NgModule} from '@angular/core'; import {CommonModule} from '@angular/common'; import {ProjectDialogComponent} from '@shared/modules/project-dialog/project-dialog.component'; -import {NbButtonModule, NbCardModule, NbFormFieldModule, NbInputModule} from '@nebular/theme'; +import {NbButtonModule, NbCardModule, NbFormFieldModule, NbInputModule, NbSelectModule} from '@nebular/theme'; import {FlexLayoutModule} from '@angular/flex-layout'; import {FontAwesomeModule} from '@fortawesome/angular-fontawesome'; import {TranslateModule} from '@ngx-translate/core'; @@ -13,18 +13,19 @@ import {ReactiveFormsModule} from '@angular/forms'; declarations: [ ProjectDialogComponent ], - imports: [ - CommonModule, - CommonAppModule, - NbCardModule, - NbButtonModule, - NbFormFieldModule, - NbInputModule, - FlexLayoutModule, - FontAwesomeModule, - TranslateModule, - ReactiveFormsModule, - ], + imports: [ + CommonModule, + CommonAppModule, + NbCardModule, + NbButtonModule, + NbFormFieldModule, + NbInputModule, + FlexLayoutModule, + FontAwesomeModule, + TranslateModule, + ReactiveFormsModule, + NbSelectModule, + ], providers: [ ProjectDialogService, ], diff --git a/security-c4po-angular/src/shared/modules/project-dialog/service/project-dialog.service.ts b/security-c4po-angular/src/shared/modules/project-dialog/service/project-dialog.service.ts index c1948db..2d5c552 100644 --- a/security-c4po-angular/src/shared/modules/project-dialog/service/project-dialog.service.ts +++ b/security-c4po-angular/src/shared/modules/project-dialog/service/project-dialog.service.ts @@ -6,6 +6,7 @@ import {Project} from '@shared/models/project.model'; import {ProjectDialogComponent} from '@shared/modules/project-dialog/project-dialog.component'; import {Validators} from '@angular/forms'; import {GenericDialogData} from '@shared/models/generic-dialog-data'; +import {ReportState} from '@shared/models/state.enum'; @Injectable() export class ProjectDialogService { @@ -33,6 +34,11 @@ export class ProjectDialogService { config?: Partial | string>>): Observable { let dialogOptions: Partial | string>>; let dialogData: GenericDialogData; + let state; + // transform severity of finding if existing + if (project) { + state = typeof project.state !== 'number' ? ReportState[project.state] : project.state; + } // Setup ProjectDialogData dialogData = { form: { @@ -87,7 +93,20 @@ export class ProjectDialogService { errors: [ {errorCode: 'required', translationKey: 'project.validationMessage.summaryRequired'} ] - } + }, + pentestState: { + fieldName: 'pentestState', + type: 'state-select', + labelKey: 'project.state.label', + placeholder: 'project.state', + controlsConfig: [ + {value: project ? state : ReportState.NEW, disabled: false}, + [Validators.required] + ], + errors: [ + {errorCode: 'required', translationKey: 'project.validationMessage.stateRequired'} + ] + }, }, options: [] }; diff --git a/security-c4po-angular/src/shared/services/api/project.service.spec.ts b/security-c4po-angular/src/shared/services/api/project.service.spec.ts index a3865df..2ececb9 100644 --- a/security-c4po-angular/src/shared/services/api/project.service.spec.ts +++ b/security-c4po-angular/src/shared/services/api/project.service.spec.ts @@ -7,6 +7,7 @@ import {KeycloakService} from 'keycloak-angular'; import {Project, ProjectDialogBody} from '@shared/models/project.model'; import {environment} from '../../../environments/environment'; import {throwError} from 'rxjs'; +import {ReportState} from '@shared/models/state.enum'; describe('ProjectService', () => { let service: ProjectService; @@ -42,6 +43,7 @@ describe('ProjectService', () => { createdAt: dummyDate, tester: 'Novatester', summary: '', + state: ReportState.NEW, testingProgress: 0, createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110' }; @@ -83,6 +85,7 @@ describe('ProjectService', () => { client: 'E Corp', title: 'Some Mock API (v1.0) Scanning', tester: 'Novatester', + state: ReportState.NEW, summary: '' }; @@ -93,6 +96,7 @@ describe('ProjectService', () => { createdAt: dummyDate, tester: 'Novatester', summary: '', + state: ReportState.NEW, testingProgress: 0, createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110' }; diff --git a/security-c4po-angular/src/shared/widgets/report-state-tag/report-state-tag.component.html b/security-c4po-angular/src/shared/widgets/report-state-tag/report-state-tag.component.html new file mode 100644 index 0000000..b259507 --- /dev/null +++ b/security-c4po-angular/src/shared/widgets/report-state-tag/report-state-tag.component.html @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + diff --git a/security-c4po-angular/src/shared/widgets/report-state-tag/report-state-tag.component.spec.ts b/security-c4po-angular/src/shared/widgets/report-state-tag/report-state-tag.component.spec.ts new file mode 100644 index 0000000..247cb8a --- /dev/null +++ b/security-c4po-angular/src/shared/widgets/report-state-tag/report-state-tag.component.spec.ts @@ -0,0 +1,45 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ReportStateTagComponent } from './report-state-tag.component'; +import {HttpClientTestingModule} from '@angular/common/http/testing'; +import {NbCardModule, NbTagModule} from '@nebular/theme'; +import {MockModule} from 'ng-mocks'; +import {TranslateLoader, TranslateModule} from '@ngx-translate/core'; +import {HttpLoaderFactory} from '../../../app/common-app.module'; +import {HttpClient} from '@angular/common/http'; + +describe('ReportStateTagComponent', () => { + let component: ReportStateTagComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + ReportStateTagComponent + ], + imports: [ + HttpClientTestingModule, + NbCardModule, + MockModule(NbTagModule), + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useFactory: HttpLoaderFactory, + deps: [HttpClient] + } + }) + ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ReportStateTagComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/security-c4po-angular/src/shared/widgets/report-state-tag/report-state-tag.component.ts b/security-c4po-angular/src/shared/widgets/report-state-tag/report-state-tag.component.ts new file mode 100644 index 0000000..ccf23cb --- /dev/null +++ b/security-c4po-angular/src/shared/widgets/report-state-tag/report-state-tag.component.ts @@ -0,0 +1,29 @@ +import {ChangeDetectionStrategy, Component, Input, OnChanges, OnInit} from '@angular/core'; +import {ReportState, ReportStateText, reportStateTexts} from '@shared/models/state.enum'; +import {Severity} from '@shared/models/severity.enum'; + +@Component({ + selector: 'app-report-state-tag', + templateUrl: './report-state-tag.component.html', + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ReportStateTagComponent implements OnChanges { + + @Input() currentReportState: ReportState = ReportState.NEW; + + // HTML only + state = ReportState; + reportState: any = 0; + readonly reportStateTexts: Array = reportStateTexts; + + constructor() { } + + ngOnChanges(): void { + this.reportState = typeof this.currentReportState !== 'number' ? ReportState[this.currentReportState] : this.currentReportState; + } + + getTranslationKey(): string { + const index = this.reportStateTexts.findIndex(statusText => statusText.value === this.reportState); + return this.reportStateTexts[index].translationText; + } +} diff --git a/security-c4po-angular/src/shared/widgets/report-state-tag/report-state-tag.module.ts b/security-c4po-angular/src/shared/widgets/report-state-tag/report-state-tag.module.ts new file mode 100644 index 0000000..73d99c2 --- /dev/null +++ b/security-c4po-angular/src/shared/widgets/report-state-tag/report-state-tag.module.ts @@ -0,0 +1,22 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import {NbTagModule} from '@nebular/theme'; +import {TranslateModule} from '@ngx-translate/core'; +import {ReportStateTagComponent} from '@shared/widgets/report-state-tag/report-state-tag.component'; + + + +@NgModule({ + declarations: [ + ReportStateTagComponent + ], + imports: [ + CommonModule, + NbTagModule, + TranslateModule + ], + exports: [ + ReportStateTagComponent + ] +}) +export class ReportStateTagModule { } diff --git a/security-c4po-angular/src/shared/widgets/severity-tag/severity-tag.module.ts b/security-c4po-angular/src/shared/widgets/severity-tag/severity-tag.module.ts index d05f551..a1b39b1 100644 --- a/security-c4po-angular/src/shared/widgets/severity-tag/severity-tag.module.ts +++ b/security-c4po-angular/src/shared/widgets/severity-tag/severity-tag.module.ts @@ -8,13 +8,13 @@ import {TranslateModule} from '@ngx-translate/core'; declarations: [ SeverityTagComponent ], - exports: [ - SeverityTagComponent - ], imports: [ CommonModule, NbTagModule, TranslateModule + ], + exports: [ + SeverityTagComponent ] }) export class SeverityTagModule { } diff --git a/security-c4po-api/src/main/kotlin/com/securityc4po/api/project/Project.kt b/security-c4po-api/src/main/kotlin/com/securityc4po/api/project/Project.kt index 7f37785..94ec5f1 100644 --- a/security-c4po-api/src/main/kotlin/com/securityc4po/api/project/Project.kt +++ b/security-c4po-api/src/main/kotlin/com/securityc4po/api/project/Project.kt @@ -21,6 +21,7 @@ data class Project( val createdAt: String = Instant.now().toString(), val tester: String, val summary: String? = null, + val state: PentestState, var projectPentests: List = emptyList(), val createdBy: String ) @@ -33,6 +34,7 @@ fun buildProject(body: ProjectRequestBody, projectEntity: ProjectEntity): Projec createdAt = projectEntity.data.createdAt, tester = body.tester, summary = body.summary, + state = body.state, projectPentests = projectEntity.data.projectPentests, createdBy = projectEntity.data.createdBy ) @@ -46,6 +48,7 @@ fun Project.toProjectResponseBody(): ResponseBody { "createdAt" to createdAt, "tester" to tester, "summary" to summary, + "state" to state, /* ToDo: Calculate percentage in BE type: float */ "testingProgress" to calculateProgress(), "createdBy" to createdBy @@ -119,6 +122,7 @@ data class ProjectRequestBody( val client: String, val title: String, val tester: String, + val state: PentestState, val summary: String? ) @@ -132,6 +136,7 @@ fun ProjectRequestBody.isValid(): Boolean { this.client.isBlank() -> false this.title.isBlank() -> false this.tester.isBlank() -> false + this.state.toString().isBlank() -> false else -> true } } @@ -144,6 +149,7 @@ fun ProjectRequestBody.toProject(): Project { createdAt = Instant.now().toString(), tester = this.tester, summary = this.summary, + state = this.state, // ToDo: Should be changed to SUB from Token after adding AUTH Header createdBy = UUID.randomUUID().toString() ) diff --git a/security-c4po-api/src/main/kotlin/com/securityc4po/api/project/ProjectEntity.kt b/security-c4po-api/src/main/kotlin/com/securityc4po/api/project/ProjectEntity.kt index d8f3737..371ef4b 100644 --- a/security-c4po-api/src/main/kotlin/com/securityc4po/api/project/ProjectEntity.kt +++ b/security-c4po-api/src/main/kotlin/com/securityc4po/api/project/ProjectEntity.kt @@ -19,6 +19,7 @@ fun ProjectEntity.toProject() : Project { this.data.createdAt, this.data.tester, this.data.summary, + this.data.state, this.data.projectPentests, this.data.createdBy ) diff --git a/security-c4po-api/src/main/kotlin/com/securityc4po/api/project/State.kt b/security-c4po-api/src/main/kotlin/com/securityc4po/api/project/State.kt new file mode 100644 index 0000000..97bf0cc --- /dev/null +++ b/security-c4po-api/src/main/kotlin/com/securityc4po/api/project/State.kt @@ -0,0 +1,19 @@ +package com.securityc4po.api.project + +enum class PentestState { + NEW, + NEEDS_MORE_INFO, + // Report states depending on customer feedback + PRE_SUBMISSION, + PENDING, + TRIAGED, + RETESTING, + // Report states for closed submissions + RESOLVED, + INFORMATIVE, + DUPLICATE, + NOT_APPLICABLE, + SPAM, + OUT_OF_SCOPE, + ACCEPTED_RISK +} \ No newline at end of file diff --git a/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/PentestControllerDocumentationTest.kt b/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/PentestControllerDocumentationTest.kt index 10498ae..2354e85 100644 --- a/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/PentestControllerDocumentationTest.kt +++ b/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/PentestControllerDocumentationTest.kt @@ -6,6 +6,7 @@ import com.securityc4po.api.BaseDocumentationIntTest import com.securityc4po.api.configuration.NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR import com.securityc4po.api.configuration.RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE import com.securityc4po.api.configuration.SIC_INNER_SHOULD_BE_STATIC +import com.securityc4po.api.project.PentestState import com.securityc4po.api.project.Project import com.securityc4po.api.project.ProjectEntity import edu.umd.cs.findbugs.annotations.SuppressFBWarnings @@ -256,6 +257,7 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() { createdAt = "2021-01-10T18:05:00Z", tester = "Novatester", projectPentests = emptyList(), + state = PentestState.NEW, createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032" ) // Pentests diff --git a/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/PentestControllerIntTest.kt b/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/PentestControllerIntTest.kt index 9cd5d88..f460976 100644 --- a/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/PentestControllerIntTest.kt +++ b/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/PentestControllerIntTest.kt @@ -5,6 +5,7 @@ import com.securityc4po.api.BaseIntTest import com.securityc4po.api.configuration.NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR import com.securityc4po.api.configuration.RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE import com.securityc4po.api.configuration.SIC_INNER_SHOULD_BE_STATIC +import com.securityc4po.api.project.PentestState import com.securityc4po.api.project.Project import com.securityc4po.api.project.ProjectEntity import edu.umd.cs.findbugs.annotations.SuppressFBWarnings @@ -171,6 +172,7 @@ class PentestControllerIntTest : BaseIntTest() { title = "Some Mock API (v1.0) Scanning", createdAt = "2021-01-10T18:05:00Z", tester = "Novatester", + state = PentestState.NEW, createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032" ) // pentests diff --git a/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/comment/CommentControllerDocumentationTest.kt b/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/comment/CommentControllerDocumentationTest.kt index 13be660..6362791 100644 --- a/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/comment/CommentControllerDocumentationTest.kt +++ b/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/comment/CommentControllerDocumentationTest.kt @@ -10,6 +10,7 @@ import com.securityc4po.api.pentest.Pentest import com.securityc4po.api.pentest.PentestCategory import com.securityc4po.api.pentest.PentestEntity import com.securityc4po.api.pentest.PentestStatus +import com.securityc4po.api.project.PentestState import com.securityc4po.api.project.Project import com.securityc4po.api.project.ProjectEntity import edu.umd.cs.findbugs.annotations.SuppressFBWarnings @@ -282,6 +283,7 @@ class CommentControllerDocumentationTest : BaseDocumentationIntTest() { createdAt = "2021-01-10T18:05:00Z", tester = "Novatester", projectPentests = emptyList(), + state = PentestState.NEW, createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032" ) // Pentests diff --git a/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/comment/CommentControllerIntTest.kt b/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/comment/CommentControllerIntTest.kt index 2cbd1f2..1d37b99 100644 --- a/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/comment/CommentControllerIntTest.kt +++ b/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/comment/CommentControllerIntTest.kt @@ -9,6 +9,7 @@ import com.securityc4po.api.pentest.Pentest import com.securityc4po.api.pentest.PentestCategory import com.securityc4po.api.pentest.PentestEntity import com.securityc4po.api.pentest.PentestStatus +import com.securityc4po.api.project.PentestState import com.securityc4po.api.project.Project import com.securityc4po.api.project.ProjectEntity import edu.umd.cs.findbugs.annotations.SuppressFBWarnings @@ -179,6 +180,7 @@ class CommentControllerIntTest : BaseIntTest() { title = "Some Mock API (v1.0) Scanning", createdAt = "2021-01-10T18:05:00Z", tester = "Novatester", + state = PentestState.NEW, createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032" ) // pentests diff --git a/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/finding/FindingControllerDocumentationTest.kt b/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/finding/FindingControllerDocumentationTest.kt index 0da1b91..493c9c8 100644 --- a/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/finding/FindingControllerDocumentationTest.kt +++ b/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/finding/FindingControllerDocumentationTest.kt @@ -10,6 +10,7 @@ import com.securityc4po.api.pentest.Pentest import com.securityc4po.api.pentest.PentestCategory import com.securityc4po.api.pentest.PentestEntity import com.securityc4po.api.pentest.PentestStatus +import com.securityc4po.api.project.PentestState import com.securityc4po.api.project.Project import com.securityc4po.api.project.ProjectEntity import edu.umd.cs.findbugs.annotations.SuppressFBWarnings @@ -340,6 +341,7 @@ class FindingControllerDocumentationTest: BaseDocumentationIntTest() { createdAt = "2021-01-10T18:05:00Z", tester = "Novatester", projectPentests = emptyList(), + state = PentestState.NEW, createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032" ) // Pentests diff --git a/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/finding/FindingControllerIntTest.kt b/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/finding/FindingControllerIntTest.kt index 01c3135..10e8dd2 100644 --- a/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/finding/FindingControllerIntTest.kt +++ b/security-c4po-api/src/test/kotlin/com/securityc4po/api/pentest/finding/FindingControllerIntTest.kt @@ -9,6 +9,7 @@ import com.securityc4po.api.pentest.Pentest import com.securityc4po.api.pentest.PentestCategory import com.securityc4po.api.pentest.PentestEntity import com.securityc4po.api.pentest.PentestStatus +import com.securityc4po.api.project.PentestState import com.securityc4po.api.project.Project import com.securityc4po.api.project.ProjectEntity import edu.umd.cs.findbugs.annotations.SuppressFBWarnings @@ -207,6 +208,7 @@ class FindingControllerIntTest: BaseIntTest() { title = "Some Mock API (v1.0) Scanning", createdAt = "2021-01-10T18:05:00Z", tester = "Novatester", + state = PentestState.NEW, createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032" ) // pentests diff --git a/security-c4po-api/src/test/kotlin/com/securityc4po/api/project/ProjectControllerDocumentationTest.kt b/security-c4po-api/src/test/kotlin/com/securityc4po/api/project/ProjectControllerDocumentationTest.kt index d7d0991..844a6a5 100644 --- a/security-c4po-api/src/test/kotlin/com/securityc4po/api/project/ProjectControllerDocumentationTest.kt +++ b/security-c4po-api/src/test/kotlin/com/securityc4po/api/project/ProjectControllerDocumentationTest.kt @@ -75,6 +75,8 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() { .description("The user that is assigned as a tester in the project"), PayloadDocumentation.fieldWithPath("[].summary").type(JsonFieldType.STRING) .description("The summary of the requested project"), + PayloadDocumentation.fieldWithPath("[].state").type(JsonFieldType.STRING) + .description("The state of the requested project pentest"), PayloadDocumentation.fieldWithPath("[].createdBy").type(JsonFieldType.STRING) .description("The id of the user that created the project"), PayloadDocumentation.fieldWithPath("[].testingProgress").type(JsonFieldType.NUMBER) @@ -92,6 +94,7 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() { tester = "Novatester", summary = "Lorem Ipsum", projectPentests = emptyList(), + state = PentestState.NEW, createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032" ) val projectTwo = Project( @@ -102,6 +105,7 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() { tester = "Elliot", summary = "Lorem Ipsum", projectPentests = emptyList(), + state = PentestState.NEW, createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032" ) @@ -144,6 +148,8 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() { .description("The date where the project was created at"), PayloadDocumentation.fieldWithPath("tester").type(JsonFieldType.STRING) .description("The user that is assigned as a tester in the project"), + PayloadDocumentation.fieldWithPath("state").type(JsonFieldType.STRING) + .description("The state of the requested project pentest"), PayloadDocumentation.fieldWithPath("createdBy").type(JsonFieldType.STRING) .description("The id of the user that created the project"), PayloadDocumentation.fieldWithPath("testingProgress").type(JsonFieldType.NUMBER) @@ -157,6 +163,7 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() { client = "Novatec", title = "log4j Pentest", tester = "Stipe", + state = PentestState.NEW, summary = "" ) } @@ -230,6 +237,7 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() { createdAt = "2021-01-10T18:05:00Z", tester = "Novatester", projectPentests = emptyList(), + state = PentestState.NEW, createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032" ) } @@ -269,6 +277,8 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() { .description("The updated user that is assigned as a tester in the project"), PayloadDocumentation.fieldWithPath("summary").type(JsonFieldType.STRING) .description("The summary of the requested project"), + PayloadDocumentation.fieldWithPath("state").type(JsonFieldType.STRING) + .description("The state of the requested project pentest"), PayloadDocumentation.fieldWithPath("createdBy").type(JsonFieldType.STRING) .description("The id of the user that created the project"), PayloadDocumentation.fieldWithPath("testingProgress").type(JsonFieldType.NUMBER) @@ -282,6 +292,7 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() { client = "Novatec_updated", title = "log4j Pentest_updated", tester = "Stipe_updated", + state = PentestState.NEW, summary = "" ) @@ -292,6 +303,7 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() { createdAt = "2021-01-10T18:05:00Z", tester = "Stipe_updated", summary = "", + state = PentestState.NEW, projectPentests = emptyList(), createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032" ) @@ -306,6 +318,7 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() { createdAt = "2021-01-10T18:05:00Z", tester = "Novatester", summary = "Lorem Ipsum", + state = PentestState.NEW, projectPentests = emptyList(), createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032" ) @@ -316,6 +329,7 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() { createdAt = "2021-01-10T18:05:00Z", tester = "Elliot", summary = "Lorem Ipsum", + state = PentestState.NEW, projectPentests = emptyList(), createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032" ) diff --git a/security-c4po-api/src/test/kotlin/com/securityc4po/api/project/ProjectControllerIntTest.kt b/security-c4po-api/src/test/kotlin/com/securityc4po/api/project/ProjectControllerIntTest.kt index fad7aac..7eebf2c 100644 --- a/security-c4po-api/src/test/kotlin/com/securityc4po/api/project/ProjectControllerIntTest.kt +++ b/security-c4po-api/src/test/kotlin/com/securityc4po/api/project/ProjectControllerIntTest.kt @@ -72,6 +72,7 @@ class ProjectControllerIntTest : BaseIntTest() { createdAt = "2021-01-10T18:05:00Z", tester = "Novatester", summary = "Lorem Ipsum", + state = PentestState.NEW, createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032" ) val projectTwo = Project( @@ -81,6 +82,7 @@ class ProjectControllerIntTest : BaseIntTest() { createdAt = "2021-01-10T18:05:00Z", tester = "Elliot", summary = "Lorem Ipsum", + state = PentestState.NEW, createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032" ) @@ -116,6 +118,7 @@ class ProjectControllerIntTest : BaseIntTest() { createdAt = "2021-04-10T18:05:00Z", tester = "Stipe", summary = "", + state = PentestState.NEW, createdBy = "a8891ad2-5cf5-4519-a89e-9ef8eec9e10c" ) } @@ -149,6 +152,7 @@ class ProjectControllerIntTest : BaseIntTest() { title = "CashMyData (iOS)", createdAt = "2021-01-10T18:05:00Z", tester = "Elliot", + state = PentestState.NEW, createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032" ) } @@ -175,6 +179,7 @@ class ProjectControllerIntTest : BaseIntTest() { title = "log4j Pentest_updated", createdAt = "2021-04-10T18:05:00Z", tester = "Stipe_updated", + state = PentestState.NEW, createdBy = "a8891ad2-5cf5-4519-a89e-9ef8eec9e10c" ) } @@ -188,6 +193,7 @@ class ProjectControllerIntTest : BaseIntTest() { createdAt = "2021-01-10T18:05:00Z", tester = "Novatester", summary = "Lorem Ipsum", + state = PentestState.NEW, createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032" ) val projectTwo = Project( @@ -197,6 +203,7 @@ class ProjectControllerIntTest : BaseIntTest() { createdAt = "2021-01-10T18:05:00Z", tester = "Elliot", summary = "Lorem Ipsum", + state = PentestState.NEW, createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032" ) // persist test data in database diff --git a/security-c4po-api/src/test/resources/collections/projects.json b/security-c4po-api/src/test/resources/collections/projects.json index 8e72b25..b94d9ed 100644 --- a/security-c4po-api/src/test/resources/collections/projects.json +++ b/security-c4po-api/src/test/resources/collections/projects.json @@ -3,7 +3,7 @@ "$oid": "6405d84a13ae975803a098fa" }, "lastModified": { - "$date": "2023-03-24T12:18:06.619Z" + "$date": "2023-04-04T13:39:00.146Z" }, "data": { "_id": "575dd9d4-cb3c-4df3-981e-8a18bf8dc1d2", @@ -12,6 +12,7 @@ "createdAt": "2023-03-06T12:10:50.835664Z", "tester": "Jojo", "summary": "This report includes an Executeive Summary, the rules in regards to the scope of the pentest and the choosen approach of the pentester.\nDio Stonemask Inc. contracted Jojo to perform a Penetration Test to identify security weaknesses,\ndetermine the impact to Dio Stonemask Inc., document all findings in a clear and repeatable manner,\nand provide remediation recommendations", + "state": "TRIAGED", "projectPentests": [ { "pentestId": "54f3ce12-784a-4e44-b9b3-0a986119ec50", @@ -250,7 +251,7 @@ "$oid": "6405e92813ae975803a09905" }, "lastModified": { - "$date": "2023-03-06T13:22:48.564Z" + "$date": "2023-03-29T19:04:32.771Z" }, "data": { "_id": "d6e83738-4251-44ac-ad40-21b360780c98", @@ -258,8 +259,14 @@ "title": "CashMyData (iOS)", "createdAt": "2023-03-06T13:22:48.564351Z", "tester": "Elliot", - "projectPentests": [], - "createdBy": "5f104d76-bd8d-4258-852a-d000c7f0666d" + "projectPentests": [ + { + "pentestId": "a666322d-688c-45b2-bf34-dd7020ee71ac", + "status": "COMPLETED" + } + ], + "createdBy": "5f104d76-bd8d-4258-852a-d000c7f0666d", + "state": "NEW" }, "_class": "com.securityc4po.api.project.ProjectEntity" }] \ No newline at end of file