syncova-policies/scripts/database-backup.js
Weapie 265ca8ac38
All checks were successful
Container-Image bauen und veröffentlichen / build-and-push (push) Successful in 5m15s
Improve accessibility and access controls; verify production and database recovery
2026-09-14 11:44:41 +02:00

42 lines
2.0 KiB
JavaScript

const fs = require('node:fs')
const path = require('node:path')
const { PrismaClient } = require('@prisma/client')
const { loadEnv } = require('./lib/admin-account')
async function verify(file) {
const db = new PrismaClient({ datasources: { db: { url: 'file:' + file.split(path.sep).join('/') } } })
try {
const result = await db.$queryRawUnsafe('PRAGMA integrity_check')
if (result.length !== 1 || Object.values(result[0])[0] !== 'ok') throw new Error('SQLite integrity check failed')
const counts = {}
for (const model of ['user', 'privacyPolicy', 'policyDefaults', 'sitePages']) counts[model] = await db[model].count()
return counts
} finally { await db.$disconnect() }
}
async function main() {
loadEnv()
const [action, input, output] = process.argv.slice(2)
if (!input || !['backup', 'verify', 'restore'].includes(action)) throw new Error('Usage: node scripts/database-backup.js backup FILE | verify FILE | restore BACKUP NEW_FILE')
const file = path.resolve(input)
if (action === 'verify') {
if (!fs.existsSync(file)) throw new Error('Backup does not exist')
console.log(JSON.stringify(await verify(file)))
return
}
const target = action === 'restore' ? (output ? path.resolve(output) : null) : file
if (!target) throw new Error('Restore requires a new destination file; existing files are never overwritten')
if (fs.existsSync(target)) throw new Error('Destination already exists; refusing to overwrite')
fs.mkdirSync(path.dirname(target), { recursive: true, mode: 0o700 })
if (action === 'backup') {
const db = new PrismaClient()
try { await db.$executeRawUnsafe('VACUUM INTO ?', target) } finally { await db.$disconnect() }
} else {
if (!fs.existsSync(file)) throw new Error('Backup does not exist')
await verify(file)
fs.copyFileSync(file, target, fs.constants.COPYFILE_EXCL)
}
fs.chmodSync(target, 0o600)
console.log(JSON.stringify({ action, file: target, counts: await verify(target) }))
}
main().catch(error => { console.error(error.message); process.exitCode = 1 })