Prerequisites
- Latest java 11 with JAVA_HOME pointing to it
- Docker
To build ./gradlew build
Start / setup dependencies with compose:
docker compose up db sqs
To start the dev server on port 8888:
./gradlew bootRun
To enable hot-swapping run the following command in a separate terminal in addition to the bootRun
command:
./gradlew assemble --continuous
Run unit tests:
./gradlew test
Run integration tests (needs to have docker daemon running):
./gradlew integrationTest
To start dev server connected to integration test database (suitable for e.g. running E2E tests without cluttering development data):
./gradlew bootRunTest
Enable running flyway commands against integration test database in gradle.properties
Run linter autofix:
./gradlew ktfmtFormat
./gradlew formatKotlin
If you use IntelliJ IDEA, it's recommended to install and enable the ktfmt
plugin, and set code style to Kotlinlang.
The service has a dev API in local, dev and test environments. The API is used for creating test fixtures for E2E tests. The API is defined in DevApi.kt.
The database lies in a docker container while the tests are executed. You can access the db with eg.
docker exec -it <container> psql -U evaka_application_local -d evaka_it
where <container>
is to be found with docker ps
.
Documentation: https://backend-qa.varda-db.csc.fi/ (You need Voltti, Gofore or Reaktor IP)
- change application-dev.properties file:
fi.espoo.integration.varda.url=https://backend-qa.varda-db.csc.fi/api
- get apiKey from https://backend-qa.varda-db.csc.fi/varda/swagger/
- login using Opintopolku: See #evaka-tech pinned items
- change
vardaService.getApiKey()
to return the apiKey
This service uses a trust store to explicitly trust certificates of its integrations, such as:
The trust store is configurable with:
FI_ESPOO_VOLTTI_VTJ_XROAD_TRUSTSTORE_LOCATION
: file locationFI_ESPOO_VOLTTI_VTJ_XROAD_TRUSTSTORE_TYPE
: trust store type (usually: "JKS")FI_ESPOO_VOLTTI_VTJ_XROAD_TRUSTSTORE_PASSWORD
: trust store's password
and the actual store should contain whatever certificates you trust.
For authenticating in X-Road, the service also has a key store, configured with:
FI_ESPOO_VOLTTI_VTJ_XROAD_KEYSTORE_LOCATION
: file locationFI_ESPOO_VOLTTI_VTJ_XROAD_KEYSTORE_PASSWORD
: key store's password
and the actual store should contain your keys.
Some useful commands for managing the stores (same actions apply for both):
# Download current trust store from S3:
aws s3 cp s3://${DEPLOYMENT_BUCKET}/evaka-srv/trustStore.jks trustStore.jks
# Get trust store password from Parameter Store:
aws ssm get-parameter --with-decryption --name $PARAMETER_NAME --query 'Parameter.Value' --output text
# List certificates in trust store:
keytool -list -v -keystore trustStore.jks -storepass "$(aws ssm get-parameter --with-decryption --name $PARAMETER_NAME --query 'Parameter.Value' --output text)"
# Rotate password of trust store (prompts for new password):
keytool -storepasswd -keystore trustStore.jks -storepass "$(aws ssm get-parameter --with-decryption --name $PARAMETER_NAME --query 'Parameter.Value' --output text)"
aws ssm put-parameter --name $PARAMETER_NAME --value 'supersecretpassword' --type SecureString --overwrite
aws s3 cp trustStore.jks s3://${DEPLOYMENT_BUCKET}/evaka-srv/trustStore.jks
Repeat for all environments:
-
Download current trust store:
aws s3 cp s3://${DEPLOYMENT_BUCKET}/evaka-srv/trustStore.jks trustStore.jks
-
Find the old alias of the entry:
keytool -list -v -keystore trustStore.jks -storepass "$(aws ssm get-parameter --with-decryption --name $PARAMETER_NAME --query 'Parameter.Value' --output text)"
-
IF REPLACING: Remove old cert from trust store:
keytool -delete -alias $OLD_ALIAS -keystore trustStore.jks -storepass "$(aws ssm get-parameter --with-decryption --name $PARAMETER_NAME --query 'Parameter.Value' --output text)"
-
Fetch and import a new trusted cert:
# Replace HOST with e.g. koski.opintopolku.fi to fetch the Koski production cert keytool -printcert -sslserver "${HOST}:443" -rfc | keytool -import -noprompt -alias $NEW_ALIAS -keystore trustStore.jks -storepass "$(aws ssm get-parameter --with-decryption --name $PARAMETER_NAME --query 'Parameter.Value' --output text)"
-
Upload updated trust store:
aws s3 cp trustStore.jks s3://${DEPLOYMENT_BUCKET}/evaka-srv/trustStore.jks
-
Re-deploy all ECS service tasks:
aws ecs update-service --force-new-deployment --service evaka-srv --cluster $CLUSTER_NAME
- NOTE: Cluster and service name are deployment specific
- Run
./gradlew generateVapidKey
- Copy the printed private key to configuration (environment variable name is EVAKA_WEB_PUSH_VAPID_PRIVATE_KEY)
Add ./service/list-migrations.sh
to your existing pre-commit hook (.git/hooks/pre-commit
) to enable automatic DB migration bookkeeping
OR if you don't have a pre-commit hook yet, you can create a new one:
cat >.git/hooks/pre-commit <<EOF
#!/bin/sh
./service/list-migrations.sh
EOF
chmod a+x .git/hooks/pre-commit
Service dependencies are checked for security vulnerabilities with
the OWASP dependency-check-gradle
plugin. Dependencies are checked on every build with the command ./gradlew dependencyCheckAnalyze
. By default even
minor vulnerabilities break the build, but they can
be suppressed when needed. The suppression
rules are configured here.
Use the KLogger extensions in service-lib to add custom metadata to log entries (useful for querying/statistical analysis):
import fi.espoo.voltti.logging.loggers.error
try {
logger.debug(mapOf("url" to url)) { "Doing something" }
something()
} catch (error: FuelError) {
val meta = mapOf(
"method" to request.method,
"url" to request.url,
"body" to request.body.asString("application/json"),
"errorMessage" to error.errorData.decodeToString()
)
logger.error(error, meta) { "Request failed, status ${error.response.statusCode}" }
}