From 5c8e5560d47e145392905d85b24f1796d6b4daa0 Mon Sep 17 00:00:00 2001 From: Federico Justus Denkena Date: Thu, 10 Sep 2026 00:00:15 +0200 Subject: [PATCH] bisync: default to fail-closed safety flags New Bisync jobs and scheduled RC bodies start with checkAccess, deltaList, recover, resilient, slowHashSyncOnly, conflictResolve=none, maxDelete=50, and checksum compare. Explicit outer values still win. --- lib/rclone/constants.ts | 19 +++++++++++++++++++ lib/rclone/requests.ts | 6 +++++- src/pages/Bisync.tsx | 7 ++++--- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/lib/rclone/constants.ts b/lib/rclone/constants.ts index fee26c2..199e404 100644 --- a/lib/rclone/constants.ts +++ b/lib/rclone/constants.ts @@ -1,3 +1,22 @@ +// Fail-closed bisync RC defaults (forked rclone). Explicit outer values override. +export const BISYNC_SAFETY_DEFAULTS = { + checkAccess: true, + deltaList: true, + recover: true, + resilient: true, + slowHashSyncOnly: true, + conflictResolve: 'none', + maxDelete: 50, + compare: 'size,modtime,checksum', +} as const + +export const BISYNC_SAFETY_SWITCH_DEFAULTS: Record = { + checkAccess: true, + deltaList: true, + recover: true, + resilient: true, +} + export const RCLONE_CONFIG_DEFAULTS = { copy: { 'multi_thread_cutoff': '64M', diff --git a/lib/rclone/requests.ts b/lib/rclone/requests.ts index 0493c47..0490a63 100644 --- a/lib/rclone/requests.ts +++ b/lib/rclone/requests.ts @@ -1,4 +1,5 @@ import type { FlagValue } from '../../types/rclone' +import { BISYNC_SAFETY_DEFAULTS } from './constants' import { getFsInfo } from '../format' // Pure serialization of operation args into ready-to-POST rclone RC requests. This is the @@ -492,7 +493,10 @@ export function buildBisyncRequests(args: BisyncArgs): RcRequest[] { const { fullDirPath: srcFullDirPath, remoteName: srcRemoteName } = getFsInfo(source) const { fullDirPath: dstFullDirPath, remoteName: dstRemoteName } = getFsInfo(destination) - const outer = { ...(options.outer || {}) } + const outer: Record = { + ...BISYNC_SAFETY_DEFAULTS, + ...(options.outer || {}), + } // Forked rclone: --delta-list refuses to run without --check-access unless --force. if (outer.deltaList && !outer.force) { outer.checkAccess = true diff --git a/src/pages/Bisync.tsx b/src/pages/Bisync.tsx index bb5ae8f..4166eaf 100644 --- a/src/pages/Bisync.tsx +++ b/src/pages/Bisync.tsx @@ -7,7 +7,7 @@ import { onErrorDialog } from '../../lib/errors' import { getOptionsSubtitle } from '../../lib/flags' import { useFlags } from '../../lib/hooks' import { startBisync } from '../../lib/rclone/api' -import { RCLONE_CONFIG_DEFAULTS } from '../../lib/rclone/constants' +import { BISYNC_SAFETY_SWITCH_DEFAULTS, RCLONE_CONFIG_DEFAULTS } from '../../lib/rclone/constants' import { useSchedulingAvailable } from '../../lib/scheduler' import OperationWindowContent from '../components/OperationWindowContent' import OperationWindowFooter from '../components/OperationWindowFooter' @@ -38,7 +38,7 @@ Here's a quick guide to using the Bisync command: Use the path selectors at the top to choose Path1 and Path2. Both paths will be kept in sync with each other — there is no "source" or "destination", changes flow both ways. 2. CONFIGURE OPTIONS (Optional) -Expand the accordion sections to customize your bisync operation. The Bisync section has important switches at the top: +Expand the accordion sections to customize your bisync operation. Safety defaults are on: checkAccess, deltaList, recover, resilient, conflictResolve=none, maxDelete=50, compare=size,modtime,checksum, slowHashSyncOnly. Turn them off only if you understand the loss path. • resync — Required for the first run, or to reset bisync after an error. This makes both paths contain a matching superset of all files by copying Path2 to Path1, then Path1 to Path2. Only use resync when starting fresh, after changing filter settings, or recovering from an error — using it routinely would prevent deletions from syncing (deleted files would keep reappearing from the other side). @@ -104,7 +104,8 @@ export default function Bisync() { const filterGroup = optionGroups.filter const configGroup = optionGroups.config - const [outerBisyncOptions, setOuterBisyncOptions] = useState>({}) + const [outerBisyncOptions, setOuterBisyncOptions] = + useState>(BISYNC_SAFETY_SWITCH_DEFAULTS) const [cronExpression, setCronExpression] = useState(null) const schedulingAvailable = useSchedulingAvailable()