backup engine fixes: shared-repo unlock, non-root uid reads, lock release, local-path repo, backblaze key id
This commit is contained in:
15 files changed
+375
-313
No files matched your search
@@ -7,25 +7,12 @@ import {
|
||||
updateBackupDestination,
|
||||
deleteBackupDestination,
|
||||
decryptBackupDestination,
|
||||
getBackupConfigs,
|
||||
getEnvironment
|
||||
getBackupConfigs
|
||||
} from '$lib/server/db';
|
||||
import { registerSchedule, unregisterSchedule } from '$lib/server/scheduler';
|
||||
import { validatePolicySchedules, validateRepositoryForSave, validateFlags } from '$lib/server/backups/helpers';
|
||||
import { destinationHasRunningBackup } from '$lib/server/backups';
|
||||
|
||||
// Inlined predicates (kept in sync with the config routes) — see
|
||||
// configs/+server.ts. A local repo cannot back up a remote environment.
|
||||
function isLocalRepo(repository: string): boolean {
|
||||
return repository.startsWith('/') || repository.startsWith('./');
|
||||
}
|
||||
function isRemoteEnv(connectionType?: string | null, host?: string | null): boolean {
|
||||
if (!connectionType) return false;
|
||||
if (connectionType === 'hawser-standard' || connectionType === 'hawser-edge') return true;
|
||||
if (connectionType === 'direct' && !!host) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Single-destination response shape. envVars (decrypted cloud credentials) are
|
||||
* ONLY included for callers with backups:manage — the edit form that pre-fills
|
||||
@@ -98,23 +85,8 @@ export const PUT: RequestHandler = async (event) => {
|
||||
const flagError = validateFlags(body.flags);
|
||||
if (flagError) return json({ error: flagError }, { status: 400 });
|
||||
|
||||
// (audit #8) Changing the repository to a LOCAL path bypasses the config-route
|
||||
// guard: refuse if any config on this destination targets a remote environment
|
||||
// (the restic helper runs on the remote daemon, which can't see Dockhand's fs).
|
||||
const effectiveRepository = body.repository !== undefined ? body.repository : existing.repository;
|
||||
if (body.repository !== undefined && isLocalRepo(effectiveRepository)) {
|
||||
const configs = await getBackupConfigs();
|
||||
const envIds = [...new Set(
|
||||
configs.filter((c: any) => c.destinationId === id && c.environmentId).map((c: any) => c.environmentId as number)
|
||||
)];
|
||||
const envs = await Promise.all(envIds.map((eid) => getEnvironment(eid)));
|
||||
const remote = envs.find((env) => env && isRemoteEnv(env.connectionType, env.host));
|
||||
if (remote) {
|
||||
return json({
|
||||
error: `Local repository cannot back up containers on remote environment "${remote.name}". Use S3, REST, or another non-local backend.`
|
||||
}, { status: 400 });
|
||||
}
|
||||
}
|
||||
// A local-path repo is allowed on any env; a wrong-host mount fails loud via
|
||||
// the helper's localRepoGuard at backup/restore time.
|
||||
|
||||
try {
|
||||
const updated = await updateBackupDestination(id, {
|
||||
|
||||
Reference in new issue
Block a user