feat: refactor project model in order to calculate progress

This commit is contained in:
mhg 2022-08-10 18:22:46 +02:00 committed by GitHub
parent 24dccb3e8f
commit 843ecdc3b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 177 additions and 93 deletions

View File

@ -1,16 +1,10 @@
# security-c4po
### Chief Innovator
> Daniel Mader
## Application Architecture
![alt architecture](./wiki/C4PO-Architecture.png)
### Project Leads
* Andreas Falk
* Christina Paule
### Developers
* Marcel Haag
* Norman Schmidt
* Stipe Knez
## Data Structure
![alt datastructure](./wiki/C4PO-Datastructure.png)
### Technical Requirements
* Docker / Docker-compose
@ -22,12 +16,6 @@
* mongoDB Compass
* Postman
## Application Architecture
![alt architecture](./wiki/C4PO-Architecture.png)
## Data Structure
![alt datastructure](./wiki/C4PO-Datastructure.png)
### Conventions
* Branch: `<initial>_c4po_<issuenumber>`
* Commit: `feat: <What was implemented?>` or `fix: <What got fixed?>`

View File

@ -9,7 +9,7 @@
.export-button-container {
display: flex;
align-content: flex-end;
margin-right: 1rem;
margin-right: 0.5rem;
.export-element-icon {
}

View File

@ -20,17 +20,14 @@ import {RouterModule} from '@angular/router';
import {FormsModule} from '@angular/forms';
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
import {FlexLayoutModule} from '@angular/flex-layout';
import {LoadingSpinnerComponent} from '@shared/widgets/loading-spinner/loading-spinner.component';
@NgModule({
declarations: [
PentestHeaderComponent,
PentestCategoriesComponent,
PentestTableComponent
],
exports: [
PentestHeaderComponent,
PentestCategoriesComponent,
PentestTableComponent
PentestTableComponent,
// LoadingSpinnerComponent
],
imports: [
CommonModule,
@ -52,6 +49,12 @@ import {FlexLayoutModule} from '@angular/flex-layout';
FontAwesomeModule,
FlexLayoutModule,
NbActionsModule
],
exports: [
PentestHeaderComponent,
PentestCategoriesComponent,
PentestTableComponent,
// LoadingSpinnerComponent
]
})
export class PentestOverviewModule {

View File

@ -48,8 +48,11 @@
</th>
<td nbTreeGridCell *nbTreeGridCellDef="let pentest">
<app-findig-widget [numberOfFindigs]="pentest.data['findings']"></app-findig-widget>
<!--{{pentest.data['findings'] || '-'}}-->
<!--ToDo: Add comments {{pentest.data['comments'] || '-'}}-->
</td>
</ng-container>
</table>
</nb-card>
<!--ToDo: Add loading spinner after routing fix to avoid circular dependency issues
<app-loading-spinner [isLoading$]="isLoading()" *ngIf="isLoading() | async"></app-loading-spinner>-->

View File

@ -5,8 +5,8 @@ import {PentestService} from '@shared/services/pentest.service';
import {Store} from '@ngxs/store';
import {PROJECT_STATE_NAME, ProjectState} from '@shared/stores/project-state/project-state';
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
import {catchError, switchMap} from 'rxjs/operators';
import {of} from 'rxjs';
import {catchError, switchMap, tap} from 'rxjs/operators';
import {BehaviorSubject, Observable, of} from 'rxjs';
import {getTitleKeyForRefNumber} from '@shared/functions/categories/get-title-key-for-ref-number.function';
import {Route} from '@shared/models/route.enum';
import {Router} from '@angular/router';
@ -20,6 +20,7 @@ import {ChangePentest} from '@shared/stores/project-state/project-state.actions'
})
export class PentestTableComponent implements OnInit {
loading$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
columns: Array<PentestColumns> = [PentestColumns.TEST_ID, PentestColumns.TITLE, PentestColumns.STATUS, PentestColumns.FINDINGS];
dataSource: NbTreeGridDataSource<PentestEntry>;
@ -47,14 +48,17 @@ export class PentestTableComponent implements OnInit {
loadPentestData(): void {
this.store.select(ProjectState.selectedCategory).pipe(
switchMap(category => this.pentestService.loadPentests(category)),
tap(() => this.loading$.next(true)),
catchError(_ => of(null)),
untilDestroyed(this)
).subscribe({
next: (pentests: Pentest[]) => {
this.data = transformPentestsToEntries(pentests);
this.dataSource.setData(this.data, this.getters);
this.loading$.next(false);
},
error: error => {
this.loading$.next(false);
console.error(error);
}
});
@ -78,6 +82,11 @@ export class PentestTableComponent implements OnInit {
getTitle(refNumber: string): string {
return getTitleKeyForRefNumber(refNumber);
}
// HTML only
isLoading(): Observable<boolean> {
return this.loading$.asObservable();
}
}
enum PentestColumns {

View File

@ -34,13 +34,20 @@
</span>
</nb-card-body>
<nb-card-footer>
<!--ToDo: Display correct progress of project-->
<div fxLayout="row" fxLayoutGap="1rem" fxLayoutAlign="start end">
<nb-progress-bar class="project-progress"
status="warning"
[value]="40"
[displayValue]="true">
</nb-progress-bar>
<div class="project-progress">
<nb-progress-bar *ngIf="project.testingProgress > 0; else altProgressBar"
status="warning"
[value]="project.testingProgress"
[displayValue]="true">
</nb-progress-bar>
<ng-template #altProgressBar>
{{'popup.info' | translate}} {{'global.no.progress' | translate}}
</ng-template>
</div>
<button nbButton
status="primary"
size="small"
@ -61,7 +68,7 @@
</div>
</div>
<div *ngIf="projects.getValue().length === 0 || !isLoading()" fxLayout="row" fxLayoutAlign="center center">
<div *ngIf="projects.getValue().length === 0 && loading$.getValue() === false" fxLayout="row" fxLayoutAlign="center center">
<p class="error-text">
{{'project.overview.no.projects' | translate}}
</p>

View File

@ -131,6 +131,7 @@ export class ProjectOverviewComponent implements OnInit {
});
}
// HTML only
isLoading(): Observable<boolean> {
return this.loading$.asObservable();
}

View File

@ -2,7 +2,7 @@ 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, NbMenuModule, NbProgressBarModule, NbSidebarModule, NbSpinnerModule} from '@nebular/theme';
import {NbButtonModule, NbCardModule, NbProgressBarModule, NbSpinnerModule} from '@nebular/theme';
import {FlexLayoutModule} from '@angular/flex-layout';
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
import {TranslateModule} from '@ngx-translate/core';

View File

@ -2,7 +2,7 @@ import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {RouterModule} from '@angular/router';
import {ProjectComponent} from './project.component';
import {NbCardModule, NbLayoutModule, NbMenuModule, NbSidebarModule} from '@nebular/theme';
import {NbCardModule, NbLayoutModule} from '@nebular/theme';
import {FlexLayoutModule} from '@angular/flex-layout';
import {TranslateModule} from '@ngx-translate/core';
import {ProjectDialogModule} from '@shared/modules/project-dialog/project-dialog.module';
@ -13,9 +13,6 @@ import {PentestOverviewModule} from '../../pentest-overview';
declarations: [
ProjectComponent
],
exports: [
ProjectComponent
],
imports: [
CommonModule,
NbCardModule,
@ -29,6 +26,9 @@ import {PentestOverviewModule} from '../../pentest-overview';
FlexLayoutModule,
ProjectDialogModule,
PentestOverviewModule
],
exports: [
ProjectComponent
]
})
export class ProjectModule {

View File

@ -11,7 +11,8 @@
"action.yes": "Ja",
"action.no": "Nein",
"username": "Nutzername",
"password": "Passwort"
"password": "Passwort",
"no.progress": "Kein Fortschritt"
},
"languageKeys":{
"de-DE": "Deutsch",

View File

@ -11,7 +11,8 @@
"action.yes": "Yes",
"action.no": "No",
"username": "Username",
"password": "Password"
"password": "Password",
"no.progress": "No progress"
},
"languageKeys":{
"de-DE": "German",

View File

@ -4,19 +4,22 @@ export class Project {
title: string;
createdAt: Date;
tester: string;
testingProgress: number;
createdBy: string;
constructor(id: string,
client: string,
title: string,
createdAt: Date,
tester?: string,
tester: string,
testingProgress: number,
createdBy?: string) {
this.id = id;
this.client = client;
this.title = title;
this.createdAt = createdAt;
this.tester = tester;
this.testingProgress = testingProgress;
this.createdBy = createdBy;
}
}

View File

@ -70,7 +70,7 @@
"header": [],
"body": {
"mode": "raw",
"raw": "{\n \"client\": \"Novatec\",\n \"title\": \"log4j pentest\",\n \"tester\" : \"Stipe\",\n \"createdBy\" : \"10e06d7a-8dd0-4ecd-8963-056b45079c4f\"\n}",
"raw": "{\n \"client\": \"Novatec\",\n \"title\": \"log4j pentest\",\n \"tester\" : \"Stipe\"\n}",
"options": {
"raw": {
"language": "json"
@ -142,7 +142,7 @@
"header": [],
"body": {
"mode": "raw",
"raw": "{\n \"client\": \"updatedProject\",\n \"title\": \"log4j pentest\",\n \"tester\" : \"Stipe\"\n}",
"raw": "{\n \"client\": \"Dio Stonemask Inc.\",\n \"title\": \"log4jj bizarre adventure\",\n \"tester\" : \"Jojo\"\n}",
"options": {
"raw": {
"language": "json"
@ -150,7 +150,7 @@
}
},
"url": {
"raw": "http://localhost:8443/projects/f2738715-4005-4aca-8d34-27ce9b8efffe",
"raw": "http://localhost:8443/projects/5a4f126c-9471-43b8-80b9-6eb02b7c35d0",
"protocol": "http",
"host": [
"localhost"
@ -158,7 +158,7 @@
"port": "8443",
"path": [
"projects",
"f2738715-4005-4aca-8d34-27ce9b8efffe"
"5a4f126c-9471-43b8-80b9-6eb02b7c35d0"
]
}
},
@ -261,10 +261,24 @@
{
"name": "getPentestsByProjectIdAndCategory",
"request": {
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICItdG1lbEV0ZHhGTnRSMW9aNXlRdE5jaFFpX0RVN2VNeV9YcU44aXY0S3hzIn0.eyJleHAiOjE2NjAxNDI5NjMsImlhdCI6MTY2MDE0MjY2MywianRpIjoiNzk2YzY5NzYtZjBlYS00ZTM0LTk2MTItMjI5ZmE0ODgzOTM0IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4ODg4L2F1dGgvcmVhbG1zL2M0cG9fcmVhbG1fbG9jYWwiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiMTBlMDZkN2EtOGRkMC00ZWNkLTg5NjMtMDU2YjQ1MDc5YzRmIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoiYzRwb19sb2NhbCIsInNlc3Npb25fc3RhdGUiOiIyYWU1MmQyYy01MjA5LTQzMjEtOWY5OS0wMTQ2YjRkMmNkY2YiLCJhY3IiOiIxIiwiYWxsb3dlZC1vcmlnaW5zIjpbIioiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbImM0cG9fdXNlciIsIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJjNHBvX2xvY2FsIjp7InJvbGVzIjpbInVzZXIiXX0sImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoicHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwibmFtZSI6InRlc3QgdXNlciIsInByZWZlcnJlZF91c2VybmFtZSI6InR0dCIsImdpdmVuX25hbWUiOiJ0ZXN0IiwiZmFtaWx5X25hbWUiOiJ1c2VyIn0.EO5CC1VXZzybIx-lndq3b61TZpWOnYDI4F2CUFuxj5ECxrlIfm_tlv0TbErDTX311YsA_nhzNHYSaffRzx0OkmmUKSyyH8k9aPRKXUTUmY7Y9PLv3UCKEmAFHAnJkr5kZV08g3UMYG2blpryYBg82abEVMxeMUbh-T4M-Z9dcgQyiZ4nyNMUs1bbfH_2kAtqfEXmP_9eZ42Kwa2ixFWFZDcvOp775bjkYcGvwSnHqmyBXivONzTxyPN6Ug7uFCvMTbeo10ctgOFfXJUZfoxRt-hCspTPJR8C4TzIK41fiy19uRpGjeezG5Ghwy9upXsomunwB4knTAn1otmj4afIxw",
"type": "string"
},
{
"key": "undefined",
"type": "any"
}
]
},
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:8443/pentests?projectId=8bc16303-f652-418a-b745-8a03d89356fb&category=INFORMATION_GATHERING",
"raw": "http://localhost:8443/pentests?projectId=5a4f126c-9471-43b8-80b9-6eb02b7c35d0&category=INFORMATION_GATHERING",
"protocol": "http",
"host": [
"localhost"
@ -276,7 +290,7 @@
"query": [
{
"key": "projectId",
"value": "8bc16303-f652-418a-b745-8a03d89356fb"
"value": "5a4f126c-9471-43b8-80b9-6eb02b7c35d0"
},
{
"key": "category",

View File

@ -12,8 +12,8 @@ data class Pentest(
val title: String,
val refNumber: String,
val status: PentestStatus,
val findingIds: String,
val commentIds: String
val findingIds: List<String> = emptyList(),
val commentIds: List<String> = emptyList()
)
fun Pentest.toPentestResponseBody(): ResponseBody {

View File

@ -2,7 +2,10 @@ package com.securityc4po.api.project
import com.fasterxml.jackson.annotation.JsonFormat
import com.securityc4po.api.ResponseBody
import com.securityc4po.api.pentest.PentestStatus
import org.springframework.data.mongodb.core.index.Indexed
import java.math.RoundingMode
import java.text.DecimalFormat
import java.time.Instant
import java.util.UUID
@ -14,6 +17,7 @@ data class Project(
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssZ")
val createdAt: String = Instant.now().toString(),
val tester: String? = null,
val projectPentests: List<ProjectPentest> = emptyList(),
val createdBy: String
)
@ -24,6 +28,7 @@ fun buildProject(body: ProjectRequestBody, projectEntity: ProjectEntity): Projec
title = body.title,
createdAt = projectEntity.data.createdAt,
tester = body.tester,
projectPentests = projectEntity.data.projectPentests,
createdBy = projectEntity.data.createdBy
)
}
@ -35,6 +40,8 @@ fun Project.toProjectResponseBody(): ResponseBody {
"title" to title,
"createdAt" to createdAt,
"tester" to tester,
/* ToDo: Calculate percentage in BE type: float */
"testingProgress" to calculateProgress(),
"createdBy" to createdBy
)
}
@ -45,16 +52,31 @@ fun Project.toProjectDeleteResponseBody(): ResponseBody {
)
}
fun Project.calculateProgress(): Float {
// Total number of pentests listet in the OWASP testing guide
// https://owasp.org/www-project-web-security-testing-guide/assets/archive/OWASP_Testing_Guide_v4.pdf
val TOTALPENTESTS = 95
return if (projectPentests.isEmpty())
0F
else {
var completedPentests = 0
projectPentests.forEach { projectPentest ->
if (projectPentest.status == PentestStatus.TRIAGED) {
completedPentests++
}
}
val df = DecimalFormat("#.##")
df.roundingMode = RoundingMode.DOWN
val progress = completedPentests / TOTALPENTESTS
df.format(progress).toFloat()
}
}
data class ProjectOverview(
val projects: List<Project>
)
fun ProjectOverview.toProjectOverviewResponseBody(): ResponseBody {
return mapOf(
"projects" to projects
)
}
data class ProjectRequestBody(
val client: String,
val title: String,

View File

@ -30,7 +30,8 @@ class ProjectController(private val projectService: ProjectService) {
it.toProjectResponseBody()
}
}.map {
ResponseEntity.ok(it)
if (it.isEmpty()) ResponseEntity.noContent().build()
else ResponseEntity.ok(it)
}
}

View File

@ -18,6 +18,7 @@ fun ProjectEntity.toProject() : Project {
this.data.title,
this.data.createdAt,
this.data.tester,
this.data.projectPentests,
this.data.createdBy
)
}

View File

@ -0,0 +1,8 @@
package com.securityc4po.api.project
import com.securityc4po.api.pentest.PentestStatus
data class ProjectPentest(
val pentestId: String,
val status: PentestStatus
)

View File

@ -102,8 +102,10 @@ class ProjectService(private val projectRepository: ProjectRepository) {
)
)
return projectRepository.findProjectById(id).switchIfEmpty{
logger.info("Project with id $id not found. Updating not possible.")
Mono.empty()
logger.warn("Project with id $id not found. Updating not possible.")
val msg = "Project with id $id not found."
val ex = EntityNotFoundException(msg, Errorcode.ProjectNotFound)
throw ex
}.flatMap{projectEntity: ProjectEntity ->
projectEntity.lastModified = Instant.now()
projectEntity.data = buildProject(body, projectEntity)
@ -120,4 +122,15 @@ class ProjectService(private val projectRepository: ProjectRepository) {
}
}
}
/**
* Update testing progress of [Project]
*
* @throws [TransactionInterruptedException] if the [Project] could not be updated
* @return updated list of [ProjectPentest]s
*/
fun updateProjectTestingProgress(projectId: String, projectPentests: ProjectPentest)/*: Mono<List<ProjectPentest>>*/ {
// ToDo: update Project Entity with progress
}
}

View File

@ -97,8 +97,8 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
title = "Search engine discovery/reconnaissance",
refNumber = "OTG-INFO-001",
status = PentestStatus.NOT_STARTED,
findingIds = "",
commentIds = ""
findingIds = emptyList(),
commentIds = emptyList()
)
private val pentestTwo = Pentest(
id = "43fbc63c-f624-11ec-b939-0242ac120002",
@ -107,8 +107,8 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
title = "Fingerprint Web Server",
refNumber = "OTG-INFO-002",
status = PentestStatus.REPORTED,
findingIds = "",
commentIds = ""
findingIds = emptyList(),
commentIds = emptyList()
)
private fun getProjectsResponse() = listOf(
@ -126,8 +126,8 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
title = "Search engine discovery/reconnaissance",
refNumber = "OTG-INFO-001",
status = PentestStatus.NOT_STARTED,
findingIds = "",
commentIds = ""
findingIds = emptyList(),
commentIds = emptyList()
)
val pentestTwo = Pentest(
id = "43fbc63c-f624-11ec-b939-0242ac120002",
@ -136,8 +136,8 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
title = "Fingerprint Web Server",
refNumber = "OTG-INFO-002",
status = PentestStatus.REPORTED,
findingIds = "",
commentIds = ""
findingIds = emptyList(),
commentIds = emptyList()
)
val pentestThree = Pentest(
id = "74eae112-f62c-11ec-b939-0242ac120002",
@ -146,8 +146,8 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
title = "Testing for Credentials Transported over an Encrypted Channel",
refNumber = "OTG-AUTHN-001",
status = PentestStatus.CHECKED,
findingIds = "",
commentIds = ""
findingIds = emptyList(),
commentIds = emptyList()
)
// persist test data in database
mongoTemplate.save(PentestEntity(pentestOne))

