diff --git a/api/src/integrationTest/kotlin/com/cosmotech/api/home/dataset/DatasetControllerTests.kt b/api/src/integrationTest/kotlin/com/cosmotech/api/home/dataset/DatasetControllerTests.kt index 45c6b08a2..d8bcf7a32 100644 --- a/api/src/integrationTest/kotlin/com/cosmotech/api/home/dataset/DatasetControllerTests.kt +++ b/api/src/integrationTest/kotlin/com/cosmotech/api/home/dataset/DatasetControllerTests.kt @@ -49,6 +49,7 @@ import kotlin.test.assertEquals import org.apache.commons.io.IOUtils import org.hamcrest.Matchers.empty import org.hamcrest.Matchers.greaterThan +import org.hamcrest.core.StringContains.containsString import org.json.JSONArray import org.json.JSONObject import org.junit.jupiter.api.BeforeEach @@ -109,6 +110,61 @@ class DatasetControllerTests : ControllerTestBase() { mvc, organizationId, constructWorkspaceCreateRequest(solutionId = solutionId)) } + @Test + @WithMockOauth2User + fun get_dataset_part_with_wrong_ids_format() { + mvc.perform( + get( + "/organizations/wrong-orgId/workspaces/wrong-workspaceId/datasets/wrong-datasetId/parts/wrong-datasetPartId") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.detail", containsString("wrong-orgId:must match \"^o-\\w{10,20}\""))) + .andExpect( + jsonPath("$.detail", containsString("wrong-workspaceId:must match \"^w-\\w{10,20}\""))) + .andExpect( + jsonPath("$.detail", containsString("wrong-datasetId:must match \"^d-\\w{10,20}\""))) + .andExpect( + jsonPath( + "$.detail", containsString("wrong-datasetPartId:must match \"^dp-\\w{10,20}\""))) + + mvc.perform( + get( + "/organizations/wrong-orgId/workspaces/w-123456abcdef/datasets/d-123456azerty/parts/dp-123456azert") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.detail", containsString("wrong-orgId:must match \"^o-\\w{10,20}\""))) + + mvc.perform( + get( + "/organizations/o-1233456azer/workspaces/wrong-workspaceId/datasets/d-123456azerty/parts/dp-123456azert") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect( + jsonPath("$.detail", containsString("wrong-workspaceId:must match \"^w-\\w{10,20}\""))) + + mvc.perform( + get( + "/organizations/o-1233456azer/workspaces/w-123456abcdef/datasets/wrong-datasetId/parts/dp-123456azert") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect( + jsonPath("$.detail", containsString("wrong-datasetId:must match \"^d-\\w{10,20}\""))) + + mvc.perform( + get( + "/organizations/o-1233456azer/workspaces/w-123456abcdef/datasets/d-123456azerty/parts/wrong-datasetPartId") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect( + jsonPath( + "$.detail", containsString("wrong-datasetPartId:must match \"^dp-\\w{10,20}\""))) + } + @Test @WithMockOauth2User fun create_dataset() { diff --git a/api/src/integrationTest/kotlin/com/cosmotech/api/home/organization/OrganizationControllerTests.kt b/api/src/integrationTest/kotlin/com/cosmotech/api/home/organization/OrganizationControllerTests.kt index ff46c15e0..20835093e 100644 --- a/api/src/integrationTest/kotlin/com/cosmotech/api/home/organization/OrganizationControllerTests.kt +++ b/api/src/integrationTest/kotlin/com/cosmotech/api/home/organization/OrganizationControllerTests.kt @@ -59,6 +59,17 @@ class OrganizationControllerTests : ControllerTestBase() { .andDo(MockMvcResultHandlers.print()) } + @Test + @WithMockOauth2User + fun get_organization_with_wrong_orgId_format() { + mvc.perform( + get("/organizations/wrongid-format") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.detail").value("wrongid-format:must match \"^o-\\w{10,20}\"")) + } + @Test @WithMockOauth2User fun create_organization() { diff --git a/api/src/integrationTest/kotlin/com/cosmotech/api/home/run/RunControllerTests.kt b/api/src/integrationTest/kotlin/com/cosmotech/api/home/run/RunControllerTests.kt index 5e5402dc9..415ec5f48 100644 --- a/api/src/integrationTest/kotlin/com/cosmotech/api/home/run/RunControllerTests.kt +++ b/api/src/integrationTest/kotlin/com/cosmotech/api/home/run/RunControllerTests.kt @@ -63,6 +63,7 @@ import io.mockk.impl.annotations.MockK import io.mockk.mockk import java.time.Instant import java.util.* +import org.hamcrest.core.StringContains.containsString import org.json.JSONObject import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -171,6 +172,85 @@ class RunControllerTests : ControllerTestBase() { .getString("id") } + @Test + @WithMockOauth2User + fun get_run_with_wrong_ids_format() { + mvc.perform( + get( + "/organizations/wrong-orgId/workspaces/wrong-workspaceId/runners/wrong-runnerId/runs/wrong-runId") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.detail", containsString("wrong-orgId:must match \"^o-\\w{10,20}\""))) + .andExpect( + jsonPath("$.detail", containsString("wrong-workspaceId:must match \"^w-\\w{10,20}\""))) + .andExpect( + jsonPath("$.detail", containsString("wrong-runnerId:must match \"^(r|s)-\\w{10,20}\""))) + .andExpect( + jsonPath("$.detail", containsString("wrong-runId:must match \"^(run|sr)-\\w{10,20}\""))) + + mvc.perform( + get( + "/organizations/wrong-orgId/workspaces/w-123456abcdef/runners/r-123456azerty/runs/run-123456azerty") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.detail", containsString("wrong-orgId:must match \"^o-\\w{10,20}\""))) + + mvc.perform( + get( + "/organizations/wrong-orgId/workspaces/w-123456abcdef/runners/s-123456azerty/runs/run-123456azerty") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.detail", containsString("wrong-orgId:must match \"^o-\\w{10,20}\""))) + + mvc.perform( + get( + "/organizations/o-1233456azer/workspaces/wrong-workspaceId/runners/r-123456azerty/runs/run-123456azerty") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect( + jsonPath("$.detail", containsString("wrong-workspaceId:must match \"^w-\\w{10,20}\""))) + + mvc.perform( + get( + "/organizations/o-1233456azer/workspaces/wrong-workspaceId/runners/s-123456azerty/runs/run-123456azerty") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect( + jsonPath("$.detail", containsString("wrong-workspaceId:must match \"^w-\\w{10,20}\""))) + + mvc.perform( + get( + "/organizations/o-1233456azer/workspaces/w-123456abcdef/runners/wrong-runnerId/runs/run-123456azerty") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect( + jsonPath("$.detail", containsString("wrong-runnerId:must match \"^(r|s)-\\w{10,20}\""))) + + mvc.perform( + get( + "/organizations/o-1233456azer/workspaces/w-123456abcdef/runners/r-123456azerty/runs/wrong-runId") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect( + jsonPath("$.detail", containsString("wrong-runId:must match \"^(run|sr)-\\w{10,20}\""))) + + mvc.perform( + get( + "/organizations/o-1233456azer/workspaces/w-123456abcdef/runners/s-123456azerty/runs/wrong-runId") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect( + jsonPath("$.detail", containsString("wrong-runId:must match \"^(run|sr)-\\w{10,20}\""))) + } + @Test @WithMockOauth2User fun list_runs() { diff --git a/api/src/integrationTest/kotlin/com/cosmotech/api/home/runner/RunnerControllerTests.kt b/api/src/integrationTest/kotlin/com/cosmotech/api/home/runner/RunnerControllerTests.kt index 09ab7d3a8..74e5d29ad 100644 --- a/api/src/integrationTest/kotlin/com/cosmotech/api/home/runner/RunnerControllerTests.kt +++ b/api/src/integrationTest/kotlin/com/cosmotech/api/home/runner/RunnerControllerTests.kt @@ -41,6 +41,7 @@ import com.cosmotech.workspace.domain.WorkspaceSolution import com.cosmotech.workspace.domain.WorkspaceUpdateRequest import com.ninjasquad.springmockk.SpykBean import io.mockk.every +import org.hamcrest.core.StringContains.containsString import org.json.JSONObject import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -159,6 +160,59 @@ class RunnerControllerTests : ControllerTestBase() { .andExpect(status().is2xxSuccessful) } + @Test + @WithMockOauth2User + fun get_runner_with_wrong_ids_format() { + mvc.perform( + get("/organizations/wrong-orgId/workspaces/wrong-workspaceId/runners/wrong-runnerId") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.detail", containsString("wrong-orgId:must match \"^o-\\w{10,20}\""))) + .andExpect( + jsonPath("$.detail", containsString("wrong-workspaceId:must match \"^w-\\w{10,20}\""))) + .andExpect( + jsonPath("$.detail", containsString("wrong-runnerId:must match \"^(r|s)-\\w{10,20}\""))) + + mvc.perform( + get("/organizations/wrong-orgId/workspaces/w-123456abcdef/runners/r-123456azerty") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.detail", containsString("wrong-orgId:must match \"^o-\\w{10,20}\""))) + + mvc.perform( + get("/organizations/wrong-orgId/workspaces/w-123456abcdef/runners/s-123456azerty") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.detail", containsString("wrong-orgId:must match \"^o-\\w{10,20}\""))) + + mvc.perform( + get("/organizations/o-1233456azer/workspaces/wrong-workspaceId/runners/r-123456azerty") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect( + jsonPath("$.detail", containsString("wrong-workspaceId:must match \"^w-\\w{10,20}\""))) + + mvc.perform( + get("/organizations/o-1233456azer/workspaces/wrong-workspaceId/runners/s-123456azerty") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect( + jsonPath("$.detail", containsString("wrong-workspaceId:must match \"^w-\\w{10,20}\""))) + + mvc.perform( + get("/organizations/o-1233456azer/workspaces/w-123456abcdef/runners/wrong-runnerId") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect( + jsonPath("$.detail", containsString("wrong-runnerId:must match \"^(r|s)-\\w{10,20}\""))) + } + @Test @WithMockOauth2User fun create_runner() { diff --git a/api/src/integrationTest/kotlin/com/cosmotech/api/home/solution/SolutionControllerTests.kt b/api/src/integrationTest/kotlin/com/cosmotech/api/home/solution/SolutionControllerTests.kt index 37926d0e4..cb4b85ce2 100644 --- a/api/src/integrationTest/kotlin/com/cosmotech/api/home/solution/SolutionControllerTests.kt +++ b/api/src/integrationTest/kotlin/com/cosmotech/api/home/solution/SolutionControllerTests.kt @@ -25,6 +25,7 @@ import com.cosmotech.solution.api.SolutionApiService import com.cosmotech.solution.domain.* import io.mockk.every import io.mockk.mockk +import org.hamcrest.core.StringContains.containsString import org.json.JSONObject import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -59,6 +60,34 @@ class SolutionControllerTests : ControllerTestBase() { organizationId = createOrganizationAndReturnId(mvc, constructOrganizationCreateRequest()) } + @Test + @WithMockOauth2User + fun get_solution_with_wrong_ids_format() { + mvc.perform( + get("/organizations/wrong-orgId/solutions/wrong-solutionId") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.detail", containsString("wrong-orgId:must match \"^o-\\w{10,20}\""))) + .andExpect( + jsonPath("$.detail", containsString("wrong-solutionId:must match \"^sol-\\w{10,20}\""))) + + mvc.perform( + get("/organizations/wrong-orgId/solutions/sol-123456abcdef") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.detail", containsString("wrong-orgId:must match \"^o-\\w{10,20}\""))) + + mvc.perform( + get("/organizations/o-123456abcdef/solutions/wrong-solutionId") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect( + jsonPath("$.detail", containsString("wrong-solutionId:must match \"^sol-\\w{10,20}\""))) + } + @Test @WithMockOauth2User fun list_solutions() { diff --git a/api/src/integrationTest/kotlin/com/cosmotech/api/home/workspace/WorkspaceControllerTests.kt b/api/src/integrationTest/kotlin/com/cosmotech/api/home/workspace/WorkspaceControllerTests.kt index 9df5dae56..73a01c185 100644 --- a/api/src/integrationTest/kotlin/com/cosmotech/api/home/workspace/WorkspaceControllerTests.kt +++ b/api/src/integrationTest/kotlin/com/cosmotech/api/home/workspace/WorkspaceControllerTests.kt @@ -22,6 +22,7 @@ import com.cosmotech.common.rbac.ROLE_VIEWER import com.cosmotech.workspace.domain.WorkspaceAccessControl import com.cosmotech.workspace.domain.WorkspaceSecurity import org.apache.commons.io.IOUtils +import org.hamcrest.core.StringContains.containsString import org.json.JSONObject import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -53,6 +54,34 @@ class WorkspaceControllerTests : ControllerTestBase() { solutionId = createSolutionAndReturnId(mvc, organizationId, constructSolutionCreateRequest()) } + @Test + @WithMockOauth2User + fun get_workspace_with_wrong_ids_format() { + mvc.perform( + get("/organizations/wrong-orgId/workspaces/wrong-workspaceId") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.detail", containsString("wrong-orgId:must match \"^o-\\w{10,20}\""))) + .andExpect( + jsonPath("$.detail", containsString("wrong-workspaceId:must match \"^w-\\w{10,20}\""))) + + mvc.perform( + get("/organizations/wrong-orgId/workspaces/w-123456abcdef") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect(jsonPath("$.detail", containsString("wrong-orgId:must match \"^o-\\w{10,20}\""))) + + mvc.perform( + get("/organizations/o-123456abcdef/workspaces/wrong-workspaceId") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest) + .andExpect( + jsonPath("$.detail", containsString("wrong-workspaceId:must match \"^w-\\w{10,20}\""))) + } + @Test @WithMockOauth2User fun create_workspace() { diff --git a/common/src/main/kotlin/com/cosmotech/common/exceptions/CsmExceptionHandling.kt b/common/src/main/kotlin/com/cosmotech/common/exceptions/CsmExceptionHandling.kt index c89677491..420dcc44e 100644 --- a/common/src/main/kotlin/com/cosmotech/common/exceptions/CsmExceptionHandling.kt +++ b/common/src/main/kotlin/com/cosmotech/common/exceptions/CsmExceptionHandling.kt @@ -3,8 +3,10 @@ package com.cosmotech.common.exceptions import io.awspring.cloud.s3.S3Exception +import jakarta.validation.ConstraintViolationException import java.net.URI import org.apache.commons.lang3.NotImplementedException +import org.hibernate.validator.internal.engine.ConstraintViolationImpl import org.springframework.core.Ordered import org.springframework.core.annotation.Order import org.springframework.http.HttpHeaders @@ -129,6 +131,20 @@ open class CsmExceptionHandling : ResponseEntityExceptionHandler() { return problemDetail } + @ExceptionHandler + fun handleConstraintViolationException(exception: ConstraintViolationException): ProblemDetail { + val badRequestStatus = HttpStatus.BAD_REQUEST + val problemDetail = ProblemDetail.forStatus(badRequestStatus) + problemDetail.type = URI.create(httpStatusCodeTypePrefix + badRequestStatus.value()) + val constraintViolations = exception.constraintViolations + problemDetail.detail = + constraintViolations.joinToString { + val constraint = (it as ConstraintViolationImpl) + "${constraint.invalidValue}:${constraint.message}" + } + return problemDetail + } + @ExceptionHandler(AuthenticationServiceException::class) fun handleAuthenticationServiceException( exception: AuthenticationServiceException diff --git a/dataset/src/main/openapi/dataset.yaml b/dataset/src/main/openapi/dataset.yaml index c56d16533..5579af163 100644 --- a/dataset/src/main/openapi/dataset.yaml +++ b/dataset/src/main/openapi/dataset.yaml @@ -726,6 +726,7 @@ components: required: true schema: type: string + pattern: '^o-\w{10,20}' workspaceId: name: workspace_id in: path @@ -733,6 +734,7 @@ components: required: true schema: type: string + pattern: '^w-\w{10,20}' datasetId: name: dataset_id in: path @@ -740,6 +742,7 @@ components: required: true schema: type: string + pattern: '^d-\w{10,20}' datasetPartId: name: dataset_part_id in: path @@ -747,6 +750,7 @@ components: required: true schema: type: string + pattern: '^dp-\w{10,20}' page: name: page in: query diff --git a/doc/Apis/RunApi.md b/doc/Apis/RunApi.md index d73f2321e..45493333e 100644 --- a/doc/Apis/RunApi.md +++ b/doc/Apis/RunApi.md @@ -21,10 +21,10 @@ Delete a run |Name | Type | Description | Notes | |------------- | ------------- | ------------- | -------------| -| **organization\_id** | **String**| the Organization identifier | [default to null] | -| **workspace\_id** | **String**| the Workspace identifier | [default to null] | -| **runner\_id** | **String**| the Runner identifier | [default to null] | -| **run\_id** | **String**| the Run identifier | [default to null] | +| **organization\_id** | **String**| The Organization identifier | [default to null] | +| **workspace\_id** | **String**| The Workspace identifier | [default to null] | +| **runner\_id** | **String**| The Runner identifier | [default to null] | +| **run\_id** | **String**| The Run identifier | [default to null] | ### Return type @@ -49,10 +49,10 @@ Get the details of a run |Name | Type | Description | Notes | |------------- | ------------- | ------------- | -------------| -| **organization\_id** | **String**| the Organization identifier | [default to null] | -| **workspace\_id** | **String**| the Workspace identifier | [default to null] | -| **runner\_id** | **String**| the Runner identifier | [default to null] | -| **run\_id** | **String**| the Run identifier | [default to null] | +| **organization\_id** | **String**| The Organization identifier | [default to null] | +| **workspace\_id** | **String**| The Workspace identifier | [default to null] | +| **runner\_id** | **String**| The Runner identifier | [default to null] | +| **run\_id** | **String**| The Run identifier | [default to null] | ### Return type @@ -77,10 +77,10 @@ get the logs for the Run |Name | Type | Description | Notes | |------------- | ------------- | ------------- | -------------| -| **organization\_id** | **String**| the Organization identifier | [default to null] | -| **workspace\_id** | **String**| the Workspace identifier | [default to null] | -| **runner\_id** | **String**| the Runner identifier | [default to null] | -| **run\_id** | **String**| the Run identifier | [default to null] | +| **organization\_id** | **String**| The Organization identifier | [default to null] | +| **workspace\_id** | **String**| The Workspace identifier | [default to null] | +| **runner\_id** | **String**| The Runner identifier | [default to null] | +| **run\_id** | **String**| The Run identifier | [default to null] | ### Return type @@ -105,10 +105,10 @@ get the status for the Run |Name | Type | Description | Notes | |------------- | ------------- | ------------- | -------------| -| **organization\_id** | **String**| the Organization identifier | [default to null] | -| **workspace\_id** | **String**| the Workspace identifier | [default to null] | -| **runner\_id** | **String**| the Runner identifier | [default to null] | -| **run\_id** | **String**| the Run identifier | [default to null] | +| **organization\_id** | **String**| The Organization identifier | [default to null] | +| **workspace\_id** | **String**| The Workspace identifier | [default to null] | +| **runner\_id** | **String**| The Runner identifier | [default to null] | +| **run\_id** | **String**| The Run identifier | [default to null] | ### Return type @@ -133,9 +133,9 @@ get the list of Runs for the Runner |Name | Type | Description | Notes | |------------- | ------------- | ------------- | -------------| -| **organization\_id** | **String**| the Organization identifier | [default to null] | -| **workspace\_id** | **String**| the Workspace identifier | [default to null] | -| **runner\_id** | **String**| the Runner identifier | [default to null] | +| **organization\_id** | **String**| The Organization identifier | [default to null] | +| **workspace\_id** | **String**| The Workspace identifier | [default to null] | +| **runner\_id** | **String**| The Runner identifier | [default to null] | | **page** | **Integer**| page number to query (first page is at index 0) | [optional] [default to null] | | **size** | **Integer**| amount of result by page | [optional] [default to null] | diff --git a/doc/Apis/WorkspaceApi.md b/doc/Apis/WorkspaceApi.md index 9c0f4faaa..4b58c3e6e 100644 --- a/doc/Apis/WorkspaceApi.md +++ b/doc/Apis/WorkspaceApi.md @@ -408,7 +408,7 @@ List all Workspaces |Name | Type | Description | Notes | |------------- | ------------- | ------------- | -------------| | **organization\_id** | **String**| The Organization identifier | [default to null] | -| **page** | **Integer**| page number to query (first page is at index 0) | [optional] [default to null] | +| **page** | **Integer**| Page number to query (first page is at index 0) | [optional] [default to null] | | **size** | **Integer**| Amount of result by page | [optional] [default to null] | ### Return type diff --git a/organization/src/main/openapi/organization.yaml b/organization/src/main/openapi/organization.yaml index 4dcadf187..4473b8004 100644 --- a/organization/src/main/openapi/organization.yaml +++ b/organization/src/main/openapi/organization.yaml @@ -56,18 +56,8 @@ paths: get: operationId: listOrganizations parameters: - - name: page - in: query - description: Page number to query (first page is at index 0) - required: false - schema: - type: integer - - name: size - in: query - description: Amount of result by page - required: false - schema: - type: integer + - $ref: '#/components/parameters/page' + - $ref: '#/components/parameters/size' tags: - organization summary: List all Organizations @@ -94,12 +84,7 @@ paths: /organizations/{organization_id}: parameters: - - name: organization_id - in: path - description: The Organization identifier - required: true - schema: - type: string + - $ref: '#/components/parameters/organizationId' get: operationId: getOrganization tags: @@ -204,12 +189,7 @@ paths: /organizations/{organization_id}/permissions/{role}: parameters: - - name: organization_id - in: path - description: The Organization identifier - required: true - schema: - type: string + - $ref: '#/components/parameters/organizationId' - name: role in: path description: The Role @@ -242,12 +222,7 @@ paths: /organizations/{organization_id}/security: parameters: - - name: organization_id - in: path - description: The Organization identifier - required: true - schema: - type: string + - $ref: '#/components/parameters/organizationId' get: operationId: getOrganizationSecurity tags: @@ -274,12 +249,7 @@ paths: /organizations/{organization_id}/security/default: parameters: - - name: organization_id - in: path - description: The Organization identifier - required: true - schema: - type: string + - $ref: '#/components/parameters/organizationId' patch: operationId: updateOrganizationDefaultSecurity tags: @@ -324,12 +294,7 @@ paths: /organizations/{organization_id}/security/access: parameters: - - name: organization_id - in: path - description: The Organization identifier - required: true - schema: - type: string + - $ref: '#/components/parameters/organizationId' post: operationId: createOrganizationAccessControl tags: @@ -372,12 +337,7 @@ paths: /organizations/{organization_id}/security/access/{identity_id}: parameters: - - name: organization_id - in: path - description: The Organization identifier - required: true - schema: - type: string + - $ref: '#/components/parameters/organizationId' - name: identity_id in: path description: The User identifier @@ -459,12 +419,7 @@ paths: /organizations/{organization_id}/security/users: parameters: - - name: organization_id - in: path - description: The Organization identifier - required: true - schema: - type: string + - $ref: '#/components/parameters/organizationId' get: operationId: listOrganizationSecurityUsers tags: @@ -503,6 +458,29 @@ components: authorizationUrl: "https://example.com/authorize" tokenUrl: "https://example.com/token" scopes: {} + parameters: + organizationId: + name: organization_id + in: path + description: The Organization identifier + required: true + schema: + type: string + pattern: '^o-\w{10,20}' + page: + name: page + in: query + description: Page number to query (first page is at index 0) + required: false + schema: + type: integer + size: + name: size + in: query + description: Amount of result by page + required: false + schema: + type: integer schemas: # Base Organization object that includes all information Organization: diff --git a/run/src/integrationTest/kotlin/com/cosmotech/run/service/RunServiceIntegrationTest.kt b/run/src/integrationTest/kotlin/com/cosmotech/run/service/RunServiceIntegrationTest.kt index 54373880a..7771a5639 100644 --- a/run/src/integrationTest/kotlin/com/cosmotech/run/service/RunServiceIntegrationTest.kt +++ b/run/src/integrationTest/kotlin/com/cosmotech/run/service/RunServiceIntegrationTest.kt @@ -3,7 +3,6 @@ package com.cosmotech.run.service import com.cosmotech.common.config.CsmPlatformProperties -import com.cosmotech.common.events.RunDeleted import com.cosmotech.common.events.RunStart import com.cosmotech.common.rbac.ROLE_ADMIN import com.cosmotech.common.rbac.ROLE_NONE @@ -79,23 +78,23 @@ import org.springframework.web.client.RestClientResponseException @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class RunServiceIntegrationTest : CsmTestBase() { - @Autowired lateinit var csmPlatformProperties: CsmPlatformProperties - val CONNECTED_ADMIN_USER = "test.admin@cosmotech.com" val CONNECTED_READER_USER = "test.user@cosmotech.com" + private val logger = LoggerFactory.getLogger(RunServiceIntegrationTest::class.java) @MockK(relaxed = true) private lateinit var containerFactory: RunContainerFactory @MockK(relaxed = true) private lateinit var workflowService: WorkflowService + @Autowired lateinit var csmPlatformProperties: CsmPlatformProperties @Autowired lateinit var rediSearchIndexer: RediSearchIndexer @Autowired lateinit var organizationApiService: OrganizationApiServiceInterface - @SpykBean @Autowired lateinit var datasetApiService: DatasetApiServiceInterface + @Autowired lateinit var datasetApiService: DatasetApiServiceInterface @Autowired lateinit var solutionApiService: SolutionApiServiceInterface @Autowired lateinit var workspaceApiService: WorkspaceApiServiceInterface - @SpykBean @Autowired lateinit var runnerApiService: RunnerApiServiceInterface - @SpykBean @Autowired lateinit var runServiceImpl: RunServiceImpl - @SpykBean @Autowired lateinit var runApiService: RunApiServiceInterface + @Autowired lateinit var runnerApiService: RunnerApiServiceInterface + @SpykBean lateinit var runServiceImpl: RunServiceImpl + @Autowired lateinit var runApiService: RunApiServiceInterface @Autowired lateinit var eventPublisher: com.cosmotech.common.events.CsmEventPublisher lateinit var dataset: DatasetCreateRequest @@ -155,8 +154,6 @@ class RunServiceIntegrationTest : CsmTestBase() { every { workflowService.launchRun(any(), any(), any(), any()) } returns mockWorkflowRun(organizationSaved.id, workspaceSaved.id, runnerSaved.id) - every { runnerApiService.getRunner(any(), any(), any()) } returns runnerSaved - every { eventPublisher.publishEvent(any()) } returns Unit } fun makeDatasetCreateRequest() = DatasetCreateRequest(name = "Dataset Test") diff --git a/run/src/main/openapi/run.yaml b/run/src/main/openapi/run.yaml index 467aba33a..5b7af17d6 100644 --- a/run/src/main/openapi/run.yaml +++ b/run/src/main/openapi/run.yaml @@ -14,30 +14,10 @@ tags: paths: /organizations/{organization_id}/workspaces/{workspace_id}/runners/{runner_id}/runs/{run_id}: parameters: - - name: organization_id - in: path - description: the Organization identifier - required: true - schema: - type: string - - name: workspace_id - in: path - description: the Workspace identifier - required: true - schema: - type: string - - name: runner_id - in: path - description: the Runner identifier - required: true - schema: - type: string - - name: run_id - in: path - description: the Run identifier - required: true - schema: - type: string + - $ref: '#/components/parameters/organizationId' + - $ref: '#/components/parameters/workspaceId' + - $ref: '#/components/parameters/runnerId' + - $ref: '#/components/parameters/runId' get: operationId: getRun tags: @@ -75,30 +55,10 @@ paths: description: the Run specified is unknown or you don't have access to it /organizations/{organization_id}/workspaces/{workspace_id}/runners/{runner_id}/runs/{run_id}/status: parameters: - - name: organization_id - in: path - description: the Organization identifier - required: true - schema: - type: string - - name: workspace_id - in: path - description: the Workspace identifier - required: true - schema: - type: string - - name: runner_id - in: path - description: the Runner identifier - required: true - schema: - type: string - - name: run_id - in: path - description: the Run identifier - required: true - schema: - type: string + - $ref: '#/components/parameters/organizationId' + - $ref: '#/components/parameters/workspaceId' + - $ref: '#/components/parameters/runnerId' + - $ref: '#/components/parameters/runId' get: operationId: getRunStatus tags: @@ -122,30 +82,10 @@ paths: $ref: '#/components/examples/BreweryRunStatus' /organizations/{organization_id}/workspaces/{workspace_id}/runners/{runner_id}/runs/{run_id}/logs: parameters: - - name: organization_id - in: path - description: the Organization identifier - required: true - schema: - type: string - - name: workspace_id - in: path - description: the Workspace identifier - required: true - schema: - type: string - - name: runner_id - in: path - description: the Runner identifier - required: true - schema: - type: string - - name: run_id - in: path - description: the Run identifier - required: true - schema: - type: string + - $ref: '#/components/parameters/organizationId' + - $ref: '#/components/parameters/workspaceId' + - $ref: '#/components/parameters/runnerId' + - $ref: '#/components/parameters/runId' get: operationId: getRunLogs tags: @@ -163,24 +103,9 @@ paths: $ref: '#/components/examples/BreweryRunLogs' /organizations/{organization_id}/workspaces/{workspace_id}/runners/{runner_id}/runs: parameters: - - name: organization_id - in: path - description: the Organization identifier - required: true - schema: - type: string - - name: workspace_id - in: path - description: the Workspace identifier - required: true - schema: - type: string - - name: runner_id - in: path - description: the Runner identifier - required: true - schema: - type: string + - $ref: '#/components/parameters/organizationId' + - $ref: '#/components/parameters/workspaceId' + - $ref: '#/components/parameters/runnerId' get: operationId: listRuns parameters: @@ -230,6 +155,53 @@ components: authorizationUrl: "https://example.com/authorize" tokenUrl: "https://example.com/token" scopes: {} + parameters: + organizationId: + name: organization_id + in: path + description: The Organization identifier + required: true + schema: + type: string + pattern: '^o-\w{10,20}' + workspaceId: + name: workspace_id + in: path + description: The Workspace identifier + required: true + schema: + type: string + pattern: '^w-\w{10,20}' + runnerId: + name: runner_id + in: path + description: The Runner identifier + required: true + schema: + type: string + pattern: '^(r|s)-\w{10,20}' + runId: + name: run_id + in: path + description: The Run identifier + required: true + schema: + type: string + pattern: '^(run|sr)-\w{10,20}' + page: + name: page + in: query + description: Page number to query (first page is at index 0) + required: false + schema: + type: integer + size: + name: size + in: query + description: Amount of result by page + required: false + schema: + type: integer schemas: RunStatus: type: object diff --git a/runner/src/integrationTest/kotlin/com/cosmotech/runner/service/RunnerServiceIntegrationTest.kt b/runner/src/integrationTest/kotlin/com/cosmotech/runner/service/RunnerServiceIntegrationTest.kt index a560dac80..c9f94f2ed 100644 --- a/runner/src/integrationTest/kotlin/com/cosmotech/runner/service/RunnerServiceIntegrationTest.kt +++ b/runner/src/integrationTest/kotlin/com/cosmotech/runner/service/RunnerServiceIntegrationTest.kt @@ -98,11 +98,11 @@ class RunnerServiceIntegrationTest : CsmTestBase() { private val logger = LoggerFactory.getLogger(RunnerServiceIntegrationTest::class.java) private val defaultName = "my.account-tester@cosmotech.com" - @SpykBean @Autowired private lateinit var eventPublisher: CsmEventPublisher + @SpykBean private lateinit var eventPublisher: CsmEventPublisher @Autowired lateinit var rediSearchIndexer: RediSearchIndexer @Autowired lateinit var organizationApiService: OrganizationApiServiceInterface - @SpykBean @Autowired lateinit var datasetApiService: DatasetApiServiceInterface + @SpykBean lateinit var datasetApiService: DatasetApiServiceInterface @Autowired lateinit var solutionApiService: SolutionApiServiceInterface @Autowired lateinit var workspaceApiService: WorkspaceApiServiceInterface @Autowired lateinit var runnerApiService: RunnerApiServiceInterface diff --git a/runner/src/main/openapi/runner.yaml b/runner/src/main/openapi/runner.yaml index 50af254f1..20b3062ca 100644 --- a/runner/src/main/openapi/runner.yaml +++ b/runner/src/main/openapi/runner.yaml @@ -520,6 +520,7 @@ components: required: true schema: type: string + pattern: '^o-\w{10,20}' workspaceId: name: workspace_id in: path @@ -527,6 +528,7 @@ components: required: true schema: type: string + pattern: '^w-\w{10,20}' runnerId: name: runner_id in: path @@ -534,6 +536,7 @@ components: required: true schema: type: string + pattern: '^(r|s)-\w{10,20}' page: name: page in: query diff --git a/solution/src/integrationTest/kotlin/com/cosmotech/solution/service/SolutionServiceIntegrationTest.kt b/solution/src/integrationTest/kotlin/com/cosmotech/solution/service/SolutionServiceIntegrationTest.kt index b0aa8ea51..3972f6334 100644 --- a/solution/src/integrationTest/kotlin/com/cosmotech/solution/service/SolutionServiceIntegrationTest.kt +++ b/solution/src/integrationTest/kotlin/com/cosmotech/solution/service/SolutionServiceIntegrationTest.kt @@ -45,7 +45,6 @@ import org.junit.runner.RunWith import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest -import org.springframework.core.io.ResourceLoader import org.springframework.test.context.ActiveProfiles import org.springframework.test.context.junit.jupiter.SpringExtension import org.springframework.test.context.junit4.SpringRunner @@ -64,13 +63,10 @@ class SolutionServiceIntegrationTest : CsmTestBase() { private val logger = LoggerFactory.getLogger(SolutionServiceIntegrationTest::class.java) - val fileName = "test_solution_file.txt" - @Autowired lateinit var rediSearchIndexer: RediSearchIndexer @Autowired lateinit var organizationApiService: OrganizationApiServiceInterface @Autowired lateinit var solutionApiService: SolutionApiServiceInterface @Autowired lateinit var csmPlatformProperties: CsmPlatformProperties - @Autowired lateinit var resourceLoader: ResourceLoader private var containerRegistryService: ContainerRegistryService = mockk(relaxed = true) private var startTime: Long = 0 diff --git a/solution/src/main/openapi/solution.yaml b/solution/src/main/openapi/solution.yaml index 0482f0093..c02de1f1c 100644 --- a/solution/src/main/openapi/solution.yaml +++ b/solution/src/main/openapi/solution.yaml @@ -759,6 +759,7 @@ components: required: true schema: type: string + pattern: '^o-\w{10,20}' solutionId: name: solution_id in: path @@ -766,6 +767,7 @@ components: required: true schema: type: string + pattern: '^sol-\w{10,20}' runTemplateId: name: run_template_id in: path diff --git a/workspace/src/main/openapi/workspace.yaml b/workspace/src/main/openapi/workspace.yaml index 79a711e80..71fe4d93c 100644 --- a/workspace/src/main/openapi/workspace.yaml +++ b/workspace/src/main/openapi/workspace.yaml @@ -14,12 +14,7 @@ tags: paths: /organizations/{organization_id}/workspaces: parameters: - - name: organization_id - in: path - description: The Organization identifier - required: true - schema: - type: string + - $ref: '#/components/parameters/organizationId' post: operationId: createWorkspace tags: @@ -62,18 +57,8 @@ paths: get: operationId: listWorkspaces parameters: - - name: page - in: query - description: page number to query (first page is at index 0) - required: false - schema: - type: integer - - name: size - in: query - description: Amount of result by page - required: false - schema: - type: integer + - $ref: '#/components/parameters/page' + - $ref: '#/components/parameters/size' tags: - workspace summary: List all Workspaces @@ -99,18 +84,8 @@ paths: $ref: '#/components/examples/WorkspaceList' /organizations/{organization_id}/workspaces/{workspace_id}: parameters: - - name: organization_id - in: path - description: The Organization identifier - required: true - schema: - type: string - - name: workspace_id - in: path - description: The Workspace identifier - required: true - schema: - type: string + - $ref: '#/components/parameters/organizationId' + - $ref: '#/components/parameters/workspaceId' get: operationId: getWorkspace tags: @@ -190,18 +165,8 @@ paths: /organizations/{organization_id}/workspaces/{workspace_id}/files: parameters: - - name: organization_id - in: path - description: The Organization identifier - required: true - schema: - type: string - - name: workspace_id - in: path - description: The Workspace identifier - required: true - schema: - type: string + - $ref: '#/components/parameters/organizationId' + - $ref: '#/components/parameters/workspaceId' post: operationId: createWorkspaceFile tags: @@ -298,18 +263,8 @@ paths: /organizations/{organization_id}/workspaces/{workspace_id}/files/download: parameters: - - name: organization_id - in: path - description: The Organization identifier - required: true - schema: - type: string - - name: workspace_id - in: path - description: The Workspace identifier - required: true - schema: - type: string + - $ref: '#/components/parameters/organizationId' + - $ref: '#/components/parameters/workspaceId' - name: file_name in: query description: The file name @@ -334,18 +289,8 @@ paths: /organizations/{organization_id}/workspaces/{workspace_id}/files/delete: parameters: - - name: organization_id - in: path - description: The Organization identifier - required: true - schema: - type: string - - name: workspace_id - in: path - description: The Workspace identifier - required: true - schema: - type: string + - $ref: '#/components/parameters/organizationId' + - $ref: '#/components/parameters/workspaceId' - name: file_name in: query description: The file name @@ -365,18 +310,8 @@ paths: /organizations/{organization_id}/workspaces/{workspace_id}/permissions/{role}: parameters: - - name: organization_id - in: path - description: The Organization identifier - required: true - schema: - type: string - - name: workspace_id - in: path - description: The Workspace identifier - required: true - schema: - type: string + - $ref: '#/components/parameters/organizationId' + - $ref: '#/components/parameters/workspaceId' - name: role in: path description: The Role @@ -401,18 +336,8 @@ paths: /organizations/{organization_id}/workspaces/{workspace_id}/security: parameters: - - name: organization_id - in: path - description: The Organization identifier - required: true - schema: - type: string - - name: workspace_id - in: path - description: The Workspace identifier - required: true - schema: - type: string + - $ref: '#/components/parameters/organizationId' + - $ref: '#/components/parameters/workspaceId' get: operationId: getWorkspaceSecurity tags: @@ -439,18 +364,8 @@ paths: /organizations/{organization_id}/workspaces/{workspace_id}/security/default: parameters: - - name: organization_id - in: path - description: The Organization identifier - required: true - schema: - type: string - - name: workspace_id - in: path - description: The Workspace identifier - required: true - schema: - type: string + - $ref: '#/components/parameters/organizationId' + - $ref: '#/components/parameters/workspaceId' patch: operationId: updateWorkspaceDefaultSecurity tags: @@ -495,18 +410,8 @@ paths: /organizations/{organization_id}/workspaces/{workspace_id}/security/access: parameters: - - name: organization_id - in: path - description: The Organization identifier - required: true - schema: - type: string - - name: workspace_id - in: path - description: The Workspace identifier - required: true - schema: - type: string + - $ref: '#/components/parameters/organizationId' + - $ref: '#/components/parameters/workspaceId' post: operationId: createWorkspaceAccessControl tags: @@ -549,18 +454,8 @@ paths: /organizations/{organization_id}/workspaces/{workspace_id}/security/access/{identity_id}: parameters: - - name: organization_id - in: path - description: The Organization identifier - required: true - schema: - type: string - - name: workspace_id - in: path - description: The Workspace identifier - required: true - schema: - type: string + - $ref: '#/components/parameters/organizationId' + - $ref: '#/components/parameters/workspaceId' - name: identity_id in: path description: The User identifier @@ -642,18 +537,8 @@ paths: /organizations/{organization_id}/workspaces/{workspace_id}/security/users: parameters: - - name: organization_id - in: path - description: The Organization identifier - required: true - schema: - type: string - - name: workspace_id - in: path - description: The Workspace identifier - required: true - schema: - type: string + - $ref: '#/components/parameters/organizationId' + - $ref: '#/components/parameters/workspaceId' get: operationId: listWorkspaceSecurityUsers tags: @@ -682,6 +567,37 @@ components: authorizationUrl: "https://example.com/authorize" tokenUrl: "https://example.com/token" scopes: {} + parameters: + organizationId: + name: organization_id + in: path + description: The Organization identifier + required: true + schema: + type: string + pattern: '^o-\w{10,20}' + workspaceId: + name: workspace_id + in: path + description: The Workspace identifier + required: true + schema: + type: string + pattern: '^w-\w{10,20}' + page: + name: page + in: query + description: Page number to query (first page is at index 0) + required: false + schema: + type: integer + size: + name: size + in: query + description: Amount of result by page + required: false + schema: + type: integer schemas: # Base Workspace object that includes all information Workspace: