From 104acf21174af51f77cbef6f22f7c53fe3b5f0dc Mon Sep 17 00:00:00 2001 From: Jasper <54336703+JazJax@users.noreply.github.com> Date: Tue, 17 Sep 2024 14:49:45 +0100 Subject: [PATCH] Elm 2135 fixing linting errors (#4) * Fixing linting errors (and amending tests the fixes affect) * Updated readme --- README.md | 117 +++------------- ...cMonitoringDatastoreApiExceptionHandler.kt | 2 +- .../config/OpenApiConfiguration.kt | 2 +- .../config/WebClientConfiguration.kt | 6 +- ...lthPingCheck.kt => HmppsAuthHealthPing.kt} | 0 .../integration/ExampleResourceIntTest.kt | 129 ------------------ .../integration/health/HealthCheckTest.kt | 1 - .../integration/health/InfoTest.kt | 2 +- 8 files changed, 23 insertions(+), 236 deletions(-) rename src/main/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/health/{HealthPingCheck.kt => HmppsAuthHealthPing.kt} (100%) delete mode 100644 src/test/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/integration/ExampleResourceIntTest.kt diff --git a/README.md b/README.md index 36f199f..e519a16 100644 --- a/README.md +++ b/README.md @@ -1,109 +1,11 @@ -# hmpps-template-kotlin +# Electronic Monitoring Datastore API [![repo standards badge](https://img.shields.io/badge/endpoint.svg?&style=flat&logo=github&url=https%3A%2F%2Foperations-engineering-reports.cloud-platform.service.justice.gov.uk%2Fapi%2Fv1%2Fcompliant_public_repositories%2Fhmpps-template-kotlin)](https://operations-engineering-reports.cloud-platform.service.justice.gov.uk/public-report/hmpps-template-kotlin "Link to report") [![CircleCI](https://circleci.com/gh/ministryofjustice/hmpps-template-kotlin/tree/main.svg?style=svg)](https://circleci.com/gh/ministryofjustice/hmpps-template-kotlin) [![Docker Repository on Quay](https://img.shields.io/badge/quay.io-repository-2496ED.svg?logo=docker)](https://quay.io/repository/hmpps/hmpps-template-kotlin) [![API docs](https://img.shields.io/badge/API_docs_-view-85EA2D.svg?logo=swagger)](https://hmpps-template-kotlin-dev.hmpps.service.justice.gov.uk/webjars/swagger-ui/index.html?configUrl=/v3/api-docs) -Template github repo used for new Kotlin based projects. - -# Instructions - -If this is a HMPPS project then the project will be created as part of bootstrapping - -see [dps-project-bootstrap](https://github.com/ministryofjustice/dps-project-bootstrap). You are able to specify a -template application using the `github_template_repo` attribute to clone without the need to manually do this yourself -within GitHub. - -This project is community managed by the mojdt `#kotlin-dev` slack channel. -Please raise any questions or queries there. Contributions welcome! - -Our security policy is located [here](https://github.com/ministryofjustice/hmpps-template-kotlin/security/policy). - -## Creating a Cloud Platform namespace - -When deploying to a new namespace, you may wish to use the -[templates project namespace](https://github.com/ministryofjustice/cloud-platform-environments/tree/main/namespaces/live.cloud-platform.service.justice.gov.uk/hmpps-templates-dev) -as the basis for your new namespace. This namespace contains both the kotlin and typescript template projects, which -is the usual way that projects are setup. - -Copy this folder and update all the existing namespace references. If you only need the kotlin configuration then remove -all typescript references and remove the elasticache configuration. Submit a PR to the Cloud Platform team in -#ask-cloud-platform. Further instructions from the Cloud Platform team can be found in -the [Cloud Platform User Guide](https://user-guide.cloud-platform.service.justice.gov.uk/#cloud-platform-user-guide) - -## Renaming from HMPPS Template Kotlin - github Actions - -Once the new repository is deployed. Navigate to the repository in github, and select the `Actions` tab. -Click the link to `Enable Actions on this repository`. - -Find the Action workflow named: `rename-project-create-pr` and click `Run workflow`. This workflow will -execute the `rename-project.bash` and create Pull Request for you to review. Review the PR and merge. - -Note: ideally this workflow would run automatically however due to a recent change github Actions are not -enabled by default on newly created repos. There is no way to enable Actions other then to click the button in the UI. -If this situation changes we will update this project so that the workflow is triggered during the bootstrap project. -Further reading: - -The script takes six arguments: - -### New project name - -This should start with `hmpps-` e.g. `hmpps-prison-visits` so that it can be easily distinguished in github from -other departments projects. Try to avoid using abbreviations so that others can understand easily what your project is. - -### Slack channel for release notifications - -By default, release notifications are only enabled for production. The circleci configuration can be amended to send -release notifications for deployments to other environments if required. Note that if the configuration is amended, -the slack channel should then be amended to your own team's channel as `dps-releases` is strictly for production release -notifications. If the slack channel is set to something other than `dps-releases`, production release notifications -will still automatically go to `dps-releases` as well. This is configured by `releases-slack-channel` in -`.circleci/config.yml`. - -### Slack channel for pipeline security notifications - -Ths channel should be specific to your team and is for daily / weekly security scanning job results. It is your team's -responsibility to keep up-to-date with security issues and update your application so that these jobs pass. You will -only be notified if the jobs fail. The scan results can always be found in circleci for your project. This is -configured by `alerts-slack-channel` in `.circleci/config.yml`. - -### Non production kubernetes alerts - -By default Prometheus alerts are created in the application namespaces to monitor your application e.g. if your -application is crash looping, there are a significant number of errors from the ingress. Since Prometheus runs in -cloud platform AlertManager needs to be setup first with your channel. Please see -[Create your own custom alerts](https://user-guide.cloud-platform.service.justice.gov.uk/documentation/monitoring-an-app/how-to-create-alarms.html) -in the Cloud Platform user guide. Once that is setup then the `custom severity label` can be used for -`alertSeverity` in the `helm_deploy/values-*.yaml` configuration. - -Normally it is worth setting up two separate labels and therefore two separate slack channels - one for your production -alerts and one for your non-production alerts. Using the same channel can mean that production alerts are sometimes -lost within non-production issues. - -### Production kubernetes alerts - -This is the severity label for production, determined by the `custom severity label`. See the above -#non-production-kubernetes-alerts for more information. This is configured in `helm_deploy/values-prod.yaml`. - -### Product ID - -This is so that we can link a component to a product and thus provide team and product information in the Developer -Portal. Refer to the developer portal at https://developer-portal.hmpps.service.justice.gov.uk/products to find your -product id. This is configured in `helm_deploy//values.yaml`. - -## Manually branding from template app - -Run the `rename-project.bash` without any arguments. This will prompt for the six required parameters and create a PR. -The script requires a recent version of `bash` to be installed, as well as GNU `sed` in the path. - -## TODOs and Examples - -We have tried to provide some examples of best practice in the application - so there are lots of TODOs in the code -where changes are required to meet your requirements. There is an `ExampleResource` that includes best practice and also -serve as spring security examples. The template typescript project has a demonstration that calls this endpoint as well. - -For the demonstration, rather than introducing a dependency on a different service, this application calls out to -itself. This is only to show a service calling out to another service and is certainly not recommended! +API to access the Electronic Monitoring datastore in the Modernisation Platform. ## Running the application locally @@ -111,6 +13,12 @@ The application comes with a `dev` spring profile that includes default settings necessary when deploying to kubernetes as these values are included in the helm configuration templates - e.g. `values-dev.yaml`. +### Checking the app has started successfully: +If using docker, your app is probably exposed at `localhost:8080`. +Call http://localhost:8080/health with a browser to get app health info. + +### Running with Docker + There is also a `docker-compose.yml` that can be used to run a local instance of the template in docker and also an instance of HMPPS Auth (required if your service calls out to other services using a token). @@ -128,4 +36,13 @@ docker compose pull && docker compose up --scale hmpps-template-kotlin=0 will just start a docker instance of HMPPS Auth. The application should then be started with a `dev` active profile in Intellij. +## Note on remaining TODOs and Examples from template app + +We have tried to provide some examples of best practice in the application - so there are lots of TODOs in the code +where changes are required to meet your requirements. There is an `ExampleResource` that includes best practice and also +serve as spring security examples. The template typescript project has a demonstration that calls this endpoint as well. + +For the demonstration, rather than introducing a dependency on a different service, this application calls out to +itself. This is only to show a service calling out to another service and is certainly not recommended! + diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/config/HmppsElectronicMonitoringDatastoreApiExceptionHandler.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/config/HmppsElectronicMonitoringDatastoreApiExceptionHandler.kt index 2b816dd..a5416b0 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/config/HmppsElectronicMonitoringDatastoreApiExceptionHandler.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/config/HmppsElectronicMonitoringDatastoreApiExceptionHandler.kt @@ -14,7 +14,7 @@ import org.springframework.web.servlet.resource.NoResourceFoundException import uk.gov.justice.hmpps.kotlin.common.ErrorResponse @RestControllerAdvice -class HmppsElectronicMonitoringDatastoreExceptionHandler { +class HmppsElectronicMonitoringDatastoreApiExceptionHandler { @ExceptionHandler(ValidationException::class) fun handleValidationException(e: ValidationException): ResponseEntity = ResponseEntity .status(BAD_REQUEST) diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/config/OpenApiConfiguration.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/config/OpenApiConfiguration.kt index 37fd580..e45a2dd 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/config/OpenApiConfiguration.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/config/OpenApiConfiguration.kt @@ -7,10 +7,10 @@ import io.swagger.v3.oas.models.info.Info import io.swagger.v3.oas.models.security.SecurityRequirement import io.swagger.v3.oas.models.security.SecurityScheme import io.swagger.v3.oas.models.servers.Server -import io.swagger.v3.oas.models.tags.Tag import org.springframework.boot.info.BuildProperties import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration +// import io.swagger.v3.oas.models.tags.Tag @Configuration class OpenApiConfiguration(buildProperties: BuildProperties) { diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/config/WebClientConfiguration.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/config/WebClientConfiguration.kt index 957b25e..e1cba42 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/config/WebClientConfiguration.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/config/WebClientConfiguration.kt @@ -3,11 +3,11 @@ package uk.gov.justice.digital.hmpps.templatepackagename.config import org.springframework.beans.factory.annotation.Value import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration -import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager import org.springframework.web.reactive.function.client.WebClient -import uk.gov.justice.hmpps.kotlin.auth.authorisedWebClient import uk.gov.justice.hmpps.kotlin.auth.healthWebClient import java.time.Duration +// import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager +// import uk.gov.justice.hmpps.kotlin.auth.authorisedWebClient @Configuration class WebClientConfiguration( @@ -25,7 +25,7 @@ class WebClientConfiguration( // @Bean // fun exampleApiHealthWebClient(builder: WebClient.Builder): WebClient = builder.healthWebClient(exampleApiBaseUri, healthTimeout) - // This is an example of a bean for calling other services + // This is an example of a bean for calling other services // @Bean // fun exampleApiWebClient(authorizedClientManager: OAuth2AuthorizedClientManager, builder: WebClient.Builder): WebClient = // builder.authorisedWebClient(authorizedClientManager, registrationId = "example-api", url = exampleApiBaseUri, timeout) diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/health/HealthPingCheck.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/health/HmppsAuthHealthPing.kt similarity index 100% rename from src/main/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/health/HealthPingCheck.kt rename to src/main/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/health/HmppsAuthHealthPing.kt diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/integration/ExampleResourceIntTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/integration/ExampleResourceIntTest.kt deleted file mode 100644 index 39af6b2..0000000 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/integration/ExampleResourceIntTest.kt +++ /dev/null @@ -1,129 +0,0 @@ -package uk.gov.justice.digital.hmpps.templatepackagename.integration - -import com.github.tomakehurst.wiremock.client.WireMock -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.DisplayName -import org.junit.jupiter.api.Nested -import org.junit.jupiter.api.Test -import uk.gov.justice.digital.hmpps.templatepackagename.integration.wiremock.ExampleApiExtension.Companion.exampleApi -import uk.gov.justice.digital.hmpps.templatepackagename.integration.wiremock.HmppsAuthApiExtension.Companion.hmppsAuth -import java.time.LocalDate - -class ExampleResourceIntTest : IntegrationTestBase() { - - @Nested - @DisplayName("GET /example/time") - inner class TimeEndpoint { - - @Test - fun `should return unauthorized if no token`() { - webTestClient.get() - .uri("/example/time") - .exchange() - .expectStatus() - .isUnauthorized - } - - @Test - fun `should return forbidden if no role`() { - webTestClient.get() - .uri("/example/time") - .headers(setAuthorisation()) - .exchange() - .expectStatus() - .isForbidden - } - - @Test - fun `should return forbidden if wrong role`() { - webTestClient.get() - .uri("/example/time") - .headers(setAuthorisation(roles = listOf("ROLE_WRONG"))) - .exchange() - .expectStatus() - .isForbidden - } - - @Test - fun `should return OK`() { - webTestClient.get() - .uri("/example/time") - .headers(setAuthorisation(roles = listOf("ROLE_TEMPLATE_KOTLIN__UI"))) - .exchange() - .expectStatus() - .isOk - .expectBody() - .jsonPath("$").value { - assertThat(it).startsWith("${LocalDate.now()}") - } - } - } - - @Nested - @DisplayName("GET /example/message/{parameter}") - inner class UserDetailsEndpoint { - - @Test - fun `should return unauthorized if no token`() { - webTestClient.get() - .uri("/example/message/{parameter}", "bob") - .exchange() - .expectStatus() - .isUnauthorized - } - - @Test - fun `should return forbidden if no role`() { - webTestClient.get() - .uri("/example/message/{parameter}", "bob") - .headers(setAuthorisation(roles = listOf())) - .exchange() - .expectStatus() - .isForbidden - } - - @Test - fun `should return forbidden if wrong role`() { - webTestClient.get() - .uri("/example/message/{parameter}", "bob") - .headers(setAuthorisation(roles = listOf("ROLE_WRONG"))) - .exchange() - .expectStatus() - .isForbidden - } - - @Test - fun `should return OK`() { - hmppsAuth.stubGrantToken() - exampleApi.stubExampleExternalApiUserMessage() - webTestClient.get() - .uri("/example/message/{parameter}", "bob") - .headers(setAuthorisation(username = "AUTH_OK", roles = listOf("ROLE_TEMPLATE_KOTLIN__UI"))) - .exchange() - .expectStatus() - .isOk - .expectBody() - .jsonPath("$.message").isEqualTo("A stubbed message") - - exampleApi.verify(WireMock.getRequestedFor(WireMock.urlEqualTo("/example-external-api/bob"))) - hmppsAuth.verify(1, WireMock.postRequestedFor(WireMock.urlEqualTo("/auth/oauth/token"))) - } - - @Test - fun `should return empty response if user not found`() { - hmppsAuth.stubGrantToken() - exampleApi.stubExampleExternalApiNotFound() - webTestClient.get() - .uri("/example/message/{parameter}", "bob") - .headers(setAuthorisation(username = "AUTH_NOTFOUND", roles = listOf("ROLE_TEMPLATE_KOTLIN__UI"))) - .exchange() - .expectStatus() - .isOk - .expectBody() - .jsonPath("$.message").doesNotExist() - - exampleApi.verify(WireMock.getRequestedFor(WireMock.urlEqualTo("/example-external-api/bob"))) - hmppsAuth.verify(1, WireMock.postRequestedFor(WireMock.urlEqualTo("/auth/oauth/token"))) - } - } -} diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/integration/health/HealthCheckTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/integration/health/HealthCheckTest.kt index 1a9a954..7abb3bd 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/integration/health/HealthCheckTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/integration/health/HealthCheckTest.kt @@ -30,7 +30,6 @@ class HealthCheckTest : IntegrationTestBase() { .expectBody() .jsonPath("status").isEqualTo("DOWN") .jsonPath("components.hmppsAuth.status").isEqualTo("DOWN") - .jsonPath("components.exampleApi.status").isEqualTo("DOWN") } @Test diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/integration/health/InfoTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/integration/health/InfoTest.kt index f7adf23..41272e7 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/integration/health/InfoTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/electronicmonitoringdatastoreapi/integration/health/InfoTest.kt @@ -16,7 +16,7 @@ class InfoTest : IntegrationTestBase() { .expectStatus() .isOk .expectBody() - .jsonPath("build.name").isEqualTo("hmpps-template-kotlin") + .jsonPath("build.name").isEqualTo("hmpps-electronic-monitoring-datastore-api") } @Test