From fd238d96111dc1ace26bc900a3b733e92b1d4cb8 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Sun, 25 Oct 2026 04:54:19 +0100 Subject: [PATCH 1/3] chore(deps): consolidate standalone dependency updates (#62) --- .github/scripts/test_backend_runtime.sh | 59 +++++++++++++++ .github/workflows/agent-cli-provisioning.yml | 2 +- .github/workflows/android-release.yml | 4 +- .github/workflows/ci.yml | 16 ++-- .../copilot_close_inactive_issues.yml | 2 +- .github/workflows/copilot_commit.yml | 2 +- .../copilot_deployment_orchestration.yml | 2 +- .github/workflows/copilot_issue.yml | 2 +- .github/workflows/copilot_pull_request.yml | 2 +- .../copilot_pull_request_review_state.yml | 2 +- .github/workflows/docker.yml | 30 ++++++-- .github/workflows/docker_client_contract.yml | 2 +- .github/workflows/hotfix_workflow.yml | 6 +- .github/workflows/release_workflow.yml | 6 +- .github/workflows/security.yml | 8 +- CHANGELOG.md | 7 ++ backend/api/build.gradle.kts | 2 + .../com/vaultstadio/api/config/Database.kt | 2 +- .../vaultstadio/api/plugins/CronScheduler.kt | 3 +- .../api/plugins/CronSchedulerTest.kt | 7 +- backend/build.gradle.kts | 11 ++- backend/gradle/libs.versions.toml | 28 +++---- .../ExposedCollaborationMappers.kt | 2 +- .../ExposedCollaborationRepository.kt | 24 +++--- .../persistence/ExposedFederationMappers.kt | 2 +- .../ExposedFederationRepository.kt | 26 ++++--- .../ExposedFileVersionRepository.kt | 30 ++++---- .../persistence/ExposedMetadataRepository.kt | 18 ++--- .../persistence/ExposedShareRepository.kt | 24 +++--- .../ExposedStorageItemRepository.kt | 22 +++--- .../persistence/ExposedSyncMappers.kt | 2 +- .../persistence/ExposedSyncRepository.kt | 28 +++---- .../persistence/ExposedTransactionManager.kt | 2 +- .../persistence/ExposedUserRepository.kt | 16 ++-- .../persistence/entities/Tables.kt | 4 +- .../ExposedStorageItemRepositoryTest.kt | 8 +- .../persistence/ExposedUserRepositoryTest.kt | 8 +- docker/Dockerfile.backend | 4 +- docker/Dockerfile.frontend | 2 +- docs/development/DEPENDENCY_UPDATE_62.md | 75 +++++++++++++++++++ docs/development/EXPOSED_UPGRADE.md | 18 +++++ frontend/gradle/libs.versions.toml | 22 +++--- 42 files changed, 369 insertions(+), 173 deletions(-) create mode 100644 .github/scripts/test_backend_runtime.sh create mode 100644 docs/development/DEPENDENCY_UPDATE_62.md create mode 100644 docs/development/EXPOSED_UPGRADE.md diff --git a/.github/scripts/test_backend_runtime.sh b/.github/scripts/test_backend_runtime.sh new file mode 100644 index 00000000..92c8af01 --- /dev/null +++ b/.github/scripts/test_backend_runtime.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +# Verify the loaded PR image on its declared JRE, including application startup. +set -euo pipefail +image="${1:?Expected the loaded candidate image}" +[[ "$image" =~ ^[a-zA-Z0-9][a-zA-Z0-9_.:/@-]*$ ]] || exit 2 +root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)" +expected="$(sed -nE 's/^FROM eclipse-temurin:([0-9]+)-jre([@[:space:]].*)?$/\1/p' "$root/docker/Dockerfile.backend")" +[[ "$expected" =~ ^[0-9]+$ ]] || { echo 'Runtime JRE declaration is ambiguous.' >&2; exit 1; } +state="$(mktemp -d "${RUNNER_TEMP:-${TMPDIR:-/tmp}}/vault-runtime.XXXXXX")" +chmod 700 "$state" +network_id='' +database_id='' +application_id='' +cleanup() { + [[ -z "$application_id" ]] || docker rm -f "$application_id" >/dev/null 2>&1 || true + [[ -z "$database_id" ]] || docker rm -f "$database_id" >/dev/null 2>&1 || true + [[ -z "$network_id" ]] || docker network rm "$network_id" >/dev/null 2>&1 || true + rm -rf "$state" +} +trap cleanup EXIT +trap 'exit 130' INT +trap 'exit 143' TERM + +docker run --rm --pull=never --network none "$image" \ + java -XshowSettings:properties -version > "$state/java-version" 2>&1 +actual="$(awk '$1 == "java.specification.version" && $2 == "=" { print $3 }' "$state/java-version")" +[[ "$actual" == "$expected" ]] || { echo 'Loaded candidate JRE differs from its Dockerfile.' >&2; exit 1; } +echo "Candidate JRE $actual verified." + +scope="vault-smoke-${state##*/}" +network_id="$(docker network create --label vypdev.verification=runtime "$scope")" +database_id="$(docker run -d --network "$network_id" --network-alias database \ + --memory 512m --cpus 1 -e POSTGRES_DB=runtime_test \ + -e POSTGRES_USER=runtime_test -e POSTGRES_PASSWORD=runtime_test postgres:16-alpine)" +ready=false +for _ in $(seq 1 30); do + if docker exec "$database_id" pg_isready -U runtime_test -d runtime_test >/dev/null 2>&1; then ready=true; break; fi + sleep 2 +done +[[ "$ready" == true ]] || { echo 'Private smoke database did not become ready.' >&2; docker logs --tail 100 "$database_id" >&2 || true; exit 1; } + +application_id="$(docker run -d --pull=never --network "$network_id" \ + --memory 768m --cpus 2 \ + -e DATABASE_URL=jdbc:postgresql://database:5432/runtime_test \ + -e DATABASE_USER=runtime_test -e DATABASE_PASSWORD=runtime_test \ + -e 'JAVA_OPTS=-Xms64m -Xmx384m' \ + -e JWT_SECRET=runtime-smoke-only-not-a-production-secret "$image")" +deadline=$(( $(date +%s) + 300 )) +while (( $(date +%s) < deadline )); do + if docker exec "$application_id" curl --fail --silent --show-error --connect-timeout 1 --max-time 2 http://127.0.0.1:8080/health > "$state/health" 2>/dev/null; then + echo 'Candidate application started and passed its health endpoint on the declared JRE.' + exit 0 + fi + if [[ "$(docker inspect --format '{{.State.Running}}' "$application_id" 2>/dev/null || true)" != true ]]; then break; fi + sleep 2 +done +echo 'Candidate runtime application failed its startup/health smoke.' >&2 +docker logs --tail 100 "$application_id" >&2 || true +exit 1 diff --git a/.github/workflows/agent-cli-provisioning.yml b/.github/workflows/agent-cli-provisioning.yml index 61ed08e3..8641099b 100644 --- a/.github/workflows/agent-cli-provisioning.yml +++ b/.github/workflows/agent-cli-provisioning.yml @@ -18,7 +18,7 @@ jobs: contents: read steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v7 with: persist-credentials: false diff --git a/.github/workflows/android-release.yml b/.github/workflows/android-release.yml index 3a8f5ab4..fe94739f 100644 --- a/.github/workflows/android-release.yml +++ b/.github/workflows/android-release.yml @@ -33,7 +33,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Set up JDK uses: actions/setup-java@v4 @@ -105,7 +105,7 @@ jobs: - name: Upload to GitHub Release if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }} - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@v3 with: files: | frontend/androidApp/build/outputs/apk/**/release/*.apk diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 634963fc..de800dee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Set up JDK uses: actions/setup-java@v4 @@ -147,7 +147,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Set up JDK uses: actions/setup-java@v4 @@ -185,7 +185,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Download backend coverage reports uses: actions/download-artifact@v7 @@ -220,7 +220,7 @@ jobs: echo "Found coverage files: $FILES" - name: Upload to Codecov - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@v7 with: disable_search: true files: ${{ steps.coverage-files.outputs.list }} @@ -238,7 +238,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Set up JDK uses: actions/setup-java@v4 @@ -270,7 +270,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Set up JDK uses: actions/setup-java@v4 @@ -312,7 +312,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Set up JDK uses: actions/setup-java@v4 @@ -367,7 +367,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@master diff --git a/.github/workflows/copilot_close_inactive_issues.yml b/.github/workflows/copilot_close_inactive_issues.yml index a955aef1..452cb130 100644 --- a/.github/workflows/copilot_close_inactive_issues.yml +++ b/.github/workflows/copilot_close_inactive_issues.yml @@ -28,7 +28,7 @@ jobs: contents: read steps: - name: Checkout Repository - uses: actions/checkout@v5 + uses: actions/checkout@v7 with: persist-credentials: false diff --git a/.github/workflows/copilot_commit.yml b/.github/workflows/copilot_commit.yml index 0da14726..0ae08bf6 100644 --- a/.github/workflows/copilot_commit.yml +++ b/.github/workflows/copilot_commit.yml @@ -27,7 +27,7 @@ jobs: contents: read steps: - name: Checkout Repository - uses: actions/checkout@v5 + uses: actions/checkout@v7 with: persist-credentials: false fetch-depth: 0 diff --git a/.github/workflows/copilot_deployment_orchestration.yml b/.github/workflows/copilot_deployment_orchestration.yml index 00c47279..2694998e 100644 --- a/.github/workflows/copilot_deployment_orchestration.yml +++ b/.github/workflows/copilot_deployment_orchestration.yml @@ -85,7 +85,7 @@ jobs: actions: write steps: - name: Checkout trusted base branch - uses: actions/checkout@v5 + uses: actions/checkout@v7 with: persist-credentials: false ref: ${{ github.event.pull_request.base.ref }} diff --git a/.github/workflows/copilot_issue.yml b/.github/workflows/copilot_issue.yml index e50c8d50..fa020c59 100644 --- a/.github/workflows/copilot_issue.yml +++ b/.github/workflows/copilot_issue.yml @@ -19,7 +19,7 @@ jobs: contents: read steps: - name: Checkout Repository - uses: actions/checkout@v5 + uses: actions/checkout@v7 with: persist-credentials: false diff --git a/.github/workflows/copilot_pull_request.yml b/.github/workflows/copilot_pull_request.yml index 0c6be3ce..27be88b6 100644 --- a/.github/workflows/copilot_pull_request.yml +++ b/.github/workflows/copilot_pull_request.yml @@ -24,7 +24,7 @@ jobs: contents: read steps: - name: Checkout Repository - uses: actions/checkout@v5 + uses: actions/checkout@v7 with: persist-credentials: false fetch-depth: 0 diff --git a/.github/workflows/copilot_pull_request_review_state.yml b/.github/workflows/copilot_pull_request_review_state.yml index 5948620e..b8587ef4 100644 --- a/.github/workflows/copilot_pull_request_review_state.yml +++ b/.github/workflows/copilot_pull_request_review_state.yml @@ -24,7 +24,7 @@ jobs: contents: read steps: - name: Checkout Repository - uses: actions/checkout@v5 + uses: actions/checkout@v7 with: persist-credentials: false fetch-depth: 0 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 6d66e3a1..73b466d8 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -14,6 +14,7 @@ on: paths: - .github/workflows/docker.yml - .github/actions/prepare-docker/** + - .github/scripts/test_backend_runtime.sh - backend/** - frontend/** - docker/** @@ -39,7 +40,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Prepare private Docker client uses: ./.github/actions/prepare-docker @@ -92,11 +93,30 @@ jobs: file: ./docker/Dockerfile.backend platforms: linux/amd64 push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} + load: ${{ github.event_name == 'pull_request' }} + tags: | + ${{ steps.meta.outputs.tags }} + ${{ github.event_name == 'pull_request' && format('vaultstadio-runtime-test:{0}-{1}', github.run_id, github.run_attempt) || '' }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha,scope=vaultstadio-backend cache-to: type=gha,mode=max,scope=vaultstadio-backend + - name: Verify the candidate JRE and application startup + if: github.event_name == 'pull_request' + timeout-minutes: 8 + env: + CANDIDATE_IMAGE: vaultstadio-runtime-test:${{ github.run_id }}-${{ github.run_attempt }} + run: bash .github/scripts/test_backend_runtime.sh "$CANDIDATE_IMAGE" + + - name: Retire this job's local smoke tag + if: always() && github.event_name == 'pull_request' + env: + CANDIDATE_IMAGE: vaultstadio-runtime-test:${{ github.run_id }}-${{ github.run_attempt }} + run: | + if docker image inspect "$CANDIDATE_IMAGE" >/dev/null 2>&1; then + docker image rm "$CANDIDATE_IMAGE" + fi + build-frontend: name: Build Frontend Image runs-on: @@ -110,7 +130,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Prepare private Docker client uses: ./.github/actions/prepare-docker @@ -180,7 +200,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Set up JDK uses: actions/setup-java@v4 @@ -198,7 +218,7 @@ jobs: run: ./gradlew :api:distZip -x test - name: Create Release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@v3 with: files: | backend/api/build/distributions/*.zip diff --git a/.github/workflows/docker_client_contract.yml b/.github/workflows/docker_client_contract.yml index c96c5801..66864950 100644 --- a/.github/workflows/docker_client_contract.yml +++ b/.github/workflows/docker_client_contract.yml @@ -25,7 +25,7 @@ jobs: labels: [self-hosted, macOS, ARM64] timeout-minutes: 5 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 with: persist-credentials: false - name: Test private credentials with native Docker and a fixture registry diff --git a/.github/workflows/hotfix_workflow.yml b/.github/workflows/hotfix_workflow.yml index 844c340d..4e621929 100644 --- a/.github/workflows/hotfix_workflow.yml +++ b/.github/workflows/hotfix_workflow.yml @@ -91,7 +91,7 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v7 with: persist-credentials: true # Add project-specific version, build, validation, smoke-test and generated-file steps here. @@ -121,7 +121,7 @@ jobs: pull-requests: write actions: write steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v7 with: persist-credentials: false - name: Create or resume promotion PR @@ -169,7 +169,7 @@ jobs: issues: write pull-requests: write steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v7 with: persist-credentials: false ref: ${{ vars.MAIN_BRANCH || 'master' }} diff --git a/.github/workflows/release_workflow.yml b/.github/workflows/release_workflow.yml index fcdc2d65..807f45fa 100644 --- a/.github/workflows/release_workflow.yml +++ b/.github/workflows/release_workflow.yml @@ -91,7 +91,7 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v7 with: persist-credentials: true # Add project-specific version, build, validation, smoke-test and generated-file steps here. @@ -121,7 +121,7 @@ jobs: pull-requests: write actions: write steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v7 with: persist-credentials: false - name: Create or resume promotion PR @@ -169,7 +169,7 @@ jobs: issues: write pull-requests: write steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v7 with: persist-credentials: false ref: ${{ vars.MAIN_BRANCH || 'master' }} diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 412c3a42..765c3110 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -24,7 +24,7 @@ jobs: labels: [self-hosted, macOS, X64] steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Set up JDK uses: actions/setup-java@v4 @@ -49,7 +49,7 @@ jobs: security-events: write steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Isolate CodeQL database and Gradle state for this analysis id: codeql-state @@ -108,7 +108,7 @@ jobs: SCAN_IMAGE: vaultstadio-backend:scan-${{ github.run_id }}-${{ github.run_attempt }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: persist-credentials: false @@ -159,7 +159,7 @@ jobs: labels: [self-hosted, macOS, X64] steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: fetch-depth: 0 diff --git a/CHANGELOG.md b/CHANGELOG.md index a728740f..e08fc568 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Changed +- Consolidate dependency maintenance from issue #62 across the standalone backend and frontend builds: Kotlin and kotlinx, Ktor, Exposed, Flyway, Koin, MinIO, AndroidX and testing dependencies. +- Update Docker builders to Gradle 9.8 with JDK 17 and backend runtime to Temurin JRE 25; verify the candidate runtime against a private PostgreSQL smoke test. +- Update checkout, Codecov and release Actions while preserving runner routing and verification gates. + ## [2.2.0] - 2026-01-30 ### Added diff --git a/backend/api/build.gradle.kts b/backend/api/build.gradle.kts index b8a6346f..ecc08657 100644 --- a/backend/api/build.gradle.kts +++ b/backend/api/build.gradle.kts @@ -62,6 +62,8 @@ dependencies { // Ktor Server implementation(libs.bundles.ktor.server) implementation(libs.ktor.server.openapi) + // Ktor 3.4.0 exposes this Swagger API type without exporting its dependency. + implementation(libs.ktor.server.routing.openapi) implementation(libs.ktor.server.swagger) // Kotlinx diff --git a/backend/api/src/main/kotlin/com/vaultstadio/api/config/Database.kt b/backend/api/src/main/kotlin/com/vaultstadio/api/config/Database.kt index a3bae048..57f35c7e 100644 --- a/backend/api/src/main/kotlin/com/vaultstadio/api/config/Database.kt +++ b/backend/api/src/main/kotlin/com/vaultstadio/api/config/Database.kt @@ -10,7 +10,7 @@ import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource import io.github.oshai.kotlinlogging.KotlinLogging import org.flywaydb.core.Flyway -import org.jetbrains.exposed.sql.Database +import org.jetbrains.exposed.v1.jdbc.Database import javax.sql.DataSource private val logger = KotlinLogging.logger {} diff --git a/backend/api/src/main/kotlin/com/vaultstadio/api/plugins/CronScheduler.kt b/backend/api/src/main/kotlin/com/vaultstadio/api/plugins/CronScheduler.kt index f6973416..bcb297fd 100644 --- a/backend/api/src/main/kotlin/com/vaultstadio/api/plugins/CronScheduler.kt +++ b/backend/api/src/main/kotlin/com/vaultstadio/api/plugins/CronScheduler.kt @@ -20,6 +20,7 @@ import kotlinx.datetime.Instant import kotlinx.datetime.LocalDateTime import kotlinx.datetime.TimeZone import kotlinx.datetime.plus +import kotlinx.datetime.toDeprecatedInstant import kotlinx.datetime.toInstant import kotlinx.datetime.toLocalDateTime @@ -133,7 +134,7 @@ data class CronExpression( candidateDateTime.minute, 0, 0, - ).toInstant(timeZone) + ).toInstant(timeZone).toDeprecatedInstant() val maxIterations = 60 * 24 * 365 * 2 var iterations = 0 diff --git a/backend/api/src/test/kotlin/com/vaultstadio/api/plugins/CronSchedulerTest.kt b/backend/api/src/test/kotlin/com/vaultstadio/api/plugins/CronSchedulerTest.kt index 58e948c0..33f7adf2 100644 --- a/backend/api/src/test/kotlin/com/vaultstadio/api/plugins/CronSchedulerTest.kt +++ b/backend/api/src/test/kotlin/com/vaultstadio/api/plugins/CronSchedulerTest.kt @@ -8,6 +8,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import kotlinx.datetime.LocalDateTime import kotlinx.datetime.TimeZone +import kotlinx.datetime.toDeprecatedInstant import kotlinx.datetime.toInstant import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested @@ -170,7 +171,7 @@ class CronSchedulerTest { fun `should calculate next execution for simple expression`() { val cron = CronExpression.parse("0 * * * *")!! // Every hour at minute 0 val now = LocalDateTime(2024, 6, 15, 14, 30, 0, 0) - .toInstant(TimeZone.UTC) + .toInstant(TimeZone.UTC).toDeprecatedInstant() val next = cron.nextExecution(now, TimeZone.UTC) @@ -182,7 +183,7 @@ class CronSchedulerTest { fun `should find next execution for every minute`() { val cron = CronExpression.parse("* * * * *")!! val now = LocalDateTime(2024, 6, 15, 14, 30, 30, 0) - .toInstant(TimeZone.UTC) + .toInstant(TimeZone.UTC).toDeprecatedInstant() val next = cron.nextExecution(now, TimeZone.UTC) @@ -194,7 +195,7 @@ class CronSchedulerTest { fun `should find next execution for specific time`() { val cron = CronExpression.parse("30 15 * * *")!! // Every day at 15:30 val now = LocalDateTime(2024, 6, 15, 14, 0, 0, 0) - .toInstant(TimeZone.UTC) + .toInstant(TimeZone.UTC).toDeprecatedInstant() val next = cron.nextExecution(now, TimeZone.UTC) diff --git a/backend/build.gradle.kts b/backend/build.gradle.kts index d78fbf78..e179a75c 100644 --- a/backend/build.gradle.kts +++ b/backend/build.gradle.kts @@ -6,12 +6,14 @@ */ plugins { - kotlin("jvm") version "2.0.21" apply false - kotlin("plugin.serialization") version "2.0.21" apply false + kotlin("jvm") version "2.3.10" apply false + kotlin("plugin.serialization") version "2.3.10" apply false alias(libs.plugins.detekt) alias(libs.plugins.ktlint) } +val junitPlatformLauncher = libs.junit.platform.launcher + allprojects { group = "com.vaultstadio" version = "1.0.0-SNAPSHOT" @@ -31,6 +33,10 @@ subprojects { apply(plugin = "io.gitlab.arturbosch.detekt") apply(plugin = "org.jlleitschuh.gradle.ktlint") + pluginManager.withPlugin("org.jetbrains.kotlin.jvm") { + dependencies.add("testRuntimeOnly", junitPlatformLauncher) + } + configure { filter { exclude { lintError -> @@ -60,7 +66,6 @@ subprojects { tasks.withType().configureEach { compilerOptions { jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17) - freeCompilerArgs.add("-Xcontext-receivers") } } diff --git a/backend/gradle/libs.versions.toml b/backend/gradle/libs.versions.toml index 64159af9..0f4c75bf 100644 --- a/backend/gradle/libs.versions.toml +++ b/backend/gradle/libs.versions.toml @@ -1,29 +1,29 @@ [versions] # Kotlin -kotlin = "2.0.21" -kotlinx-coroutines = "1.9.0" -kotlinx-serialization = "1.7.3" -kotlinx-datetime = "0.6.1" +kotlin = "2.3.10" +kotlinx-coroutines = "1.10.2" +kotlinx-serialization = "1.10.0" +kotlinx-datetime = "0.7.1-0.6.x-compat" # Ktor -ktor = "3.0.2" +ktor = "3.4.0" # Koin - Dependency Injection -koin = "4.0.0" +koin = "4.1.1" koin-annotations = "2.0.1-Beta1" # KSP (Kotlin Symbol Processing) ksp = "2.0.21-1.0.27" # Database -exposed = "0.56.0" +exposed = "1.0.0" hikari = "6.0.0" postgresql = "42.7.4" h2 = "2.3.232" -flyway = "10.21.0" +flyway = "12.0.1" # Storage -minio = "8.5.13" +minio = "8.6.0" aws-sdk = "1.3.68" # Redis @@ -34,8 +34,8 @@ logback = "1.5.12" kotlin-logging = "7.0.0" # Testing -junit = "5.11.3" -mockk = "1.13.13" +junit = "6.0.3" +mockk = "1.14.9" testcontainers = "1.21.4" # Code Quality @@ -52,9 +52,9 @@ android-compileSdk = "35" android-minSdk = "24" android-targetSdk = "35" androidx-core = "1.13.1" -androidx-lifecycle = "2.8.7" +androidx-lifecycle = "2.10.0" androidx-activity = "1.9.3" -androidx-test-ext-junit = "1.2.1" +androidx-test-ext-junit = "1.3.0" androidx-test-espresso = "3.6.1" # Image Loading @@ -92,6 +92,7 @@ ktor-server-websockets = { module = "io.ktor:ktor-server-websockets-jvm", versio ktor-server-config-yaml = { module = "io.ktor:ktor-server-config-yaml-jvm", version.ref = "ktor" } ktor-server-tests = { module = "io.ktor:ktor-server-test-host-jvm", version.ref = "ktor" } ktor-server-openapi = { module = "io.ktor:ktor-server-openapi-jvm", version.ref = "ktor" } +ktor-server-routing-openapi = { module = "io.ktor:ktor-server-routing-openapi-jvm", version.ref = "ktor" } ktor-server-swagger = { module = "io.ktor:ktor-server-swagger-jvm", version.ref = "ktor" } ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json-jvm", version.ref = "ktor" } ktor-serialization-kotlinx-json-multiplatform = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" } @@ -153,6 +154,7 @@ kotlin-logging = { module = "io.github.oshai:kotlin-logging-jvm", version.ref = # Testing junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" } +junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher", version.ref = "junit" } mockk = { module = "io.mockk:mockk", version.ref = "mockk" } testcontainers-core = { module = "org.testcontainers:testcontainers", version.ref = "testcontainers" } testcontainers-junit = { module = "org.testcontainers:junit-jupiter", version.ref = "testcontainers" } diff --git a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedCollaborationMappers.kt b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedCollaborationMappers.kt index 9f978b00..656f5975 100644 --- a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedCollaborationMappers.kt +++ b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedCollaborationMappers.kt @@ -23,7 +23,7 @@ import com.vaultstadio.infrastructure.persistence.entities.CommentRepliesTable import com.vaultstadio.infrastructure.persistence.entities.DocumentCommentsTable import com.vaultstadio.infrastructure.persistence.entities.DocumentStatesTable import com.vaultstadio.infrastructure.persistence.entities.UserPresenceTable -import org.jetbrains.exposed.sql.ResultRow +import org.jetbrains.exposed.v1.core.ResultRow internal fun ResultRow.toCollaborationSession(participants: List): CollaborationSession = CollaborationSession( diff --git a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedCollaborationRepository.kt b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedCollaborationRepository.kt index dc9df6bb..05c967af 100644 --- a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedCollaborationRepository.kt +++ b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedCollaborationRepository.kt @@ -30,17 +30,19 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.datetime.Clock import kotlinx.datetime.Instant -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.SqlExpressionBuilder.isNull -import org.jetbrains.exposed.sql.SqlExpressionBuilder.less -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.andWhere -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.insert -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.greater +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.core.isNull +import org.jetbrains.exposed.v1.core.less +import org.jetbrains.exposed.v1.jdbc.andWhere +import org.jetbrains.exposed.v1.jdbc.deleteWhere +import org.jetbrains.exposed.v1.jdbc.insert +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.experimental.newSuspendedTransaction +import org.jetbrains.exposed.v1.jdbc.update /** * Exposed implementation of CollaborationRepository. diff --git a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedFederationMappers.kt b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedFederationMappers.kt index e9b05a91..5fa58686 100644 --- a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedFederationMappers.kt +++ b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedFederationMappers.kt @@ -19,7 +19,7 @@ import com.vaultstadio.infrastructure.persistence.entities.FederatedIdentitiesTa import com.vaultstadio.infrastructure.persistence.entities.FederatedInstancesTable import com.vaultstadio.infrastructure.persistence.entities.FederatedSharesTable import kotlinx.serialization.json.Json -import org.jetbrains.exposed.sql.ResultRow +import org.jetbrains.exposed.v1.core.ResultRow private val json = Json { ignoreUnknownKeys = true } diff --git a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedFederationRepository.kt b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedFederationRepository.kt index d42f29ff..914e3b32 100644 --- a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedFederationRepository.kt +++ b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedFederationRepository.kt @@ -27,18 +27,20 @@ import kotlinx.coroutines.flow.flow import kotlinx.datetime.Instant import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater -import org.jetbrains.exposed.sql.SqlExpressionBuilder.less -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.andWhere -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.insert -import org.jetbrains.exposed.sql.or -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.greater +import org.jetbrains.exposed.v1.core.isNull +import org.jetbrains.exposed.v1.core.less +import org.jetbrains.exposed.v1.core.neq +import org.jetbrains.exposed.v1.core.or +import org.jetbrains.exposed.v1.jdbc.andWhere +import org.jetbrains.exposed.v1.jdbc.deleteWhere +import org.jetbrains.exposed.v1.jdbc.insert +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.experimental.newSuspendedTransaction +import org.jetbrains.exposed.v1.jdbc.update /** * Exposed implementation of FederationRepository. diff --git a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedFileVersionRepository.kt b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedFileVersionRepository.kt index 47e1302b..e4cdfa08 100644 --- a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedFileVersionRepository.kt +++ b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedFileVersionRepository.kt @@ -22,20 +22,20 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.datetime.Clock -import org.jetbrains.exposed.sql.ResultRow -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.SqlExpressionBuilder.inList -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.count -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.insert -import org.jetbrains.exposed.sql.max -import org.jetbrains.exposed.sql.select -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.sum -import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.count +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.core.max +import org.jetbrains.exposed.v1.core.sum +import org.jetbrains.exposed.v1.jdbc.deleteWhere +import org.jetbrains.exposed.v1.jdbc.insert +import org.jetbrains.exposed.v1.jdbc.select +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.experimental.newSuspendedTransaction +import org.jetbrains.exposed.v1.jdbc.update import kotlin.time.Duration.Companion.days /** @@ -127,7 +127,7 @@ class ExposedFileVersionRepository : FileVersionRepository { FileVersionsTable.selectAll() .where { FileVersionsTable.itemId eq itemId } .orderBy(FileVersionsTable.versionNumber, SortOrder.DESC) - .limit(limit, offset.toLong()) + .limit(limit).offset(offset.toLong()) .map { it.toFileVersion() } }.right() } catch (e: Exception) { diff --git a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedMetadataRepository.kt b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedMetadataRepository.kt index 4bdea747..bfaed730 100644 --- a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedMetadataRepository.kt +++ b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedMetadataRepository.kt @@ -16,15 +16,15 @@ import com.vaultstadio.infrastructure.persistence.entities.StorageItemMetadataTa import io.github.oshai.kotlinlogging.KotlinLogging import kotlinx.coroutines.Dispatchers import kotlinx.datetime.Clock -import org.jetbrains.exposed.sql.ResultRow -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.SqlExpressionBuilder.like -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.insert -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.like +import org.jetbrains.exposed.v1.jdbc.deleteWhere +import org.jetbrains.exposed.v1.jdbc.insert +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.experimental.newSuspendedTransaction +import org.jetbrains.exposed.v1.jdbc.update import java.util.UUID private val logger = KotlinLogging.logger {} diff --git a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedShareRepository.kt b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedShareRepository.kt index 4a775afe..887b4fba 100644 --- a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedShareRepository.kt +++ b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedShareRepository.kt @@ -22,16 +22,16 @@ import com.vaultstadio.infrastructure.persistence.entities.ShareLinksTable import io.github.oshai.kotlinlogging.KotlinLogging import kotlinx.coroutines.Dispatchers import kotlinx.datetime.Instant -import org.jetbrains.exposed.sql.ResultRow -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.SqlExpressionBuilder.lessEq -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.insert -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.lessEq +import org.jetbrains.exposed.v1.jdbc.deleteWhere +import org.jetbrains.exposed.v1.jdbc.insert +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.experimental.newSuspendedTransaction +import org.jetbrains.exposed.v1.jdbc.update private val logger = KotlinLogging.logger {} @@ -257,7 +257,7 @@ class ExposedActivityRepository : ActivityRepository { dbQuery { ActivitiesTable.selectAll() .where { ActivitiesTable.userId eq userId } - .orderBy(ActivitiesTable.createdAt, org.jetbrains.exposed.sql.SortOrder.DESC) + .orderBy(ActivitiesTable.createdAt, org.jetbrains.exposed.v1.core.SortOrder.DESC) .limit(limit) .map { it.toActivity() } }.right() @@ -269,7 +269,7 @@ class ExposedActivityRepository : ActivityRepository { dbQuery { ActivitiesTable.selectAll() .where { ActivitiesTable.itemId eq itemId } - .orderBy(ActivitiesTable.createdAt, org.jetbrains.exposed.sql.SortOrder.DESC) + .orderBy(ActivitiesTable.createdAt, org.jetbrains.exposed.v1.core.SortOrder.DESC) .limit(limit) .map { it.toActivity() } }.right() diff --git a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedStorageItemRepository.kt b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedStorageItemRepository.kt index 8f262ac2..80f3ed92 100644 --- a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedStorageItemRepository.kt +++ b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedStorageItemRepository.kt @@ -23,17 +23,17 @@ import io.github.oshai.kotlinlogging.KotlinLogging import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow -import org.jetbrains.exposed.sql.Op -import org.jetbrains.exposed.sql.ResultRow -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.SqlExpressionBuilder.isNull -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.insert -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction -import org.jetbrains.exposed.sql.update -import org.jetbrains.exposed.sql.SortOrder as ExposedSortOrder +import org.jetbrains.exposed.v1.core.Op +import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.isNull +import org.jetbrains.exposed.v1.jdbc.deleteWhere +import org.jetbrains.exposed.v1.jdbc.insert +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.experimental.newSuspendedTransaction +import org.jetbrains.exposed.v1.jdbc.update +import org.jetbrains.exposed.v1.core.SortOrder as ExposedSortOrder private val logger = KotlinLogging.logger {} diff --git a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedSyncMappers.kt b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedSyncMappers.kt index f0974b1c..bf3d09e0 100644 --- a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedSyncMappers.kt +++ b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedSyncMappers.kt @@ -17,7 +17,7 @@ import com.vaultstadio.infrastructure.persistence.entities.SyncConflictsTable import com.vaultstadio.infrastructure.persistence.entities.SyncDevicesTable import kotlinx.datetime.Clock import kotlinx.serialization.json.Json -import org.jetbrains.exposed.sql.ResultRow +import org.jetbrains.exposed.v1.core.ResultRow private val json = Json { ignoreUnknownKeys = true } diff --git a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedSyncRepository.kt b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedSyncRepository.kt index d5c4d311..dd24635d 100644 --- a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedSyncRepository.kt +++ b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedSyncRepository.kt @@ -25,19 +25,21 @@ import kotlinx.datetime.Clock import kotlinx.datetime.Instant import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater -import org.jetbrains.exposed.sql.SqlExpressionBuilder.isNotNull -import org.jetbrains.exposed.sql.SqlExpressionBuilder.less -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.andWhere -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.insert -import org.jetbrains.exposed.sql.max -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.greater +import org.jetbrains.exposed.v1.core.isNotNull +import org.jetbrains.exposed.v1.core.isNull +import org.jetbrains.exposed.v1.core.less +import org.jetbrains.exposed.v1.core.max +import org.jetbrains.exposed.v1.jdbc.andWhere +import org.jetbrains.exposed.v1.jdbc.deleteWhere +import org.jetbrains.exposed.v1.jdbc.insert +import org.jetbrains.exposed.v1.jdbc.select +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.experimental.newSuspendedTransaction +import org.jetbrains.exposed.v1.jdbc.update /** * Exposed implementation of SyncRepository. diff --git a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedTransactionManager.kt b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedTransactionManager.kt index 0e409026..9e8a42ad 100644 --- a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedTransactionManager.kt +++ b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedTransactionManager.kt @@ -8,7 +8,7 @@ package com.vaultstadio.infrastructure.persistence import com.vaultstadio.core.domain.service.TransactionManager import kotlinx.coroutines.Dispatchers -import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction +import org.jetbrains.exposed.v1.jdbc.transactions.experimental.newSuspendedTransaction /** * Exposed implementation of TransactionManager. diff --git a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedUserRepository.kt b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedUserRepository.kt index f8ea52ea..b923c17d 100644 --- a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedUserRepository.kt +++ b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/ExposedUserRepository.kt @@ -25,14 +25,14 @@ import com.vaultstadio.infrastructure.persistence.entities.UsersTable import io.github.oshai.kotlinlogging.KotlinLogging import kotlinx.coroutines.Dispatchers import kotlinx.datetime.Clock -import org.jetbrains.exposed.sql.ResultRow -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.SqlExpressionBuilder.lessEq -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.insert -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.lessEq +import org.jetbrains.exposed.v1.jdbc.deleteWhere +import org.jetbrains.exposed.v1.jdbc.insert +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.experimental.newSuspendedTransaction +import org.jetbrains.exposed.v1.jdbc.update private val logger = KotlinLogging.logger {} diff --git a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/entities/Tables.kt b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/entities/Tables.kt index fcb254e9..dd9eb498 100644 --- a/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/entities/Tables.kt +++ b/backend/infrastructure/src/main/kotlin/com/vaultstadio/infrastructure/persistence/entities/Tables.kt @@ -4,8 +4,8 @@ package com.vaultstadio.infrastructure.persistence.entities -import org.jetbrains.exposed.sql.Table -import org.jetbrains.exposed.sql.kotlin.datetime.timestamp +import org.jetbrains.exposed.v1.core.Table +import org.jetbrains.exposed.v1.datetime.xTimestamp as timestamp /** * Users table. diff --git a/backend/infrastructure/src/test/kotlin/com/vaultstadio/infrastructure/persistence/ExposedStorageItemRepositoryTest.kt b/backend/infrastructure/src/test/kotlin/com/vaultstadio/infrastructure/persistence/ExposedStorageItemRepositoryTest.kt index 1adf0c55..d6a26c51 100644 --- a/backend/infrastructure/src/test/kotlin/com/vaultstadio/infrastructure/persistence/ExposedStorageItemRepositoryTest.kt +++ b/backend/infrastructure/src/test/kotlin/com/vaultstadio/infrastructure/persistence/ExposedStorageItemRepositoryTest.kt @@ -21,10 +21,10 @@ import com.vaultstadio.infrastructure.persistence.entities.StorageItemsTable import com.vaultstadio.infrastructure.persistence.entities.UsersTable import kotlinx.coroutines.test.runTest import kotlinx.datetime.Clock -import org.jetbrains.exposed.sql.Database -import org.jetbrains.exposed.sql.SchemaUtils -import org.jetbrains.exposed.sql.deleteAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.jdbc.Database +import org.jetbrains.exposed.v1.jdbc.SchemaUtils +import org.jetbrains.exposed.v1.jdbc.deleteAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.BeforeEach diff --git a/backend/infrastructure/src/test/kotlin/com/vaultstadio/infrastructure/persistence/ExposedUserRepositoryTest.kt b/backend/infrastructure/src/test/kotlin/com/vaultstadio/infrastructure/persistence/ExposedUserRepositoryTest.kt index 77635c7f..1783ba9a 100644 --- a/backend/infrastructure/src/test/kotlin/com/vaultstadio/infrastructure/persistence/ExposedUserRepositoryTest.kt +++ b/backend/infrastructure/src/test/kotlin/com/vaultstadio/infrastructure/persistence/ExposedUserRepositoryTest.kt @@ -16,10 +16,10 @@ import com.vaultstadio.infrastructure.persistence.entities.UserSessionsTable import com.vaultstadio.infrastructure.persistence.entities.UsersTable import kotlinx.coroutines.test.runTest import kotlinx.datetime.Clock -import org.jetbrains.exposed.sql.Database -import org.jetbrains.exposed.sql.SchemaUtils -import org.jetbrains.exposed.sql.deleteAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.jdbc.Database +import org.jetbrains.exposed.v1.jdbc.SchemaUtils +import org.jetbrains.exposed.v1.jdbc.deleteAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.BeforeEach diff --git a/docker/Dockerfile.backend b/docker/Dockerfile.backend index 0767d80b..de671958 100644 --- a/docker/Dockerfile.backend +++ b/docker/Dockerfile.backend @@ -3,7 +3,7 @@ # Backend is a standalone Gradle project; build from backend/ context. # Stage 1: Build -FROM gradle:8.10-jdk17 AS builder +FROM gradle:9.8-jdk17 AS builder WORKDIR /app @@ -15,7 +15,7 @@ WORKDIR /app/backend RUN ./gradlew :api:installDist --no-daemon # Stage 2: Runtime -FROM eclipse-temurin:17-jre +FROM eclipse-temurin:25-jre WORKDIR /app diff --git a/docker/Dockerfile.frontend b/docker/Dockerfile.frontend index 0e61a138..c7ce234c 100644 --- a/docker/Dockerfile.frontend +++ b/docker/Dockerfile.frontend @@ -3,7 +3,7 @@ # Stage 1: Build # Wasm/JS artifacts are portable; compile natively and keep the runtime target separate. -FROM --platform=$BUILDPLATFORM gradle:8.10-jdk17 AS builder +FROM --platform=$BUILDPLATFORM gradle:9.8-jdk17 AS builder # Kotlin's downloaded Node runtime requires libatomic on Linux. USER root diff --git a/docs/development/DEPENDENCY_UPDATE_62.md b/docs/development/DEPENDENCY_UPDATE_62.md new file mode 100644 index 00000000..6441b0b1 --- /dev/null +++ b/docs/development/DEPENDENCY_UPDATE_62.md @@ -0,0 +1,75 @@ +# Consolidated dependency update (#62) + +This PR implements the 15 proposals recorded in [issue #62](https://github.com/vypdev/vaultstadio/issues/62) +on its Action-managed branch. Changes apply to the standalone backend/frontend +projects and active workflows. The issue preserves the complete artifact list and +source commits; this table records how every proposal is reconciled. + +| Source PR | Proposal | Result in this PR | +| --- | --- | --- | +| #18 | Temurin JRE 17 to 25 | Backend runtime uses `25-jre`; PR image builds verify its Java version and application health against an isolated PostgreSQL container. | +| #24 | Kotlin and kotlinx group (11 entries) | Backend compiler/serialization plugin `2.3.10`; both projects use coroutines `1.10.2` and serialization `1.10.0`. Backend datetime uses `0.7.1-0.6.x-compat`. Preserve frontend Kotlin `2.3.20-Beta1` and datetime `0.7.1`. | +| #25 | Ktor group (23 entries) | Both catalogs use `3.4.0`; explicitly include `ktor-server-routing-openapi-jvm` for the Swagger API exposed by Ktor 3.4. | +| #27 | Testing group (6 entries) | JUnit Jupiter `6.0.3`, MockK `1.14.9`, Testcontainers `1.21.4`; preserve the already-updated backend Testcontainers version. Declare the JUnit Platform launcher at test runtime. | +| #28 | Koin group (7 entries) | Backend `4.1.1`; preserve frontend `4.2.0-RC1` and compiler plugin `0.3.0`, which are newer than the proposal. | +| #29 | AndroidX test JUnit extension | Both catalogs use `1.3.0`; the separate JUnit 4 coordinate used by Android local tests is unchanged. | +| #30 | MinIO | Both catalogs use `8.6.0`. | +| #31 | Flyway | Both catalogs use `12.0.1`; include the existing PostgreSQL integration and startup checks. | +| #32 | Exposed group (4 entries) | Both catalogs use `1.0.0`; migrate actual backend imports, predicates, pagination and timestamp adapters. | +| #33 | AndroidX lifecycle (2 entries) | Both catalogs use `2.10.0`; preserve the separate JetBrains multiplatform lifecycle version. | +| #35 | Gradle builder image 9.5 | Superseded by #64; no second image target is retained. | +| #64 | Gradle builder image 9.8 | Both builders use `9.8-jdk17`. Existing project wrappers still select Gradle 8.10 for backend and 9.1.0 for frontend; preserve native frontend build placement and published image platforms. | +| #65 | Checkout Action v7 | Active workflows consistently use `actions/checkout@v7`; preserve credential persistence choices and default fork protections. | +| #66 | Codecov Action v7 | Use `codecov/codecov-action@v7` with existing report discovery, authentication and error policy. | +| #67 | Release Action v3 | Existing Docker and Android release steps use `softprops/action-gh-release@v3`. This dependency update does not invoke a release. | + +Catalog declarations shared between projects are synchronized where applicable, +including entries not currently consumed by the frontend. Newer frontend Kotlin, +Koin, Compose and AGP versions are preserved. KSP and Koin annotation entries that +are not applied by these builds remain untouched; no obsolete root Gradle build +is restored. + +## Compatibility changes + +- Remove the unused backend context-receivers compiler flag, which is unsupported + by the newer Kotlin compiler. No context receiver declarations exist in the backend. +- Keep the backend Instant model through the datetime compatibility artifact and + explicit conversions in cron scheduling. Exposed's `xTimestamp` retains the SQL + mapping; see [Exposed compatibility](EXPOSED_UPGRADE.md). +- Align the JUnit test launcher with Jupiter 6 instead of relying on the older + launcher bundled by Gradle. Preserve every existing test and coverage gate. +- The candidate runtime smoke test uses a private Docker network, no published + host ports and cleanup limited to IDs/tag created by the job. + +## Validation + +Local verification of the combined candidate on JDK 17: + +- Backend: `test` passes 1,756 tests with zero failures, errors or skips, including + 727 API tests and 318 real PostgreSQL/storage infrastructure tests. +- Backend: `ktlintFormat`, `detektMain`, `jacocoTestReport` and `:api:installDist` + pass. Fourteen backend coverage XML reports are generated. Verification used + a 4 GiB Gradle heap, two workers and in-process Kotlin compilation. +- Frontend: `desktopTest`, `:composeApp:jacocoTestReport` and + `:androidApp:assembleDevDebug` pass; 1,127 desktop tests have zero failures, + errors or skips. `detektDesktopMain` passes with the existing rules. +- Docker client isolation: all three existing contract tests pass. +- All active workflow YAML files parse. Actionlint 1.7.12 reports no new findings + compared with develop when configured with the existing `codex` runner label; + its three existing `concurrency.queue` parser limitations remain unchanged. +- Full frontend `ktlintFormat` reports eight pre-existing file-naming/line-length + violations in untouched common tests. No lint rule or gate is disabled, and + unrelated formatter-only edits are excluded from this PR. +- Both Docker images and the JRE 25 startup smoke are being verified against the + candidate. Their result and the remote CI status are recorded in the PR. + +Existing results from the closed source PRs are reference material and are not +claimed as results for this combined candidate. + +## Upstream migration references + +- [JUnit 6.0.3 release notes](https://docs.junit.org/6.0.3/release-notes.html) +- [Ktor 3.4 changes](https://ktor.io/docs/whats-new-340.html) +- [Exposed 1.0 migration](https://www.jetbrains.com/help/exposed/migration-guide-1-0-0.html) +- [Checkout v7 changes](https://github.com/actions/checkout/blob/v7/README.md) +- [Codecov v7 changes](https://github.com/codecov/codecov-action/blob/v7/README.md) diff --git a/docs/development/EXPOSED_UPGRADE.md b/docs/development/EXPOSED_UPGRADE.md new file mode 100644 index 00000000..4e0ecdc4 --- /dev/null +++ b/docs/development/EXPOSED_UPGRADE.md @@ -0,0 +1,18 @@ +# Exposed 1.0 compatibility + +The standalone backend uses Exposed 1.0 as part of the consolidated dependency +update in issue #62. Imports follow the upstream `org.jetbrains.exposed.v1.core` +and `org.jetbrains.exposed.v1.jdbc` namespaces. Query predicates are top-level +extensions; separate `limit` and `offset` calls preserve existing pagination. + +The domain model still uses `kotlinx.datetime.Instant`. Table declarations use +upstream `xTimestamp` (imported as `timestamp`) with the backend datetime +compatibility artifact to preserve the existing model and SQL column declarations. +No schema migration or domain-wide migration to `kotlin.time` is introduced. + +The existing PostgreSQL repository, storage and API suites verify the migrated +persistence layer. See [the consolidated update inventory](DEPENDENCY_UPDATE_62.md) +for the related dependency changes and validation evidence. + +References: [upstream migration guide](https://www.jetbrains.com/help/exposed/migration-guide-1-0-0.html) +and [versioned datetime adapter sources](https://repo.maven.apache.org/maven2/org/jetbrains/exposed/exposed-kotlin-datetime/1.0.0/exposed-kotlin-datetime-1.0.0-sources.jar). diff --git a/frontend/gradle/libs.versions.toml b/frontend/gradle/libs.versions.toml index f3d2160a..84dd4c01 100644 --- a/frontend/gradle/libs.versions.toml +++ b/frontend/gradle/libs.versions.toml @@ -1,12 +1,12 @@ [versions] # Kotlin (2.3.20+ required for Koin Compiler Plugin typed startKoin) kotlin = "2.3.20-Beta1" -kotlinx-coroutines = "1.9.0" -kotlinx-serialization = "1.7.3" +kotlinx-coroutines = "1.10.2" +kotlinx-serialization = "1.10.0" kotlinx-datetime = "0.7.1" # Ktor -ktor = "3.0.2" +ktor = "3.4.0" # Koin - Dependency Injection (4.2.0-RC1 for Compiler Plugin; annotations same version as koin-core) koin = "4.2.0-RC1" @@ -16,14 +16,14 @@ koin-plugin = "0.3.0" ksp = "2.0.21-1.0.27" # Database -exposed = "0.56.0" +exposed = "1.0.0" hikari = "6.0.0" postgresql = "42.7.4" h2 = "2.3.232" -flyway = "10.21.0" +flyway = "12.0.1" # Storage -minio = "8.5.13" +minio = "8.6.0" aws-sdk = "1.3.68" # Redis @@ -34,9 +34,9 @@ logback = "1.5.12" kotlin-logging = "7.0.0" # Testing -junit = "5.11.3" -mockk = "1.13.13" -testcontainers = "1.20.4" +junit = "6.0.3" +mockk = "1.14.9" +testcontainers = "1.21.4" # Code Quality detekt = "1.23.8" @@ -52,9 +52,9 @@ android-compileSdk = "35" android-minSdk = "24" android-targetSdk = "35" androidx-core = "1.13.1" -androidx-lifecycle = "2.8.7" +androidx-lifecycle = "2.10.0" androidx-activity = "1.9.3" -androidx-test-ext-junit = "1.2.1" +androidx-test-ext-junit = "1.3.0" androidx-test-espresso = "3.6.1" # Image Loading From 65033dc6367e8d6a175e94f0d9023ec9e72e373a Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Sun, 25 Oct 2026 05:31:49 +0100 Subject: [PATCH 2/3] docs: record consolidated dependency verification --- docs/development/DEPENDENCY_UPDATE_62.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/development/DEPENDENCY_UPDATE_62.md b/docs/development/DEPENDENCY_UPDATE_62.md index 6441b0b1..6f35e409 100644 --- a/docs/development/DEPENDENCY_UPDATE_62.md +++ b/docs/development/DEPENDENCY_UPDATE_62.md @@ -60,8 +60,12 @@ Local verification of the combined candidate on JDK 17: - Full frontend `ktlintFormat` reports eight pre-existing file-naming/line-length violations in untouched common tests. No lint rule or gate is disabled, and unrelated formatter-only edits are excluded from this PR. -- Both Docker images and the JRE 25 startup smoke are being verified against the - candidate. Their result and the remote CI status are recorded in the PR. +- Both candidate Docker images build successfully for `linux/amd64`. The backend + reports JRE 25 and passes application startup and health checks against the + private PostgreSQL container. The frontend builds its production Web/Wasm + distribution natively inside the Linux builder. +- The standalone Web/Wasm production distribution also passes on macOS. Remote + CI and review status remain visible on the PR rather than in this static record. Existing results from the closed source PRs are reference material and are not claimed as results for this combined candidate. From 438c872af3e77e6b8c8dd0768b6f0c15f3885407 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Sun, 25 Oct 2026 07:45:41 +0100 Subject: [PATCH 3/3] fix(ci): allow cold Trivy Java database scans (#62) --- .github/workflows/security.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 765c3110..ad4aaee5 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -99,7 +99,7 @@ jobs: runs-on: group: vypdev labels: [self-hosted, macOS, ARM64] - timeout-minutes: 45 + timeout-minutes: 60 if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} permissions: contents: read @@ -136,6 +136,8 @@ jobs: uses: aquasecurity/trivy-action@master with: image-ref: ${{ env.SCAN_IMAGE }} + # Isolated caches download the Java DB before the first image scan. + timeout: '30m' format: 'sarif' output: 'trivy-results.sarif' cache-dir: ${{ runner.temp }}/trivy-${{ github.run_id }}-${{ github.run_attempt }}