fix(backup): keep GUI backup paths under BACKUP_ROOT and limit the schedule

backup:configure could point automatic backups at any writable directory
(e.g. a statically served one) and set a cron of every second; an invalid
expression deleted the running job before failing, silently ending
backups.

- A path entered in the UI is resolved under BACKUP_ROOT (default
  ./backups) and refused if it leaves it; env values stay unrestricted.
- The schedule must be a five-field cron that runs at most hourly.
- reload() validates before replacing the running job.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Opus 5.5 committed 2026-10-01 02:14:18 +02:00
1 parent bd592adf66
commit ebeb499a18
6 files changed
+148 -3

No files matched your search

@@ -225,8 +225,13 @@ function ScheduleSettingsForm({
value={storagePath}
disabled={envOverrides.storagePath}
onChange={(event) => setStoragePath(event.target.value)}
placeholder="/data/backups"
placeholder="nightly"
/>
{!envOverrides.storagePath ? (
<p className="text-xs text-muted-foreground">
Unterordner im Backup-Verzeichnis des Servers (BACKUP_ROOT), z. B. „nightly“.
</p>
) : null}
{envOverrides.storagePath ? (
<p className="text-xs text-muted-foreground">
Durch BACKUP_STORAGE_PATH vorgegeben.
@@ -241,7 +246,11 @@ function ScheduleSettingsForm({
disabled={envOverrides.cronSchedule}
onChange={(event) => setCronSchedule(event.target.value)}
placeholder="0 3 * * *"
aria-describedby="backup-cron-hint"
/>
<p id="backup-cron-hint" className="text-xs text-muted-foreground">
Fünf Felder, höchstens einmal pro Stunde. „0 3 * * *“ = täglich um 3 Uhr.
</p>
{envOverrides.cronSchedule ? (
<p className="text-xs text-muted-foreground">
Durch BACKUP_CRON_SCHEDULE vorgegeben.