Skip to content

fix(database): migrate H2 safely and protect backup restores - #7207

Draft
Ludy87 wants to merge 6 commits into
mainfrom
bump_h2_2_4_240
Draft

fix(database): migrate H2 safely and protect backup restores#7207
Ludy87 wants to merge 6 commits into
mainfrom
bump_h2_2_4_240

Conversation

@Ludy87

@Ludy87 Ludy87 commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Description of Changes

  • Upgraded the runtime H2 database dependency to 2.4.240.
  • Added an automatic startup migration that exports legacy H2 2.3.232 databases with the bundled legacy driver and imports them into a new H2 2.4.240 database file.
  • Preserved the original legacy database as a fallback and kept existing files in configs/backup untouched.
  • Hardened database restore operations by creating and verifying a pre-restore safety backup before applying an import.
  • Added automatic rollback when a restore import fails.
  • Prevented existing server-side backup files from being copied, overwritten, or deleted when applied.
  • Ensured temporary uploaded SQL files are cleaned up after successful or failed imports.
  • Added migration, restore rollback, backup preservation, and H2 version compatibility tests.
  • Added an H2 compatibility lock and a Gradle verification task that runs as part of :proprietary:check, blocking CI when runtime or migration-driver H2 versions differ from the reviewed lock.
  • Updated JaCoCo configuration to analyse compiled classes only, preventing the embedded legacy H2 JAR from causing duplicate-class coverage-report failures.

The change was made because H2 2.4 uses an incompatible database file format compared with H2 2.3. Existing installations and historical backups must remain recoverable during the upgrade.


Checklist

General

Documentation

Translations (if applicable)

UI Changes (if applicable)

  • Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR)

Testing (if applicable)

  • I have run task check to verify linters, typechecks, and tests pass
  • I have tested my changes locally. Refer to the Testing Guide for more details.

Add automated migration from legacy H2 2.3.232 on-disk DBs to H2 2.4.240: new H2DatabaseMigration class exports the old DB with a bundled 2.3 driver and imports into a new 2.4 database, invoked reflectively from SPDFApplication. Build and resources updated to bundle the old H2 driver for migration; default datasource names/URLs updated to the 2.4 filename. Harden DatabaseService import flow: verify backups, create a pre-restore safety backup, run import and restore on failure (propagating IOException). Minor fixes: DatabaseController temp-file cleanup, updated tests covering migration and import rollback, updated migration test script and fixture README.
@stirlingbot stirlingbot Bot added Documentation Improvements or additions to documentation Java Pull requests that update Java code Back End Issues related to back-end development Docker Pull requests that update Docker code Security Security-related issues or pull requests API API-related issues or pull requests Test Testing-related issues or pull requests Gradle Pull requests that update Gradle code labels Jul 30, 2026
Restrict jacocoReport to the project's compiled application classes and source dirs to avoid analysing embedded migration/dependency classes that appear in SourceSetOutput. Sets classDirectories to sourceSets.main.output.classesDirs and sourceDirectories to sourceSets.main.allSource.srcDirs so coverage only covers app code (keeps the existing dependsOn(test) and report settings).
@Ludy87 Ludy87 changed the title H2 DB migration to 2.4 and safer imports fix(database): migrate H2 safely and protect backup restores Jul 30, 2026
@stirlingbot stirlingbot Bot added the Bugfix Pull requests that fix bugs label Jul 30, 2026
@Ludy87
Ludy87 marked this pull request as ready for review July 30, 2026 21:56
@dosubot dosubot Bot added the size:L This PR changes 100-499 lines ignoring generated files. label Jul 30, 2026
printStartupLogs();
}

private static void migrateLegacyH2Database() throws IOException {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Introduced reflective startup of H2 migration via Class.forName/method.invoke; prefer explicit wiring to keep startup behaviour transparent

Details

✨ AI Reasoning
​The code attempts to run an optional migration class by loading it reflectively and invoking its migrateIfNeeded method. Reflection and dynamic invocation can obscure behavior from static analysis and reviewers because the class may be absent in some builds (caught ClassNotFoundException) and the invocation path is not visible in normal call graphs. This construct changes startup semantics and was added in this change set, increasing the use of reflection in startup flow which can be used to hide or dynamically alter behavior.

🔧 How do I fix it?
Ensure code is transparent and not intentionally obfuscated. Avoid hiding functionality from code review. Focus on intent and deception, not specific patterns.

Reply @AikidoSec feedback: [FEEDBACK] to get better review comments in the future.
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info

+ database.toAbsolutePath()
+ ";IFEXISTS=TRUE;ACCESS_MODE_DATA=r;DB_CLOSE_ON_EXIT=FALSE;MODE=PostgreSQL";
ClassLoader previous = Thread.currentThread().getContextClassLoader();
try (URLClassLoader loader =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uses URLClassLoader + Thread.setContextClassLoader + reflective invocation of org.h2.tools.Script.process; dynamic loading obscures runtime behavior

Details

✨ AI Reasoning
​The migration class extracts a bundled legacy H2 JAR to a temp file, creates a URLClassLoader over it, sets it as the thread context class loader, and then reflectively looks up and invokes org.h2.tools.Script.process. These steps intentionally divert classloading and invocation into a dynamically-loaded JAR, making it harder to inspect via static analysis and obscuring the executed code path. This exact mechanism was added by the PR, increasing obfuscation-like patterns.

🔧 How do I fix it?
Ensure code is transparent and not intentionally obfuscated. Avoid hiding functionality from code review. Focus on intent and deception, not specific patterns.

Reply @AikidoSec feedback: [FEEDBACK] to get better review comments in the future.
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info

@stirlingbot stirlingbot Bot added the has conflicts Pull request has merge conflicts with the base branch label Aug 3, 2026
@stirlingbot stirlingbot Bot removed the has conflicts Pull request has merge conflicts with the base branch label Aug 3, 2026
@stirlingbot stirlingbot Bot added the has conflicts Pull request has merge conflicts with the base branch label Aug 12, 2026
@Ludy87
Ludy87 marked this pull request as draft August 13, 2026 11:54
@github-actions github-actions Bot removed the has conflicts Pull request has merge conflicts with the base branch label Aug 23, 2026
@github-actions github-actions Bot deleted a comment from stirlingbot Bot Aug 23, 2026
@stirlingbot

stirlingbot Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

✅ Backend License Check Passed

All backend dependencies have valid and allowed licenses.

The backend license report has been updated successfully.

@github-actions

Copy link
Copy Markdown
Contributor

🚀 V2 Auto-Deployment Complete!

🔗 Direct Test URL (non-SSL) http://54.175.155.236:7207

🧩 Admin portal included - try it at http://54.175.155.236:7207/portal.

This deployment will be automatically cleaned up when the PR is closed.

🔄 Auto-deployed for approved V2 contributors.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

API API-related issues or pull requests Back End Issues related to back-end development Bugfix Pull requests that fix bugs Docker Pull requests that update Docker code Documentation Improvements or additions to documentation Gradle Pull requests that update Gradle code Java Pull requests that update Java code Security Security-related issues or pull requests size:L This PR changes 100-499 lines ignoring generated files. Test Testing-related issues or pull requests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant