refuse to start with an empty database when data exists elsewhere (#1118)

When the data directory holds no database, startup treats it as a first run and
silently creates an empty one. A deployment that loses DATA_DIR — an .env file
the service no longer loads, a volume that did not mount — lands in exactly that
state, so the user is asked to register an admin account again while the real
database sits untouched one directory over. It is indistinguishable from the
upgrade having deleted everything.

Check the known data locations before creating a new database and refuse to
start when one of them already holds a database, naming both directories.
ALLOW_EMPTY_DATA_DIR=true starts anyway for anyone deliberately starting over.

This matches how a failed decryption already behaves: it throws rather than
falling back to an empty database.

Closes Termix-SSH/Support#1006
This commit is contained in:
ZacharyZcR
2026-07-28 01:48:48 +08:00
committed by GitHub
parent 384abebe37
commit ac5da581e2
3 changed files with 231 additions and 0 deletions
+10
View File
@@ -8,6 +8,10 @@ import { DatabaseFileEncryption } from "../../utils/database-file-encryption.js"
import { SystemCrypto } from "../../utils/system-crypto.js";
import { DatabaseMigration } from "../../utils/database-migration.js";
import { DatabaseSaveTrigger } from "../../utils/database-save-trigger.js";
import {
assertDataDirIsNotMisconfigured,
DataDirMisconfiguredError,
} from "../../utils/data-dir-guard.js";
import { getDefaultGuacdUrl } from "../../utils/guacd-config.js";
const dataDir = process.env.DATA_DIR || "./db/data";
@@ -104,11 +108,16 @@ async function initializeDatabaseAsync(): Promise<void> {
);
}
} else {
assertDataDirIsNotMisconfigured(dataDir);
memoryDatabase = new Database(":memory:");
isNewDatabase = true;
}
}
} catch (error) {
// Not a decryption problem: the database is fine, we are pointed at the
// wrong directory. Surface that message as-is.
if (error instanceof DataDirMisconfiguredError) throw error;
databaseLogger.error("Failed to initialize memory database", error, {
operation: "db_memory_init_failed",
errorMessage: error instanceof Error ? error.message : "Unknown error",
@@ -145,6 +154,7 @@ async function initializeDatabaseAsync(): Promise<void> {
);
}
} else {
assertDataDirIsNotMisconfigured(dataDir);
memoryDatabase = new Database(":memory:");
isNewDatabase = true;
}