View File

@ -72,8 +72,8 @@ class PentestControllerIntTest : BaseIntTest() {
title = "Search engine discovery/reconnaissance",
refNumber = "OTG-INFO-001",
status = PentestStatus.NOT_STARTED,
findingIds = "",
commentIds = ""
findingIds = emptyList(),
commentIds = emptyList()
)
private val pentestTwo = Pentest(
id = "43fbc63c-f624-11ec-b939-0242ac120002",
@ -82,8 +82,8 @@ class PentestControllerIntTest : BaseIntTest() {
title = "Fingerprint Web Server",
refNumber = "OTG-INFO-002",
status = PentestStatus.REPORTED,
findingIds = "",
commentIds = ""
findingIds = emptyList(),
commentIds = emptyList()
)
private fun getPentests() = listOf(
@ -101,8 +101,8 @@ class PentestControllerIntTest : BaseIntTest() {
title = "Search engine discovery/reconnaissance",
refNumber = "OTG-INFO-001",
status = PentestStatus.NOT_STARTED,
findingIds = "",
commentIds = ""
findingIds = emptyList(),
commentIds = emptyList()
)
val pentestTwo = Pentest(
id = "43fbc63c-f624-11ec-b939-0242ac120002",
@ -111,8 +111,8 @@ class PentestControllerIntTest : BaseIntTest() {
title = "Fingerprint Web Server",
refNumber = "OTG-INFO-002",
status = PentestStatus.REPORTED,
findingIds = "",
commentIds = ""
findingIds = emptyList(),
commentIds = emptyList()
)
val pentestThree = Pentest(
id = "74eae112-f62c-11ec-b939-0242ac120002",
@ -121,8 +121,8 @@ class PentestControllerIntTest : BaseIntTest() {
title = "Testing for Credentials Transported over an Encrypted Channel",
refNumber = "OTG-AUTHN-001",
status = PentestStatus.CHECKED,
findingIds = "",
commentIds = ""
findingIds = emptyList(),
commentIds = emptyList()
)
// persist test data in database
mongoTemplate.save(PentestEntity(pentestOne))

View File

@ -86,6 +86,7 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() {
title = "Some Mock API (v1.0) Scanning",
createdAt = "2021-01-10T18:05:00Z",
tester = "Novatester",
projectPentests = emptyList<ProjectPentest>(),
createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032"
)
val projectTwo = Project(
@ -94,6 +95,7 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() {
title = "CashMyData (iOS)",
createdAt = "2021-01-10T18:05:00Z",
tester = "Elliot",
projectPentests = emptyList<ProjectPentest>(),
createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032"
)
@ -218,6 +220,7 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() {
title = "Some Mock API (v1.0) Scanning",
createdAt = "2021-01-10T18:05:00Z",
tester = "Novatester",
projectPentests = emptyList<ProjectPentest>(),
createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032"
)
}
@ -268,6 +271,7 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() {
title = "log4j Pentest_updated",
createdAt = "2021-01-10T18:05:00Z",
tester = "Stipe_updated",
projectPentests = emptyList<ProjectPentest>(),
createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032"
)
}
@ -280,6 +284,7 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() {
title = "Some Mock API (v1.0) Scanning",
createdAt = "2021-01-10T18:05:00Z",
tester = "Novatester",
projectPentests = emptyList<ProjectPentest>(),
createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032"
)
val projectTwo = Project(
@ -288,6 +293,7 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() {
title = "CashMyData (iOS)",
createdAt = "2021-01-10T18:05:00Z",
tester = "Elliot",
projectPentests = emptyList<ProjectPentest>(),
createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032"
)
// persist test data in database

View File

@ -1,55 +1,58 @@
[{
"_id": {
"$oid": "62c4018f18f1f463ed1e11be"
"$oid": "62f3c50c7acde34f740ba737"
},
"lastModified": {
"$date": {
"$numberLong": "1657012623629"
"$numberLong": "1660142860140"
}
},
"data": {
"_id": "41051d0a-63ef-4290-b984-e6fbd736f218",
"_id": "5a4f126c-9471-43b8-80b9-6eb02b7c35d0",
"client": "E Corp",
"title": "Some Mock API (v1.0) Scanning",
"createdAt": "2022-07-05T09:17:03.629331Z",
"createdAt": "2022-08-10T14:47:40.140406Z",
"tester": "Novatester",
"createdBy": "ca447a34-cac3-495e-9295-0a5bf5de502a"
"projectPentests": [],
"createdBy": "3c4ae87f-0d56-4634-a824-b4883c403c8a"
},
"_class": "com.securityc4po.api.project.ProjectEntity"
},{
"_id": {
"$oid": "62c401b718f1f463ed1e11bf"
"$oid": "62f3c5317acde34f740ba738"
},
"lastModified": {
"$date": {
"$numberLong": "1657012663386"
"$numberLong": "1660142897912"
}
},
"data": {
"_id": "0fa17ddb-7094-4f9c-b295-3433244c32c2",
"_id": "42b8c0df-b70e-4526-8ed0-7c022195fe85",
"client": "Allsafe",
"title": "CashMyData (iOS)",
"createdAt": "2022-07-05T09:17:43.386782Z",
"createdAt": "2022-08-10T14:48:17.912592Z",
"tester": "Elliot",
"createdBy": "1ac9753a-5a62-4bf7-8412-6fde779ea33a"
"projectPentests": [],
"createdBy": "6740ad72-8f42-486a-bcf3-e057e6afb0de"
},
"_class": "com.securityc4po.api.project.ProjectEntity"
},{
"_id": {
"$oid": "62c401e318f1f463ed1e11c0"
"$oid": "62f3c5427acde34f740ba739"
},
"lastModified": {
"$date": {
"$numberLong": "1657012707557"
"$numberLong": "1660142914204"
}
},
"data": {
"_id": "85aa8d79-5899-4b68-894c-d07f3b168cd4",
"_id": "1120bfa1-0d2b-4e42-a209-0289a1256266",
"client": "Novatec",
"title": "Openspace log4J",
"createdAt": "2022-07-05T09:18:27.557740Z",
"createdAt": "2022-08-10T14:48:34.204234Z",
"tester": "mhg",
"createdBy": "3201f6f8-10a4-4826-9b49-b6bdef28b152"
"projectPentests": [],
"createdBy": "5a4a8032-0726-4851-a105-9f079c3989b9"
},
"_class": "com.securityc4po.api.project.ProjectEntity"
}]