From 58b1f0b57e35135f30ae21d4538e3ab4e361e27b Mon Sep 17 00:00:00 2001 From: Vladislav Frolov <50615459+Cheshiriks@users.noreply.github.com> Date: Fri, 19 Jan 2024 13:15:25 +0300 Subject: [PATCH 1/3] Added configuration for save db in cosv module (#2906) * Added configuration for save db in cosv module --- .../event/VulnerabilityMetadataListener.kt | 5 +- .../repository/ProjectProblemRepository.kt | 2 +- .../backend/service/ProjectProblemService.kt | 4 +- .../save/entities/cosv/VulnerabilityExt.kt | 2 +- .../entities/cosv/VulnerabilityMetadataDto.kt | 18 ++- .../com/saveourtool/save/entities/Comment.kt | 2 +- .../saveourtool/save/entities/Organization.kt | 3 + .../save/entities/OriginalLogin.kt | 2 + .../save/entities/ProjectProblem.kt | 9 +- .../com/saveourtool/save/entities/User.kt | 3 + .../cosv => entitiescosv}/CosvFile.kt | 5 +- .../cosv => entitiescosv}/CosvGeneratedId.kt | 2 +- .../LnkVulnerabilityMetadataTag.kt | 16 +-- .../LnkVulnerabilityMetadataUser.kt | 9 +- .../cosv => entitiescosv}/RawCosvFile.kt | 33 +++--- .../VulnerabilityMetadata.kt | 48 +++++--- .../VulnerabilityMetadataProject.kt | 2 +- .../VulnerabilityMetadataEvent.kt | 4 +- .../save/spring/entity/BaseEntityWithDate.kt | 3 + .../views/vuln/VulnerabilityBadge.kt | 12 +- .../vuln/VulnerabilityGeneralInfoProps.kt | 7 +- .../views/vuln/VulnerabilityHeader.kt | 9 +- .../views/vuln/VulnerabilityInfoTab.kt | 2 +- .../views/vuln/VulnerabilityTagsComponent.kt | 12 +- .../saveourtool/save/cosv/CosvApplication.kt | 2 +- .../save/cosv/CosvConfiguration.kt | 50 +++++++- .../save/cosv/configs/ConfigProperties.kt | 2 + .../PersistenceSaveAutoConfiguration.kt | 55 +++++++++ .../cosv/controllers/CommentController.kt | 109 ++++++++++++++++++ .../save/cosv/controllers/CosvController.kt | 3 +- .../cosv/controllers/RawCosvFileController.kt | 40 ++++--- .../save/cosv/event/CommentListener.kt | 12 +- .../cosv/repository/CosvFileRepository.kt | 2 +- .../repository/CosvGeneratedIdRepository.kt | 2 +- .../save/cosv/repository/CosvRepository.kt | 2 +- .../repository/CosvRepositoryInStorage.kt | 2 +- .../LnkVulnerabilityMetadataTagRepository.kt | 12 +- .../LnkVulnerabilityMetadataUserRepository.kt | 6 +- .../cosv/repository/RawCosvFileRepository.kt | 24 ++-- .../save/cosv/repository/UserRepository.kt | 37 ------ .../VulnerabilityMetadataProjectRepository.kt | 2 +- .../VulnerabilityMetadataRepository.kt | 3 +- .../cosv/repositorysave/CommentRepository.kt | 36 ++++++ .../NotificationRepository.kt | 2 +- .../OrganizationRepository.kt | 2 +- .../TagRepository.kt | 15 ++- .../cosv/repositorysave/UserRepository.kt | 96 +++++++++++++++ .../security/CommentPermissionEvaluator.kt | 42 +++++++ .../VulnerabilityPermissionEvaluator.kt | 4 +- .../save/cosv/service/CommentService.kt | 74 ++++++++++++ .../save/cosv/service/CosvService.kt | 39 ++++--- .../save/cosv/service/OrganizationService.kt | 10 +- .../save/cosv/service/TagService.kt | 17 +-- .../save/cosv/service/UserService.kt | 19 ++- .../service/VulnerabilityMetadataService.kt | 22 ++-- .../service/VulnerabilityRatingService.kt | 18 ++- .../save/cosv/service/VulnerabilityService.kt | 67 +++++++---- .../save/cosv/storage/CosvFileS3KeyManager.kt | 4 +- .../save/cosv/storage/CosvFileStorage.kt | 2 +- .../cosv/storage/RawCosvFileS3KeyManager.kt | 43 ++++--- .../save/cosv/storage/RawCosvFileStorage.kt | 34 +++--- .../main/resources/application-dev.properties | 4 + .../src/main/resources/application.properties | 3 +- .../views/vuln/VulnerabilityTableComponent.kt | 27 ++--- 64 files changed, 870 insertions(+), 289 deletions(-) rename save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/{entities/cosv => entitiescosv}/CosvFile.kt (85%) rename save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/{entities/cosv => entitiescosv}/CosvGeneratedId.kt (89%) rename save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/{entities/cosv => entitiescosv}/LnkVulnerabilityMetadataTag.kt (55%) rename save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/{entities/cosv => entitiescosv}/LnkVulnerabilityMetadataUser.kt (75%) rename save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/{entities/cosv => entitiescosv}/RawCosvFile.kt (72%) rename save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/{entities/cosv => entitiescosv}/VulnerabilityMetadata.kt (58%) rename save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/{entities/cosv => entitiescosv}/VulnerabilityMetadataProject.kt (96%) rename save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/{entities/cosv => entitiescosv}/evententities/VulnerabilityMetadataEvent.kt (53%) create mode 100644 save-cosv/src/main/kotlin/com/saveourtool/save/cosv/configs/PersistenceSaveAutoConfiguration.kt create mode 100644 save-cosv/src/main/kotlin/com/saveourtool/save/cosv/controllers/CommentController.kt delete mode 100644 save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/UserRepository.kt create mode 100644 save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repositorysave/CommentRepository.kt rename save-cosv/src/main/kotlin/com/saveourtool/save/cosv/{repository => repositorysave}/NotificationRepository.kt (94%) rename save-cosv/src/main/kotlin/com/saveourtool/save/cosv/{repository => repositorysave}/OrganizationRepository.kt (98%) rename save-cosv/src/main/kotlin/com/saveourtool/save/cosv/{repository => repositorysave}/TagRepository.kt (66%) create mode 100644 save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repositorysave/UserRepository.kt create mode 100644 save-cosv/src/main/kotlin/com/saveourtool/save/cosv/security/CommentPermissionEvaluator.kt create mode 100644 save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/CommentService.kt diff --git a/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/vulnerability/event/VulnerabilityMetadataListener.kt b/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/vulnerability/event/VulnerabilityMetadataListener.kt index 0fdd3bb072..5a6ae07e71 100644 --- a/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/vulnerability/event/VulnerabilityMetadataListener.kt +++ b/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/vulnerability/event/VulnerabilityMetadataListener.kt @@ -4,9 +4,10 @@ import com.saveourtool.save.backend.service.NotificationService import com.saveourtool.save.backend.service.UserDetailsService import com.saveourtool.save.domain.Role import com.saveourtool.save.entities.Notification -import com.saveourtool.save.entities.cosv.VulnerabilityMetadata -import com.saveourtool.save.entities.cosv.evententities.VulnerabilityMetadataEvent import com.saveourtool.save.entities.vulnerability.VulnerabilityStatus +import com.saveourtool.save.entitiescosv.VulnerabilityMetadata +import com.saveourtool.save.entitiescosv.evententities.VulnerabilityMetadataEvent + import org.springframework.context.event.EventListener import org.springframework.stereotype.Component diff --git a/save-backend/src/main/kotlin/com/saveourtool/save/backend/repository/ProjectProblemRepository.kt b/save-backend/src/main/kotlin/com/saveourtool/save/backend/repository/ProjectProblemRepository.kt index cfb39ef42c..5a53e72ecf 100644 --- a/save-backend/src/main/kotlin/com/saveourtool/save/backend/repository/ProjectProblemRepository.kt +++ b/save-backend/src/main/kotlin/com/saveourtool/save/backend/repository/ProjectProblemRepository.kt @@ -1,7 +1,7 @@ package com.saveourtool.save.backend.repository import com.saveourtool.save.entities.ProjectProblem -import com.saveourtool.save.entities.cosv.VulnerabilityMetadata +import com.saveourtool.save.entitiescosv.VulnerabilityMetadata import com.saveourtool.save.spring.repository.BaseEntityRepository import org.springframework.data.jpa.repository.Query import org.springframework.data.repository.query.Param diff --git a/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/ProjectProblemService.kt b/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/ProjectProblemService.kt index 3c62a5c2d0..9704559b24 100644 --- a/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/ProjectProblemService.kt +++ b/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/ProjectProblemService.kt @@ -55,7 +55,7 @@ class ProjectProblemService( name = problem.name, description = problem.description, critical = problem.critical, - vulnerabilityMetadata = vulnerabilityMetadata, + vulnerabilityMetadataId = vulnerabilityMetadata?.requiredId(), project = project, userId = user.requiredId(), isClosed = false, @@ -75,7 +75,7 @@ class ProjectProblemService( description = projectProblemDto.description critical = projectProblemDto.critical isClosed = projectProblemDto.isClosed - this.vulnerabilityMetadata = vulnerabilityMetadata + this.vulnerabilityMetadataId = vulnerabilityMetadata?.requiredId() } projectProblemRepository.save(problem) } diff --git a/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/entities/cosv/VulnerabilityExt.kt b/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/entities/cosv/VulnerabilityExt.kt index c1c063df9d..1c05c84620 100644 --- a/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/entities/cosv/VulnerabilityExt.kt +++ b/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/entities/cosv/VulnerabilityExt.kt @@ -13,7 +13,7 @@ import kotlinx.serialization.Serializable **/ @Serializable data class VulnerabilityExt( - val metadataDto: VulnerabilityMetadataDto, + val metadataDto: VulnerabilityMetadataDtoWithUserAndOrganization, val cosv: RawCosvSchema, val saveContributors: List, ) { diff --git a/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/entities/cosv/VulnerabilityMetadataDto.kt b/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/entities/cosv/VulnerabilityMetadataDto.kt index 536f2ef37e..8df682996a 100644 --- a/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/entities/cosv/VulnerabilityMetadataDto.kt +++ b/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/entities/cosv/VulnerabilityMetadataDto.kt @@ -1,3 +1,5 @@ +@file:Suppress("HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE") + package com.saveourtool.save.entities.cosv import com.saveourtool.save.entities.OrganizationDto @@ -14,8 +16,6 @@ import kotlinx.serialization.Serializable * @property severityNum [com.saveourtool.osv4k.Severity.scoreNum] * @property modified [com.saveourtool.osv4k.OsvSchema.modified] * @property submitted - * @property user - * @property organization * @property language * @property status * @property tags @@ -28,8 +28,6 @@ data class VulnerabilityMetadataDto( val severityNum: Float, val modified: LocalDateTime, val submitted: LocalDateTime, - val user: UserInfo, - val organization: OrganizationDto?, val language: VulnerabilityLanguage, val status: VulnerabilityStatus, val tags: Set = emptySet(), @@ -43,3 +41,15 @@ data class VulnerabilityMetadataDto( const val SUMMARY_LENGTH = 250 } } + +/** + * @property vulnerabilityMetadataDto + * @property user + * @property organization + **/ +@Serializable +data class VulnerabilityMetadataDtoWithUserAndOrganization( + val vulnerabilityMetadataDto: VulnerabilityMetadataDto, + val user: UserInfo, + val organization: OrganizationDto?, +) diff --git a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/Comment.kt b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/Comment.kt index eb298d1fb1..b08b1cdde5 100644 --- a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/Comment.kt +++ b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/Comment.kt @@ -15,7 +15,7 @@ import kotlinx.datetime.toKotlinLocalDateTime * @property user */ @Entity -@Table(name = "comments") +@Table(schema = "save_cloud", name = "comments") class Comment( var message: String, diff --git a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/Organization.kt b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/Organization.kt index 2e5aeaab0d..fad9835e11 100644 --- a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/Organization.kt +++ b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/Organization.kt @@ -27,10 +27,13 @@ data class Organization( @Enumerated(EnumType.STRING) var status: OrganizationStatus, @Contextual + @Column(name = "date_created") var dateCreated: LocalDateTime, var avatar: String? = null, var description: String? = null, + @Column(name = "can_create_contests") var canCreateContests: Boolean = false, + @Column(name = "can_bulk_upload") var canBulkUpload: Boolean = false, var rating: Long = 0, ) : BaseEntityWithDto() { diff --git a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/OriginalLogin.kt b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/OriginalLogin.kt index 44433d4687..30bb3260e6 100644 --- a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/OriginalLogin.kt +++ b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/OriginalLogin.kt @@ -7,6 +7,7 @@ import com.fasterxml.jackson.annotation.JsonBackReference import javax.persistence.Entity import javax.persistence.JoinColumn import javax.persistence.ManyToOne +import javax.persistence.Table /** * @property name @@ -14,6 +15,7 @@ import javax.persistence.ManyToOne * @property source */ @Entity +@Table(schema = "save_cloud", name = "original_login") class OriginalLogin( var name: String, @ManyToOne diff --git a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/ProjectProblem.kt b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/ProjectProblem.kt index 90d22cc4ec..a378befcf9 100644 --- a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/ProjectProblem.kt +++ b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/ProjectProblem.kt @@ -1,6 +1,5 @@ package com.saveourtool.save.entities -import com.saveourtool.save.entities.cosv.VulnerabilityMetadata import com.saveourtool.save.spring.entity.BaseEntityWithDateAndDto import javax.persistence.* @@ -8,7 +7,7 @@ import javax.persistence.* * @property name * @property description * @property critical - * @property vulnerabilityMetadata + * @property vulnerabilityMetadataId * @property project * @property userId * @property isClosed @@ -24,9 +23,7 @@ class ProjectProblem( @Enumerated(EnumType.STRING) var critical: ProjectProblemCritical, - @ManyToOne - @JoinColumn(name = "vulnerability_metadata_id") - var vulnerabilityMetadata: VulnerabilityMetadata?, + var vulnerabilityMetadataId: Long?, @ManyToOne @JoinColumn(name = "project_id") @@ -41,7 +38,7 @@ class ProjectProblem( name = name, description = description, critical = critical, - identifier = vulnerabilityMetadata?.identifier, + identifier = "", organizationName = project.organization.name, projectName = project.name, isClosed = isClosed, diff --git a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/User.kt b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/User.kt index fcaab15bb2..2b18c0d3c7 100644 --- a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/User.kt +++ b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/User.kt @@ -41,6 +41,7 @@ class User( var company: String? = null, var location: String? = null, var linkedin: String? = null, + @Column(name = "git_hub") var gitHub: String? = null, var twitter: String? = null, @Enumerated(EnumType.STRING) @@ -54,7 +55,9 @@ class User( var originalLogins: List = emptyList(), var rating: Long = 0, var website: String? = null, + @Column(name = "free_text") var freeText: String? = null, + @Column(name = "real_name") var realName: String? = null, ) : BaseEntityWithDate() { /** diff --git a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/CosvFile.kt b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/CosvFile.kt similarity index 85% rename from save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/CosvFile.kt rename to save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/CosvFile.kt index 5d1efb5b2c..cf0cf8e370 100644 --- a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/CosvFile.kt +++ b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/CosvFile.kt @@ -1,11 +1,13 @@ -package com.saveourtool.save.entities.cosv +package com.saveourtool.save.entitiescosv +import com.saveourtool.save.entities.cosv.CosvFileDto import com.saveourtool.save.spring.entity.BaseEntity import java.time.LocalDateTime import javax.persistence.Entity import javax.persistence.JoinColumn import javax.persistence.OneToOne +import javax.persistence.Table import kotlinx.datetime.toKotlinLocalDateTime @@ -16,6 +18,7 @@ import kotlinx.datetime.toKotlinLocalDateTime * @property prevCosvFile */ @Entity +@Table(name = "cosv_file") class CosvFile( var identifier: String, var modified: LocalDateTime, diff --git a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/CosvGeneratedId.kt b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/CosvGeneratedId.kt similarity index 89% rename from save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/CosvGeneratedId.kt rename to save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/CosvGeneratedId.kt index fbd09929be..613f48642c 100644 --- a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/CosvGeneratedId.kt +++ b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/CosvGeneratedId.kt @@ -1,4 +1,4 @@ -package com.saveourtool.save.entities.cosv +package com.saveourtool.save.entitiescosv import com.saveourtool.save.spring.entity.BaseEntityWithDate import javax.persistence.Entity diff --git a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/LnkVulnerabilityMetadataTag.kt b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/LnkVulnerabilityMetadataTag.kt similarity index 55% rename from save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/LnkVulnerabilityMetadataTag.kt rename to save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/LnkVulnerabilityMetadataTag.kt index 4e08c61d2a..d30938cd26 100644 --- a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/LnkVulnerabilityMetadataTag.kt +++ b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/LnkVulnerabilityMetadataTag.kt @@ -1,26 +1,22 @@ -package com.saveourtool.save.entities.cosv +package com.saveourtool.save.entitiescosv -import com.saveourtool.save.entities.Tag import com.saveourtool.save.spring.entity.BaseEntity import com.fasterxml.jackson.annotation.JsonBackReference - -import javax.persistence.Entity -import javax.persistence.JoinColumn -import javax.persistence.ManyToOne +import javax.persistence.* /** * @property vulnerabilityMetadata [VulnerabilityMetadata] - * @property tag [Tag] associated with [vulnerabilityMetadata] + * @property tagId associated with [vulnerabilityMetadata] */ @Entity +@Table(schema = "cosv", name = "lnk_vulnerability_metadata_tag") class LnkVulnerabilityMetadataTag( @ManyToOne @JoinColumn(name = "vulnerability_metadata_id") @JsonBackReference var vulnerabilityMetadata: VulnerabilityMetadata, - @ManyToOne - @JoinColumn(name = "tag_id") - var tag: Tag, + @Column(name = "tag_id") + var tagId: Long, ) : BaseEntity() diff --git a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/LnkVulnerabilityMetadataUser.kt b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/LnkVulnerabilityMetadataUser.kt similarity index 75% rename from save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/LnkVulnerabilityMetadataUser.kt rename to save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/LnkVulnerabilityMetadataUser.kt index 10612888ea..738fbb4857 100644 --- a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/LnkVulnerabilityMetadataUser.kt +++ b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/LnkVulnerabilityMetadataUser.kt @@ -1,12 +1,11 @@ -package com.saveourtool.save.entities.cosv +package com.saveourtool.save.entitiescosv -import com.saveourtool.save.entities.User import com.saveourtool.save.spring.entity.BaseEntity import javax.persistence.* /** * @property vulnerabilityMetadataId - * @property user in vulnerability with [vulnerabilityMetadataId] + * @property userId in vulnerability with [vulnerabilityMetadataId] */ @Entity @Suppress("KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT") @@ -17,8 +16,6 @@ class LnkVulnerabilityMetadataUser( var vulnerabilityMetadataId: Long, - @ManyToOne - @JoinColumn(name = "user_id") - var user: User, + var userId: Long, ) : BaseEntity() diff --git a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/RawCosvFile.kt b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/RawCosvFile.kt similarity index 72% rename from save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/RawCosvFile.kt rename to save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/RawCosvFile.kt index 48a6bb9a60..bbdc4d3be8 100644 --- a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/RawCosvFile.kt +++ b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/RawCosvFile.kt @@ -1,7 +1,7 @@ -package com.saveourtool.save.entities.cosv +package com.saveourtool.save.entitiescosv -import com.saveourtool.save.entities.Organization -import com.saveourtool.save.entities.User +import com.saveourtool.save.entities.cosv.RawCosvFileDto +import com.saveourtool.save.entities.cosv.RawCosvFileStatus import com.saveourtool.save.spring.entity.BaseEntityWithDtoWithId import com.saveourtool.save.spring.entity.IBaseEntityWithDate import com.saveourtool.save.utils.ZIP_ARCHIVE_EXTENSION @@ -17,25 +17,24 @@ import kotlinx.datetime.toKotlinLocalDateTime * Entity for table `raw_cosv_file` * * @property fileName - * @property user - * @property organization * @property status * @property statusMessage * @property contentLength * @property createDate * @property updateDate * @property isZip + * @property userId + * @property organizationId */ @Entity +@Table(schema = "cosv", name = "raw_cosv_file") @Suppress("LongParameterList") class RawCosvFile( var fileName: String, - @ManyToOne - @JoinColumn(name = "user_id") - var user: User, - @ManyToOne - @JoinColumn(name = "organization_id") - var organization: Organization, + @Column(name = "user_id") + var userId: Long, + @Column(name = "organization_id") + var organizationId: Long, @Enumerated(EnumType.STRING) var status: RawCosvFileStatus, @Formula("LOWER(file_name) LIKE '%_$ZIP_ARCHIVE_EXTENSION'") @@ -47,8 +46,8 @@ class RawCosvFile( ) : BaseEntityWithDtoWithId(), IBaseEntityWithDate { override fun toDto(): RawCosvFileDto = RawCosvFileDto( fileName = fileName, - userName = user.name, - organizationName = organization.name, + userName = "", + organizationName = "", status = status, statusMessage = statusMessage, contentLength = contentLength, @@ -63,12 +62,12 @@ class RawCosvFile( * @return [RawCosvFile] from [RawCosvFileDto] */ fun RawCosvFileDto.toNewEntity( - userResolver: (String) -> User, - organizationResolver: (String) -> Organization, + userResolver: (String) -> Long, + organizationResolver: (String) -> Long, ): RawCosvFile = RawCosvFile( fileName = fileName, - user = userResolver(userName), - organization = organizationResolver(organizationName), + userId = userResolver(userName), + organizationId = organizationResolver(organizationName), status = status, contentLength = contentLength, ) diff --git a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/VulnerabilityMetadata.kt b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/VulnerabilityMetadata.kt similarity index 58% rename from save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/VulnerabilityMetadata.kt rename to save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/VulnerabilityMetadata.kt index d14f8632a2..ad50c436d6 100644 --- a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/VulnerabilityMetadata.kt +++ b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/VulnerabilityMetadata.kt @@ -1,10 +1,12 @@ -package com.saveourtool.save.entities.cosv +package com.saveourtool.save.entitiescosv -import com.saveourtool.save.entities.Organization -import com.saveourtool.save.entities.User +import com.saveourtool.save.entities.OrganizationDto +import com.saveourtool.save.entities.cosv.VulnerabilityMetadataDto import com.saveourtool.save.entities.cosv.VulnerabilityMetadataDto.Companion.SUMMARY_LENGTH +import com.saveourtool.save.entities.cosv.VulnerabilityMetadataDtoWithUserAndOrganization import com.saveourtool.save.entities.vulnerability.VulnerabilityLanguage import com.saveourtool.save.entities.vulnerability.VulnerabilityStatus +import com.saveourtool.save.info.UserInfo import com.saveourtool.save.spring.entity.BaseEntityWithDto import java.time.LocalDateTime @@ -19,8 +21,8 @@ import kotlinx.datetime.toKotlinLocalDateTime * @property severityNum [com.saveourtool.osv4k.Severity.scoreNum] * @property modified [com.saveourtool.osv4k.OsvSchema.modified] * @property submitted when vulnerability submitted to saveourtool platform - * @property user [User] who uploaded COSV to save - * @property organization [Organization] to which COSV was uploaded + * @property userId id of user who uploaded COSV to save + * @property organizationId id of organization to which COSV was uploaded * @property language * @property status * @property latestCosvFile @@ -33,6 +35,7 @@ class VulnerabilityMetadata( @Column(length = SUMMARY_LENGTH) var summary: String, var details: String, + @Column(name = "severity_num") var severityNum: Float, var modified: LocalDateTime, var submitted: LocalDateTime, @@ -40,12 +43,10 @@ class VulnerabilityMetadata( var language: VulnerabilityLanguage, @Enumerated(EnumType.STRING) var status: VulnerabilityStatus, - @ManyToOne - @JoinColumn(name = "user_id") - var user: User, - @ManyToOne - @JoinColumn(name = "organization_id") - var organization: Organization?, + @Column(name = "user_id") + var userId: Long, + @Column(name = "organization_id") + var organizationId: Long?, @OneToOne @JoinColumn(name = "latest_cosv_file_id") var latestCosvFile: CosvFile, @@ -57,9 +58,30 @@ class VulnerabilityMetadata( severityNum = severityNum, modified = modified.toKotlinLocalDateTime(), submitted = submitted.toKotlinLocalDateTime(), - user = user.toUserInfo(), - organization = organization?.toDto(), language = language, status = status, ) + + /** + * @param user + * @param organization + * @return VulnerabilityMetadataDtoWithUserAndOrganization + */ + fun toDtoWithUserAndOrganization( + user: UserInfo, + organization: OrganizationDto?, + ): VulnerabilityMetadataDtoWithUserAndOrganization = VulnerabilityMetadataDtoWithUserAndOrganization( + VulnerabilityMetadataDto( + identifier = identifier, + summary = summary, + details = details, + severityNum = severityNum, + modified = modified.toKotlinLocalDateTime(), + submitted = submitted.toKotlinLocalDateTime(), + language = language, + status = status, + ), + user = user, + organization = organization, + ) } diff --git a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/VulnerabilityMetadataProject.kt b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/VulnerabilityMetadataProject.kt similarity index 96% rename from save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/VulnerabilityMetadataProject.kt rename to save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/VulnerabilityMetadataProject.kt index 908c824206..91bcc3de7d 100644 --- a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/VulnerabilityMetadataProject.kt +++ b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/VulnerabilityMetadataProject.kt @@ -1,4 +1,4 @@ -package com.saveourtool.save.entities.cosv +package com.saveourtool.save.entitiescosv import com.saveourtool.save.entities.vulnerability.VulnerabilityProjectDto import com.saveourtool.save.entities.vulnerability.VulnerabilityProjectType diff --git a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/evententities/VulnerabilityMetadataEvent.kt b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/evententities/VulnerabilityMetadataEvent.kt similarity index 53% rename from save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/evententities/VulnerabilityMetadataEvent.kt rename to save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/evententities/VulnerabilityMetadataEvent.kt index cd2ee90db2..3acf01306b 100644 --- a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entities/cosv/evententities/VulnerabilityMetadataEvent.kt +++ b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/entitiescosv/evententities/VulnerabilityMetadataEvent.kt @@ -1,6 +1,6 @@ -package com.saveourtool.save.entities.cosv.evententities +package com.saveourtool.save.entitiescosv.evententities -import com.saveourtool.save.entities.cosv.VulnerabilityMetadata +import com.saveourtool.save.entitiescosv.VulnerabilityMetadata /** * @property vulnerabilityMetadata diff --git a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/spring/entity/BaseEntityWithDate.kt b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/spring/entity/BaseEntityWithDate.kt index b88ead5975..10c13fe702 100644 --- a/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/spring/entity/BaseEntityWithDate.kt +++ b/save-cloud-common/src/jvmMain/kotlin/com/saveourtool/save/spring/entity/BaseEntityWithDate.kt @@ -2,6 +2,7 @@ package com.saveourtool.save.spring.entity import com.saveourtool.save.listeners.DateListener import java.time.LocalDateTime +import javax.persistence.Column import javax.persistence.EntityListeners import javax.persistence.MappedSuperclass @@ -15,10 +16,12 @@ abstract class BaseEntityWithDate : BaseEntity(), IBaseEntityWithDate { /** * Create date of entity **/ + @Column(name = "create_date") override var createDate: LocalDateTime? = null /** * Update date of entity **/ + @Column(name = "update_date") override var updateDate: LocalDateTime? = null } diff --git a/save-cosv-frontend/src/main/kotlin/com/saveourtool/save/cosv/frontend/components/views/vuln/VulnerabilityBadge.kt b/save-cosv-frontend/src/main/kotlin/com/saveourtool/save/cosv/frontend/components/views/vuln/VulnerabilityBadge.kt index cae28cb4a2..3dd4250607 100644 --- a/save-cosv-frontend/src/main/kotlin/com/saveourtool/save/cosv/frontend/components/views/vuln/VulnerabilityBadge.kt +++ b/save-cosv-frontend/src/main/kotlin/com/saveourtool/save/cosv/frontend/components/views/vuln/VulnerabilityBadge.kt @@ -34,7 +34,7 @@ private const val MAX_VALUE = 10.0f val vulnerabilityBadge: FC = FC { props -> val (t) = useTranslation("vulnerability") - val severityNum = props.vulnerability.metadataDto.severityNum + val severityNum = props.vulnerability.metadataDto.vulnerabilityMetadataDto.severityNum val cvssCalculatorWindowOpenness = useWindowOpenness() @Suppress("EMPTY_BLOCK_STRUCTURE_ERROR") @@ -65,10 +65,13 @@ val vulnerabilityBadge: FC = FC { props -> ) ) + val vulnerabilityMetadataDto = props.vulnerability.metadataDto.vulnerabilityMetadataDto props.setVulnerability { it?.copy( cosv = props.vulnerability.cosv.copy(severity = severityList.toList()), - metadataDto = props.vulnerability.metadataDto.copy(severityNum = cvssVector.calculateBaseScore()) + metadataDto = props.vulnerability.metadataDto.copy( + vulnerabilityMetadataDto = vulnerabilityMetadataDto.copy(severityNum = cvssVector.calculateBaseScore()) + ) ) } } ?: run { @@ -79,10 +82,13 @@ val vulnerabilityBadge: FC = FC { props -> scoreNum = cvssVector.calculateBaseScore().toString(), )) + val vulnerabilityMetadataDto = props.vulnerability.metadataDto.vulnerabilityMetadataDto props.setVulnerability { it?.copy( cosv = props.vulnerability.cosv.copy(severity = severityList), - metadataDto = props.vulnerability.metadataDto.copy(severityNum = cvssVector.calculateBaseScore()) + metadataDto = props.vulnerability.metadataDto.copy( + vulnerabilityMetadataDto = vulnerabilityMetadataDto.copy(severityNum = cvssVector.calculateBaseScore()) + ) ) } } diff --git a/save-cosv-frontend/src/main/kotlin/com/saveourtool/save/cosv/frontend/components/views/vuln/VulnerabilityGeneralInfoProps.kt b/save-cosv-frontend/src/main/kotlin/com/saveourtool/save/cosv/frontend/components/views/vuln/VulnerabilityGeneralInfoProps.kt index 9404164939..f4befae9fd 100644 --- a/save-cosv-frontend/src/main/kotlin/com/saveourtool/save/cosv/frontend/components/views/vuln/VulnerabilityGeneralInfoProps.kt +++ b/save-cosv-frontend/src/main/kotlin/com/saveourtool/save/cosv/frontend/components/views/vuln/VulnerabilityGeneralInfoProps.kt @@ -97,7 +97,7 @@ val vulnerabilityGeneralInfoProps: FC = FC { prop // ================= summary =================== textarea { className = ClassName("auto_height form-control-plaintext px-2 pt-0 pb-0 text-gray-900") - value = cosv.summary ?: props.vulnerability.metadataDto.summary + value = cosv.summary ?: props.vulnerability.metadataDto.vulnerabilityMetadataDto.summary disabled = props.isEditDisabled rows = 2 if (!props.isEditDisabled) { @@ -267,7 +267,7 @@ val vulnerabilityGeneralInfoProps: FC = FC { prop // ================= tags =================== - if (!props.isEditDisabled || props.vulnerability.metadataDto.tags.isNotEmpty()) { + if (!props.isEditDisabled || props.vulnerability.metadataDto.vulnerabilityMetadataDto.tags.isNotEmpty()) { hr { } h6 { className = ClassName("font-weight-bold text-primary-blue mb-4") @@ -532,7 +532,8 @@ private fun List.mergeContactsForOneUser() = this */ private fun hasRightsToEdit(currentUserInfo: UserInfo?, vulnerability: VulnerabilityExt): Boolean = currentUserInfo?.isSuperAdmin() == true || ((currentUserInfo?.name == vulnerability.metadataDto.user.name || - currentUserInfo?.name in vulnerability.getAllParticipants().map { it.name }) && vulnerability.metadataDto.status != VulnerabilityStatus.APPROVED) + currentUserInfo?.name in vulnerability.getAllParticipants().map { it.name }) && + vulnerability.metadataDto.vulnerabilityMetadataDto.status != VulnerabilityStatus.APPROVED) private fun updateCredits( cosvCredits: List, diff --git a/save-cosv-frontend/src/main/kotlin/com/saveourtool/save/cosv/frontend/components/views/vuln/VulnerabilityHeader.kt b/save-cosv-frontend/src/main/kotlin/com/saveourtool/save/cosv/frontend/components/views/vuln/VulnerabilityHeader.kt index c9be4c69c5..d542fabcd3 100644 --- a/save-cosv-frontend/src/main/kotlin/com/saveourtool/save/cosv/frontend/components/views/vuln/VulnerabilityHeader.kt +++ b/save-cosv-frontend/src/main/kotlin/com/saveourtool/save/cosv/frontend/components/views/vuln/VulnerabilityHeader.kt @@ -206,7 +206,8 @@ internal val headerMenu: FC = FC { props -> height = HEADER_HEIGHT.unsafeCast() } - when (props.vulnerability.metadataDto.status) { + val status = props.vulnerability.metadataDto.vulnerabilityMetadataDto.status + when (status) { VulnerabilityStatus.APPROVED -> div { className = ClassName("ribbon-approved") +"Approved".t() @@ -261,7 +262,7 @@ internal val headerMenu: FC = FC { props -> } if (props.permissions.isSuperAdmin || - (props.permissions.isOwner && props.vulnerability.metadataDto.status != VulnerabilityStatus.APPROVED) + (props.permissions.isOwner && props.vulnerability.metadataDto.vulnerabilityMetadataDto.status != VulnerabilityStatus.APPROVED) ) { buttonBuilder( faTrash, @@ -272,7 +273,7 @@ internal val headerMenu: FC = FC { props -> ) { deleteVulnerabilityWindowOpenness.openWindow() } - if (props.vulnerability.metadataDto.status == VulnerabilityStatus.REJECTED) { + if (props.vulnerability.metadataDto.vulnerabilityMetadataDto.status == VulnerabilityStatus.REJECTED) { buttonBuilder(label = "Ready for review".t(), classes = "mr-2 btn-sm", style = "success") { setButtonType(ButtonType.FOR_REVIEW) rejectVulnerabilityWindowOpenness.openWindow() @@ -280,7 +281,7 @@ internal val headerMenu: FC = FC { props -> } } - if (props.permissions.isSuperAdmin && props.vulnerability.metadataDto.status.let { + if (props.permissions.isSuperAdmin && props.vulnerability.metadataDto.vulnerabilityMetadataDto.status.let { it == VulnerabilityStatus.CREATED || it == VulnerabilityStatus.PENDING_REVIEW }) { buttonBuilder(label = "Approve".t(), classes = "mr-2 btn-sm", style = "success") { diff --git a/save-cosv-frontend/src/main/kotlin/com/saveourtool/save/cosv/frontend/components/views/vuln/VulnerabilityInfoTab.kt b/save-cosv-frontend/src/main/kotlin/com/saveourtool/save/cosv/frontend/components/views/vuln/VulnerabilityInfoTab.kt index bce2235e78..05624be43c 100644 --- a/save-cosv-frontend/src/main/kotlin/com/saveourtool/save/cosv/frontend/components/views/vuln/VulnerabilityInfoTab.kt +++ b/save-cosv-frontend/src/main/kotlin/com/saveourtool/save/cosv/frontend/components/views/vuln/VulnerabilityInfoTab.kt @@ -242,7 +242,7 @@ val vulnerabilityInfoTab: FC = FC { props -> .getTimeline() .plus( VulnerabilityDateDto( - props.vulnerability.metadataDto.submitted, + props.vulnerability.metadataDto.vulnerabilityMetadataDto.submitted, VulnerabilityDateType.SUBMITTED_COSV, props.vulnerability.cosv.id, ) diff --git a/save-cosv-frontend/src/main/kotlin/com/saveourtool/save/cosv/frontend/components/views/vuln/VulnerabilityTagsComponent.kt b/save-cosv-frontend/src/main/kotlin/com/saveourtool/save/cosv/frontend/components/views/vuln/VulnerabilityTagsComponent.kt index 4ff86d9648..68906361da 100644 --- a/save-cosv-frontend/src/main/kotlin/com/saveourtool/save/cosv/frontend/components/views/vuln/VulnerabilityTagsComponent.kt +++ b/save-cosv-frontend/src/main/kotlin/com/saveourtool/save/cosv/frontend/components/views/vuln/VulnerabilityTagsComponent.kt @@ -56,10 +56,13 @@ val vulnerabilityTagsComponent: FC = FC { props div { className = ClassName("input-group-append") buttonBuilder(faPlus, isOutline = true, isDisabled = !newTag.isValidTag()) { + val vulnerabilityMetadataDto = props.vulnerability.metadataDto.vulnerabilityMetadataDto props.setVulnerabilityExt( props.vulnerability.copy( metadataDto = props.vulnerability.metadataDto.copy( - tags = props.vulnerability.metadataDto.tags + newTag + vulnerabilityMetadataDto = vulnerabilityMetadataDto.copy( + tags = vulnerabilityMetadataDto.tags + newTag + ) ) ) ) @@ -70,7 +73,7 @@ val vulnerabilityTagsComponent: FC = FC { props } div { className = ClassName("col pl-0") - props.vulnerability.metadataDto.tags.forEach { tag -> + props.vulnerability.metadataDto.vulnerabilityMetadataDto.tags.forEach { tag -> val tagEditable = props.currentUserInfo?.name == props.vulnerability.metadataDto.user.name buttonBuilder( tag, @@ -80,10 +83,13 @@ val vulnerabilityTagsComponent: FC = FC { props if (tagEditable && !props.isEditDisabled) { // TODO: use translation with substitution if (window.confirm("Do you want to remove tag '$tag' from this vulnerability?")) { + val vulnerabilityMetadataDto = props.vulnerability.metadataDto.vulnerabilityMetadataDto props.setVulnerabilityExt( props.vulnerability.copy( metadataDto = props.vulnerability.metadataDto.copy( - tags = props.vulnerability.metadataDto.tags - tag + vulnerabilityMetadataDto = vulnerabilityMetadataDto.copy( + tags = vulnerabilityMetadataDto.tags - tag + ) ) ) ) diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/CosvApplication.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/CosvApplication.kt index 10f2bd7952..43a7bcfff7 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/CosvApplication.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/CosvApplication.kt @@ -16,7 +16,7 @@ import org.springframework.context.annotation.Import @Import( DefaultS3Configuration::class, ) -@EntityScan("com.saveourtool.save.entities") +@EntityScan(basePackages = ["com.saveourtool.save.entities", "com.saveourtool.save.entitiescosv"]) class CosvApplication fun main(args: Array) { diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/CosvConfiguration.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/CosvConfiguration.kt index 146b7e60a3..7e6ccf3ec9 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/CosvConfiguration.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/CosvConfiguration.kt @@ -1,8 +1,20 @@ package com.saveourtool.save.cosv +import com.zaxxer.hikari.HikariDataSource +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties +import org.springframework.boot.context.properties.ConfigurationProperties +import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder +import org.springframework.context.annotation.Bean import org.springframework.context.annotation.ComponentScan import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Primary import org.springframework.data.jpa.repository.config.EnableJpaRepositories +import org.springframework.orm.jpa.JpaTransactionManager +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean +import org.springframework.transaction.PlatformTransactionManager +import javax.persistence.EntityManagerFactory +import javax.sql.DataSource /** * Configuration for Vulnerability @@ -10,4 +22,40 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories @Configuration @ComponentScan @EnableJpaRepositories(basePackages = ["com.saveourtool.save.cosv.repository"]) -class CosvConfiguration +class CosvConfiguration { + /** + * @param properties + * @return HikariDataSource + */ + @Primary + @Bean + @ConfigurationProperties("spring.datasource") + fun dataSource(properties: DataSourceProperties): HikariDataSource? = properties.initializeDataSourceBuilder().type(HikariDataSource::class.java) + .build() + + /** + * @param builder + * @param dataSource + * @return LocalContainerEntityManagerFactoryBean + */ + @Primary + @Bean(name = ["entityManagerFactory"]) + fun entityManagerFactory( + builder: EntityManagerFactoryBuilder, + @Qualifier("dataSource") dataSource: DataSource? + ): LocalContainerEntityManagerFactoryBean? = builder + .dataSource(dataSource) + .packages("com.saveourtool.save.entitiescosv") + .persistenceUnit("cosv") + .build() + + /** + * @param entityManagerFactory + * @return PlatformTransactionManager + */ + @Primary + @Bean(name = ["transactionManager"]) + fun transactionManager( + @Qualifier("entityManagerFactory") entityManagerFactory: EntityManagerFactory + ): PlatformTransactionManager? = JpaTransactionManager(entityManagerFactory) +} diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/configs/ConfigProperties.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/configs/ConfigProperties.kt index b7bd8073ca..4c00430d22 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/configs/ConfigProperties.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/configs/ConfigProperties.kt @@ -10,10 +10,12 @@ import java.nio.file.Path * * @property s3Storage configuration of S3 storage * @property workingDir a local folder for tmp files + * @property gatewayUrl */ @ConstructorBinding @ConfigurationProperties(prefix = "cosv") data class ConfigProperties( override val s3Storage: S3OperationsProperties, val workingDir: Path, + val gatewayUrl: String, ) : S3OperationsProperties.Provider diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/configs/PersistenceSaveAutoConfiguration.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/configs/PersistenceSaveAutoConfiguration.kt new file mode 100644 index 0000000000..d2c97da325 --- /dev/null +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/configs/PersistenceSaveAutoConfiguration.kt @@ -0,0 +1,55 @@ +package com.saveourtool.save.cosv.configs + +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.boot.context.properties.ConfigurationProperties +import org.springframework.boot.jdbc.DataSourceBuilder +import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.data.jpa.repository.config.EnableJpaRepositories +import org.springframework.orm.jpa.JpaTransactionManager +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean +import org.springframework.transaction.PlatformTransactionManager +import javax.persistence.EntityManagerFactory +import javax.sql.DataSource + +/** + * Configuration for Save database + */ +@Configuration +@EnableJpaRepositories( + basePackages = ["com.saveourtool.save.cosv.repositorysave"], + entityManagerFactoryRef = "saveEntityManagerFactory", + transactionManagerRef = "saveTransactionManager") +class PersistenceSaveAutoConfiguration { + /** + * @return DataSource + */ + @Bean(name = ["saveDataSource"]) + @ConfigurationProperties(prefix = "spring.second-datasource") + fun saveDataSource(): DataSource? = DataSourceBuilder.create().build() + + /** + * @param builder + * @param saveDataSource + * @return LocalContainerEntityManagerFactoryBean + */ + @Bean(name = ["saveEntityManagerFactory"]) + fun saveEntityManagerFactory( + builder: EntityManagerFactoryBuilder, + @Qualifier("saveDataSource") saveDataSource: DataSource? + ): LocalContainerEntityManagerFactoryBean? = builder + .dataSource(saveDataSource) + .packages("com.saveourtool.save.entities") + .persistenceUnit("save") + .build() + + /** + * @param saveEntityManagerFactory + * @return PlatformTransactionManager + */ + @Bean(name = ["saveTransactionManager"]) + fun saveTransactionManager( + @Qualifier("saveEntityManagerFactory") saveEntityManagerFactory: EntityManagerFactory + ): PlatformTransactionManager? = JpaTransactionManager(saveEntityManagerFactory) +} diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/controllers/CommentController.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/controllers/CommentController.kt new file mode 100644 index 0000000000..e17a577b98 --- /dev/null +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/controllers/CommentController.kt @@ -0,0 +1,109 @@ +package com.saveourtool.save.cosv.controllers + +import com.saveourtool.save.configs.ApiSwaggerSupport +import com.saveourtool.save.cosv.security.CommentPermissionEvaluator +import com.saveourtool.save.cosv.service.CommentService +import com.saveourtool.save.entities.Comment +import com.saveourtool.save.entities.CommentDto +import com.saveourtool.save.permission.Permission +import com.saveourtool.save.utils.StringResponse +import com.saveourtool.save.utils.blockingToMono +import com.saveourtool.save.utils.switchIfEmptyToNotFound +import com.saveourtool.save.utils.switchIfEmptyToResponseException +import com.saveourtool.save.v1 +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.tags.Tag +import io.swagger.v3.oas.annotations.tags.Tags +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.security.access.prepost.PreAuthorize +import org.springframework.security.core.Authentication +import org.springframework.web.bind.annotation.* +import org.springframework.web.server.ResponseStatusException +import reactor.core.publisher.Mono +import reactor.kotlin.core.publisher.toMono + +/** + * Controller for working with comments. + */ +@ApiSwaggerSupport +@Tags( + Tag(name = "comments"), +) +@RestController +@RequestMapping(path = ["/api/$v1/comments"]) +class CommentController( + private val commentService: CommentService, + private val commentPermissionEvaluator: CommentPermissionEvaluator, +) { + @PostMapping("/save") + @Operation( + method = "POST", + summary = "Save new comment.", + description = "Save new comment.", + ) + @ApiResponse(responseCode = "200", description = "Successfully saved project problem") + @PreAuthorize("permitAll()") + fun save( + @RequestBody comment: CommentDto, + authentication: Authentication, + ): Mono = blockingToMono { + if (comment.section.isEmpty()) { + throw ResponseStatusException(HttpStatus.FORBIDDEN, "section is empty") + } + commentService.saveComment(comment, authentication) + }.map { + ResponseEntity.ok("User comment was successfully saved") + } + + @GetMapping("/get-all") + @Operation( + method = "GET", + summary = "Get all comments in section.", + description = "Get all comments in section.", + ) + @ApiResponse(responseCode = "200", description = "Successfully return all comments in section") + @PreAuthorize("permitAll()") + @Suppress("TYPE_ALIAS") + fun getAllBySection( + @RequestParam section: String, + ): Mono> = blockingToMono { + commentService.findAllBySection(section).map(Comment::toDto) + } + + @GetMapping("/get-all-count") + @Operation( + method = "GET", + summary = "Get count comments in section.", + description = "Get count comments in section.", + ) + @ApiResponse(responseCode = "200", description = "Successfully return count comments in section") + @PreAuthorize("permitAll()") + @Suppress("TYPE_ALIAS") + fun getAllCountBySection( + @RequestParam section: String, + ): Mono = blockingToMono { + commentService.countBySection(section) + } + + @PostMapping("/delete") + @Operation( + method = "POST", + summary = "Delete comment.", + description = "Delete comment.", + ) + @ApiResponse(responseCode = "200", description = "Successfully deleted comment") + @ApiResponse(responseCode = "403", description = "User permissions are not enough to delete requested comment") + @ApiResponse(responseCode = "404", description = "Requested comment was not found") + @PreAuthorize("permitAll()") + fun deleteComment( + @RequestBody comment: CommentDto, + authentication: Authentication, + ): Mono = comment.toMono() + .filter { commentPermissionEvaluator.hasPermission(authentication, it, Permission.DELETE) } + .switchIfEmptyToResponseException(HttpStatus.FORBIDDEN) { "Permissions required for comment deletion were not granted." } + .flatMap { blockingToMono { commentService.deleteComment(it) } } + .switchIfEmptyToNotFound { "Could not find requested comment." } + .map { StringResponse.ok("Successfully deleted requested comment.") } +} diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/controllers/CosvController.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/controllers/CosvController.kt index 364697496f..3368bfec69 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/controllers/CosvController.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/controllers/CosvController.kt @@ -7,6 +7,7 @@ import com.saveourtool.save.cosv.service.OrganizationService import com.saveourtool.save.cosv.service.UserService import com.saveourtool.save.entities.cosv.CosvFileDto import com.saveourtool.save.entities.cosv.VulnerabilityMetadataDto +import com.saveourtool.save.entities.cosv.VulnerabilityMetadataDtoWithUserAndOrganization import com.saveourtool.save.utils.* import com.saveourtool.save.v1 import org.springframework.http.HttpStatus @@ -44,7 +45,7 @@ class CosvController( @RequestParam(required = false, defaultValue = "false") isGenerateIdentifier: Boolean, @RequestParam(required = false) organizationName: String?, authentication: Authentication, - ): Mono = cosv.id.toMono() + ): Mono = cosv.id.toMono() .filter { identifier -> isGenerateIdentifier && identifier.isEmpty() || identifier.isNotEmpty() } .switchIfEmptyToResponseException(HttpStatus.CONFLICT) { "Identifier is not provided: either set identifier auto-generation and provide no identifier or provide an identifier." diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/controllers/RawCosvFileController.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/controllers/RawCosvFileController.kt index 3f3eecaee6..5c0af1bd93 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/controllers/RawCosvFileController.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/controllers/RawCosvFileController.kt @@ -1,7 +1,9 @@ package com.saveourtool.save.cosv.controllers +import com.saveourtool.save.authservice.utils.userId import com.saveourtool.save.configs.ApiSwaggerSupport import com.saveourtool.save.configs.RequiresAuthorizationSourceHeader +import com.saveourtool.save.cosv.configs.ConfigProperties import com.saveourtool.save.cosv.service.CosvService import com.saveourtool.save.cosv.service.OrganizationService import com.saveourtool.save.cosv.service.UserService @@ -32,7 +34,6 @@ import reactor.kotlin.core.publisher.toFlux import java.nio.ByteBuffer import java.nio.file.Files import java.nio.file.Path -import java.nio.file.Paths import kotlin.io.path.* typealias RawCosvFileDtoFlux = Flux @@ -51,10 +52,10 @@ class RawCosvFileController( private val rawCosvFileStorage: RawCosvFileStorage, private val userService: UserService, private val organizationService: OrganizationService, + private val configProperties: ConfigProperties, ) { private fun createTempDirectoryForArchive() = Files.createTempDirectory( - // FixMe: Need to read the path from ConfigurationProperties - Paths.get(WORKING_DIR).createDirectories(), + configProperties.workingDir.createDirectories(), "archive-" ) @@ -258,15 +259,18 @@ class RawCosvFileController( fun submitAllUploadedToProcess( @PathVariable organizationName: String, authentication: Authentication, - ): Mono = rawCosvFileStorage.listByOrganizationAndUser(organizationName, authentication.name) - .map { files -> - files - .filter { it.isUploadedJsonFile() } - .map { it.requiredId() } - } - .flatMap { ids -> - doSubmitToProcess(organizationName, ids, authentication) - } + ): Mono { + val organization = organizationService.getOrganizationByName(organizationName) + return rawCosvFileStorage.listByOrganizationAndUser(organization.requiredId(), authentication.userId()) + .map { files -> + files + .filter { it.isUploadedJsonFile() } + .map { it.requiredId() } + } + .flatMap { ids -> + doSubmitToProcess(organizationName, ids, authentication) + } + } private fun doSubmitToProcess( organizationName: String, @@ -300,7 +304,8 @@ class RawCosvFileController( authentication: Authentication, ): Mono = hasPermission(authentication, organizationName, Permission.READ, "read") .flatMap { - rawCosvFileStorage.statisticsByOrganizationAndUser(organizationName, authentication.name) + val organization = organizationService.getOrganizationByName(organizationName) + rawCosvFileStorage.statisticsByOrganizationAndUser(organization.requiredId(), authentication.userId()) } /** @@ -323,7 +328,10 @@ class RawCosvFileController( authentication: Authentication, ): ResponseEntity = hasPermission(authentication, organizationName, Permission.READ, "read") .flatMap { - rawCosvFileStorage.listByOrganizationAndUser(organizationName, authentication.name, PageRequest.of(page, size, Sort.by("isZip").descending().and(Sort.by("id")))) + val organization = organizationService.getOrganizationByName(organizationName) + rawCosvFileStorage.listByOrganizationAndUser(organization.requiredId(), authentication.userId(), PageRequest.of(page, size, Sort.by("isZip").descending().and(Sort.by( + "id" + )))) } .flatMapIterable { it } .let { @@ -391,7 +399,8 @@ class RawCosvFileController( authentication: Authentication, ): Mono = hasPermission(authentication, organizationName, Permission.DELETE, "delete") .flatMap { - rawCosvFileStorage.listByOrganizationAndUser(organizationName, authentication.name) + val organization = organizationService.getOrganizationByName(organizationName) + rawCosvFileStorage.listByOrganizationAndUser(organization.requiredId(), authentication.userId()) .map { files -> files.filter { it.isDuplicate() } } @@ -443,7 +452,6 @@ class RawCosvFileController( // to show progress bar private const val PROGRESS_FOR_ARCHIVE = 5 - private const val WORKING_DIR = "/home/cnb/working-dir" private fun RawCosvFileStorage.uploadAndWrapDuplicateKeyException( key: RawCosvFileDto, diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/event/CommentListener.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/event/CommentListener.kt index fb81d9db34..89cb446f7b 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/event/CommentListener.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/event/CommentListener.kt @@ -1,7 +1,7 @@ package com.saveourtool.save.cosv.event import com.saveourtool.save.cosv.repository.LnkVulnerabilityMetadataUserRepository -import com.saveourtool.save.cosv.repository.NotificationRepository +import com.saveourtool.save.cosv.repositorysave.NotificationRepository import com.saveourtool.save.cosv.service.VulnerabilityMetadataService import com.saveourtool.save.entities.User import com.saveourtool.save.evententities.CommentEvent @@ -36,15 +36,15 @@ class CommentListener( val vulnerability = vulnerabilityMetadataService.findByIdentifier(identifier).orNotFound { "Vulnerability with id: $identifier not found" } val recipients = lnkVulnerabilityMetadataUserRepository.findByVulnerabilityMetadataId(vulnerability.requiredId()) - .map { it.user } - .plus(vulnerability.user) + .map { it.userId } + .plus(vulnerability.userId) .minus( - commentOwner + commentOwner.requiredId() ) val message = messageNewVulnComment(commentOwner, identifier) - recipients.map { user -> - notificationRepository.saveNotification(message, user.requiredId()) + recipients.map { userId -> + notificationRepository.saveNotification(message, userId) } } diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/CosvFileRepository.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/CosvFileRepository.kt index bd80132027..6e6bf163f9 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/CosvFileRepository.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/CosvFileRepository.kt @@ -1,6 +1,6 @@ package com.saveourtool.save.cosv.repository -import com.saveourtool.save.entities.cosv.CosvFile +import com.saveourtool.save.entitiescosv.CosvFile import com.saveourtool.save.spring.repository.BaseEntityRepository import org.springframework.stereotype.Repository import java.time.LocalDateTime diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/CosvGeneratedIdRepository.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/CosvGeneratedIdRepository.kt index fe5e779e90..ac4bc8e633 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/CosvGeneratedIdRepository.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/CosvGeneratedIdRepository.kt @@ -1,6 +1,6 @@ package com.saveourtool.save.cosv.repository -import com.saveourtool.save.entities.cosv.CosvGeneratedId +import com.saveourtool.save.entitiescosv.CosvGeneratedId import com.saveourtool.save.spring.repository.BaseEntityRepository import org.springframework.stereotype.Repository diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/CosvRepository.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/CosvRepository.kt index 683cd1e4e7..6593653ecb 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/CosvRepository.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/CosvRepository.kt @@ -1,7 +1,7 @@ package com.saveourtool.save.cosv.repository -import com.saveourtool.save.entities.cosv.CosvFile import com.saveourtool.save.entities.cosv.CosvFileDto +import com.saveourtool.save.entitiescosv.CosvFile import com.saveourtool.osv4k.OsvSchema import reactor.core.publisher.Flux diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/CosvRepositoryInStorage.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/CosvRepositoryInStorage.kt index 1e7678228b..4e06eff6a6 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/CosvRepositoryInStorage.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/CosvRepositoryInStorage.kt @@ -2,8 +2,8 @@ package com.saveourtool.save.cosv.repository import com.saveourtool.save.cosv.storage.CosvFileS3KeyManager import com.saveourtool.save.cosv.storage.CosvFileStorage -import com.saveourtool.save.entities.cosv.CosvFile import com.saveourtool.save.entities.cosv.CosvFileDto +import com.saveourtool.save.entitiescosv.CosvFile import com.saveourtool.save.utils.* import org.springframework.stereotype.Component diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/LnkVulnerabilityMetadataTagRepository.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/LnkVulnerabilityMetadataTagRepository.kt index 39c7492e5c..857053fe3e 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/LnkVulnerabilityMetadataTagRepository.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/LnkVulnerabilityMetadataTagRepository.kt @@ -1,6 +1,6 @@ package com.saveourtool.save.cosv.repository -import com.saveourtool.save.entities.cosv.LnkVulnerabilityMetadataTag +import com.saveourtool.save.entitiescosv.LnkVulnerabilityMetadataTag import com.saveourtool.save.spring.repository.BaseEntityRepository import org.springframework.data.domain.Pageable import org.springframework.stereotype.Repository @@ -30,15 +30,15 @@ interface LnkVulnerabilityMetadataTagRepository : BaseEntityRepository + fun findAllByTagIdIn(ids: List, page: Pageable): List } diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/LnkVulnerabilityMetadataUserRepository.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/LnkVulnerabilityMetadataUserRepository.kt index f406e75c0d..c5de995715 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/LnkVulnerabilityMetadataUserRepository.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/LnkVulnerabilityMetadataUserRepository.kt @@ -1,6 +1,6 @@ package com.saveourtool.save.cosv.repository -import com.saveourtool.save.entities.cosv.LnkVulnerabilityMetadataUser +import com.saveourtool.save.entitiescosv.LnkVulnerabilityMetadataUser import com.saveourtool.save.spring.repository.BaseEntityRepository import org.springframework.stereotype.Repository @@ -16,8 +16,8 @@ interface LnkVulnerabilityMetadataUserRepository : BaseEntityRepository /** - * @param userName name of user + * @param userId id of user * @param cosvMetadataId id of cosv metadata */ - fun deleteByUserNameAndVulnerabilityMetadataId(userName: String, cosvMetadataId: Long) + fun deleteByUserIdAndVulnerabilityMetadataId(userId: Long, cosvMetadataId: Long) } diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/RawCosvFileRepository.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/RawCosvFileRepository.kt index 5da6ed0376..4faaef05dd 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/RawCosvFileRepository.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/RawCosvFileRepository.kt @@ -1,6 +1,6 @@ package com.saveourtool.save.cosv.repository -import com.saveourtool.save.entities.cosv.RawCosvFile +import com.saveourtool.save.entitiescosv.RawCosvFile import com.saveourtool.save.spring.repository.BaseEntityRepository import org.springframework.data.domain.PageRequest import org.springframework.stereotype.Repository @@ -11,25 +11,25 @@ import org.springframework.stereotype.Repository @Repository interface RawCosvFileRepository : BaseEntityRepository { /** - * @param organizationName name from [RawCosvFile.organization] - * @param userName name from [RawCosvFile.user] + * @param organizationId id from [RawCosvFile.organizationId] + * @param userId id from [RawCosvFile.userId] * @param fileName [RawCosvFile.fileName] * @return found [RawCosvFile] by provided values */ - fun findByOrganizationNameAndUserNameAndFileName(organizationName: String, userName: String, fileName: String): RawCosvFile? + fun findByOrganizationIdAndUserIdAndFileName(organizationId: Long, userId: Long, fileName: String): RawCosvFile? /** - * @param organizationName name from [RawCosvFile.organization] - * @param userName name from [RawCosvFile.user] - * @return all [RawCosvFile]s which has provided [RawCosvFile.organization] + * @param organizationId id from [RawCosvFile.organizationId] + * @param userId id from [RawCosvFile.userId] + * @return all [RawCosvFile]s which has provided [RawCosvFile.organizationId] */ - fun findAllByOrganizationNameAndUserName(organizationName: String, userName: String): Collection + fun findAllByOrganizationIdAndUserId(organizationId: Long, userId: Long): Collection /** - * @param organizationName name from [RawCosvFile.organization] - * @param userName name from [RawCosvFile.user] + * @param organizationId id from [RawCosvFile.organizationId] + * @param userId id from [RawCosvFile.userId] * @param pageRequest - * @return all [RawCosvFile]s which has provided [RawCosvFile.organization] + * @return all [RawCosvFile]s which has provided [RawCosvFile.organizationId] */ - fun findAllByOrganizationNameAndUserName(organizationName: String, userName: String, pageRequest: PageRequest): Collection + fun findAllByOrganizationIdAndUserId(organizationId: Long, userId: Long, pageRequest: PageRequest): Collection } diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/UserRepository.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/UserRepository.kt deleted file mode 100644 index 6200ea8765..0000000000 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/UserRepository.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.saveourtool.save.cosv.repository - -import com.saveourtool.save.entities.User -import com.saveourtool.save.spring.repository.BaseEntityRepository -import org.springframework.data.jpa.repository.Query -import org.springframework.data.repository.query.Param -import org.springframework.stereotype.Repository - -/** - * Repository to access data about users - */ -@Repository -interface UserRepository : BaseEntityRepository { - /** - * @param userName user name for update - * @param rating new user rating - * @return updated user - */ - @Query( - value = "update save_cloud.user u set u.rating = :rating where u.name = :user_name", - nativeQuery = true, - ) - fun updateUser( - @Param("user_name") userName: String, - @Param("rating") rating: Long, - ) - - /** - * @param name name of organization - * @return found [User] by name - */ - @Query( - value = "select * from save_cloud.user where name = :name", - nativeQuery = true, - ) - fun getUserByName(@Param("name") name: String): User -} diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/VulnerabilityMetadataProjectRepository.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/VulnerabilityMetadataProjectRepository.kt index 4aeb1b46e2..d6680c5b26 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/VulnerabilityMetadataProjectRepository.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/VulnerabilityMetadataProjectRepository.kt @@ -1,6 +1,6 @@ package com.saveourtool.save.cosv.repository -import com.saveourtool.save.entities.cosv.VulnerabilityMetadataProject +import com.saveourtool.save.entitiescosv.VulnerabilityMetadataProject import com.saveourtool.save.spring.repository.BaseEntityRepository import org.springframework.stereotype.Repository diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/VulnerabilityMetadataRepository.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/VulnerabilityMetadataRepository.kt index 99b92a485d..ca8a3da57d 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/VulnerabilityMetadataRepository.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/VulnerabilityMetadataRepository.kt @@ -1,8 +1,9 @@ package com.saveourtool.save.cosv.repository -import com.saveourtool.save.entities.cosv.VulnerabilityMetadata import com.saveourtool.save.entities.vulnerability.VulnerabilityStatus +import com.saveourtool.save.entitiescosv.VulnerabilityMetadata import com.saveourtool.save.spring.repository.BaseEntityRepository + import org.springframework.stereotype.Repository /** diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repositorysave/CommentRepository.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repositorysave/CommentRepository.kt new file mode 100644 index 0000000000..856544a52e --- /dev/null +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repositorysave/CommentRepository.kt @@ -0,0 +1,36 @@ +package com.saveourtool.save.cosv.repositorysave + +import com.saveourtool.save.entities.Comment +import com.saveourtool.save.spring.repository.BaseEntityRepository +import org.springframework.stereotype.Repository +import java.time.LocalDateTime + +/** + * Repository to access data about user comments + */ +@Repository +interface CommentRepository : BaseEntityRepository { + /** + * @param section section of Save + * @return list of user comments + */ + fun getAllBySection(section: String): List + + /** + * @param section section of Save + * @return count comments + */ + fun countAllBySection(section: String): Int + + /** + * @param userName comment author username + * @param section [Comment.section] + * @param creationDate [Comment.createDate] + * @return [Comment] if found, null otherwise + */ + fun findByUserNameAndSectionAndCreateDate( + userName: String, + section: String, + creationDate: LocalDateTime?, + ): Comment? +} diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/NotificationRepository.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repositorysave/NotificationRepository.kt similarity index 94% rename from save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/NotificationRepository.kt rename to save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repositorysave/NotificationRepository.kt index a755148e1a..846668a97c 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/NotificationRepository.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repositorysave/NotificationRepository.kt @@ -1,4 +1,4 @@ -package com.saveourtool.save.cosv.repository +package com.saveourtool.save.cosv.repositorysave import com.saveourtool.save.entities.Notification import com.saveourtool.save.spring.repository.BaseEntityRepository diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/OrganizationRepository.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repositorysave/OrganizationRepository.kt similarity index 98% rename from save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/OrganizationRepository.kt rename to save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repositorysave/OrganizationRepository.kt index be18b06e45..e79816ff38 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/OrganizationRepository.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repositorysave/OrganizationRepository.kt @@ -1,4 +1,4 @@ -package com.saveourtool.save.cosv.repository +package com.saveourtool.save.cosv.repositorysave import com.saveourtool.save.domain.Role import com.saveourtool.save.entities.LnkUserOrganization diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/TagRepository.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repositorysave/TagRepository.kt similarity index 66% rename from save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/TagRepository.kt rename to save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repositorysave/TagRepository.kt index 9426b956b1..594cf424d3 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repository/TagRepository.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repositorysave/TagRepository.kt @@ -1,6 +1,7 @@ -package com.saveourtool.save.cosv.repository +package com.saveourtool.save.cosv.repositorysave import com.saveourtool.save.entities.Tag +import com.saveourtool.save.entitiescosv.LnkVulnerabilityMetadataTag import com.saveourtool.save.spring.repository.BaseEntityRepository import org.springframework.data.jpa.repository.Query import org.springframework.data.repository.query.Param @@ -34,4 +35,16 @@ interface TagRepository : BaseEntityRepository { fun saveTag( @Param("name") name: String, ): Tag + + /** + * @param prefix [LnkVulnerabilityMetadataTag.tag] name prefix + * @return [List] of [LnkVulnerabilityMetadataTag]s with name that starts with [prefix] + */ + fun findAllByNameStartingWith(prefix: String): List + + /** + * @param ids tags id + * @return [List] of [Tag]s + */ + fun findAllByIdIn(ids: List): List } diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repositorysave/UserRepository.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repositorysave/UserRepository.kt new file mode 100644 index 0000000000..b5e402f60f --- /dev/null +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/repositorysave/UserRepository.kt @@ -0,0 +1,96 @@ +package com.saveourtool.save.cosv.repositorysave + +import com.saveourtool.save.entities.User +import com.saveourtool.save.info.UserStatus +import com.saveourtool.save.spring.repository.BaseEntityRepository +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.query.Param +import org.springframework.stereotype.Repository + +/** + * Repository to access data about users + */ +@Repository +interface UserRepository : BaseEntityRepository { + /** + * @param userName user name for update + * @param rating new user rating + * @return updated user + */ + @Query( + value = "update save_cloud.user u set u.rating = :rating where u.name = :user_name", + nativeQuery = true, + ) + fun updateUser( + @Param("user_name") userName: String, + @Param("rating") rating: Long, + ) + + /** + * @param ids + * @return users with [ids] + */ + fun findAllByIdIn(ids: List): List + + /** + * @param username + * @return user or null if no results have been found + */ + fun findByName(username: String): User? + + /** + * @param role + * @return users with status + */ + fun findByRole(role: String): List + + /** + * @param status + * @return users with status + */ + fun findByStatus(status: UserStatus): List + + /** + * @param status + * @return count users + */ + fun countByStatus(status: UserStatus): Int + + /** + * @param username + * @param ids set of id of people that should not be found + * @return list of users with [username] except those whose ids are in [ids] + */ + fun findByNameAndIdNotIn(username: String, ids: Set): List + + /** + * @param prefix + * @param ids + * @param page + * @return [Page] of users with names that start with [prefix] and id not in [ids] + */ + fun findByNameStartingWithAndIdNotIn(prefix: String, ids: Set, page: Pageable): Page + + /** + * @param prefix + * @param names + * @param page + * @return [Page] of users with names that start with [prefix] and name not in [names] + */ + fun findByNameStartingWithAndNameNotIn(prefix: String, names: Set, page: Pageable): Page + + /** + * @param prefix + * @return list of users with names that start with [prefix] + */ + fun findByNameStartingWith(prefix: String): List + + /** + * @param prefix + * @param page + * @return [Page] of users with names that start with [prefix] + */ + fun findByNameStartingWith(prefix: String, page: Pageable): Page +} diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/security/CommentPermissionEvaluator.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/security/CommentPermissionEvaluator.kt new file mode 100644 index 0000000000..778eb36526 --- /dev/null +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/security/CommentPermissionEvaluator.kt @@ -0,0 +1,42 @@ +package com.saveourtool.save.cosv.security + +import com.saveourtool.save.cosv.utils.hasRole +import com.saveourtool.save.domain.Role +import com.saveourtool.save.entities.Comment +import com.saveourtool.save.entities.CommentDto +import com.saveourtool.save.permission.Permission +import org.springframework.security.core.Authentication +import org.springframework.stereotype.Component + +/** + * Class that is capable of assessing user permissions. + * + * TODO: move all the hasPermission methods here + */ +@Component +class CommentPermissionEvaluator { + /** + * Check permission for user to read, write and delete [Comment]s by its [CommentDto] + * + * @param authentication + * @param comment + * @param permission + * @return true if user with [authentication] has [permission] for [comment] + */ + fun hasPermission( + authentication: Authentication?, + comment: CommentDto, + permission: Permission, + ): Boolean { + authentication ?: return false + + if (authentication.hasRole(Role.SUPER_ADMIN)) { + return true + } + + return when (permission) { + Permission.READ -> true + else -> comment.userName == authentication.name + } + } +} diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/security/VulnerabilityPermissionEvaluator.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/security/VulnerabilityPermissionEvaluator.kt index 88158369fd..fc0864ed78 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/security/VulnerabilityPermissionEvaluator.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/security/VulnerabilityPermissionEvaluator.kt @@ -1,5 +1,6 @@ package com.saveourtool.save.cosv.security +import com.saveourtool.save.authservice.utils.userId import com.saveourtool.save.cosv.service.VulnerabilityService import com.saveourtool.save.cosv.utils.hasRole import com.saveourtool.save.domain.Role @@ -52,6 +53,7 @@ class VulnerabilityPermissionEvaluator( */ fun hasFullPermission(vulnerability: VulnerabilityMetadataDto, authentication: Authentication): Boolean { val linkUsers = vulnerabilityService.findUsersByVulnerabilityId(vulnerability.identifier).map { it.name } - return vulnerability.user.name == authentication.name || authentication.name in linkUsers + val vuln = vulnerabilityService.findByIdentifier(vulnerability.identifier) + return vuln.userId == authentication.userId() || authentication.name in linkUsers } } diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/CommentService.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/CommentService.kt new file mode 100644 index 0000000000..956a85868e --- /dev/null +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/CommentService.kt @@ -0,0 +1,74 @@ +package com.saveourtool.save.cosv.service + +import com.saveourtool.save.authservice.utils.userId +import com.saveourtool.save.cosv.repositorysave.CommentRepository +import com.saveourtool.save.cosv.repositorysave.UserRepository +import com.saveourtool.save.entities.Comment +import com.saveourtool.save.entities.CommentDto +import com.saveourtool.save.evententities.CommentEvent +import com.saveourtool.save.utils.getByIdOrNotFound + +import org.springframework.context.ApplicationEventPublisher +import org.springframework.security.core.Authentication +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional + +import kotlinx.datetime.toJavaLocalDateTime + +/** + * Service for comments + */ +@Service +@Transactional(readOnly = true) +class CommentService( + private val commentRepository: CommentRepository, + private val userRepository: UserRepository, + private val applicationEventPublisher: ApplicationEventPublisher, +) { + /** + * @param comment comment of user + * @param authentication + */ + @Transactional + fun saveComment(comment: CommentDto, authentication: Authentication) { + val userId = authentication.userId() + val user = userRepository.getByIdOrNotFound(userId) + + val newComment = Comment( + comment.message, + comment.section, + user, + ) + + applicationEventPublisher.publishEvent(CommentEvent(newComment)) + + commentRepository.save(newComment) + } + + /** + * @param section section with comments + * @return list of messages + */ + fun findAllBySection(section: String) = commentRepository.getAllBySection(section) + + /** + * @param section section with comments + * @return count messages + */ + fun countBySection(section: String) = commentRepository.countAllBySection(section) + + /** + * @param comment [CommentDto] that matches the [Comment] that should be deleted + * @return [Unit] if comment was found, `null` otherwise + */ + @Transactional + fun deleteComment(comment: CommentDto): Unit? { + val requestedComment = commentRepository.findByUserNameAndSectionAndCreateDate( + comment.userName, + comment.section, + comment.createDate?.toJavaLocalDateTime() + ) + + return requestedComment?.let { commentRepository.delete(it) } + } +} diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/CosvService.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/CosvService.kt index f345893967..1c0d7db139 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/CosvService.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/CosvService.kt @@ -5,10 +5,12 @@ import com.saveourtool.save.cosv.repository.CosvGeneratedIdRepository import com.saveourtool.save.cosv.repository.CosvRepository import com.saveourtool.save.cosv.repository.CosvSchema import com.saveourtool.save.cosv.repository.LnkVulnerabilityMetadataTagRepository +import com.saveourtool.save.cosv.repositorysave.TagRepository import com.saveourtool.save.cosv.storage.RawCosvFileStorage import com.saveourtool.save.entities.Organization import com.saveourtool.save.entities.User import com.saveourtool.save.entities.cosv.* +import com.saveourtool.save.entitiescosv.CosvGeneratedId import com.saveourtool.save.utils.* import com.saveourtool.osv4k.* @@ -29,7 +31,7 @@ import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds import kotlinx.serialization.serializer -typealias VulnerabilityMetadataDtoList = List +typealias VulnerabilityMetadataDtoList = List /** * Service for vulnerabilities @@ -47,6 +49,7 @@ class CosvService( private val vulnerabilityRatingService: VulnerabilityRatingService, private val lnkVulnerabilityMetadataTagRepository: LnkVulnerabilityMetadataTagRepository, private val cosvGeneratedIdRepository: CosvGeneratedIdRepository, + private val tagRepository: TagRepository, ) { private val scheduler = Schedulers.boundedElastic() @@ -132,10 +135,10 @@ class CosvService( .map { it.flatten() } .flatMap { metadataList -> Mono.just(metadataList.size).doOnSuccess { - metadataList.toFlux().flatMap { vulnerabilityMetadataDto -> - getVulnerabilityExt(vulnerabilityMetadataDto.identifier).mapNotNull { vulnerabilityExt -> + metadataList.toFlux().flatMap { metadataDto -> + getVulnerabilityExt(metadataDto.vulnerabilityMetadataDto.identifier).mapNotNull { vulnerabilityExt -> vulnerabilityExt.cosv.affected?.mapNotNull { it.`package`?.ecosystem }?.toSet()?.let { - vulnerabilityExt.metadataDto.identifier to it + vulnerabilityExt.metadataDto.vulnerabilityMetadataDto.identifier to it } } } @@ -162,9 +165,9 @@ class CosvService( rawCosvFileId: Long, user: User, organization: Organization, - ): Mono<*> = rawCosvFileStorage.getOrganizationAndOwner(rawCosvFileId) - .filter { (organizationForRawCosvFile, userForRawCosvFile) -> - organization.requiredId() == organizationForRawCosvFile.requiredId() && user.requiredId() == userForRawCosvFile.requiredId() + ): Mono<*> = rawCosvFileStorage.getOrganizationIdAndOwnerId(rawCosvFileId) + .filter { (organizationIdForRawCosvFile, userIdForRawCosvFile) -> + organization.requiredId() == organizationIdForRawCosvFile && user.requiredId() == userIdForRawCosvFile } .switchIfEmpty { log.error { @@ -198,7 +201,7 @@ class CosvService( rawCosvFileStorage.update( rawCosvFileId, RawCosvFileStatus.PROCESSED, - "Processed as ${metadataList.map(VulnerabilityMetadataDto::identifier)}" + "Processed as ${metadataList.map(VulnerabilityMetadataDtoWithUserAndOrganization::vulnerabilityMetadataDto).map(VulnerabilityMetadataDto::identifier)}" ) .flatMap { rawCosvFileStorage.deleteById(rawCosvFileId) @@ -219,7 +222,7 @@ class CosvService( fun update( cosvId: String, updater: (RawCosvSchema) -> Mono, - ): Mono = getVulnerabilityExt(cosvId) + ): Mono = getVulnerabilityExt(cosvId) .blockingMap { rawCosvExt -> rawCosvExt to Pair( userService.getUserByName(rawCosvExt.metadataDto.user.name), @@ -250,17 +253,18 @@ class CosvService( cosv: ManualCosvSchema, user: User, organization: Organization?, - ): Mono = save(cosv, user, organization) + ): Mono = save(cosv, user, organization) private inline fun save( cosv: CosvSchema, user: User, organization: Organization?, isAutoApprove: Boolean = false, - ): Mono = cosvRepository.save(cosv, serializer()) + ): Mono = cosvRepository.save(cosv, serializer()) .flatMap { key -> blockingToMono { - vulnerabilityMetadataService.createOrUpdate(key, cosv, user, organization, isAutoApprove).toDto() + vulnerabilityMetadataService.createOrUpdate(key, cosv, user, organization, isAutoApprove) + .toDtoWithUserAndOrganization(user.toUserInfo(), organization?.toDto()) } .onErrorResume { error -> log.error(error) { @@ -279,13 +283,16 @@ class CosvService( fun getVulnerabilityExt(identifier: String): Mono = blockingToMono { vulnerabilityMetadataService.findByIdentifier(identifier) } .flatMap { metadata -> cosvRepository.download(metadata.latestCosvFile, serializer()).blockingMap { content -> - val tags = lnkVulnerabilityMetadataTagRepository + val links = lnkVulnerabilityMetadataTagRepository .findAllByVulnerabilityMetadataIdentifier(identifier) - .map { it.tag.name } - .toSet() + .map { it.tagId } + + val tags = tagRepository.findAllByIdIn(links).map { it.name }.toSet() + val user = userService.findById(metadata.userId).toUserInfo() + val organization = metadata.organizationId?.let { organizationService.getOrganizationById(it).toDto() } VulnerabilityExt( - metadataDto = metadata.toDto().copy(tags = tags), + metadataDto = VulnerabilityMetadataDtoWithUserAndOrganization(metadata.toDto().copy(tags = tags), user, organization), cosv = content, // FixMe: need to fix bug here when mapping is empty saveContributors = content.getSaveContributes().map { userService.getUserByName(it.name).toUserInfo() }, diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/OrganizationService.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/OrganizationService.kt index 2449135b51..ae889fd520 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/OrganizationService.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/OrganizationService.kt @@ -1,7 +1,7 @@ package com.saveourtool.save.cosv.service import com.saveourtool.save.authservice.utils.userId -import com.saveourtool.save.cosv.repository.OrganizationRepository +import com.saveourtool.save.cosv.repositorysave.OrganizationRepository import com.saveourtool.save.cosv.utils.hasRole import com.saveourtool.save.domain.Role import com.saveourtool.save.entities.Organization @@ -9,7 +9,9 @@ import com.saveourtool.save.entities.OrganizationStatus import com.saveourtool.save.info.UserPermissions import com.saveourtool.save.info.UserPermissionsInOrganization import com.saveourtool.save.permission.Permission +import com.saveourtool.save.utils.orNotFound import org.jetbrains.annotations.Blocking +import org.springframework.data.repository.findByIdOrNull import org.springframework.security.core.Authentication import org.springframework.stereotype.Service @@ -32,6 +34,12 @@ class OrganizationService( */ fun getOrganizationByName(name: String): Organization = organizationRepository.getOrganizationByName(name) + /** + * @param id + * @return organization with [id] + */ + fun getOrganizationById(id: Long): Organization = organizationRepository.findByIdOrNull(id).orNotFound { "Organization with id: $id not found" } + /** * @param authentication * @param organizationName name of organization diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/TagService.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/TagService.kt index ec7d9b92dc..c746850360 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/TagService.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/TagService.kt @@ -1,15 +1,16 @@ package com.saveourtool.save.cosv.service import com.saveourtool.save.cosv.repository.LnkVulnerabilityMetadataTagRepository -import com.saveourtool.save.cosv.repository.TagRepository import com.saveourtool.save.cosv.repository.VulnerabilityMetadataRepository +import com.saveourtool.save.cosv.repositorysave.TagRepository import com.saveourtool.save.entities.Tag -import com.saveourtool.save.entities.cosv.LnkVulnerabilityMetadataTag +import com.saveourtool.save.entitiescosv.LnkVulnerabilityMetadataTag import com.saveourtool.save.utils.error import com.saveourtool.save.utils.getLogger import com.saveourtool.save.utils.orNotFound import com.saveourtool.save.validation.TAG_ERROR_MESSAGE import com.saveourtool.save.validation.isValidTag + import org.slf4j.Logger import org.springframework.data.domain.Pageable import org.springframework.http.HttpStatus @@ -54,7 +55,7 @@ class TagService( val tag = tagRepository.findByName(tagName) ?: tagRepository.saveTag(tagName) return lnkVulnerabilityMetadataTagRepository.save( - LnkVulnerabilityMetadataTag(metadata, tag) + LnkVulnerabilityMetadataTag(metadata, tag.requiredId()) ) } @@ -78,7 +79,7 @@ class TagService( val links = tagNames.map { tagRepository.findByName(it) ?: tagRepository.saveTag(it) }.map { - LnkVulnerabilityMetadataTag(metadata, it) + LnkVulnerabilityMetadataTag(metadata, it.requiredId()) } return lnkVulnerabilityMetadataTagRepository.saveAll(links) @@ -94,9 +95,10 @@ class TagService( "Could not find metadata for vulnerability $identifier" } - val link = lnkVulnerabilityMetadataTagRepository.findByVulnerabilityMetadataIdAndTagName( + val tag = tagRepository.findByName(tagName).orNotFound { "Could not find tag with name $tagName" } + val link = lnkVulnerabilityMetadataTagRepository.findByVulnerabilityMetadataIdAndTagId( metadata.requiredId(), - tagName + tag.requiredId() ).orNotFound { "Tag '$tagName' is not linked with vulnerability $identifier." } lnkVulnerabilityMetadataTagRepository.delete(link) @@ -107,10 +109,11 @@ class TagService( * @param page [Pageable] * @return [List] of [Tag]s with [Tag.name] that starts with [prefix] */ + @Suppress("UnusedParameter") fun getVulnerabilityTagsByPrefix( prefix: String, page: Pageable, - ) = lnkVulnerabilityMetadataTagRepository.findAllByTagNameStartingWith(prefix, page).map { it.tag } + ) = tagRepository.findAllByNameStartingWith(prefix) companion object { private val log: Logger = getLogger() diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/UserService.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/UserService.kt index 40b9cba98b..2f66ad5198 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/UserService.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/UserService.kt @@ -2,12 +2,13 @@ package com.saveourtool.save.cosv.service import com.saveourtool.save.authservice.utils.userId import com.saveourtool.save.authservice.utils.username -import com.saveourtool.save.cosv.repository.OrganizationRepository -import com.saveourtool.save.cosv.repository.UserRepository +import com.saveourtool.save.cosv.repositorysave.OrganizationRepository +import com.saveourtool.save.cosv.repositorysave.UserRepository import com.saveourtool.save.domain.Role import com.saveourtool.save.entities.User import com.saveourtool.save.utils.getHighestRole import com.saveourtool.save.utils.orNotFound +import org.springframework.data.repository.findByIdOrNull import org.springframework.security.core.Authentication import org.springframework.stereotype.Service @@ -29,7 +30,19 @@ class UserService( * @param name * @return user with [name] */ - fun getUserByName(name: String): User = userRepository.getUserByName(name).orNotFound { "Not found user by name $name" } + fun getUserByName(name: String): User = userRepository.findByName(name).orNotFound { "Not found user by name $name" } + + /** + * @param id + * @return user with [id] + */ + fun findById(id: Long): User = userRepository.findByIdOrNull(id).orNotFound { "Not found user by id $id" } + + /** + * @param ids + * @return users with [ids] + */ + fun findAllByIdIn(ids: List): List = userRepository.findAllByIdIn(ids) /** * @param authentication diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/VulnerabilityMetadataService.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/VulnerabilityMetadataService.kt index 5eb1ddcb7d..462d1b8972 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/VulnerabilityMetadataService.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/VulnerabilityMetadataService.kt @@ -7,13 +7,13 @@ import com.saveourtool.save.cosv.storage.CosvFileS3KeyManager import com.saveourtool.save.cvsscalculator.calculateBaseScore import com.saveourtool.save.entities.Organization import com.saveourtool.save.entities.User -import com.saveourtool.save.entities.cosv.CosvFile -import com.saveourtool.save.entities.cosv.VulnerabilityMetadata import com.saveourtool.save.entities.cosv.VulnerabilityMetadataDto import com.saveourtool.save.entities.cosv.VulnerabilityMetadataDto.Companion.SUMMARY_LENGTH -import com.saveourtool.save.entities.cosv.evententities.VulnerabilityMetadataEvent import com.saveourtool.save.entities.vulnerability.VulnerabilityLanguage import com.saveourtool.save.entities.vulnerability.VulnerabilityStatus +import com.saveourtool.save.entitiescosv.CosvFile +import com.saveourtool.save.entitiescosv.VulnerabilityMetadata +import com.saveourtool.save.entitiescosv.evententities.VulnerabilityMetadataEvent import com.saveourtool.save.utils.ELLIPSIS import com.saveourtool.save.utils.getCurrentLocalDateTime import com.saveourtool.save.utils.getLanguage @@ -99,8 +99,8 @@ class VulnerabilityMetadataService( severityNum = getSeverityNumber(), modified = modified.toJavaLocalDateTime(), submitted = getCurrentLocalDateTime().toJavaLocalDateTime(), - user = user, - organization = organization, + userId = user.requiredId(), + organizationId = organization?.requiredId(), language = getLanguage() ?: VulnerabilityLanguage.OTHER, status = toVulnerabilityStatus(isAutoApprove, true), latestCosvFile = cosvFile, @@ -134,17 +134,17 @@ class VulnerabilityMetadataService( HttpStatus.BAD_REQUEST, "${errorPrefix()}: existed entry has newer version (${existedMetadata.modified})", ) - existedMetadata.user.requiredId() != user.requiredId() -> throw ResponseStatusException( + existedMetadata.userId != user.requiredId() -> throw ResponseStatusException( HttpStatus.FORBIDDEN, "${errorPrefix()} by userId=${user.requiredId()}: " + - "already existed in save uploaded by another userId=${existedMetadata.user.requiredId()}", + "already existed in save uploaded by another userId=${existedMetadata.userId}", ) - else -> existedMetadata.organization?.run { - if (requiredId() != organization?.requiredId()) { + else -> existedMetadata.organizationId?.run { + if (this != organization?.requiredId()) { throw ResponseStatusException( HttpStatus.FORBIDDEN, - "${errorPrefix()} to organizationId=${requiredId()}: " + - "already existed in save in another organizationId=${existedMetadata.organization?.requiredId()}", + "${errorPrefix()} to organizationId=$this: " + + "already existed in save in another organizationId=${existedMetadata.organizationId}", ) } } diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/VulnerabilityRatingService.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/VulnerabilityRatingService.kt index 126a7b159b..ecadf19b89 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/VulnerabilityRatingService.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/VulnerabilityRatingService.kt @@ -2,7 +2,7 @@ package com.saveourtool.save.cosv.service import com.saveourtool.save.entities.Organization import com.saveourtool.save.entities.User -import com.saveourtool.save.entities.cosv.VulnerabilityMetadata +import com.saveourtool.save.entitiescosv.VulnerabilityMetadata import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional @@ -22,7 +22,7 @@ class VulnerabilityRatingService( */ @Transactional fun addRatingForManualUpload(vulnerabilityMetadata: VulnerabilityMetadata) { - doAddRating(vulnerabilityMetadata.user, MANUAL_UPLOAD_OWNER_RATING, vulnerabilityMetadata.organization, MANUAL_UPLOAD_ORGANIZATION_RATING) + doAddRating(vulnerabilityMetadata.userId, MANUAL_UPLOAD_OWNER_RATING, vulnerabilityMetadata.organizationId, MANUAL_UPLOAD_ORGANIZATION_RATING) } /** @@ -47,6 +47,20 @@ class VulnerabilityRatingService( } } + private fun doAddRating( + ownerId: Long, + ownerRatingIncrement: Long, + organizationId: Long?, + organizationRatingIncrement: Long, + ) { + val owner = userService.findById(ownerId) + userService.saveUser(owner.apply { rating += ownerRatingIncrement }) + val organization = organizationId?.let { organizationService.getOrganizationById(it) } + organization?.let { + organizationService.saveOrganization(organization.apply { rating += organizationRatingIncrement }) + } + } + companion object { private const val BULD_UPLOAD_ORGANIZATION_RATING = 1L private const val BULD_UPLOAD_OWNER_RATING = 1L diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/VulnerabilityService.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/VulnerabilityService.kt index 222274d023..b6f8d1a897 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/VulnerabilityService.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/service/VulnerabilityService.kt @@ -2,6 +2,7 @@ package com.saveourtool.save.cosv.service import com.saveourtool.save.authservice.utils.userId import com.saveourtool.save.cosv.repository.* +import com.saveourtool.save.cosv.repositorysave.TagRepository import com.saveourtool.save.cosv.utils.hasRole import com.saveourtool.save.domain.Role import com.saveourtool.save.entities.Organization @@ -9,6 +10,10 @@ import com.saveourtool.save.entities.Tag import com.saveourtool.save.entities.User import com.saveourtool.save.entities.cosv.* import com.saveourtool.save.entities.vulnerability.* +import com.saveourtool.save.entitiescosv.LnkVulnerabilityMetadataTag +import com.saveourtool.save.entitiescosv.LnkVulnerabilityMetadataUser +import com.saveourtool.save.entitiescosv.VulnerabilityMetadata +import com.saveourtool.save.entitiescosv.VulnerabilityMetadataProject import com.saveourtool.save.filters.VulnerabilityFilter import com.saveourtool.save.info.UserInfo import com.saveourtool.save.utils.* @@ -42,10 +47,12 @@ class VulnerabilityService( private val lnkVulnerabilityMetadataTagRepository: LnkVulnerabilityMetadataTagRepository, private val vulnerabilityRatingService: VulnerabilityRatingService, private val userService: UserService, + private val organizationService: OrganizationService, private val tagService: TagService, + private val tagRepository: TagRepository, ) { private fun List.toTagMap() = lnkVulnerabilityMetadataTagRepository.findByVulnerabilityMetadataIdIn(this.map { it.requiredId() }) - .map { link -> link.vulnerabilityMetadata to link.tag } + .map { link -> link.vulnerabilityMetadata to link.tagId } .groupBy { (metadata, _) -> metadata } .mapValues { (_, list) -> list.map { it.second }.toSet() } @@ -55,6 +62,12 @@ class VulnerabilityService( */ fun findByName(name: String) = vulnerabilityMetadataRepository.findByIdentifier(name)?.toDto() + /** + * @param identifier identifier of vulnerability + * @return vulnerability by identifier + */ + fun findByIdentifier(identifier: String) = vulnerabilityMetadataRepository.findByIdentifier(identifier).orNotFound { "Not found metadata for vulnerability $identifier" } + /** * @param userName * @param status @@ -75,7 +88,8 @@ class VulnerabilityService( identifier: String ): List = vulnerabilityMetadataRepository.findByIdentifier(identifier).orNotFound { "Not found metadata for vulnerability $identifier" } .let { metadata -> - lnkVulnerabilityMetadataUserRepository.findByVulnerabilityMetadataId(metadata.requiredId()).map { it.user.toUserInfo() } + val userIds = lnkVulnerabilityMetadataUserRepository.findByVulnerabilityMetadataId(metadata.requiredId()).map { it.requiredId() } + userService.findAllByIdIn(userIds).map { it.toUserInfo() } } /** @@ -93,16 +107,23 @@ class VulnerabilityService( filter: VulnerabilityFilter, page: Int, size: Int, - ): List { + ): List { val metadataList = vulnerabilityMetadataRepository.kFindAll(PageRequest.of(page, size)) { root, cq, cb -> getFilterPredicate(root, cq, cb, filter) } val tagMap = metadataList.content.toTagMap() return metadataList.content.map { metadata -> metadata to tagMap[metadata].orEmpty() } - .map { (metadata, tags) -> - metadata.toDto().copy( - tags = tags.map { it.name }.toSet(), + .map { (metadata, tagIds) -> + val tags = tagRepository.findAllByIdIn(tagIds.toList()) + val user = userService.findById(metadata.userId).toUserInfo() + val organization = metadata.organizationId?.let { organizationService.getOrganizationById(it).toDto() } + VulnerabilityMetadataDtoWithUserAndOrganization( + metadata.toDto().copy( + tags = tags.map { it.name }.toSet(), + ), + user, + organization ) } } @@ -176,26 +197,27 @@ class VulnerabilityService( * @param authentication * @throws ResponseStatusException */ - fun update(vulnerabilityExt: VulnerabilityExt, authentication: Authentication): Mono = blockingToMono { - val vulnerabilityId = vulnerabilityExt.metadataDto.identifier + fun update(vulnerabilityExt: VulnerabilityExt, authentication: Authentication): Mono = blockingToMono { + val vulnerabilityId = vulnerabilityExt.metadataDto.vulnerabilityMetadataDto.identifier val metadata = vulnerabilityMetadataRepository.findByIdentifier(vulnerabilityId).orNotFound() // only Super Users and Owners of unapproved vuln. can edit it if (authentication.hasRole(Role.SUPER_ADMIN) || - authentication.userId() == metadata.user.requiredId() && metadata.status != VulnerabilityStatus.APPROVED) { + authentication.userId() == metadata.userId && metadata.status != VulnerabilityStatus.APPROVED) { // updating status in the metadata, because this field is not included into the COSV schema val metadataUpdate = metadata.apply { - status = vulnerabilityExt.metadataDto.status + status = vulnerabilityExt.metadataDto.vulnerabilityMetadataDto.status } vulnerabilityMetadataRepository.save(metadataUpdate) // updating tags in the tags table and vuln->tags link table, it is also not included into COSV schema - val existingTags = lnkVulnerabilityMetadataTagRepository + val existingTagIds = lnkVulnerabilityMetadataTagRepository .findAllByVulnerabilityMetadataIdentifier(vulnerabilityId) - .map { it.tag.name } - .toSet() + .map { it.tagId } + + val existingTags = tagRepository.findAllByIdIn(existingTagIds).map { it.name }.toSet() - val updatedTags = vulnerabilityExt.metadataDto.tags + val updatedTags = vulnerabilityExt.metadataDto.vulnerabilityMetadataDto.tags // performance issues are not possible here as tags number is very limited, but need to FixMe it (updatedTags - existingTags).forEach { @@ -208,7 +230,7 @@ class VulnerabilityService( throw ResponseStatusException(HttpStatus.FORBIDDEN) } }.flatMap { - cosvService.update(vulnerabilityExt.metadataDto.identifier) { + cosvService.update(vulnerabilityExt.metadataDto.vulnerabilityMetadataDto.identifier) { vulnerabilityExt.cosv.toMono() } } @@ -266,7 +288,7 @@ class VulnerabilityService( ) { val metadata = vulnerabilityMetadataRepository.findByIdentifier(vulnerabilityIdentifier).orNotFound() - if ((authentication.hasRole(Role.SUPER_ADMIN) || authentication.userId() == metadata.user.requiredId()) && metadata.status == VulnerabilityStatus.REJECTED) { + if ((authentication.hasRole(Role.SUPER_ADMIN) || authentication.userId() == metadata.userId) && metadata.status == VulnerabilityStatus.REJECTED) { val metadataUpdate = metadata.apply { status = VulnerabilityStatus.PENDING_REVIEW } @@ -331,7 +353,7 @@ class VulnerabilityService( } ).toMono() } - }.map { it.identifier } + }.map { it.vulnerabilityMetadataDto.identifier } /** * @param identifier vulnerability identifier @@ -347,7 +369,7 @@ class VulnerabilityService( lnkVulnerabilityMetadataUserRepository.save( LnkVulnerabilityMetadataUser( vulnerabilityMetadataId = metadata.requiredId(), - user = user, + userId = user.requiredId(), ) ) } @@ -365,7 +387,7 @@ class VulnerabilityService( } ) } - }.map { it.identifier } + }.map { it.vulnerabilityMetadataDto.identifier } } /** @@ -375,7 +397,8 @@ class VulnerabilityService( */ fun deleteUser(userName: String, identifier: String): Mono = blockingToMono { val metadata = vulnerabilityMetadataRepository.findByIdentifier(identifier).orNotFound { "Not found metadata for vulnerability $identifier" } - lnkVulnerabilityMetadataUserRepository.deleteByUserNameAndVulnerabilityMetadataId(userName, metadata.requiredId()) + val user = userService.getUserByName(userName) + lnkVulnerabilityMetadataUserRepository.deleteByUserIdAndVulnerabilityMetadataId(user.requiredId(), metadata.requiredId()) }.flatMap { cosvService.update(identifier) { cosv -> blockingToMono { @@ -388,7 +411,7 @@ class VulnerabilityService( ?.takeUnless { it.isEmpty() } ) } - }.map { it.identifier } + }.map { it.vulnerabilityMetadataDto.identifier } } /** @@ -422,7 +445,7 @@ class VulnerabilityService( timeline = cosv.timeline?.minus(dateDto.asTimelineEntry())?.takeUnless { it.isEmpty() }, ).toMono() } - }.map { it.identifier } + }.map { it.vulnerabilityMetadataDto.identifier } private fun getPredicateForTags( root: Root, diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/storage/CosvFileS3KeyManager.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/storage/CosvFileS3KeyManager.kt index bb69c7e7ca..7a7b6d138f 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/storage/CosvFileS3KeyManager.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/storage/CosvFileS3KeyManager.kt @@ -1,8 +1,8 @@ package com.saveourtool.save.cosv.storage import com.saveourtool.save.cosv.repository.CosvFileRepository -import com.saveourtool.save.entities.cosv.CosvFile -import com.saveourtool.save.entities.cosv.VulnerabilityMetadata +import com.saveourtool.save.entitiescosv.CosvFile +import com.saveourtool.save.entitiescosv.VulnerabilityMetadata import com.saveourtool.save.s3.S3OperationsProperties import com.saveourtool.save.storage.concatS3Key import com.saveourtool.save.storage.key.AbstractS3KeyEntityManager diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/storage/CosvFileStorage.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/storage/CosvFileStorage.kt index 434528b386..ad0533b35a 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/storage/CosvFileStorage.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/storage/CosvFileStorage.kt @@ -1,6 +1,6 @@ package com.saveourtool.save.cosv.storage -import com.saveourtool.save.entities.cosv.CosvFile +import com.saveourtool.save.entitiescosv.CosvFile import com.saveourtool.save.s3.S3Operations import com.saveourtool.save.storage.DefaultStorageProjectReactor import com.saveourtool.save.storage.ReactiveStorageWithDatabase diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/storage/RawCosvFileS3KeyManager.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/storage/RawCosvFileS3KeyManager.kt index f49b79938b..7deb9ae211 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/storage/RawCosvFileS3KeyManager.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/storage/RawCosvFileS3KeyManager.kt @@ -3,17 +3,16 @@ package com.saveourtool.save.cosv.storage import com.saveourtool.save.cosv.repository.RawCosvFileRepository import com.saveourtool.save.cosv.service.OrganizationService import com.saveourtool.save.cosv.service.UserService -import com.saveourtool.save.entities.Organization -import com.saveourtool.save.entities.User -import com.saveourtool.save.entities.cosv.RawCosvFile -import com.saveourtool.save.entities.cosv.RawCosvFile.Companion.toNewEntity import com.saveourtool.save.entities.cosv.RawCosvFileDto import com.saveourtool.save.entities.cosv.RawCosvFileStatus +import com.saveourtool.save.entitiescosv.RawCosvFile +import com.saveourtool.save.entitiescosv.RawCosvFile.Companion.toNewEntity import com.saveourtool.save.s3.S3OperationsProperties import com.saveourtool.save.storage.concatS3Key import com.saveourtool.save.storage.key.AbstractS3KeyDtoManager import com.saveourtool.save.utils.BlockingBridge import com.saveourtool.save.utils.getByIdOrNotFound + import org.springframework.data.domain.PageRequest import org.springframework.stereotype.Component import org.springframework.transaction.annotation.Transactional @@ -33,28 +32,34 @@ class RawCosvFileS3KeyManager( rawCosvFileRepository, blockingBridge, ) { - override fun findByDto(dto: RawCosvFileDto): RawCosvFile? = repository.findByOrganizationNameAndUserNameAndFileName( - organizationName = dto.organizationName, - userName = dto.userName, - fileName = dto.fileName, - ) + override fun findByDto(dto: RawCosvFileDto): RawCosvFile? { + val organization = organizationService.getOrganizationByName(dto.organizationName) + val user = userService.getUserByName(dto.userName) + return repository.findByOrganizationIdAndUserIdAndFileName( + organizationId = organization.requiredId(), + userId = user.requiredId(), + fileName = dto.fileName, + ) + } override fun createNewEntityFromDto(dto: RawCosvFileDto): RawCosvFile = - dto.toNewEntity(userService::getUserByName, organizationService::getOrganizationByName) + dto.toNewEntity({ userName -> userService.getUserByName(userName).requiredId() }, + { organizationName -> organizationService.getOrganizationByName(organizationName).requiredId() } + ) /** - * @param organizationName - * @param userName + * @param organizationId + * @param userId * @param pageRequest * @return all [RawCosvFileDto]s which has provided [RawCosvFileDto.organizationName] and [RawCosvFileDto.userName] */ fun listByOrganizationAndUser( - organizationName: String, - userName: String, + organizationId: Long, + userId: Long, pageRequest: PageRequest? = null, ): Collection = run { - pageRequest?.let { repository.findAllByOrganizationNameAndUserName(organizationName, userName, it) } - ?: repository.findAllByOrganizationNameAndUserName(organizationName, userName) + pageRequest?.let { repository.findAllByOrganizationIdAndUserId(organizationId, userId, it) } + ?: repository.findAllByOrganizationIdAndUserId(organizationId, userId) }.map { it.toDto() } /** @@ -90,12 +95,12 @@ class RawCosvFileS3KeyManager( /** * @param id - * @return [Organization] to which is uploaded and [User] who uploaded + * @return organizationId to which is uploaded and userId who uploaded */ fun getOrganizationAndOwner( id: Long, - ): Pair = repository.getByIdOrNotFound(id).let { - it.organization to it.user + ): Pair = repository.getByIdOrNotFound(id).let { + it.organizationId to it.userId } @Transactional diff --git a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/storage/RawCosvFileStorage.kt b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/storage/RawCosvFileStorage.kt index c4f8e66584..43c11fc3f2 100644 --- a/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/storage/RawCosvFileStorage.kt +++ b/save-cosv/src/main/kotlin/com/saveourtool/save/cosv/storage/RawCosvFileStorage.kt @@ -2,7 +2,6 @@ package com.saveourtool.save.cosv.storage import com.saveourtool.save.entities.Organization import com.saveourtool.save.entities.User -import com.saveourtool.save.entities.cosv.RawCosvFile import com.saveourtool.save.entities.cosv.RawCosvFileDto import com.saveourtool.save.entities.cosv.RawCosvFileDto.Companion.isDuplicate import com.saveourtool.save.entities.cosv.RawCosvFileDto.Companion.isHasErrors @@ -12,18 +11,21 @@ import com.saveourtool.save.entities.cosv.RawCosvFileDto.Companion.isUploadedJso import com.saveourtool.save.entities.cosv.RawCosvFileDto.Companion.isZipArchive import com.saveourtool.save.entities.cosv.RawCosvFileStatisticsDto import com.saveourtool.save.entities.cosv.RawCosvFileStatus +import com.saveourtool.save.entitiescosv.RawCosvFile import com.saveourtool.save.s3.S3Operations import com.saveourtool.save.storage.DefaultStorageProjectReactor import com.saveourtool.save.storage.ReactiveStorageWithDatabase import com.saveourtool.save.storage.deleteUnexpectedKeys import com.saveourtool.save.utils.* + import org.springframework.data.domain.PageRequest import org.springframework.stereotype.Component import reactor.core.publisher.Flux import reactor.core.publisher.Mono + import java.nio.ByteBuffer -typealias OrganizationAndOwner = Pair +typealias OrganizationIdAndOwnerId = Pair typealias RawCosvFileDtoCollection = Collection /** @@ -68,15 +70,15 @@ class RawCosvFileStorage( .publishOn(s3Operations.scheduler) /** - * @param organizationName - * @param userName - * @return statistics [RawCosvFileStatisticDto] for all [RawCosvFileDto]s which belongs to [organizationName] and uploaded by [userName] + * @param organizationId + * @param userId + * @return statistics [RawCosvFileStatisticDto] for all [RawCosvFileDto]s which belongs to [organizationId] and uploaded by [userId] */ fun statisticsByOrganizationAndUser( - organizationName: String, - userName: String, + organizationId: Long, + userId: Long, ): Mono = blockingToMono { - val filesList = s3KeyManager.listByOrganizationAndUser(organizationName, userName).toList() + val filesList = s3KeyManager.listByOrganizationAndUser(organizationId, userId).toList() RawCosvFileStatisticsDto( filesList.count(), filesList.count { it.isZipArchive() }, @@ -89,17 +91,17 @@ class RawCosvFileStorage( } /** - * @param organizationName - * @param userName + * @param organizationId + * @param userId * @param pageRequest - * @return all [RawCosvFileDto]s which belongs to [organizationName] and uploaded by [userName] + * @return all [RawCosvFileDto]s which belongs to [organizationId] and uploaded by [userId] */ fun listByOrganizationAndUser( - organizationName: String, - userName: String, + organizationId: Long, + userId: Long, pageRequest: PageRequest? = null, ): Mono = blockingToMono { - s3KeyManager.listByOrganizationAndUser(organizationName, userName, pageRequest).toList() + s3KeyManager.listByOrganizationAndUser(organizationId, userId, pageRequest).toList() } /** @@ -128,9 +130,9 @@ class RawCosvFileStorage( * @param id * @return [Organization] to which is uploaded and [User] who uploaded */ - fun getOrganizationAndOwner( + fun getOrganizationIdAndOwnerId( id: Long, - ): Mono = blockingToMono { s3KeyManager.getOrganizationAndOwner(id) } + ): Mono = blockingToMono { s3KeyManager.getOrganizationAndOwner(id) } /** * @param id diff --git a/save-cosv/src/main/resources/application-dev.properties b/save-cosv/src/main/resources/application-dev.properties index b728d11994..b4bce49fd9 100644 --- a/save-cosv/src/main/resources/application-dev.properties +++ b/save-cosv/src/main/resources/application-dev.properties @@ -1,9 +1,13 @@ spring.datasource.url=jdbc:mysql://localhost:3306/cosv spring.datasource.username=root spring.datasource.password=123 +spring.second-datasource.jdbc-url = jdbc:mysql://localhost:3306/save_cloud +spring.second-datasource.username = root +spring.second-datasource.password = 123 cosv.s3-storage.endpoint=http://localhost:9000 cosv.s3-storage.bucketName=cnb cosv.s3-storage.credentials.accessKeyId=admin cosv.s3-storage.credentials.secretAccessKey=adminadmin cosv.s3-storage.createBucketIfNotExists=true +cosv.gatewayUrl=http://localhost:5300 cosv.working-dir=${user.home}/.save-cloud/cosv-working-dir diff --git a/save-cosv/src/main/resources/application.properties b/save-cosv/src/main/resources/application.properties index 64ddc0fa52..89a17ab07b 100644 --- a/save-cosv/src/main/resources/application.properties +++ b/save-cosv/src/main/resources/application.properties @@ -9,8 +9,9 @@ spring.jpa.properties.hibernate.jdbc.batch_size=100 spring.jpa.properties.hibernate.order_inserts=true spring.jpa.properties.hibernate.order_updates=true logging.level.org.hibernate.engine.internal.StatisticalLoggingSessionEventListener=WARN +cosv.gatewayUrl=http://gateway:5300 cosv.s3-storage.endpoint=${s3-storage.endpoint} cosv.s3-storage.bucketName=${s3-storage.bucketName} -cosv.s3-storage.prefix=cnb/cosv +cosv.s3-storage.prefix=cnb/files cosv.s3-storage.credentials.accessKeyId=${s3-storage.credentials.accessKeyId} cosv.s3-storage.credentials.secretAccessKey=${s3-storage.credentials.secretAccessKey} diff --git a/save-frontend-common/src/main/kotlin/com/saveourtool/save/frontend/common/components/views/vuln/VulnerabilityTableComponent.kt b/save-frontend-common/src/main/kotlin/com/saveourtool/save/frontend/common/components/views/vuln/VulnerabilityTableComponent.kt index 667a7b3bb8..9c98454072 100644 --- a/save-frontend-common/src/main/kotlin/com/saveourtool/save/frontend/common/components/views/vuln/VulnerabilityTableComponent.kt +++ b/save-frontend-common/src/main/kotlin/com/saveourtool/save/frontend/common/components/views/vuln/VulnerabilityTableComponent.kt @@ -4,7 +4,7 @@ package com.saveourtool.save.frontend.common.components.views.vuln -import com.saveourtool.save.entities.cosv.VulnerabilityMetadataDto +import com.saveourtool.save.entities.cosv.VulnerabilityMetadataDtoWithUserAndOrganization import com.saveourtool.save.entities.vulnerability.VulnerabilityStatus import com.saveourtool.save.filters.VulnerabilityFilter import com.saveourtool.save.frontend.TabMenuBar @@ -101,20 +101,20 @@ val vulnerabilityTableComponent: FC = FC { pro tableComponent( columns = { columns { - column(id = "identifier", header = "Identifier".t(), { identifier }) { cellContext -> + column(id = "identifier", header = "Identifier".t(), { vulnerabilityMetadataDto.identifier }) { cellContext -> Fragment.create { td { className = ClassName("align-middle text-nowrap") div { className = ClassName("row m-0") Link { - to = "/${FrontendCosvRoutes.VULNERABILITY_SINGLE}/${cellContext.row.original.identifier}" + to = "/${FrontendCosvRoutes.VULNERABILITY_SINGLE}/${cellContext.row.original.vulnerabilityMetadataDto.identifier}" +cellContext.value } } div { className = ClassName("row m-0") - cellContext.row.original.tags.forEach { tag -> + cellContext.row.original.vulnerabilityMetadataDto.tags.forEach { tag -> div { className = ClassName("rounded-pill px-1 mt-1 mr-1") style = jso { @@ -129,18 +129,19 @@ val vulnerabilityTableComponent: FC = FC { pro } } } - column(id = "summary", header = "Summary".t(), { summary }) { cellContext -> + column(id = "summary", header = "Summary".t(), { vulnerabilityMetadataDto.summary }) { cellContext -> Fragment.create { td { + val vulnerabilityMetadataDto = cellContext.row.original.vulnerabilityMetadataDto className = ClassName("align-middle") - +splitLongWordsInText(cellContext.row.original.summary) + +splitLongWordsInText(vulnerabilityMetadataDto.summary) } } } - column(id = "severityNum", header = "Criticality".t(), { severityNum }) { cellContext -> + column(id = "severityNum", header = "Criticality".t(), { vulnerabilityMetadataDto.severityNum }) { cellContext -> Fragment.create { td { - val severityNum = cellContext.row.original.severityNum + val severityNum = cellContext.row.original.vulnerabilityMetadataDto.severityNum val severityNumColor = when (severityNum) { in 0.0f..3.9f -> "text-success" in 3.9f..6.9f -> "text-warning" @@ -152,11 +153,11 @@ val vulnerabilityTableComponent: FC = FC { pro } } } - column(id = "language", header = "Language".t(), { language }) { cellContext -> + column(id = "language", header = "Language".t(), { vulnerabilityMetadataDto.language }) { cellContext -> Fragment.create { td { className = ClassName("align-middle text-center") - +"${cellContext.row.original.language}" + +"${cellContext.row.original.vulnerabilityMetadataDto.language}" } } } @@ -191,10 +192,10 @@ val vulnerabilityTableComponent: FC = FC { pro } } if (isNeedToShowStatus) { - column(id = "status", header = "Status".t(), { status }) { cellContext -> + column(id = "status", header = "Status".t(), { vulnerabilityMetadataDto.status }) { cellContext -> Fragment.create { td { - val status = cellContext.row.original.status.value + val status = cellContext.row.original.vulnerabilityMetadataDto.status.value val statusColor = when (status) { "Approved" -> "text-success" "Created", "Edited" -> "text-warning" @@ -315,7 +316,7 @@ enum class VulnerabilityListTab { /** * [TableProps] for vulnerabilities table */ -external interface VulnerabilityTableProps : TableProps { +external interface VulnerabilityTableProps : TableProps { /** * All filters in one value [filters] */ From 6b57e7cf9dbc53250ab3127bbd98a2ec58bcd374 Mon Sep 17 00:00:00 2001 From: Andrey Kuleshov Date: Fri, 19 Jan 2024 19:07:47 +0300 Subject: [PATCH 2/3] Update README.md --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e2b41c1a2a..d992d147d5 100644 --- a/README.md +++ b/README.md @@ -13,24 +13,28 @@ Our key focus is to make life of developers who analyze code easier. - Use SAVE to create an **online demo for your analyzer** and set it up for your community's use; - Benchmarks Archive with the **list of popular benchmarks** (with a reference to [awesome-benchmarks](https://github.com/saveourtool/awesome-benchmarks)). -2. **VULN** - A platform designed for the **reporting**, aggregation, and deduplication of one-day **vulnerabilities**. +2. **COSV** - A platform designed for the **reporting**, aggregation, and deduplication of one-day **vulnerabilities**. -Additionally, on our platform we host **contests** in the field of code analysis. +Additionally, on our platform we host **contests** in the field of code analysis. This provides an opportunity for you to submit your automated solutions for bug detection, and compete with other innovative projects. ## Links - Collection of Code Analyzers Demo: [Demo](https://saveourtool.com/demo) - Benchmarks Archive: [Benchmarks](https://saveourtool.com/awesome-benchmarks) - CI projects: [CI Projects](https://saveourtool.com/projects) -- Vulnerabilities Collection: [1-day Vulnerabilities](https://saveourtool.com/vuln/list) +- Vulnerabilities Collection: [1-day Vulnerabilities](https://cosv.gitlink.org.cn) ## Motivation - [Motivation of **SAVE** and more details](info/SaveMotivation.md) - Motivation of **VULN** and more details: TBD ## High-level perspective +#### SAVE ![SAVE processing](https://user-images.githubusercontent.com/58667063/146387903-24ba9c91-a2a3-45e7-a07a-cb7bc388e4aa.jpg) +#### COSV +image + ## Build and deploy To build the project and run all tests, execute `./gradlew build`. From 66563486bebb6a642a44d1aedcdea53c286eb2e9 Mon Sep 17 00:00:00 2001 From: Andrey Kuleshov Date: Sun, 21 Jan 2024 14:34:57 +0300 Subject: [PATCH 3/3] Removing Sandbox from SAVE (#2909) ### What's: - Sandbox was a not friendly idea which was implemented not clearly; - Need to remove that to reduce the complexity of the repository; --- .github/workflows/build_and_test.yml | 8 - .github/workflows/deploy_images.yml | 21 +- .github/workflows/deploy_images_reusable.yml | 4 +- .run/Sandbox-LocalRunOnWindows.run.xml | 16 - ...calRunOnWindows (ContainerDesktop).run.xml | 14 - CONTRIBUTING.md | 10 +- api-gateway/README.md | 1 - .../src/main/resources/application-dev.yml | 2 - .../src/main/resources/application.yml | 10 - .../src/test/resources/application-dev.yml | 2 - .../authservice/config/WebSecurityConfig.kt | 2 +- .../save/buildutils/DatabaseUtils.kt | 2 +- .../buildutils/DockerStackConfiguration.kt | 12 +- docker-compose.yaml | 20 - .../spring-boot-app-configuration.gradle.kts | 2 +- save-cloud-charts/save-cloud/README.md | 3 +- .../agent-network-policy-orchestrator.yaml | 14 +- .../templates/agent-sandbox-service.yaml | 14 - .../templates/gateway-configmap.yaml | 1 - .../templates/mysql-deployment.yaml | 1 - .../templates/sandbox-configmap.yaml | 25 - .../templates/sandbox-deployment.yaml | 152 ------ .../templates/sandbox-service-account.yaml | 22 - .../save-cloud/templates/sandbox-service.yaml | 12 - .../save-cloud/values-images.yaml | 2 - .../save-cloud/values-minikube.yaml | 7 - save-cloud-charts/save-cloud/values.yaml | 10 - .../save/domain/SandboxFileInfo.kt | 15 - .../save/validation/FrontendRoutes.kt | 1 - save-deploy/README.md | 5 +- save-frontend-common/README.md | 11 - save-frontend/README.md | 11 - .../codeeditor/SandboxCodeEditorComponent.kt | 187 ------- .../basic/fileuploader/SandboxFileUploader.kt | 142 ------ .../frontend/components/topbar/TopBarLinks.kt | 1 - .../frontend/components/views/SandboxView.kt | 169 ------- .../save/frontend/routing/BasicRouting.kt | 1 - save-frontend/webpack.config.d/dev-server.js | 11 - save-sandbox/build.gradle.kts | 39 -- save-sandbox/db/db.changelog-sandbox.xml | 18 - save-sandbox/db/tables/agent-status.xml | 28 -- save-sandbox/db/tables/agent.xml | 26 - .../db/tables/db.changelog-tables.xml | 17 - save-sandbox/db/tables/execution.xml | 62 --- .../db/tables/lnk-execution-agent.xml | 31 -- .../saveourtool/save/sandbox/SaveSandbox.kt | 25 - .../save/sandbox/config/ConfigProperties.kt | 26 - .../save/sandbox/config/LogServiceConfig.kt | 21 - .../save/sandbox/config/WebSecurityConfig.kt | 27 - .../sandbox/controller/SandboxController.kt | 466 ------------------ .../controller/SandboxInternalController.kt | 129 ----- .../save/sandbox/entity/SandboxExecution.kt | 54 -- .../entity/SandboxLnkExecutionAgent.kt | 24 - .../repository/SandboxAgentRepository.kt | 19 - .../SandboxAgentStatusRepository.kt | 36 -- .../repository/SandboxExecutionRepository.kt | 23 - .../SandboxLnkExecutionAgentRepository.kt | 21 - .../SandboxOrchestratorAgentService.kt | 183 ------- .../storage/SandboxInternalFileStorage.kt | 26 - .../save/sandbox/storage/SandboxStorage.kt | 46 -- .../save/sandbox/storage/SandboxStorageKey.kt | 30 -- .../sandbox/storage/SandboxStorageKeyType.kt | 11 - .../main/resources/META-INF/spring.factories | 1 - .../application-container-desktop.properties | 3 - .../main/resources/application-dev.properties | 9 - .../resources/application-kafka.properties | 1 - .../resources/application-minikube.properties | 14 - .../resources/application-prod.properties | 1 - .../src/main/resources/application.properties | 19 - save-sandbox/src/main/resources/bootstrap.yml | 32 -- save-sandbox/src/main/resources/logback.xml | 13 - settings.gradle.kts | 1 - 72 files changed, 18 insertions(+), 2407 deletions(-) delete mode 100644 .run/Sandbox-LocalRunOnWindows.run.xml delete mode 100644 .run/SaveSandbox-LocalRunOnWindows (ContainerDesktop).run.xml delete mode 100644 save-cloud-charts/save-cloud/templates/agent-sandbox-service.yaml delete mode 100644 save-cloud-charts/save-cloud/templates/sandbox-configmap.yaml delete mode 100644 save-cloud-charts/save-cloud/templates/sandbox-deployment.yaml delete mode 100644 save-cloud-charts/save-cloud/templates/sandbox-service-account.yaml delete mode 100644 save-cloud-charts/save-cloud/templates/sandbox-service.yaml delete mode 100644 save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/domain/SandboxFileInfo.kt delete mode 100644 save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/codeeditor/SandboxCodeEditorComponent.kt delete mode 100644 save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/fileuploader/SandboxFileUploader.kt delete mode 100644 save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/SandboxView.kt delete mode 100644 save-sandbox/build.gradle.kts delete mode 100644 save-sandbox/db/db.changelog-sandbox.xml delete mode 100644 save-sandbox/db/tables/agent-status.xml delete mode 100644 save-sandbox/db/tables/agent.xml delete mode 100644 save-sandbox/db/tables/db.changelog-tables.xml delete mode 100644 save-sandbox/db/tables/execution.xml delete mode 100644 save-sandbox/db/tables/lnk-execution-agent.xml delete mode 100644 save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/SaveSandbox.kt delete mode 100644 save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/config/ConfigProperties.kt delete mode 100644 save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/config/LogServiceConfig.kt delete mode 100644 save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/config/WebSecurityConfig.kt delete mode 100644 save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/controller/SandboxController.kt delete mode 100644 save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/controller/SandboxInternalController.kt delete mode 100644 save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/entity/SandboxExecution.kt delete mode 100644 save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/entity/SandboxLnkExecutionAgent.kt delete mode 100644 save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxAgentRepository.kt delete mode 100644 save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxAgentStatusRepository.kt delete mode 100644 save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxExecutionRepository.kt delete mode 100644 save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxLnkExecutionAgentRepository.kt delete mode 100644 save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/service/SandboxOrchestratorAgentService.kt delete mode 100644 save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxInternalFileStorage.kt delete mode 100644 save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxStorage.kt delete mode 100644 save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxStorageKey.kt delete mode 100644 save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxStorageKeyType.kt delete mode 100644 save-sandbox/src/main/resources/META-INF/spring.factories delete mode 100644 save-sandbox/src/main/resources/application-container-desktop.properties delete mode 100644 save-sandbox/src/main/resources/application-dev.properties delete mode 100644 save-sandbox/src/main/resources/application-kafka.properties delete mode 100644 save-sandbox/src/main/resources/application-minikube.properties delete mode 100644 save-sandbox/src/main/resources/application-prod.properties delete mode 100644 save-sandbox/src/main/resources/application.properties delete mode 100644 save-sandbox/src/main/resources/bootstrap.yml delete mode 100644 save-sandbox/src/main/resources/logback.xml diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 88c06f6793..3b745ff4f8 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -35,7 +35,6 @@ jobs: save-orchestrator: ${{ steps.calculate-dependencies.outputs.save-orchestrator }} save-orchestrator-common: ${{ steps.calculate-dependencies.outputs.save-orchestrator-common }} save-preprocessor: ${{ steps.calculate-dependencies.outputs.save-preprocessor }} - save-sandbox: ${{ steps.calculate-dependencies.outputs.save-sandbox }} test-analysis-core: ${{ steps.calculate-dependencies.outputs.test-analysis-core }} test-utils: ${{ steps.calculate-dependencies.outputs.test-utils }} steps: @@ -87,8 +86,6 @@ jobs: - save-orchestrator-common/** save-preprocessor: - save-preprocessor/** - save-sandbox: - - save-sandbox/** test-analysis-core: - test-analysis-core/** test-utils: @@ -118,7 +115,6 @@ jobs: save_frontend=$(( $save_cloud_common + $save_frontend_common + ${{ steps.git-changed-files.outputs.save-frontend_all_changed_files_count }} )) save_orchestrator=$(( $save_cloud_common + $save_orchestrator_common + $test_utils + ${{ steps.git-changed-files.outputs.save-orchestrator_all_changed_files_count }} )) save_preprocessor=$(( $save_cloud_common + $test_utils + ${{ steps.git-changed-files.outputs.save-preprocessor_all_changed_files_count }} )) - save_sandbox=$(( $save_cloud_common + $authentication_service + $test_utils + ${{ steps.git-changed-files.outputs.save-sandbox_all_changed_files_count }} )) echo "api-gateway=$api_gateway" >> "$GITHUB_OUTPUT" echo "authentication-service=$authentication_service" >> "$GITHUB_OUTPUT" @@ -137,7 +133,6 @@ jobs: echo "save-orchestrator=$save_orchestrator" >> "$GITHUB_OUTPUT" echo "save-orchestrator-common=$save_orchestrator_common" >> "$GITHUB_OUTPUT" echo "save-preprocessor=$save_preprocessor" >> "$GITHUB_OUTPUT" - echo "save-sandbox=$save_sandbox" >> "$GITHUB_OUTPUT" echo "test-analysis-core=$test_analysis_core" >> "$GITHUB_OUTPUT" echo "test-utils=$test_utils" >> "$GITHUB_OUTPUT" build_save-cloud-common: @@ -185,7 +180,6 @@ jobs: 'save-frontend', 'save-orchestrator', 'save-preprocessor', - 'save-sandbox', 'test-analysis-core', 'test-utils' ] @@ -220,8 +214,6 @@ jobs: do-build: ${{ github.event_name == 'push' || needs.calculate_build_flags.outputs.save-orchestrator > 0 }} - module: save-preprocessor do-build: ${{ github.event_name == 'push' || needs.calculate_build_flags.outputs.save-preprocessor > 0 }} - - module: save-sandbox - do-build: ${{ github.event_name == 'push' || needs.calculate_build_flags.outputs.save-sandbox > 0 }} - module: test-analysis-core do-build: ${{ github.event_name == 'push' || needs.calculate_build_flags.outputs.test-analysis-core > 0 }} - module: test-utils diff --git a/.github/workflows/deploy_images.yml b/.github/workflows/deploy_images.yml index b040f12c75..377595cfac 100644 --- a/.github/workflows/deploy_images.yml +++ b/.github/workflows/deploy_images.yml @@ -33,11 +33,6 @@ on: default: true description: Build new image of save-orchestrator required: false - sandbox: - type: boolean - default: true - description: Build new image of save-sandbox - required: false preprocessor: type: boolean default: true @@ -64,7 +59,7 @@ jobs: uses: ./.github/workflows/build_save-agent_reusable.yml with: branch: ${{ inputs.branch }} - build-save-agent: ${{ github.event_name != 'workflow_dispatch' || inputs.backend || inputs.sandbox }} + build-save-agent: ${{ github.event_name != 'workflow_dispatch' || inputs.backend }} build-save-demo-agent: ${{ github.event_name != 'workflow_dispatch' || inputs.demo }} deploy_backend: @@ -77,18 +72,6 @@ jobs: do-build: ${{ github.event_name != 'workflow_dispatch' || inputs.backend }} override-docker-tag: ${{ github.event_name == 'workflow_dispatch' }} save-cli-version: ${{ needs.build_cli.outputs.version }} - - deploy_sandbox: - name: save-sandbox - uses: ./.github/workflows/deploy_images_reusable.yml - needs: [ build_cli, build_agents ] - with: - module: save-sandbox - branch: ${{ inputs.branch }} - do-build: ${{ github.event_name != 'workflow_dispatch' || inputs.sandbox }} - override-docker-tag: ${{ github.event_name == 'workflow_dispatch' }} - save-cli-version: ${{ needs.build_cli.outputs.version }} - deploy_demo: name: save-demo uses: ./.github/workflows/deploy_images_reusable.yml @@ -101,7 +84,7 @@ jobs: save-cli-version: stub deploy_all: - name: all excluding save-backend, save-sandbox and save-demo + name: all excluding save-backend and save-demo strategy: fail-fast: false matrix: diff --git a/.github/workflows/deploy_images_reusable.yml b/.github/workflows/deploy_images_reusable.yml index 5a4844f066..076c2e8a15 100644 --- a/.github/workflows/deploy_images_reusable.yml +++ b/.github/workflows/deploy_images_reusable.yml @@ -75,13 +75,13 @@ jobs: echo SAVE_CLI_GRADLE_OPTS=-PsaveCliVersion=${{ inputs.save-cli-version }} -PsaveCliPath=${{ github.workspace }}/save-cli >> $GITHUB_ENV - name: Download save-agent - if: inputs.module == 'save-backend' || inputs.module == 'save-sandbox' + if: inputs.module == 'save-backend' uses: actions/download-artifact@v3 with: name: save-agent path: ${{ github.workspace }}/save-agent - name: Set saveAgentPath in Gradle - if: inputs.module == 'save-backend' || inputs.module == 'save-sandbox' + if: inputs.module == 'save-backend' run: | echo SAVE_AGENT_GRADLE_OPTS=-PsaveAgentPath=${{ github.workspace }}/save-agent >> $GITHUB_ENV diff --git a/.run/Sandbox-LocalRunOnWindows.run.xml b/.run/Sandbox-LocalRunOnWindows.run.xml deleted file mode 100644 index 48ef6d9518..0000000000 --- a/.run/Sandbox-LocalRunOnWindows.run.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - \ No newline at end of file diff --git a/.run/SaveSandbox-LocalRunOnWindows (ContainerDesktop).run.xml b/.run/SaveSandbox-LocalRunOnWindows (ContainerDesktop).run.xml deleted file mode 100644 index 7e03ceeff7..0000000000 --- a/.run/SaveSandbox-LocalRunOnWindows (ContainerDesktop).run.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ac737cc614..edd010df1c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,11 +20,11 @@ You can enable hot reload by passing `--continuous` flag. ## Spring Intellij Idea Ultimate plugin In order to make Spring Intellij Idea Ultimate plugin work properly, you need to set these active profiles in service's configuration: -| | SaveApplication | SaveGateway | SaveOrchestrator | SavePreprocessor | SaveSandbox | -|:-------:|:----------------:|:-----------:|:--------------------:|:----------------:|:---------------------------:| -| Mac | `mac,dev,secure` | `mac,dev` | `dev,mac,docker-tcp` | `dev,mac` | `dev,mac,docker-tcp,secure` | -| Windows | `dev,secure` | `dev` | `dev,win,docker-tcp` | `dev` | `dev,win,docker-tcp,secure` | -| Linux | `dev,secure` | `dev` | `dev,docker-tcp` | `dev` | `dev,docker-tcp,secure` | +| | SaveApplication | SaveGateway | SaveOrchestrator | SavePreprocessor | +|:-------:|:----------------:|:-----------:|:--------------------:|:----------------:| +| Mac | `mac,dev,secure` | `mac,dev` | `dev,mac,docker-tcp` | `dev,mac` | +| Windows | `dev,secure` | `dev` | `dev,win,docker-tcp` | `dev` | +| Linux | `dev,secure` | `dev` | `dev,docker-tcp` | `dev` | ### Mac M1 contributors In order to run `save-orchestrator` on Mac with M1 in order to make it run executions, in addition to `save-deploy/README.md` you need to diff --git a/api-gateway/README.md b/api-gateway/README.md index 3fe4b83d39..2e7e27224a 100644 --- a/api-gateway/README.md +++ b/api-gateway/README.md @@ -25,7 +25,6 @@ and performs some necessary filtering and header manipulation to ensure proper c The routes are defined based on specific URI paths: - `/sec/**` is not forwarded anywhere but `api-gateway`'s `SecurityInfoController`, which is responsible for `/sec/oauth-providers` endpoint - - `/api/sandbox` is forwarded to `save-sandbox` - `/api/demo` is forwarded to `save-demo` - `/api/cpg` is forwarded to `save-cpg-demo` - `/api/**` is forwarded to `save-backend` diff --git a/api-gateway/src/main/resources/application-dev.yml b/api-gateway/src/main/resources/application-dev.yml index 111161597c..ad621419de 100644 --- a/api-gateway/src/main/resources/application-dev.yml +++ b/api-gateway/src/main/resources/application-dev.yml @@ -4,8 +4,6 @@ gateway: frontend: # In the "dev" environment, the front-end uses TCP port 8080 when run using `webpack-dev-server` (i.e. `browserDevelopmentRun` or `run` Gradle task). url: http://localhost:8080 - sandbox: - url: http://localhost:5400 demo: url: http://localhost:5421 demo-cpg: diff --git a/api-gateway/src/main/resources/application.yml b/api-gateway/src/main/resources/application.yml index 47ad6521a2..c268bf988c 100644 --- a/api-gateway/src/main/resources/application.yml +++ b/api-gateway/src/main/resources/application.yml @@ -7,8 +7,6 @@ gateway: url: http://backend:5800 frontend: url: http://frontend:5810 - sandbox: - url: http://sandbox:5400 demo: url: http://demo:5421 demo-cpg: @@ -27,14 +25,6 @@ spring: cloud: gateway: routes: - - id: sandbox-api_route - uri: ${gateway.sandbox.url} - predicates: - - Path=/api/sandbox/** - filters: - # If SESSION cookie is passed to downstream, it is then removed, because downstream discards it - - RemoveRequestHeader=Cookie - - AuthorizationHeaders= - id: demo-api_route uri: ${gateway.demo.url} predicates: diff --git a/api-gateway/src/test/resources/application-dev.yml b/api-gateway/src/test/resources/application-dev.yml index f1f81a97e4..c749b56c33 100644 --- a/api-gateway/src/test/resources/application-dev.yml +++ b/api-gateway/src/test/resources/application-dev.yml @@ -4,8 +4,6 @@ gateway: frontend: # In the "dev" environment, the front-end uses TCP port 8080 when run using `webpack-dev-server` (i.e. `browserDevelopmentRun` or `run` Gradle task). url: http://localhost:8080 - sandbox: - url: http://localhost:5400 demo: url: http://localhost:5421 demo-cpg: diff --git a/authentication-service/src/main/kotlin/com/saveourtool/save/authservice/config/WebSecurityConfig.kt b/authentication-service/src/main/kotlin/com/saveourtool/save/authservice/config/WebSecurityConfig.kt index f81fce31ef..6d924879c2 100644 --- a/authentication-service/src/main/kotlin/com/saveourtool/save/authservice/config/WebSecurityConfig.kt +++ b/authentication-service/src/main/kotlin/com/saveourtool/save/authservice/config/WebSecurityConfig.kt @@ -97,7 +97,7 @@ class WebSecurityConfig( // they are not proxied from gateway. "/actuator/**", "/internal/**", - // Agents should communicate with sandbox without authorization + // Agents should communicate without authorization "/heartbeat", // `CollectionView` is a public page "/api/$v1/projects/by-filters", diff --git a/buildSrc/src/main/kotlin/com/saveourtool/save/buildutils/DatabaseUtils.kt b/buildSrc/src/main/kotlin/com/saveourtool/save/buildutils/DatabaseUtils.kt index f2ec0089c5..a7e434bc68 100644 --- a/buildSrc/src/main/kotlin/com/saveourtool/save/buildutils/DatabaseUtils.kt +++ b/buildSrc/src/main/kotlin/com/saveourtool/save/buildutils/DatabaseUtils.kt @@ -23,7 +23,7 @@ data class DatabaseCredentials( } /** - * @param projectName save-backend, save-sandbox or save-demo + * @param projectName save-backend or save-demo * @param profile a profile to get credentials for * @return an instance of [DatabaseCredentials] for [profile] in [projectName] */ diff --git a/buildSrc/src/main/kotlin/com/saveourtool/save/buildutils/DockerStackConfiguration.kt b/buildSrc/src/main/kotlin/com/saveourtool/save/buildutils/DockerStackConfiguration.kt index d303d3eda7..1e9d7832f3 100644 --- a/buildSrc/src/main/kotlin/com/saveourtool/save/buildutils/DockerStackConfiguration.kt +++ b/buildSrc/src/main/kotlin/com/saveourtool/save/buildutils/DockerStackConfiguration.kt @@ -30,11 +30,7 @@ fun Project.registerLiquibaseTask(profile: String) { relativeChangeLogFile = "db/db.changelog-master.xml", profile = profile ) - val registerLiquibaseTaskSandbox = registerLiquibaseTask( - projectName = "save-sandbox", - relativeChangeLogFile = "save-sandbox/db/db.changelog-sandbox.xml", - profile = profile - ) + val registerLiquibaseTaskDemo = registerLiquibaseTask( projectName = "save-demo", relativeChangeLogFile = "save-demo/db/db.changelog-demo.xml", @@ -48,7 +44,6 @@ fun Project.registerLiquibaseTask(profile: String) { tasks.register("liquibaseUpdate") { dependsOn( registerLiquibaseTaskBackend, - registerLiquibaseTaskSandbox, registerLiquibaseTaskDemo, registerLiquibaseTaskCosv, ) @@ -211,7 +206,6 @@ fun Project.createStackDeployTask(profile: String) { FRONTEND_TAG=${defaultVersionOrProperty("frontend.dockerTag")} GATEWAY_TAG=${defaultVersionOrProperty("gateway.dockerTag")} ORCHESTRATOR_TAG=${defaultVersionOrProperty("orchestrator.dockerTag")} - SANDBOX_TAG=${defaultVersionOrProperty("sandbox.dockerTag")} PREPROCESSOR_TAG=${defaultVersionOrProperty("preprocessor.dockerTag")} DEMO_TAG=${defaultVersionOrProperty("demo.dockerTag")} PROFILE=$profile @@ -248,7 +242,6 @@ fun Project.createStackDeployTask(profile: String) { Files.createDirectories(configsDir.resolve("backend")) Files.createDirectories(configsDir.resolve("gateway")) Files.createDirectories(configsDir.resolve("orchestrator")) - Files.createDirectories(configsDir.resolve("sandbox")) Files.createDirectories(configsDir.resolve("preprocessor")) Files.createDirectories(configsDir.resolve("demo")) } @@ -331,7 +324,6 @@ fun Project.createStackDeployTask(profile: String) { "up", "-d", "orchestrator", - "sandbox", "backend", "frontend", "preprocessor", @@ -351,7 +343,7 @@ fun Project.createStackDeployTask(profile: String) { project(componentName).tasks.named("bootBuildImage") dependsOn(buildTask) val serviceName = when (componentName) { - "save-backend", "save-frontend", "save-orchestrator", "save-sandbox", "save-preprocessor" -> "save_${componentName.substringAfter("save-")}" + "save-backend", "save-frontend", "save-orchestrator", "save-preprocessor" -> "save_${componentName.substringAfter("save-")}" "api-gateway" -> "save_gateway" else -> error("Wrong component name $componentName") } diff --git a/docker-compose.yaml b/docker-compose.yaml index c3fd867f84..b7457743dc 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -33,26 +33,6 @@ services: labels: - "prometheus-job=save-orchestrator" logging: *loki-logging-jvm - sandbox: - image: ghcr.io/saveourtool/save-sandbox:${SANDBOX_TAG} - user: root # to access host's docker socket - environment: - - "SPRING_PROFILES_ACTIVE=${PROFILE},secure,docker-secrets" - secrets: - - db_username - - db_password - ports: - - "5400:5400" - volumes: - - "/var/run/docker.sock:/var/run/docker.sock" - - /home/saveu/configs/sandbox:/home/cnb/config - - save-tmp-resources:/tmp - extra_hosts: - - "host.docker.internal:host-gateway" - deploy: - labels: - - "prometheus-job=save-sandbox" - logging: *loki-logging-jvm backend: image: ghcr.io/saveourtool/save-backend:${BACKEND_TAG} environment: diff --git a/gradle/plugins/src/main/kotlin/com/saveourtool/save/buildutils/spring-boot-app-configuration.gradle.kts b/gradle/plugins/src/main/kotlin/com/saveourtool/save/buildutils/spring-boot-app-configuration.gradle.kts index dd8656b355..8569d9f873 100644 --- a/gradle/plugins/src/main/kotlin/com/saveourtool/save/buildutils/spring-boot-app-configuration.gradle.kts +++ b/gradle/plugins/src/main/kotlin/com/saveourtool/save/buildutils/spring-boot-app-configuration.gradle.kts @@ -33,7 +33,7 @@ tasks.withType().configureEach { os.isWindows -> append(",win") os.isMacOsX -> append(",mac") } - if (listOf("save-sandbox", "save-backend", "save-cosv").any { project.path.contains(it) }) { + if (listOf("save-backend", "save-cosv").any { project.path.contains(it) }) { append(",secure") } } diff --git a/save-cloud-charts/save-cloud/README.md b/save-cloud-charts/save-cloud/README.md index 0dc0a52bb4..c1d71d8cae 100644 --- a/save-cloud-charts/save-cloud/README.md +++ b/save-cloud-charts/save-cloud/README.md @@ -10,7 +10,6 @@ api-gateway acts as an entrypoint and svc/gateway is actually a LoadBalancer. * `spring.datasource.username` * `spring.datasource.password` * `spring.datasource.backend-url` - * `spring.datasource.sandbox-url` * `spring.datasource.demo-url` These secrets are then mounted under the path specified as `DATABASE_SECRETS_PATH` environment variable. @@ -75,6 +74,6 @@ command line using `--set` flag. $ helm --kube-context=minikube --namespace=save-cloud upgrade -i save-cloud save-cloud-0.1.0.tgz/ --values values-minikube.yaml --values=values-images.yaml ``` * Database migrations can be run by setting value `mysql.migrations.enabled` to `true` (no additional setup, migrations - are executed by init container, but may be too slow with constant recreations of backend/sandbox pods) + are executed by init container, but may be too slow with constant recreations of backend pods) or port 3306 of mysql pod can be forwarded and `liquibaseUpdate` can be executed manually. If needed, don't forget that JDBC URL for liquibase in dev profile is read from `application-dev.properties` value `dev.datasource.url`. diff --git a/save-cloud-charts/save-cloud/templates/agent-network-policy-orchestrator.yaml b/save-cloud-charts/save-cloud/templates/agent-network-policy-orchestrator.yaml index f92dba1a16..c01ab713d0 100644 --- a/save-cloud-charts/save-cloud/templates/agent-network-policy-orchestrator.yaml +++ b/save-cloud-charts/save-cloud/templates/agent-network-policy-orchestrator.yaml @@ -6,8 +6,7 @@ metadata: spec: # Should be applied to save-agents only # - # As for now, there is no way to tell orchestrator pod from sandbox pod so need to allow connection to both - # orchestrator and sandbox. + # As for now, there is no way to tell orchestrator pod so need to allow connection to orchestrator. podSelector: matchLabels: io.kompose.service: save-agent @@ -36,14 +35,3 @@ spec: ports: - protocol: TCP port: {{ .Values.backend.containerPort }} - - to: - # Allow traffic to save-sandbox - - namespaceSelector: - matchLabels: - name: {{ .Values.namespace }} - - podSelector: - matchLabels: - io.kompose.service: sandbox - ports: - - protocol: TCP - port: {{ .Values.sandbox.containerPort }} \ No newline at end of file diff --git a/save-cloud-charts/save-cloud/templates/agent-sandbox-service.yaml b/save-cloud-charts/save-cloud/templates/agent-sandbox-service.yaml deleted file mode 100644 index 8cb2441a77..0000000000 --- a/save-cloud-charts/save-cloud/templates/agent-sandbox-service.yaml +++ /dev/null @@ -1,14 +0,0 @@ -{{ if .Values.agentNamespace }} - -apiVersion: v1 -kind: Service -metadata: - name: {{ .Values.sandbox.name }} - namespace: {{ .Values.agentNamespace }} -spec: - type: ExternalName - externalName: {{ .Values.sandbox.name }}.{{ .Values.namespace }}.svc.cluster.local - ports: - - port: {{ .Values.sandbox.containerPort }} - -{{ end }} diff --git a/save-cloud-charts/save-cloud/templates/gateway-configmap.yaml b/save-cloud-charts/save-cloud/templates/gateway-configmap.yaml index 8cdad682bf..68a3c773c1 100644 --- a/save-cloud-charts/save-cloud/templates/gateway-configmap.yaml +++ b/save-cloud-charts/save-cloud/templates/gateway-configmap.yaml @@ -6,7 +6,6 @@ data: application.properties: | gateway.backend.url=http://backend gateway.frontend.url=http://frontend - gateway.sandbox.url=http://sandbox gateway.demo-cpg.url=http://demo-cpg gateway.demo.url=http://demo server.shutdown=graceful diff --git a/save-cloud-charts/save-cloud/templates/mysql-deployment.yaml b/save-cloud-charts/save-cloud/templates/mysql-deployment.yaml index 5b829410f1..6b604a7191 100644 --- a/save-cloud-charts/save-cloud/templates/mysql-deployment.yaml +++ b/save-cloud-charts/save-cloud/templates/mysql-deployment.yaml @@ -7,7 +7,6 @@ metadata: name: db-secrets stringData: spring.datasource.backend-url: 'jdbc:mysql://mysql-service:3306/{{ .Values.mysql.backend_schema }}' - spring.datasource.sandbox-url: 'jdbc:mysql://mysql-service:3306/{{ .Values.mysql.sandbox_schema }}' spring.datasource.demo-url: 'jdbc:mysql://mysql-service:3306/{{ .Values.mysql.demo_schema }}' spring.datasource.username: root spring.datasource.password: {{ .Values.mysql.root_password | quote }} diff --git a/save-cloud-charts/save-cloud/templates/sandbox-configmap.yaml b/save-cloud-charts/save-cloud/templates/sandbox-configmap.yaml deleted file mode 100644 index 3a304a1c94..0000000000 --- a/save-cloud-charts/save-cloud/templates/sandbox-configmap.yaml +++ /dev/null @@ -1,25 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ .Values.sandbox.name }}-config -data: - application.properties: | - orchestrator.kubernetes.apiServerUrl=http://kubernetes.default.svc - orchestrator.kubernetes.serviceAccount=${POD_SERVICE_ACCOUNT} - orchestrator.kubernetes.current-namespace=${POD_NAMESPACE} - orchestrator.kubernetes.agent-namespace= {{ .Values.agentNamespace }} - - server.shutdown=graceful - management.endpoints.web.exposure.include=* - management.server.port={{ .Values.sandbox.managementPort }} - spring.datasource.url=${spring.datasource.sandbox-url} - - sandbox.agent-settings.sandbox-url=http://{{ .Values.sandbox.name }} - orchestrator.agent-settings.heartbeat-url=http://{{ .Values.sandbox.name }}/heartbeat - orchestrator.agent-settings.debug=true - - logging.level.com.saveourtool.save.orchestrator.kubernetes=DEBUG - - {{ if .Values.sandbox.applicationProperties }} - {{- .Values.sandbox.applicationProperties | nindent 4 }} - {{ end }} \ No newline at end of file diff --git a/save-cloud-charts/save-cloud/templates/sandbox-deployment.yaml b/save-cloud-charts/save-cloud/templates/sandbox-deployment.yaml deleted file mode 100644 index 0502bcfb55..0000000000 --- a/save-cloud-charts/save-cloud/templates/sandbox-deployment.yaml +++ /dev/null @@ -1,152 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: sandbox - labels: - {{- include "common.labels" (merge (dict "service" .Values.sandbox) .) | nindent 4 }} -spec: - selector: - matchLabels: - io.kompose.service: sandbox - replicas: 1 - strategy: - # Because of shared volume with multi-attach problem - type: Recreate - template: - metadata: - labels: - {{- include "pod.common.labels" (merge (dict "service" .Values.sandbox ) .) | nindent 8 }} - annotations: - {{- include "pod.common.annotations" (dict "service" .Values.backend ) | nindent 8 }} - spec: - serviceAccountName: sandbox-sa - restartPolicy: Always - {{- if .Values.sandbox.nodeName }} - nodeName: {{ .Values.sandbox.nodeName }} - {{- end }} - {{- include "cnb.securityContext" . | nindent 6 }} - containers: - - name: sandbox - {{- include "spring-boot.common" (merge (dict "service" .Values.sandbox) .) | nindent 10 }} - env: - {{- include "spring-boot.common.env" (merge (dict "service" .Values.sandbox) .) | nindent 12 }} - - name: HOST_IP - valueFrom: - fieldRef: - fieldPath: status.hostIP - - name: DATABASE_SECRETS_PATH - value: {{ .Values.mysql.dbPasswordFile }} - - name: S3_SECRETS_PATH - value: {{ .Values.s3.secretFile }} - - name: JAVA_TOOL_OPTIONS - value: -XX:ReservedCodeCacheSize=48M - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: POD_SERVICE_ACCOUNT - valueFrom: - fieldRef: - fieldPath: spec.serviceAccountName - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - volumeMounts: - - {{ include "spring-boot.config-volume-mount" . | indent 14 | trim }} - - name: database-secret - mountPath: {{ .Values.mysql.dbPasswordFile }} - - name: s3-secrets - mountPath: {{ .Values.s3.secretFile }} - {{- include "spring-boot.management" .Values.sandbox | nindent 10 }} - resources: - limits: - memory: 800M - requests: - memory: 600M - {{ if .Values.mysql.migrations.enabled }} - initContainers: - - name: git-cloner - image: alpine/git - env: - {{ if .Values.proxy.enabled }} - {{- with .Values.proxy.extraEnv }} - {{- toYaml . | nindent 12 }} - {{- end }} - {{ end }} - args: - - clone - - --progress - - --verbose - {{ if .Values.proxy.enabled }} - {{- with .Values.proxy.extraArgs }} - {{- toYaml . | nindent 12 }} - {{- end }} - {{ end }} - - --single-branch - - --branch - - {{ .Values.mysql.migrations.branch | default "master" }} - - -- - - https://github.com/saveourtool/save-cloud.git - - /data - volumeMounts: - - mountPath: /data - name: migrations-data - - name: liquibase-runner - image: liquibase/liquibase:4.20 - securityContext: - runAsUser: 1001 - runAsGroup: 1001 - args: - - --url=$(DB_URL)?createDatabaseIfNotExist=true - - --changeLogFile=save-sandbox/db/db.changelog-sandbox.xml - - --username=$(DB_USERNAME) - - --password=$(DB_PASSWORD) - - --log-level=info - - --contexts={{ .Values.profile }} - - update - resources: - requests: - memory: 100M - limits: - memory: 300M - env: - # See https://hub.docker.com/r/liquibase/liquibase, section 'Notice for MySQL Users' - - name: INSTALL_MYSQL - value: 'true' - - name: DB_URL - valueFrom: - secretKeyRef: - name: db-secrets - key: spring.datasource.sandbox-url - - name: DB_USERNAME - valueFrom: - secretKeyRef: - name: db-secrets - key: spring.datasource.username - - name: DB_PASSWORD - valueFrom: - secretKeyRef: - name: db-secrets - key: spring.datasource.password - {{ if .Values.proxy.enabled }} - {{- with .Values.proxy.extraEnv }} - {{- toYaml . | nindent 12 }} - {{- end }} - {{ end }} - volumeMounts: - - mountPath: /liquibase/changelog - name: migrations-data - - mountPath: {{ .Values.mysql.dbPasswordFile }} - name: database-secret - {{ end }} - volumes: - - {{ include "spring-boot.config-volume" (dict "service" .Values.sandbox) | indent 10 | trim }} - - name: database-secret - secret: - secretName: db-secrets - - name: s3-secrets - secret: - secretName: s3-secrets - - name: migrations-data - emptyDir: { } diff --git a/save-cloud-charts/save-cloud/templates/sandbox-service-account.yaml b/save-cloud-charts/save-cloud/templates/sandbox-service-account.yaml deleted file mode 100644 index c7ad887be0..0000000000 --- a/save-cloud-charts/save-cloud/templates/sandbox-service-account.yaml +++ /dev/null @@ -1,22 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: sandbox-sa - ---- - -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: sandbox-jobs-binding - {{ if .Values.agentNamespace }} - namespace: {{ .Values.agentNamespace }} - {{ end }} -subjects: - - kind: ServiceAccount - name: sandbox-sa - namespace: {{ .Values.namespace }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: jobs-executor diff --git a/save-cloud-charts/save-cloud/templates/sandbox-service.yaml b/save-cloud-charts/save-cloud/templates/sandbox-service.yaml deleted file mode 100644 index a2cdb9e7f6..0000000000 --- a/save-cloud-charts/save-cloud/templates/sandbox-service.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: -{{- include "service.common.metadata" (dict "service" .Values.sandbox) | nindent 2 }} -spec: - {{ if .Values.sandbox.clusterIP }} - clusterIP: {{ .Values.sandbox.clusterIP }} - {{ end }} - ports: - {{- include "service.common.ports" (dict "service" .Values.sandbox) | nindent 4 }} - selector: - {{- include "service.common.selectors" (dict "service" .Values.sandbox) | nindent 4 }} diff --git a/save-cloud-charts/save-cloud/values-images.yaml b/save-cloud-charts/save-cloud/values-images.yaml index e7c1283710..1c729aa564 100644 --- a/save-cloud-charts/save-cloud/values-images.yaml +++ b/save-cloud-charts/save-cloud/values-images.yaml @@ -17,8 +17,6 @@ preprocessor: dockerTag: '0.4.0-alpha.0.379-70423bd' orchestrator: dockerTag: '0.4.0-alpha.0.379-70423bd' -sandbox: - dockerTag: '0.4.0-alpha.0.379-70423bd' demo: dockerTag: '0.4.0-alpha.0.379-70423bd' demo_cpg: diff --git a/save-cloud-charts/save-cloud/values-minikube.yaml b/save-cloud-charts/save-cloud/values-minikube.yaml index 2fc3bf2587..bbd5e41648 100644 --- a/save-cloud-charts/save-cloud/values-minikube.yaml +++ b/save-cloud-charts/save-cloud/values-minikube.yaml @@ -18,13 +18,6 @@ orchestrator: orchestrator.agents-count=1 logging.level.com.saveourtool=DEBUG orchestrator.kubernetes.useGvisor=false -sandbox: - profile: dev,kubernetes,minikube - dockerHost: tcp://${HOST_IP}:2376 - applicationProperties: | - orchestrator.docker.host=tcp://localhost:2376 - logging.level.com.saveourtool=DEBUG - orchestrator.kubernetes.useGvisor=false demo_cpg: profile: dev demo: diff --git a/save-cloud-charts/save-cloud/values.yaml b/save-cloud-charts/save-cloud/values.yaml index 9983321f80..bf1830bb90 100644 --- a/save-cloud-charts/save-cloud/values.yaml +++ b/save-cloud-charts/save-cloud/values.yaml @@ -30,15 +30,6 @@ orchestrator: # Fixed ClusterIP can be assigned to make it easier to query orchestrator from services outside Kubernetes clusterIP: null dockerHost: tcp://${HOST_IP}:2375 -sandbox: - name: sandbox - profile: dev,secure - imageName: save-sandbox - containerPort: 5400 - managementPort: 5401 - # Fixed ClusterIP can be assigned to make it easier to query orchestrator from services outside Kubernetes - clusterIP: null - dockerHost: tcp://${HOST_IP}:2375 preprocessor: name: preprocessor imageName: save-preprocessor @@ -78,7 +69,6 @@ mysql: ip: 192.168.65.2 # Name of the database schema that will be used by save-cloud deployment backend_schema: save_cloud - sandbox_schema: save_sandbox demo_schema: save_demo cosv_schema: cosv root_password: '123' diff --git a/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/domain/SandboxFileInfo.kt b/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/domain/SandboxFileInfo.kt deleted file mode 100644 index f6a28e6d11..0000000000 --- a/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/domain/SandboxFileInfo.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.saveourtool.save.domain - -import kotlinx.serialization.Serializable - -/** - * Class that contains metadata of Sandbox files - * - * @property sizeBytes size in bytes - * @property name name of a file - */ -@Serializable -data class SandboxFileInfo( - val name: String, - val sizeBytes: Long, -) diff --git a/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/validation/FrontendRoutes.kt b/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/validation/FrontendRoutes.kt index c427a6b502..f34758f3ca 100644 --- a/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/validation/FrontendRoutes.kt +++ b/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/validation/FrontendRoutes.kt @@ -33,7 +33,6 @@ enum class FrontendRoutes(val path: String) { PROFILE("profile"), PROJECTS("projects"), REGISTRATION("registration"), - SANDBOX("sandbox"), SAVE("save"), SETTINGS_DELETE("$SETTINGS/delete"), SETTINGS_EMAIL("$SETTINGS/email"), diff --git a/save-deploy/README.md b/save-deploy/README.md index 5fac7eaaa6..4eee066d87 100644 --- a/save-deploy/README.md +++ b/save-deploy/README.md @@ -18,12 +18,12 @@ Deployment is performed on server via docker swarm or locally via `docker compos The `libs.version.toml` contains `save-cli` version. The `save-agent` uses this version as a compile dependency to read execution's reports. -The `save-backend` and `save-sandbox` download newer versions of `save-cli` from _GitHub_ on startup. +The `save-backend` downloads newer versions of `save-cli` from _GitHub_ on startup. #### Using a `SNAPSHOT` version of `save-cli` If `save-cli` is set to snapshot version in `lib.version.toml`, we download `save-cli`'s sources and build them in _GitHub_ action: [Build and push Docker images](../.github/workflows/deploy_images.yml). -Then _Gradle_ adds the result (_.kexe_) to `save-backend` and `save-sandbox` as a runtime dependency +Then _Gradle_ adds the result (_.kexe_) to `save-backend` as a runtime dependency **Under the hood:** _Gradle_ supports two variables `saveCliVersion` and `saveCliPath`. The `saveCliVersion` overrides version of `save-cli` from `lib.version.toml`. @@ -283,7 +283,6 @@ Do not forget to use `mac` profile. | 5100 | save-orchestrator | | 5200 | save-test-preprocessor | | 5300 | api-gateway | -| 5400 | save-sandbox | | 9090 | prometheus | | 9091 | node_exporter | | 9100 | grafana | diff --git a/save-frontend-common/README.md b/save-frontend-common/README.md index 906098999c..2b58f82104 100644 --- a/save-frontend-common/README.md +++ b/save-frontend-common/README.md @@ -53,17 +53,6 @@ config.devServer = Object.assign( return middlewares; }, proxy: [ - { - context: ["/api/sandbox/**"], - target: 'http://localhost:5400', - logLevel: 'debug', - onProxyReq: function (proxyReq, req, res) { - proxyReq.setHeader("X-Authorization-Id", "1"); - proxyReq.setHeader("X-Authorization-Name", "admin"); - proxyReq.setHeader("X-Authorization-Roles", "ROLE_SUPER_ADMIN"); - proxyReq.setHeader("X-Authorization-Status", "ACTIVE"); - } - }, { context: ["/api/demo/**"], target: 'http://localhost:5421', diff --git a/save-frontend/README.md b/save-frontend/README.md index 90ac2ec60c..786c923e1f 100644 --- a/save-frontend/README.md +++ b/save-frontend/README.md @@ -62,17 +62,6 @@ config.devServer = Object.assign( return middlewares; }, proxy: [ - { - context: ["/api/sandbox/**"], - target: 'http://localhost:5400', - logLevel: 'debug', - onProxyReq: function (proxyReq, req, res) { - proxyReq.setHeader("X-Authorization-Id", "1"); - proxyReq.setHeader("X-Authorization-Name", "admin"); - proxyReq.setHeader("X-Authorization-Roles", "ROLE_SUPER_ADMIN"); - proxyReq.setHeader("X-Authorization-Status", "ACTIVE"); - } - }, { context: ["/api/demo/**"], target: 'http://localhost:5421', diff --git a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/codeeditor/SandboxCodeEditorComponent.kt b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/codeeditor/SandboxCodeEditorComponent.kt deleted file mode 100644 index 7d942cc73d..0000000000 --- a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/codeeditor/SandboxCodeEditorComponent.kt +++ /dev/null @@ -1,187 +0,0 @@ -@file:Suppress("FILE_NAME_MATCH_CLASS", "HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE") - -package com.saveourtool.save.frontend.components.basic.codeeditor - -import com.saveourtool.save.frontend.common.utils.* -import com.saveourtool.save.frontend.common.utils.WithRequestStatusContext -import com.saveourtool.save.frontend.components.basic.codeeditor.FileType.Companion.getTypedOption -import com.saveourtool.save.frontend.components.basic.codeeditor.FileType.SAVE_TOML -import com.saveourtool.save.frontend.components.basic.codeeditor.FileType.SETUP_SH -import com.saveourtool.save.frontend.components.basic.codeeditor.FileType.TEST -import com.saveourtool.save.frontend.components.views.sandboxApiUrl -import com.saveourtool.save.frontend.externals.reactace.AceThemes -import com.saveourtool.save.utils.Languages - -import react.FC -import react.Props -import react.dom.html.ReactHTML.div -import react.dom.html.ReactHTML.h6 -import react.useState -import web.cssom.ClassName - -import kotlinx.browser.window -import kotlinx.coroutines.await - -private const val DEFAULT_EDITOR_MESSAGE = "Select one of the files above to start editing it!" - -private const val TEXT_PLACEHOLDER = "Please load data from server using button above." - -/** - * CodeEditor component for sandbox that encapsulates toolbar and oen editor for three different files. - */ -val sandboxCodeEditorComponent = sandboxCodeEditorComponent() - -/** - * SandboxCodeEditor functional component [Props] - */ -external interface SandboxCodeEditorComponentProps : Props { - /** - * Title of an editor - */ - var editorTitle: String? - - /** - * Action to run execution - */ - var doRunExecution: () -> Unit - - /** - * Action to reload debug info - */ - var doResultReload: () -> Unit -} - -private suspend fun WithRequestStatusContext.postTextRequest( - urlPart: String, - content: String, - fileName: String, -) = post( - url = "$sandboxApiUrl/upload-$urlPart-as-text?fileName=$fileName", - headers = jsonHeaders, - body = content, - loadingHandler = ::noopLoadingHandler, -).ok - -private suspend fun WithRequestStatusContext.getTextRequest( - urlPart: String, - fileName: String, -) = get( - url = "$sandboxApiUrl/download-$urlPart-as-text?fileName=$fileName", - headers = jsonHeaders, - loadingHandler = ::noopLoadingHandler, -) - .let { response -> - if (response.ok) { - response.text().await() - } else { - null - } - } - -@Suppress("TOO_LONG_FUNCTION", "LongMethod", "ComplexMethod") -private fun sandboxCodeEditorComponent() = FC { props -> - val (selectedMode, setSelectedMode) = useState(Languages.KOTLIN) - val (selectedTheme, setSelectedTheme) = useState(AceThemes.CHROME) - val (selectedFileType, setSelectedFileType) = useState(null) - - val (draftCodeText, setDraftCodeText) = useState(TEXT_PLACEHOLDER) - val (draftConfigText, setDraftConfigText) = useState(TEXT_PLACEHOLDER) - val (draftSetupShText, setDraftSetupShText) = useState(TEXT_PLACEHOLDER) - - val (savedCodeText, setSavedCodeText) = useState(TEXT_PLACEHOLDER) - val (savedConfigText, setSavedConfigText) = useState(TEXT_PLACEHOLDER) - val (savedSetupShText, setSavedSetupShText) = useState(TEXT_PLACEHOLDER) - - val fetchTexts = useDeferredRequest { - FileType.values().forEach { fileType -> - val text = getTextRequest(fileType.urlPart, fileType.fileName) ?: TEXT_PLACEHOLDER - getTypedOption(fileType, setSavedCodeText, setSavedConfigText, setSavedSetupShText)(text) - getTypedOption(fileType, setDraftCodeText, setDraftConfigText, setDraftSetupShText)(text) - } - } - - val fetchText = useDeferredRequest { - selectedFileType?.let { fileType -> - val text = getTextRequest(fileType.urlPart, fileType.fileName) ?: TEXT_PLACEHOLDER - getTypedOption(fileType, setSavedCodeText, setSavedConfigText, setSavedSetupShText)(text) - getTypedOption(fileType, setDraftCodeText, setDraftConfigText, setDraftSetupShText)(text) - } - } - - val uploadText = useDeferredRequest { - selectedFileType?.let { fileType -> - val content = getTypedOption(fileType, draftCodeText, draftConfigText, draftSetupShText) - if (postTextRequest(fileType.urlPart, content, fileType.fileName)) { - getTypedOption(fileType, setSavedCodeText, setSavedConfigText, setSavedSetupShText)(content) - } - } - } - - val uploadTexts = useDeferredRequest { - FileType.values().forEach { fileType -> - val content = getTypedOption(fileType, draftCodeText, draftConfigText, draftSetupShText) - if (postTextRequest(fileType.urlPart, content, fileType.fileName)) { - getTypedOption(fileType, setSavedCodeText, setSavedConfigText, setSavedSetupShText)(content) - } - } - } - - useOnce(fetchTexts) - - div { - props.editorTitle?.let { editorTitle -> - h6 { - className = ClassName("text-center text-primary") - +editorTitle - } - } - val hasUncommittedChanges = mapOf( - TEST to (savedCodeText != draftCodeText), - SAVE_TOML to (savedConfigText != draftConfigText), - SETUP_SH to (savedSetupShText != draftSetupShText), - ) - displayCodeEditorToolbar( - selectedMode, - selectedTheme, - selectedFileType, - hasUncommittedChanges, - { newModeName -> setSelectedMode(Languages.values().find { it.modeName == newModeName }!!) }, - { newThemeName -> setSelectedTheme(AceThemes.values().find { it.themeName == newThemeName }!!) }, - onUploadChanges = uploadText, - onReloadChanges = fetchText, - onResultReload = props.doResultReload, - onRunExecution = { - val hasAnyUncommittedChanges = hasUncommittedChanges.any { (_, hasChanges) -> - hasChanges - } - if (hasAnyUncommittedChanges) { - if (window.confirm("Some changes are not saved. Save and run execution?")) { - uploadTexts() - props.doRunExecution() - } else { - window.alert("Run canceled.") - } - } else { - uploadTexts() - props.doRunExecution() - } - }, - ) { fileType -> - if (fileType == selectedFileType) { - setSelectedFileType(null) - } else { - setSelectedFileType(fileType) - } - } - - codeEditorComponent { - editorTitle = props.editorTitle - isDisabled = selectedFileType == null - this.selectedTheme = selectedTheme - this.selectedMode = selectedMode - onDraftTextUpdate = { text -> getTypedOption(selectedFileType, setDraftCodeText, setDraftConfigText, setDraftSetupShText)?.invoke(text) } - savedText = getTypedOption(selectedFileType, savedCodeText, savedConfigText, savedSetupShText) ?: DEFAULT_EDITOR_MESSAGE - draftText = getTypedOption(selectedFileType, draftCodeText, draftConfigText, draftSetupShText) ?: DEFAULT_EDITOR_MESSAGE - } - } -} diff --git a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/fileuploader/SandboxFileUploader.kt b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/fileuploader/SandboxFileUploader.kt deleted file mode 100644 index b37b2ff9a6..0000000000 --- a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/fileuploader/SandboxFileUploader.kt +++ /dev/null @@ -1,142 +0,0 @@ -/** - * Component for uploading files - */ - -@file:Suppress("FILE_NAME_MATCH_CLASS") - -package com.saveourtool.save.frontend.components.basic.fileuploader - -import com.saveourtool.save.domain.* -import com.saveourtool.save.frontend.common.components.basic.fileuploader.deleteFileButton -import com.saveourtool.save.frontend.common.components.basic.fileuploader.downloadFileButton -import com.saveourtool.save.frontend.common.components.inputform.dragAndDropForm -import com.saveourtool.save.frontend.common.http.postUploadFile -import com.saveourtool.save.frontend.common.utils.* -import com.saveourtool.save.frontend.common.utils.noopLoadingHandler -import com.saveourtool.save.frontend.components.basic.codeeditor.FileType - -import js.core.asList -import react.* -import react.dom.html.ReactHTML.div -import react.dom.html.ReactHTML.li -import react.dom.html.ReactHTML.ul -import web.cssom.ClassName -import web.file.File - -import kotlinx.browser.window - -/** - * [FC] for sandbox file uploading - */ -@Suppress( - "TOO_LONG_FUNCTION", - "TYPE_ALIAS", - "LongMethod", - "ComplexMethod", -) -val sandboxFileUploader: FC = FC { props -> - val (selectedFiles, setSelectedFiles) = useState>(emptyList()) - - useRequest { - val listOfFileInfos: List = get( - props.getUrlForAvailableFilesFetch(), - jsonHeaders, - loadingHandler = ::noopLoadingHandler, - ).decodeFromJsonString() - setSelectedFiles { it + listOfFileInfos } - } - - val (fileToDelete, setFileToDelete) = useState(null) - val deleteFile = useDeferredRequest { - fileToDelete?.let { - val response = delete( - props.getUrlForFileDeletion(fileToDelete), - jsonHeaders, - loadingHandler = ::loadingHandler, - ) - - if (response.ok) { - setSelectedFiles { it - fileToDelete } - setFileToDelete(null) - } - } - } - - val (filesForUploading, setFilesForUploading) = useState>(emptyList()) - val uploadFiles = useDeferredRequest { - filesForUploading.forEach { fileForUploading -> - if (fileForUploading.name != FileType.SETUP_SH.fileName) { - val uploadedFileInfo: SandboxFileInfo = postUploadFile( - url = props.getUrlForFileUpload(), - file = fileForUploading, - loadingHandler = ::loadingHandler, - ) - .decodeFromJsonString() - setSelectedFiles { it + uploadedFileInfo } - } else { - window.alert("Use code editor instead of file uploader to manage ${fileForUploading.name}, please.") - } - } - } - - div { - ul { - className = ClassName("list-group") - - // ===== SELECTED FILES ===== - selectedFiles - .filter { it.name != FileType.SETUP_SH.fileName } - .map { file -> - li { - className = ClassName("list-group-item") - downloadFileButton(file, SandboxFileInfo::name, props.getUrlForFileDownload) - deleteFileButton(file, SandboxFileInfo::name) { - setFileToDelete(it) - deleteFile() - } - +file.name - } - } - - // ===== UPLOAD FILES BUTTON ===== - li { - className = ClassName("list-group-item p-0 d-flex bg-light") - dragAndDropForm { - isDisabled = false - isMultipleFilesSupported = false - tooltipMessage = "upload your tested tool and all other needed files" - onChangeEventHandler = { files -> - setFilesForUploading(files!!.asList()) - uploadFiles() - } - } - } - } - } - useTooltip() -} - -/** - * Props for file uploader - */ -external interface SandboxFileUploaderProps : Props { - /** - * Url for fetching existing in storage files - */ - var getUrlForAvailableFilesFetch: () -> String - - /** - * Callback to get url for file uploading to storage - */ - var getUrlForFileUpload: () -> String - - /** - * Callback to get url for file downloading from storage - */ - var getUrlForFileDownload: (SandboxFileInfo) -> String - - /** - * Callback to get url for file deletion from storage - */ - var getUrlForFileDeletion: (SandboxFileInfo) -> String -} diff --git a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/topbar/TopBarLinks.kt b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/topbar/TopBarLinks.kt index 81981a8edc..a516f97106 100644 --- a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/topbar/TopBarLinks.kt +++ b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/topbar/TopBarLinks.kt @@ -31,7 +31,6 @@ val topBarLinks: FC = FC { props -> TopBarLink(hrefAnchor = FrontendRoutes.DEMO.path, text = "Demo".t()), TopBarLink(hrefAnchor = "${FrontendRoutes.DEMO}/cpg", text = "CPG".t()), TopBarLink(hrefAnchor = FrontendRoutes.AWESOME_BENCHMARKS.path, text = "Awesome Benchmarks".t()), - TopBarLink(hrefAnchor = FrontendRoutes.SANDBOX.path, text = "Try SAVE format".t()), TopBarLink(hrefAnchor = FrontendRoutes.PROJECTS.path, text = "Projects board".t()), TopBarLink(hrefAnchor = FrontendRoutes.CONTESTS.path, text = "Contests".t()), TopBarLink(hrefAnchor = FrontendRoutes.ABOUT_US.path, text = "About us".t()), diff --git a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/SandboxView.kt b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/SandboxView.kt deleted file mode 100644 index 505f070cbf..0000000000 --- a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/SandboxView.kt +++ /dev/null @@ -1,169 +0,0 @@ -@file:Suppress("HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE") - -package com.saveourtool.save.frontend.components.views - -import com.saveourtool.save.core.result.Crash -import com.saveourtool.save.core.result.Fail -import com.saveourtool.save.core.result.Ignored -import com.saveourtool.save.core.result.Pass -import com.saveourtool.save.domain.Sdk -import com.saveourtool.save.domain.TestResultDebugInfo -import com.saveourtool.save.frontend.common.components.modal.displayModal -import com.saveourtool.save.frontend.common.components.modal.largeTransparentModalStyle -import com.saveourtool.save.frontend.common.externals.fontawesome.faTimesCircle -import com.saveourtool.save.frontend.common.externals.fontawesome.fontAwesomeIcon -import com.saveourtool.save.frontend.common.utils.* -import com.saveourtool.save.frontend.common.utils.get -import com.saveourtool.save.frontend.components.basic.codeeditor.sandboxCodeEditorComponent -import com.saveourtool.save.frontend.components.basic.fileuploader.sandboxFileUploader -import com.saveourtool.save.frontend.components.basic.sdkSelection - -import io.ktor.http.* -import js.core.jso -import org.w3c.fetch.Headers -import react.* -import react.dom.aria.AriaRole -import react.dom.aria.ariaLabel -import react.dom.html.ReactHTML.button -import react.dom.html.ReactHTML.div -import react.dom.html.ReactHTML.h2 -import react.dom.html.ReactHTML.h4 -import web.cssom.ClassName -import web.cssom.Color -import web.html.ButtonType - -import kotlinx.browser.window - -val sandboxApiUrl = "${window.location.origin}/api/sandbox" - -/** - * A view for testing config files - */ -val sandboxView: FC = FC { - useBackground(Style.SAVE_DARK) - val (debugInfo, setDebugInfo) = useState(null) - val (selectedSdk, setSelectedSdk) = useState(Sdk.Default) - val (isModalOpen, setIsModalOpen) = useState(false) - - val resultReload = useDeferredRequest { - val response = get( - "$sandboxApiUrl/get-debug-info", - Headers().withAcceptOctetStream(), - loadingHandler = ::loadingHandler, - responseHandler = ::noopResponseHandler, - ) - - if (response.ok) { - val resultDebugInfo: TestResultDebugInfo = response.decodeFromJsonString() - setDebugInfo(resultDebugInfo) - } else { - window.alert("There is no debug info yet. Try to run execution and wait until it is finished.") - } - } - - val runExecution = useDeferredRequest { - val response = post( - url = "$sandboxApiUrl/run-execution?sdk=$selectedSdk", - headers = jsonHeaders, - body = undefined, - loadingHandler = ::loadingHandler, - responseHandler = ::responseHandlerWithValidation, - ) - if (response.ok) { - window.alert("Successfully saved and started execution") - } else if (response.isConflict()) { - window.alert("There is already a running execution") - } - } - - h2 { - className = ClassName("text-center mt-3") - style = jso { color = Color("#FFFFFF") } - +"Sandbox" - } - - h4 { - className = ClassName("text-center") - +"try your SAVE configuration online" - } - debugInfo?.let { - displayModal( - isOpen = isModalOpen, - title = "Additional debug info", - classes = "modal-lg", - bodyBuilder = { displayTestResultDebugInfo(debugInfo) }, - modalStyle = largeTransparentModalStyle, - onCloseButtonPressed = { setIsModalOpen(false) }, - ) { - buttonBuilder("Ok") { setIsModalOpen(false) } - } - } - div { - className = ClassName("d-flex justify-content-center") - div { - className = ClassName(" flex-wrap col-10") - debugInfo?.let { debugInfo -> - div { - val alertStyle = when (debugInfo.testStatus) { - is Pass -> "success" - is Fail -> "danger" - is Ignored -> "secondary" - is Crash -> "danger" - else -> "info" - } - div { - className = ClassName("alert alert-$alertStyle alert-dismissible fade show") - role = "alert".unsafeCast() - div { - displayTestResultDebugInfoStatus(debugInfo) - buttonBuilder("See more details...", "link", classes = "p-0") { - setIsModalOpen(true) - } - } - button { - type = ButtonType.button - className = ClassName("align-self-center close") - asDynamic()["data-dismiss"] = "alert" - ariaLabel = "Close" - fontAwesomeIcon(icon = faTimesCircle) - onClick = { setDebugInfo(null) } - } - } - } - } - div { - className = ClassName("") - sandboxCodeEditorComponent { - editorTitle = "" - doRunExecution = runExecution - doResultReload = resultReload - } - } - div { - className = ClassName("row mt-3 mb-3") - div { - className = ClassName("col-4") - sandboxFileUploader { - getUrlForAvailableFilesFetch = { "$sandboxApiUrl/list-file" } - getUrlForFileUpload = { "$sandboxApiUrl/upload-file" } - getUrlForFileDownload = { fileInfo -> - "$sandboxApiUrl/download-file?fileName=${fileInfo.name.escapeIfNeeded()}" - } - getUrlForFileDeletion = { fileInfo -> - "$sandboxApiUrl/delete-file?fileName=${fileInfo.name.escapeIfNeeded()}" - } - } - } - div { - className = ClassName("col-8") - // ======== sdk selection ========= - sdkSelection { - title = "" - this.selectedSdk = selectedSdk - onSdkChange = { newSdk -> setSelectedSdk(newSdk) } - } - } - } - } - } -} diff --git a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/routing/BasicRouting.kt b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/routing/BasicRouting.kt index a6b8b02447..a53d1c5369 100644 --- a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/routing/BasicRouting.kt +++ b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/routing/BasicRouting.kt @@ -156,7 +156,6 @@ val basicRouting: FC = FC { props -> listOf( indexView.create { userInfo = props.userInfo } to "/", saveWelcomeView.create { userInfo = props.userInfo } to SAVE, - sandboxView.create() to SANDBOX, AboutUsView::class.react.create() to ABOUT_US, createOrganizationView.create() to CREATE_ORGANIZATION, registrationView.create { diff --git a/save-frontend/webpack.config.d/dev-server.js b/save-frontend/webpack.config.d/dev-server.js index 574c4ba722..79ba953645 100644 --- a/save-frontend/webpack.config.d/dev-server.js +++ b/save-frontend/webpack.config.d/dev-server.js @@ -7,17 +7,6 @@ config.devServer = Object.assign( return middlewares; }, proxy: [ - { - context: ["/api/sandbox/**"], - target: 'http://localhost:5400', - logLevel: 'debug', - onProxyReq: function (proxyReq, req, res) { - proxyReq.setHeader("X-Authorization-Id", "1"); - proxyReq.setHeader("X-Authorization-Name", "admin"); - proxyReq.setHeader("X-Authorization-Roles", "ROLE_SUPER_ADMIN"); - proxyReq.setHeader("X-Authorization-Status", "ACTIVE"); - } - }, { context: ["/api/demo/**"], target: 'http://localhost:5421', diff --git a/save-sandbox/build.gradle.kts b/save-sandbox/build.gradle.kts deleted file mode 100644 index b31de4f1a6..0000000000 --- a/save-sandbox/build.gradle.kts +++ /dev/null @@ -1,39 +0,0 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - -@Suppress("DSL_SCOPE_VIOLATION", "RUN_IN_SCRIPT") // https://github.com/gradle/gradle/issues/22797 -plugins { - id("com.saveourtool.save.buildutils.kotlin-jvm-configuration") - id("com.saveourtool.save.buildutils.spring-boot-app-configuration") - id("com.saveourtool.save.buildutils.spring-data-configuration") - id("com.saveourtool.save.buildutils.save-cli-configuration") - id("com.saveourtool.save.buildutils.save-agent-configuration") - id("com.saveourtool.save.buildutils.code-quality-convention") - kotlin("plugin.allopen") - alias(libs.plugins.kotlin.plugin.jpa) -} - -kotlin { - allOpen { - annotation("javax.persistence.Entity") - } -} - -tasks.withType { - compilerOptions { - freeCompilerArgs.add("-Xcontext-receivers") - } -} - -dependencies { - implementation(projects.saveOrchestratorCommon) - implementation(libs.zip4j) - implementation(libs.spring.cloud.starter.kubernetes.client.config) - implementation(libs.hibernate.jpa21.api) - implementation(libs.save.plugins.warn.jvm) - implementation(projects.authenticationService) - implementation(libs.spring.boot.starter.security) - implementation(libs.spring.security.core) - implementation(libs.save.common.jvm) - testImplementation(projects.testUtils) - testImplementation(libs.fabric8.kubernetes.server.mock) -} diff --git a/save-sandbox/db/db.changelog-sandbox.xml b/save-sandbox/db/db.changelog-sandbox.xml deleted file mode 100644 index 7b27bed7af..0000000000 --- a/save-sandbox/db/db.changelog-sandbox.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - diff --git a/save-sandbox/db/tables/agent-status.xml b/save-sandbox/db/tables/agent-status.xml deleted file mode 100644 index b6f1b67790..0000000000 --- a/save-sandbox/db/tables/agent-status.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/save-sandbox/db/tables/agent.xml b/save-sandbox/db/tables/agent.xml deleted file mode 100644 index 78bb05256f..0000000000 --- a/save-sandbox/db/tables/agent.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/save-sandbox/db/tables/db.changelog-tables.xml b/save-sandbox/db/tables/db.changelog-tables.xml deleted file mode 100644 index 5bf99a4d66..0000000000 --- a/save-sandbox/db/tables/db.changelog-tables.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/save-sandbox/db/tables/execution.xml b/save-sandbox/db/tables/execution.xml deleted file mode 100644 index 50b231edcc..0000000000 --- a/save-sandbox/db/tables/execution.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/save-sandbox/db/tables/lnk-execution-agent.xml b/save-sandbox/db/tables/lnk-execution-agent.xml deleted file mode 100644 index 7e73c13b6e..0000000000 --- a/save-sandbox/db/tables/lnk-execution-agent.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - insert into lnk_execution_agent(execution_id, agent_id) - select execution_id, id - from agent; - - - - - - diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/SaveSandbox.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/SaveSandbox.kt deleted file mode 100644 index 023e03971b..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/SaveSandbox.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.saveourtool.save.sandbox - -import com.saveourtool.save.s3.DefaultS3Configuration -import com.saveourtool.save.sandbox.config.ConfigProperties -import org.springframework.boot.SpringApplication -import org.springframework.boot.autoconfigure.SpringBootApplication -import org.springframework.boot.autoconfigure.domain.EntityScan -import org.springframework.boot.context.properties.EnableConfigurationProperties -import org.springframework.context.annotation.Import - -/** - * An entrypoint for spring boot for save-sandbox - */ -@SpringBootApplication -@EnableConfigurationProperties(ConfigProperties::class) -@Import(DefaultS3Configuration::class) -@EntityScan( - "com.saveourtool.save.entities", - "com.saveourtool.save.sandbox.entity", -) -open class SaveSandbox - -fun main(args: Array) { - SpringApplication.run(SaveSandbox::class.java, *args) -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/config/ConfigProperties.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/config/ConfigProperties.kt deleted file mode 100644 index 4a7d3b8205..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/config/ConfigProperties.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.saveourtool.save.sandbox.config - -import com.saveourtool.save.s3.S3OperationsProperties -import com.saveourtool.save.service.LokiConfig -import org.springframework.boot.context.properties.ConfigurationProperties -import org.springframework.boot.context.properties.ConstructorBinding - -/** - * @property s3Storage configuration of S3 storage - * @property agentSettings properties for save-agents - * @property lokiConfig config of loki service for logging - */ -@ConstructorBinding -@ConfigurationProperties(prefix = "sandbox") -data class ConfigProperties( - override val s3Storage: S3OperationsProperties, - val agentSettings: AgentSettings, - val lokiConfig: LokiConfig? = null, -) : S3OperationsProperties.Provider { - /** - * @property sandboxUrl the URL of save-sandbox that will be reported to save-agents. - */ - data class AgentSettings( - val sandboxUrl: String, - ) -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/config/LogServiceConfig.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/config/LogServiceConfig.kt deleted file mode 100644 index 3c60ca31ea..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/config/LogServiceConfig.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.saveourtool.save.sandbox.config - -import com.saveourtool.save.service.LogService -import com.saveourtool.save.service.LokiLogService -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration - -/** - * Spring's configuration to configure [LogService] - */ -@Configuration -class LogServiceConfig { - /** - * @param configProperties - * @return [LokiLogService] when properties *sandbox.loki.** are set - */ - @Bean - fun logService( - configProperties: ConfigProperties, - ): LogService = LokiLogService.createOrStub(configProperties.lokiConfig) -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/config/WebSecurityConfig.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/config/WebSecurityConfig.kt deleted file mode 100644 index 843e20c46d..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/config/WebSecurityConfig.kt +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Configuration beans for security in different profiles - */ - -package com.saveourtool.save.sandbox.config - -import com.saveourtool.save.authservice.config.NoopWebSecurityConfig -import com.saveourtool.save.authservice.config.WebSecurityConfig -import org.springframework.context.annotation.Import -import org.springframework.context.annotation.Profile -import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity -import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity - -@EnableWebFluxSecurity -@EnableReactiveMethodSecurity -@Profile("secure") -@Import( - WebSecurityConfig::class, -) -@Suppress("MISSING_KDOC_TOP_LEVEL", "MISSING_KDOC_CLASS_ELEMENTS", "MISSING_KDOC_ON_FUNCTION") -class SandboxWebSecurityConfig - -@EnableWebFluxSecurity -@Profile("!secure") -@Import(NoopWebSecurityConfig::class) -@Suppress("MISSING_KDOC_TOP_LEVEL", "MISSING_KDOC_CLASS_ELEMENTS", "MISSING_KDOC_ON_FUNCTION") -class SandboxNoopWebSecurityConfig diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/controller/SandboxController.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/controller/SandboxController.kt deleted file mode 100644 index 84c3840488..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/controller/SandboxController.kt +++ /dev/null @@ -1,466 +0,0 @@ -package com.saveourtool.save.sandbox.controller - -import com.saveourtool.save.authservice.utils.userId -import com.saveourtool.save.authservice.utils.username -import com.saveourtool.save.configs.ApiSwaggerSupport -import com.saveourtool.save.domain.SandboxFileInfo -import com.saveourtool.save.execution.ExecutionStatus -import com.saveourtool.save.orchestrator.config.ConfigProperties -import com.saveourtool.save.orchestrator.controller.AgentsController -import com.saveourtool.save.sandbox.entity.SandboxExecution -import com.saveourtool.save.sandbox.repository.SandboxAgentRepository -import com.saveourtool.save.sandbox.repository.SandboxAgentStatusRepository -import com.saveourtool.save.sandbox.repository.SandboxExecutionRepository -import com.saveourtool.save.sandbox.repository.SandboxLnkExecutionAgentRepository -import com.saveourtool.save.sandbox.service.SandboxOrchestratorAgentService -import com.saveourtool.save.sandbox.storage.SandboxStorage -import com.saveourtool.save.sandbox.storage.SandboxStorageKey -import com.saveourtool.save.sandbox.storage.SandboxStorageKeyType -import com.saveourtool.save.service.LogService -import com.saveourtool.save.utils.* -import generated.SAVE_CLI_VERSION - -import io.swagger.v3.oas.annotations.Operation -import io.swagger.v3.oas.annotations.Parameter -import io.swagger.v3.oas.annotations.Parameters -import io.swagger.v3.oas.annotations.enums.ParameterIn -import io.swagger.v3.oas.annotations.responses.ApiResponse -import io.swagger.v3.oas.annotations.tags.Tag -import io.swagger.v3.oas.annotations.tags.Tags -import org.intellij.lang.annotations.Language -import org.springframework.http.HttpStatus -import org.springframework.http.MediaType -import org.springframework.http.codec.multipart.FilePart -import org.springframework.security.core.Authentication -import org.springframework.web.bind.annotation.* -import reactor.core.publisher.Flux -import reactor.core.publisher.Mono -import reactor.kotlin.core.publisher.toMono -import reactor.kotlin.core.util.function.component1 -import reactor.kotlin.core.util.function.component2 - -import java.nio.ByteBuffer -import java.time.LocalDateTime -import javax.transaction.Transactional - -/** - * @property configProperties - * @property storage - * @property sandboxExecutionRepository - * @property sandboxAgentRepository - * @property sandboxAgentStatusRepository - * @property sandboxLnkExecutionAgentRepository - * @property agentsController - * @property orchestratorAgentService - * @property logService - */ -@ApiSwaggerSupport -@Tags( - Tag(name = "sandbox"), -) -@RestController -@RequestMapping("/api/sandbox") -@SuppressWarnings("LongParameterList") -class SandboxController( - val configProperties: ConfigProperties, - val storage: SandboxStorage, - val sandboxExecutionRepository: SandboxExecutionRepository, - val sandboxAgentRepository: SandboxAgentRepository, - val sandboxAgentStatusRepository: SandboxAgentStatusRepository, - val sandboxLnkExecutionAgentRepository: SandboxLnkExecutionAgentRepository, - val agentsController: AgentsController, - val orchestratorAgentService: SandboxOrchestratorAgentService, - val logService: LogService, -) { - @Operation( - method = "GET", - summary = "Get a list of files for provided user", - description = "Get a list of files for provided user", - ) - @ApiResponse(responseCode = "200", description = "A list of files") - @ApiResponse(responseCode = "404", description = "User with such name was not found") - @GetMapping("/list-file") - fun listFiles( - authentication: Authentication, - ): Flux = Mono.just(authentication.userId()) - .flatMapMany { userId -> - storage.list(userId, SandboxStorageKeyType.FILE) - } - .flatMap { - Mono.zip( - it.toMono(), - storage.contentLength(it), - ) - } - .map { (storageKey, size) -> - SandboxFileInfo(storageKey.fileName, size) - } - - @Operation( - method = "POST", - summary = "Upload a file for provided user", - description = "Upload a file for provided user", - ) - @Parameters( - Parameter(name = FILE_PART_NAME, `in` = ParameterIn.DEFAULT, description = "a file which needs to be uploaded", required = true), - Parameter(name = CONTENT_LENGTH_CUSTOM, `in` = ParameterIn.HEADER, description = "size in bytes of a file", required = true), - ) - @ApiResponse(responseCode = "200", description = "Uploaded bytes") - @ApiResponse(responseCode = "404", description = "User with such name was not found") - @PostMapping("/upload-file", consumes = [MediaType.MULTIPART_FORM_DATA_VALUE]) - fun uploadFile( - @RequestPart file: Mono, - @RequestHeader(CONTENT_LENGTH_CUSTOM) contentLength: Long, - authentication: Authentication, - ): Mono = file.flatMap { filePart -> - getAsMonoStorageKey(authentication.userId(), SandboxStorageKeyType.FILE, filePart.filename()) - .flatMap { key -> - storage.overwrite( - key = key, - content = filePart, - contentLength = contentLength, - ) - } - .map { - SandboxFileInfo(filePart.filename(), contentLength) - } - } - - @Operation( - method = "POST", - summary = "Upload a file as text for provided user with provide file name", - description = "Upload a file as text for provided user with provide file name", - ) - @Parameters( - Parameter(name = "fileName", `in` = ParameterIn.QUERY, description = "file name", required = true), - Parameter(name = "content", `in` = ParameterIn.DEFAULT, description = "a content of an uploading file", required = true), - ) - @ApiResponse(responseCode = "200", description = "Uploaded bytes") - @ApiResponse(responseCode = "404", description = "User with such name was not found") - @PostMapping("/upload-file-as-text") - fun uploadFileAsText( - @RequestParam fileName: String, - @RequestBody content: String, - authentication: Authentication, - ): Mono = doUploadAsText(authentication.userId(), SandboxStorageKeyType.FILE, fileName, content) - - @Operation( - method = "GET", - summary = "Get a file for provided user with requested file name", - description = "Get a file for provided user with requested file name", - ) - @Parameters( - Parameter(name = "fileName", `in` = ParameterIn.QUERY, description = "file name", required = true), - ) - @ApiResponse(responseCode = "200", description = "Contest of a requested file") - @ApiResponse(responseCode = "404", description = "User with such name or file with such file name and user was not found") - @GetMapping("/download-file", produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE]) - fun downloadFile( - @RequestParam fileName: String, - authentication: Authentication, - ): Flux = getAsMonoStorageKey(authentication.userId(), SandboxStorageKeyType.FILE, fileName) - .flatMapMany { - storage.download(it) - } - .switchIfEmptyToNotFound { - "There is no file $fileName for user ${authentication.username()}" - } - - @Operation( - method = "GET", - summary = "Download a file as text for provided user and requested file name", - description = "Download a file as text for provided user and requested file name", - ) - @Parameters( - Parameter(name = "fileName", `in` = ParameterIn.QUERY, description = "file name", required = true), - ) - @ApiResponse(responseCode = "200", description = "Content of the file as text") - @ApiResponse(responseCode = "404", description = "User with such name was not found") - @GetMapping("/download-file-as-text") - fun downloadFileAsText( - @RequestParam fileName: String, - authentication: Authentication, - ): Mono = doDownloadAsText(authentication.userId(), SandboxStorageKeyType.FILE, fileName) - - @Operation( - method = "DELETE", - summary = "Delete a file for provided user with requested file name", - description = "Delete a file for provided user with requested file name", - ) - @Parameters( - Parameter(name = "fileName", `in` = ParameterIn.QUERY, description = "file name", required = true), - ) - @ApiResponse(responseCode = "200", description = "Result of delete operation of a requested file") - @ApiResponse(responseCode = "404", description = "User with such name was not found") - @DeleteMapping("/delete-file") - fun deleteFile( - @RequestParam fileName: String, - authentication: Authentication, - ): Mono = getAsMonoStorageKey(authentication.userId(), SandboxStorageKeyType.FILE, fileName) - .flatMap { - storage.delete(it) - } - - @Operation( - method = "POST", - summary = "Upload a test file as text for provided user with provide file name", - description = "Upload a test file as text for provided user with provide file name", - ) - @Parameters( - Parameter(name = "fileName", `in` = ParameterIn.QUERY, description = "file name", required = true), - Parameter(name = "content", `in` = ParameterIn.DEFAULT, description = "a content of an uploading file", required = true), - ) - @ApiResponse(responseCode = "200", description = "Uploaded bytes") - @ApiResponse(responseCode = "404", description = "User with such name was not found") - @PostMapping("/upload-test-as-text") - fun uploadTestAsText( - @RequestParam fileName: String, - @RequestBody content: String, - authentication: Authentication, - ): Mono = doUploadAsText(authentication.userId(), SandboxStorageKeyType.TEST, fileName, content) - - private fun doUploadAsText( - userId: Long, - type: SandboxStorageKeyType, - fileName: String, - content: String, - ): Mono = getAsMonoStorageKey(userId, type, fileName) - .flatMap { key -> - storage.overwrite( - key = key, - contentBytes = content.replace("\r\n?".toRegex(), "\n").toByteArray(), - ) - } - .map { - SandboxFileInfo(fileName, it) - } - - @Operation( - method = "GET", - summary = "Download a test file as text for provided user and requested file name", - description = "Download a test file as text for provided user and requested file name", - ) - @Parameters( - Parameter(name = "fileName", `in` = ParameterIn.QUERY, description = "file name", required = true), - ) - @ApiResponse(responseCode = "200", description = "Content of the test file as text") - @ApiResponse(responseCode = "404", description = "User with such name was not found") - @GetMapping("/download-test-as-text") - fun downloadTestAsText( - @RequestParam fileName: String, - authentication: Authentication, - ): Mono = doDownloadAsText(authentication.userId(), SandboxStorageKeyType.TEST, fileName) - - private fun doDownloadAsText( - userId: Long, - type: SandboxStorageKeyType, - fileName: String, - ): Mono = getAsMonoStorageKey(userId, type, fileName) - .flatMap { key -> - storage.download(key) - .collectToInputStream() - .map { it.bufferedReader().readText() } - } - .switchIfEmpty( - examples[fileName].toMono() - .flatMap { example -> - doUploadAsText(userId, type, fileName, example) - .thenReturn(example) - } - .switchIfEmptyToNotFound { - "There is no test file $fileName for user id $userId" - } - ) - - private fun getAsMonoStorageKey( - userId: Long, - type: SandboxStorageKeyType, - fileName: String, - ): Mono = Mono.just(userId) - .map { uid -> - SandboxStorageKey( - uid, - type, - fileName, - ) - } - - @Operation( - method = "GET", - summary = "Download a debug info for provided user", - description = "Download a debug info for provided user", - ) - @ApiResponse(responseCode = "200", description = "Content of the debug info") - @ApiResponse(responseCode = "404", description = "User with such name was not found") - @GetMapping(path = ["/get-debug-info"], produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE]) - fun getDebugInfo( - authentication: Authentication, - ): Flux = Mono.just(authentication.userId()) - .flatMapMany { userId -> - storage.download(SandboxStorageKey.debugInfoKey(userId)) - } - .switchIfEmptyToNotFound { - "There is no DebugInfo for ${authentication.username()}" - } - - @Operation( - method = "POST", - summary = "Run a new execution for provided user", - description = "Run a new execution for provided user", - ) - @Parameters( - Parameter(name = "sdk", `in` = ParameterIn.QUERY, description = "SDK", required = true), - ) - @ApiResponse(responseCode = "200", description = "empty response for execution run") - @ApiResponse(responseCode = "404", description = "User with such name was not found") - @ApiResponse(responseCode = "409", description = "There is a running execution") - @PostMapping("/run-execution") - @Transactional - fun runExecution( - @RequestParam sdk: String, - authentication: Authentication, - ): Mono { - val userId = authentication.userId() - return validateNoRunningExecution(userId) - .flatMap { - storage.delete(SandboxStorageKey.debugInfoKey(userId)) - } - .flatMap { - blockingToMono { - val execution = SandboxExecution( - startTime = LocalDateTime.now(), - endTime = null, - status = ExecutionStatus.PENDING, - sdk = sdk, - saveCliVersion = SAVE_CLI_VERSION, - userId = userId, - initialized = false, - failReason = null, - ) - sandboxExecutionRepository.save(execution) - } - } - .map { orchestratorAgentService.getRunRequest(it) } - .flatMap { request -> - agentsController.initialize(request) - } - } - - /** - * @param limit - * @param authentication - * @return logs from agent sandbox - */ - @GetMapping("/logs-from-agent") - fun getAgentLogs( - @RequestParam(required = false, defaultValue = "1000") limit: Int, - authentication: Authentication, - ): Mono = blockingToMono { - sandboxExecutionRepository.findTopByUserIdOrderByStartTimeDesc(authentication.userId()) - } - .switchIfEmptyToNotFound { - "There is no run for ${authentication.username()} yet" - } - .flatMap { execution -> - val agent = sandboxLnkExecutionAgentRepository.findByExecutionId(execution.requiredId()) - .singleOrNull() - .orConflict { "Only a single agent expected for execution ${execution.requiredId()}" } - .agent - val startTime = sandboxAgentStatusRepository.findTopByAgentOrderByStartTimeAsc(agent) - ?.startTime - .orNotFound { "Not found first agent status for execution ${execution.requiredId()}" } - val endTime = sandboxAgentStatusRepository.findTopByAgentOrderByEndTimeDesc(agent) - ?.endTime - .orNotFound { "Not found latest agent status for execution ${execution.requiredId()}" } - logService.getByContainerName(agent.containerName, - startTime.toInstantAtDefaultZone(), - endTime.toInstantAtDefaultZone(), - limit, - ) - } - - private fun validateNoRunningExecution( - userId: Long, - ): Mono = blockingToMono { - sandboxExecutionRepository.findByUserId(userId) - .filter { it.status in setOf(ExecutionStatus.RUNNING, ExecutionStatus.PENDING) } - } - .requireOrSwitchToResponseException({ isEmpty() }, HttpStatus.CONFLICT) { - "There is already a running execution" - } - .thenReturn(Unit) - - companion object { - @Language("toml") - private val saveTomlExample = """ - |# special configuration file to use save test framework: https://github.com/saveourtool/save-cli - |[general] - |execCmd = "python -m pylint" - |# === example of expected tests CHECK-MESSAGES: :[[@LINE-1]]:12: warning: test [warning-name] === - |expectedWarningsPattern = "# CHECK-MESSAGES:?\\[\\[(.+)\\]\\]: (.*)" - | - |tags = ["check_only", "clang_tidy", "huawei_specific"] - |description = "Demo suite of Huawei specific tests for Clang tidy" - |suiteName = "Fixbot codecheck-python tests" - | - | - |[warn] - |actualWarningsPattern=".*[\\\\\\/](.*):(\\d+): (.*)" - | - |execFlags = "--msg-template=\"{path}:{line}: {msg_id}: {msg} ({symbol})\"" - |linePlaceholder = "@LINE" - | - |exactWarningsMatch = false - |partialWarnTextMatch = true - |testNameRegex = ".*test.*" - |#testNameRegex = ".*.py" - |warningTextHasColumn = false - |warningTextHasLine = true - | - |lineCaptureGroup = 1 - |#columnCaptureGroup = null - |messageCaptureGroup = 2 - | - | - |fileNameCaptureGroupOut = 1 - |lineCaptureGroupOut = 2 - |#columnCaptureGroupOut = null - |messageCaptureGroupOut = 3 - """.trimMargin() - - @Language("python") - private val testExample = """ - |# CHECK-MESSAGES:[[1]]: C0114: Missing module docstring (missing-module-docstring) - |import tkinter as tk - | - |root=tk.Tk() - | - |canvas1 = tk.Canvas(root, width = 300, height = 300) - |canvas1.pack() - | - |# CHECK-MESSAGES:[[10]]: C0116: Missing function or method docstring (missing-function-docstring) - |def hello (): - | label1 = tk.Label(root, text= 'Hello World!', fg='blue', font=('helvetica', 12, 'bold')) - | canvas1.create_window(150, 200, window=label1) - | - |button1 = tk.Button(text='Click Me', command=hello, bg='brown',fg='white') - |canvas1.create_window(150, 150, window=button1) - | - |root.mainloop() - """.trimMargin() - - @Language("bash") - private val setupShExample = """ - |#!/usr/bin/env bash - | - |# Here you can add some additional commands required to run your tool e.g. - |# setup pylint, it setups all required dependencies - |pip install pylint --no-input --disable-pip-version-check --no-warn-script-location - """.trimMargin() - private val examples = mapOf( - "test" to testExample, - "save.toml" to saveTomlExample, - "setup.sh" to setupShExample, - ) - } -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/controller/SandboxInternalController.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/controller/SandboxInternalController.kt deleted file mode 100644 index b595fc027f..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/controller/SandboxInternalController.kt +++ /dev/null @@ -1,129 +0,0 @@ -package com.saveourtool.save.sandbox.controller - -import com.saveourtool.save.agent.TestExecutionResult -import com.saveourtool.save.domain.TestResultDebugInfo -import com.saveourtool.save.sandbox.storage.SandboxStorage -import com.saveourtool.save.sandbox.storage.SandboxStorageKey -import com.saveourtool.save.sandbox.storage.SandboxStorageKeyType -import com.saveourtool.save.utils.* - -import com.fasterxml.jackson.databind.ObjectMapper -import org.apache.commons.io.FileUtils -import org.apache.commons.io.IOUtils -import org.springframework.http.MediaType -import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.* -import reactor.core.publisher.Flux -import reactor.core.publisher.Mono -import reactor.kotlin.core.publisher.toMono - -import java.nio.ByteBuffer - -import kotlin.io.path.createTempDirectory -import kotlin.io.path.createTempFile -import kotlin.io.path.deleteExisting -import kotlin.io.path.outputStream - -typealias ByteBufferFluxResponse = ResponseEntity> - -/** - * Sandbox implementation of endpoints which are required for save-agent - */ -@RestController -@RequestMapping("/internal/sandbox") -class SandboxInternalController( - private val storage: SandboxStorage, - private val objectMapper: ObjectMapper, -) { - /** - * @param userId ID of User - * @return content of requested snapshot - */ - @PostMapping( - "/download-test-files", - produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE] - ) - fun downloadTestFiles( - @RequestParam userId: Long, - ): Mono { - val archiveFile = createTempFile( - prefix = "tests-", - suffix = ZIP_ARCHIVE_EXTENSION - ) - return { createTempDirectory(prefix = "tests-directory-") } - .toMono() - .flatMap { directory -> - storage.list(userId, SandboxStorageKeyType.TEST) - .flatMap { key -> - storage.download(key) - .collectToInputStream() - .map { inputStream -> - directory.resolve(key.fileName) - .outputStream() - .use { - IOUtils.copy(inputStream, it) - } - } - } - .collectList() - .map { - directory.compressAsZipTo(archiveFile) - FileUtils.deleteDirectory(directory.toFile()) - } - } - .map { - archiveFile.toByteBufferFlux() - } - .map { - ResponseEntity.ok(it) - } - .doFinally { - archiveFile.deleteExisting() - } - } - - /** - * @param userId ID of User - * @param fileName - * @return content of requested file - */ - @PostMapping("/download-file", produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE]) - fun downloadFile( - @RequestParam userId: Long, - @RequestParam fileName: String, - ): Mono = blockingToMono { - ResponseEntity.ok( - storage.download( - SandboxStorageKey( - userId = userId, - type = SandboxStorageKeyType.FILE, - fileName = fileName, - ) - ) - ) - } - - /** - * @param testExecutionResults - * @return response with text value - */ - @PostMapping("/upload-execution-data") - fun saveExecutionData( - @Suppress("UnusedParameter") @RequestBody testExecutionResults: List - ): Mono = ResponseEntity.ok("Do nothing for now") - .toMono() - - /** - * @param userId - * @param testResultDebugInfo - * @return [Mono] with count of uploaded bytes - */ - @PostMapping("/upload-debug-info") - fun uploadDebugInfo( - @RequestParam userId: Long, - @RequestBody testResultDebugInfo: TestResultDebugInfo, - ): Mono = storage.overwrite( - key = SandboxStorageKey.debugInfoKey(userId), - contentBytes = objectMapper.writeValueAsBytes(testResultDebugInfo) - ) -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/entity/SandboxExecution.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/entity/SandboxExecution.kt deleted file mode 100644 index 6dc6e77a7b..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/entity/SandboxExecution.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.saveourtool.save.sandbox.entity - -import com.saveourtool.save.domain.toSdk -import com.saveourtool.save.entities.Execution -import com.saveourtool.save.execution.ExecutionStatus -import com.saveourtool.save.request.RunExecutionRequest -import com.saveourtool.save.spring.entity.BaseEntity -import java.net.URL - -import java.time.LocalDateTime -import javax.persistence.* - -/** - * @property startTime - * @property endTime - * @property status - * @property sdk - * @property saveCliVersion - * @property userId - * @property initialized - * @property failReason - */ -@Entity -@Table(name = "execution") -@Suppress("LongParameterList") -class SandboxExecution( - var startTime: LocalDateTime, - var endTime: LocalDateTime?, - @Enumerated(EnumType.STRING) - var status: ExecutionStatus, - var sdk: String, - var saveCliVersion: String, - @Column(name = "user_id") - var userId: Long, - var initialized: Boolean, - var failReason: String?, -) : BaseEntity() { - /** - * @param saveAgentUrl an url to download save-agent - * @return [RunExecutionRequest] created from current entity - */ - fun toRunRequest( - saveAgentUrl: URL, - ): RunExecutionRequest { - require(status == ExecutionStatus.PENDING) { - "${RunExecutionRequest::class.simpleName} can be created only for ${Execution::class.simpleName} with status = ${ExecutionStatus.PENDING}" - } - return RunExecutionRequest( - executionId = requiredId(), - sdk = sdk.toSdk(), - saveAgentUrl = saveAgentUrl.toString(), - ) - } -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/entity/SandboxLnkExecutionAgent.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/entity/SandboxLnkExecutionAgent.kt deleted file mode 100644 index 9629fc062b..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/entity/SandboxLnkExecutionAgent.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.saveourtool.save.sandbox.entity - -import com.saveourtool.save.entities.Agent -import com.saveourtool.save.spring.entity.BaseEntity -import javax.persistence.Entity -import javax.persistence.JoinColumn -import javax.persistence.ManyToOne -import javax.persistence.Table - -/** - * @property execution execution that is connected to [agent] - * @property agent agent assigned to [execution] - */ -@Entity -@Table(name = "lnk_execution_agent") -class SandboxLnkExecutionAgent( - @ManyToOne - @JoinColumn(name = "execution_id") - var execution: SandboxExecution, - - @ManyToOne - @JoinColumn(name = "agent_id") - var agent: Agent, -) : BaseEntity() diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxAgentRepository.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxAgentRepository.kt deleted file mode 100644 index 62f173114d..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxAgentRepository.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.saveourtool.save.sandbox.repository - -import com.saveourtool.save.entities.Agent -import com.saveourtool.save.spring.repository.BaseEntityRepository -import org.springframework.stereotype.Repository - -/** - * Repository for [Agent] - */ -@Repository -interface SandboxAgentRepository : BaseEntityRepository { - /** - * Find agent by its container id - * - * @param containerId - * @return [Agent] - */ - fun findByContainerId(containerId: String): Agent? -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxAgentStatusRepository.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxAgentStatusRepository.kt deleted file mode 100644 index 5abeb9e2d5..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxAgentStatusRepository.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.saveourtool.save.sandbox.repository - -import com.saveourtool.save.entities.Agent -import com.saveourtool.save.entities.AgentStatus -import com.saveourtool.save.spring.repository.BaseEntityRepository -import org.springframework.stereotype.Repository - -/** - * Repository for [AgentStatus] in sandbox - */ -@Repository -interface SandboxAgentStatusRepository : BaseEntityRepository { - /** - * Find latest [AgentStatus] for agent with provided [containerId] - * - * @param containerId id of an agent - * @return [AgentStatus] of an agent - */ - fun findTopByAgentContainerIdOrderByEndTimeDescIdDesc(containerId: String): AgentStatus? - - /** - * Find [AgentStatus] by [Agent] which is first by [AgentStatus.startTime] - * - * @param agent - * @return [AgentStatus] which fits to query - */ - fun findTopByAgentOrderByStartTimeAsc(agent: Agent): AgentStatus? - - /** - * Find [AgentStatus] by [Agent] which is last by [AgentStatus.endTime] - * - * @param agent - * @return [AgentStatus] which fits to query - */ - fun findTopByAgentOrderByEndTimeDesc(agent: Agent): AgentStatus? -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxExecutionRepository.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxExecutionRepository.kt deleted file mode 100644 index e0a1090e08..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxExecutionRepository.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.saveourtool.save.sandbox.repository - -import com.saveourtool.save.sandbox.entity.SandboxExecution -import com.saveourtool.save.spring.repository.BaseEntityRepository -import org.springframework.stereotype.Repository - -/** - * Repository for [SandboxExecution] - */ -@Repository -interface SandboxExecutionRepository : BaseEntityRepository { - /** - * @param userId - * @return list of [SandboxExecution] for requested [userId] - */ - fun findByUserId(userId: Long): List - - /** - * @param userId - * @return latest [SandboxExecution] for requested [userId] - */ - fun findTopByUserIdOrderByStartTimeDesc(userId: Long): SandboxExecution? -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxLnkExecutionAgentRepository.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxLnkExecutionAgentRepository.kt deleted file mode 100644 index d1bc2831c6..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxLnkExecutionAgentRepository.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.saveourtool.save.sandbox.repository - -import com.saveourtool.save.sandbox.entity.SandboxLnkExecutionAgent -import com.saveourtool.save.spring.repository.BaseEntityRepository - -/** - * Repository of [SandboxLnkExecutionAgent] - */ -interface SandboxLnkExecutionAgentRepository : BaseEntityRepository { - /** - * @param agentId ID of [com.saveourtool.save.entities.Agent] - * @return [SandboxLnkExecutionAgent] or null - */ - fun findByAgentId(agentId: Long): SandboxLnkExecutionAgent? - - /** - * @param executionId ID of [com.saveourtool.save.sandbox.entity.SandboxExecution] - * @return list of [SandboxLnkExecutionAgent] - */ - fun findByExecutionId(executionId: Long): List -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/service/SandboxOrchestratorAgentService.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/service/SandboxOrchestratorAgentService.kt deleted file mode 100644 index 4b4ef25726..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/service/SandboxOrchestratorAgentService.kt +++ /dev/null @@ -1,183 +0,0 @@ -package com.saveourtool.save.sandbox.service - -import com.saveourtool.save.agent.AgentInitConfig -import com.saveourtool.save.agent.AgentRunConfig -import com.saveourtool.save.agent.SaveCliOverrides -import com.saveourtool.save.entities.* -import com.saveourtool.save.execution.ExecutionStatus -import com.saveourtool.save.orchestrator.service.OrchestratorAgentService -import com.saveourtool.save.orchestrator.service.TestExecutionList -import com.saveourtool.save.request.RunExecutionRequest -import com.saveourtool.save.sandbox.config.ConfigProperties -import com.saveourtool.save.sandbox.entity.SandboxExecution -import com.saveourtool.save.sandbox.entity.SandboxLnkExecutionAgent -import com.saveourtool.save.sandbox.repository.SandboxAgentRepository -import com.saveourtool.save.sandbox.repository.SandboxAgentStatusRepository -import com.saveourtool.save.sandbox.repository.SandboxExecutionRepository -import com.saveourtool.save.sandbox.repository.SandboxLnkExecutionAgentRepository -import com.saveourtool.save.sandbox.storage.SandboxInternalFileStorage -import com.saveourtool.save.sandbox.storage.SandboxStorage -import com.saveourtool.save.sandbox.storage.SandboxStorageKeyType -import com.saveourtool.save.storage.impl.InternalFileKey -import com.saveourtool.save.utils.* - -import org.springframework.data.repository.findByIdOrNull -import org.springframework.http.ResponseEntity -import org.springframework.stereotype.Component -import reactor.core.publisher.Mono -import reactor.kotlin.core.publisher.toMono -import reactor.kotlin.core.util.function.component1 -import reactor.kotlin.core.util.function.component2 -import java.util.stream.Collectors - -/** - * Sandbox implementation for agent service - */ -@Component("SandboxAgentRepositoryForOrchestrator") -@Suppress("LongParameterList") -class SandboxOrchestratorAgentService( - private val sandboxAgentRepository: SandboxAgentRepository, - private val sandboxAgentStatusRepository: SandboxAgentStatusRepository, - private val sandboxLnkExecutionAgentRepository: SandboxLnkExecutionAgentRepository, - private val sandboxExecutionRepository: SandboxExecutionRepository, - private val sandboxStorage: SandboxStorage, - private val internalFileStorage: SandboxInternalFileStorage, - configProperties: ConfigProperties, -) : OrchestratorAgentService { - private val sandboxUrlForAgent = "${configProperties.agentSettings.sandboxUrl}/internal/sandbox" - - override fun getInitConfig(containerId: String): Mono = getExecutionAsMonoByContainerId(containerId) - .zipWhen { execution -> - sandboxStorage.list(execution.userId, SandboxStorageKeyType.FILE) - .map { storageKey -> - storageKey.fileName to "$sandboxUrlForAgent/download-file?userId=${storageKey.userId}&fileName=${storageKey.fileName}" - } - .collectList() - .map { - it.toMap() - } - } - .map { (execution, fileToUrls) -> - AgentInitConfig( - saveCliUrl = internalFileStorage.generateRequiredUrlToDownloadFromContainer(InternalFileKey.saveCliKey(execution.saveCliVersion)) - .toString(), - testSuitesSourceSnapshotUrl = "$sandboxUrlForAgent/download-test-files?userId=${execution.userId}", - additionalFileNameToUrl = fileToUrls, - // sandbox doesn't support save-cli overrides for now - saveCliOverrides = SaveCliOverrides(), - ) - } - - override fun getNextRunConfig(containerId: String): Mono = getExecutionAsMonoByContainerId(containerId) - .filter { !it.initialized } - .map { execution -> sandboxExecutionRepository.save(execution.apply { initialized = true }) } - .flatMap { execution -> - sandboxStorage.list(execution.userId, SandboxStorageKeyType.TEST) - .map { it.fileName } - .filter { it.endsWith("save.toml") } - .collect(Collectors.joining(" ")) - .zipWith(execution.userId.toMono()) - } - .map { (cliArgs, userId) -> - AgentRunConfig( - cliArgs = cliArgs, - executionDataUploadUrl = "$sandboxUrlForAgent/upload-execution-data", - debugInfoUploadUrl = "$sandboxUrlForAgent/upload-debug-info?userId=$userId", - ) - } - - override fun addAgent(executionId: Long, agent: AgentDto): Mono = getExecutionAsMono(executionId) - .map { execution -> - val savedAgent = sandboxAgentRepository.save(agent.toEntity()) - sandboxLnkExecutionAgentRepository.save(SandboxLnkExecutionAgent( - execution = execution, - agent = savedAgent - )) - ResponseEntity.ok().build() - } - - override fun updateAgentStatus(agentStatus: AgentStatusDto): Mono = blockingToMono { - sandboxAgentStatusRepository.save(agentStatus.toEntity(this::getAgent)) - .let { - ResponseEntity.ok().build() - } - } - - override fun getReadyForTestingTestExecutions(containerId: String): Mono = Mono.fromCallable { - // sandbox doesn't have TestExecution at all - emptyList() - } - - override fun getExecutionStatus(executionId: Long): Mono = getExecutionAsMono(executionId) - .map { it.status } - - override fun updateExecutionStatus( - executionId: Long, - executionStatus: ExecutionStatus, - failReason: String? - ): Mono = getExecutionAsMono(executionId) - .map { execution -> - sandboxExecutionRepository.save( - execution.apply { - this.status = executionStatus - this.failReason = failReason - } - ) - } - .thenReturn(ResponseEntity.ok().build()) - - override fun getAgentStatusesByExecutionId(executionId: Long): Mono = getExecutionAsMono(executionId) - .map { execution -> - sandboxLnkExecutionAgentRepository.findByExecutionId(execution.requiredId()) - .map { it.agent } - .map { agent -> - sandboxAgentStatusRepository.findTopByAgentContainerIdOrderByEndTimeDescIdDesc(agent.containerId) - .orNotFound { - "AgentStatus not found for agent id=${agent.containerId}" - } - } - .map { - it.toDto() - } - } - - override fun markReadyForTestingTestExecutionsOfAgentAsFailed(containerId: String): Mono = Mono.fromCallable { - // sandbox doesn't have TestExecution - ResponseEntity.ok().build() - } - - override fun markAllTestExecutionsOfExecutionAsFailed(executionId: Long): Mono = Mono.fromCallable { - // sandbox doesn't have TestExecution - ResponseEntity.ok().build() - } - - /** - * @param execution - * @return a request to run execution - */ - fun getRunRequest(execution: SandboxExecution): RunExecutionRequest = execution.toRunRequest( - saveAgentUrl = internalFileStorage.generateRequiredUrlToDownloadFromContainer(InternalFileKey.saveAgentKey), - ) - - private fun getExecution(executionId: Long): SandboxExecution = sandboxExecutionRepository - .findByIdOrNull(executionId) - .orNotFound { "No execution with id $executionId" } - - private fun getExecutionAsMono(executionId: Long): Mono = blockingToMono { - getExecution(executionId) - } - - private fun getAgent(containerId: String): Agent = sandboxAgentRepository - .findByContainerId(containerId) - .orNotFound { - "No agent with containerId $containerId" - } - - private fun getExecutionAsMonoByContainerId(containerId: String): Mono = blockingToMono { - sandboxLnkExecutionAgentRepository.findByAgentId(getAgent(containerId).requiredId()) - .orNotFound { - "No linked execution to agent with containerId $containerId" - } - .execution - } -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxInternalFileStorage.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxInternalFileStorage.kt deleted file mode 100644 index 60496fbd5f..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxInternalFileStorage.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.saveourtool.save.sandbox.storage - -import com.saveourtool.save.s3.S3Operations -import com.saveourtool.save.sandbox.config.ConfigProperties -import com.saveourtool.save.storage.DefaultStorageCoroutines -import com.saveourtool.save.storage.impl.AbstractInternalFileStorage -import com.saveourtool.save.storage.impl.InternalFileKey -import generated.SAVE_CLI_VERSION -import org.springframework.stereotype.Component - -/** - * Storage for internal files used by sandbox: save-cli and save-agent - */ -@Component -class SandboxInternalFileStorage( - configProperties: ConfigProperties, - s3Operations: S3Operations, -) : AbstractInternalFileStorage( - listOf(InternalFileKey.saveAgentKey, InternalFileKey.saveCliKey(SAVE_CLI_VERSION)), - configProperties.s3Storage.prefix, - s3Operations, -) { - override suspend fun doInitAdditionally(underlying: DefaultStorageCoroutines) { - underlying.downloadSaveCliFromGithub() - } -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxStorage.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxStorage.kt deleted file mode 100644 index 031c0ce1e0..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxStorage.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.saveourtool.save.sandbox.storage - -import com.saveourtool.save.s3.S3Operations -import com.saveourtool.save.sandbox.config.ConfigProperties -import com.saveourtool.save.storage.AbstractSimpleReactiveStorage -import com.saveourtool.save.storage.PATH_DELIMITER -import com.saveourtool.save.storage.concatS3Key -import org.springframework.stereotype.Component -import reactor.core.publisher.Flux - -/** - * Storage implementation for sandbox - */ -@Component -class SandboxStorage( - configProperties: ConfigProperties, - s3Operations: S3Operations, -) : AbstractSimpleReactiveStorage( - s3Operations, - concatS3Key(configProperties.s3Storage.prefix, "sandbox"), -) { - @Suppress("DestructuringDeclarationWithTooManyEntries") - override fun doBuildKeyFromSuffix(s3KeySuffix: String): SandboxStorageKey { - val (userId, typeName, filename) = s3KeySuffix.split(PATH_DELIMITER) - return SandboxStorageKey( - userId.toLong(), - SandboxStorageKeyType.valueOf(typeName), - filename, - ) - } - - override fun doBuildS3KeySuffix(key: SandboxStorageKey): String = - concatS3Key(key.userId.toString(), key.type.name, key.fileName) - - /** - * @param userId - * @param types - * @return list of keys in storage with requested [SandboxStorageKey.type] and [SandboxStorageKey.userId] - */ - fun list( - userId: Long, - vararg types: SandboxStorageKeyType - ): Flux = list().filter { - it.userId == userId && it.type in types - } -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxStorageKey.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxStorageKey.kt deleted file mode 100644 index fa607c7f2e..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxStorageKey.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.saveourtool.save.sandbox.storage - -/** - * @property userId - * @property type - * @property fileName - */ -data class SandboxStorageKey( - val userId: Long, - val type: SandboxStorageKeyType, - val fileName: String, -) { - companion object { - private const val DEBUG_INFO_FILE_NAME = "file_name.txt" - - /** - * create key for DebugInfoKey - * - * @param userId - * @return [SandboxStorageKey] with type [SandboxStorageKeyType.DEBUG_INFO] - */ - fun debugInfoKey( - userId: Long - ): SandboxStorageKey = SandboxStorageKey( - userId, - SandboxStorageKeyType.DEBUG_INFO, - DEBUG_INFO_FILE_NAME - ) - } -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxStorageKeyType.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxStorageKeyType.kt deleted file mode 100644 index 6f317aaf96..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxStorageKeyType.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.saveourtool.save.sandbox.storage - -/** - * Type of sandbox files - */ -enum class SandboxStorageKeyType { - DEBUG_INFO, - FILE, - TEST, - ; -} diff --git a/save-sandbox/src/main/resources/META-INF/spring.factories b/save-sandbox/src/main/resources/META-INF/spring.factories deleted file mode 100644 index b1a3f50ce9..0000000000 --- a/save-sandbox/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1 +0,0 @@ -org.springframework.boot.env.EnvironmentPostProcessor=com.saveourtool.save.spring.postprocessor.DockerSecretsDatabaseProcessor \ No newline at end of file diff --git a/save-sandbox/src/main/resources/application-container-desktop.properties b/save-sandbox/src/main/resources/application-container-desktop.properties deleted file mode 100644 index a102c58f48..0000000000 --- a/save-sandbox/src/main/resources/application-container-desktop.properties +++ /dev/null @@ -1,3 +0,0 @@ -# suppress inspection "HttpUrlsUsage" -sandbox.agent-settings.sandbox-url=http://${COMPUTERNAME}.local:${server.port} -orchestrator.docker.host=npipe:////./pipe/docker_engine diff --git a/save-sandbox/src/main/resources/application-dev.properties b/save-sandbox/src/main/resources/application-dev.properties deleted file mode 100644 index d1b6ea6e54..0000000000 --- a/save-sandbox/src/main/resources/application-dev.properties +++ /dev/null @@ -1,9 +0,0 @@ -spring.datasource.url=jdbc:mysql://localhost:3306/save_sandbox -spring.datasource.username=root -spring.datasource.password=123 -sandbox.s3-storage.endpoint=http://localhost:9000 -sandbox.s3-storage.bucketName=cnb -sandbox.s3-storage.credentials.accessKeyId=admin -sandbox.s3-storage.credentials.secretAccessKey=adminadmin -sandbox.s3-storage.createBucketIfNotExists=true -orchestrator.agents-count=1 diff --git a/save-sandbox/src/main/resources/application-kafka.properties b/save-sandbox/src/main/resources/application-kafka.properties deleted file mode 100644 index f8e48bb156..0000000000 --- a/save-sandbox/src/main/resources/application-kafka.properties +++ /dev/null @@ -1 +0,0 @@ -spring.kafka.consumer.group-id=sandbox-local-group \ No newline at end of file diff --git a/save-sandbox/src/main/resources/application-minikube.properties b/save-sandbox/src/main/resources/application-minikube.properties deleted file mode 100644 index ff2cda41b7..0000000000 --- a/save-sandbox/src/main/resources/application-minikube.properties +++ /dev/null @@ -1,14 +0,0 @@ -# To get this port you should run this command: -# $ docker port minikube -# And find the following line: -# 8443/tcp -> 0.0.0.0:XXXX -# Here, XXXX is a requested port -orchestrator.kubernetes.apiServerUrl=https://127.0.0.1:61234 -orchestrator.kubernetes.serviceAccount=sandbox-sa -orchestrator.kubernetes.current-namespace=save-cloud -orchestrator.kubernetes.agent-namespace=save-agent -orchestrator.kubernetes.useGvisor=false -orchestrator.agent-settings.debug=true - -orchestrator.agent-settings.heartbeat-url=http://host.minikube.internal:5400/heartbeat -sandbox.agent-settings.sandbox-url=http://host.minikube.internal:5400 diff --git a/save-sandbox/src/main/resources/application-prod.properties b/save-sandbox/src/main/resources/application-prod.properties deleted file mode 100644 index 6bfdd3736a..0000000000 --- a/save-sandbox/src/main/resources/application-prod.properties +++ /dev/null @@ -1 +0,0 @@ -spring.datasource.url=jdbc:mysql://192.168.0.250:3306/save_sandbox diff --git a/save-sandbox/src/main/resources/application.properties b/save-sandbox/src/main/resources/application.properties deleted file mode 100644 index e58f754fdf..0000000000 --- a/save-sandbox/src/main/resources/application.properties +++ /dev/null @@ -1,19 +0,0 @@ -server.port=5400 -spring.liquibase.enabled=false -# suppress inspection "HttpUrlsUsage" -sandbox.agent-settings.sandbox-url=http://host.docker.internal:${server.port} -orchestrator.container-name-prefix=sandbox-execution- -orchestrator.agents-count=1 -spring.jpa.hibernate.use-new-id-generator-mappings=false -spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect -spring.jpa.properties.hibernate.generate_statistics=true -spring.jpa.properties.hibernate.jdbc.fetch_size=100 -spring.jpa.properties.hibernate.jdbc.batch_size=100 -spring.jpa.properties.hibernate.order_inserts=true -spring.jpa.properties.hibernate.order_updates=true -logging.level.org.hibernate.engine.internal.StatisticalLoggingSessionEventListener=WARN -sandbox.s3-storage.endpoint=${s3-storage.endpoint} -sandbox.s3-storage.bucketName=${s3-storage.bucketName} -sandbox.s3-storage.prefix=cnb/sandbox -sandbox.s3-storage.credentials.accessKeyId=${s3-storage.credentials.accessKeyId} -sandbox.s3-storage.credentials.secretAccessKey=${s3-storage.credentials.secretAccessKey} diff --git a/save-sandbox/src/main/resources/bootstrap.yml b/save-sandbox/src/main/resources/bootstrap.yml deleted file mode 100644 index e0567bc53a..0000000000 --- a/save-sandbox/src/main/resources/bootstrap.yml +++ /dev/null @@ -1,32 +0,0 @@ -spring: - cloud: - kubernetes: - enabled: false -kubernetes: - # Dependency `io.kubernetes:client-java-spring-integration` doesn't respect `kubernetes` profile, - # so some things need to be disabled manually. - informer: - enabled: false - manifests: - enabled: false ---- -spring: - config: - activate: - on-profile: kubernetes - cloud: - kubernetes: - enabled: true - config: - enabled: true - paths: /home/cnb/config/application.properties - secrets: - enabled: true - paths: - - ${DATABASE_SECRETS_PATH} - - ${S3_SECRETS_PATH} -kubernetes: - informer: - enabled: true - manifests: - enabled: true \ No newline at end of file diff --git a/save-sandbox/src/main/resources/logback.xml b/save-sandbox/src/main/resources/logback.xml deleted file mode 100644 index 0c67a06f91..0000000000 --- a/save-sandbox/src/main/resources/logback.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - %d{HH:mm:ss.SSS} [%thread] %level %logger{36} - %msg %ex{5}%n - - - - - - - - - \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 42b7a9b361..8755a9768e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -46,7 +46,6 @@ include("save-preprocessor") include("test-utils") include("save-api") include("save-api-cli") -include("save-sandbox") include("authentication-service") include("save-demo") include("save-demo-cpg")