mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
a7aaa29c16
An unreadable or empty encryption-key file was treated the same as a missing one: regenerate and overwrite. That is the one case where regenerating is the worst possible move - every secret already at rest becomes undecryptable, permanently. Both now refuse to start and say which file to fix. The key-rotation script advertised re-encrypting all stored secrets while its hardcoded column lists had drifted: the AirTrail key, the per-user LLM key and the plugin OAuth tokens were never migrated, so they silently stopped decrypting after a rotation. The parity test now pins the full set against what the code actually encrypts, rather than two tables of it. The schema_version bump ran outside the migration's transaction, so a crash in between left the schema advanced and the version stale - the next boot replayed a non-idempotent step and exited, turning one crash into a boot loop. And the TICKETJSON receipt migration matched with LIKE, which SQLite treats case-insensitively, so a note somebody had typed starting 'ticketjson:' was cut up and its text dropped. Also: APP_VERSION was interpolated into migration SQL instead of bound, the capture-metadata backfill passed (photoId, userId) to a (userId, photoId) signature and its mock keyed on the wrong argument, TRUST_PROXY=0 was accepted and silently coerced to 1, demo-reset hardcoded the db path instead of honouring TREK_DB_FILE, and a demo instance with no DEMO_ADMIN_PASS set now says out loud that its admin password is the published default.
65 lines
2.1 KiB
TypeScript
65 lines
2.1 KiB
TypeScript
/**
|
|
* Demo mode boot seeding.
|
|
*
|
|
* DEMO_MODE=true creates a role=admin account on first boot. When
|
|
* DEMO_ADMIN_PASS is unset that account gets the password published in
|
|
* demo-seed itself, so the seeder has to say so out loud.
|
|
*/
|
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
import type Database from 'better-sqlite3';
|
|
import { createTestDb } from '../../helpers/test-db';
|
|
|
|
// Baseline handling is demo-reset's job and touches the file system.
|
|
vi.mock('../../../src/demo/demo-reset', () => ({
|
|
saveBaseline: vi.fn(),
|
|
hasBaseline: vi.fn(() => true),
|
|
resetDemoUser: vi.fn(),
|
|
}));
|
|
|
|
import { seedDemoData } from '../../../src/demo/demo-seed';
|
|
|
|
describe('demo seeding', () => {
|
|
let db: Database.Database;
|
|
const realPass = process.env.DEMO_ADMIN_PASS;
|
|
|
|
beforeEach(() => {
|
|
db = createTestDb();
|
|
vi.spyOn(console, 'log').mockImplementation(() => undefined);
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
db.close();
|
|
if (realPass === undefined) delete process.env.DEMO_ADMIN_PASS;
|
|
else process.env.DEMO_ADMIN_PASS = realPass;
|
|
});
|
|
|
|
it('DEMOSEED-001: warns when the admin account is created with the default password', () => {
|
|
delete process.env.DEMO_ADMIN_PASS;
|
|
const warn = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
|
|
|
|
seedDemoData(db);
|
|
|
|
expect(warn).toHaveBeenCalledWith(expect.stringContaining('DEMO_ADMIN_PASS is not set'));
|
|
});
|
|
|
|
it('DEMOSEED-002: stays quiet when the operator set DEMO_ADMIN_PASS', () => {
|
|
process.env.DEMO_ADMIN_PASS = 'a-real-password';
|
|
const warn = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
|
|
|
|
seedDemoData(db);
|
|
|
|
expect(warn).not.toHaveBeenCalledWith(expect.stringContaining('DEMO_ADMIN_PASS is not set'));
|
|
});
|
|
|
|
it('DEMOSEED-003: does not warn again once the admin account exists', () => {
|
|
delete process.env.DEMO_ADMIN_PASS;
|
|
seedDemoData(db);
|
|
const warn = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
|
|
|
|
seedDemoData(db);
|
|
|
|
expect(warn).not.toHaveBeenCalledWith(expect.stringContaining('DEMO_ADMIN_PASS is not set'));
|
|
});
|
|
});
|