When sshfs fails, check permissions on the private key and known_hosts
files. If any have wrong permissions (not 0o600 — possible on Docker
bind-mounts with ACL inheritance such as Synology NAS), apply chmod 600
and retry the mount once with a warning log.
Add ensureFileMode helper to packages/core/src/node/fs.ts (exported from
node index) and three tests for it: correct mode (no-op), wrong mode
(fixes and returns true), non-existent file (no-op).
Agent-Logs-Url: https://github.com/mowdep/zerobyte/sessions/d5edc5d0-fa7d-424b-a763-97601f577c92
Co-authored-by: mowdep <10937987+mowdep@users.noreply.github.com>
Unlink any existing file before writing in writeFileWithMode so the
mode option is always applied on fresh file creation (Node.js ignores
mode for existing files). This prevents inheriting wrong permissions
on Docker bind-mount filesystems such as Synology NAS where ACLs can
cause SSH key files to be created with 755 instead of 600.
The fs.unlink error is only swallowed for ENOENT (file doesn't exist);
other errors (e.g. EPERM) propagate as before. The chmod call is kept
as an additional safety net against umask effects.
A test for the new-file creation case is added alongside the existing
existing-file rewrite test.
Agent-Logs-Url: https://github.com/mowdep/zerobyte/sessions/2a4ab129-9668-402e-8687-d792f9b9e704
Co-authored-by: mowdep <10937987+mowdep@users.noreply.github.com>
* fix(deps): update bun minor and patch dependencies
* fix: ci
---------
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nicolas Meienberger <github@thisprops.com>
* feat(agents): create agent registry and service
* fix: mark agent offline only if the session was removed properly
* refactor: centralize agent backup lifecycle state
* refactor: simplify session management
* refactor: move effect / async boundary in one place
* chore: regen migration
* refactor: improve error handling
* chore: pr feedback
* feat(mirrors): add selective snapshot sync to mirror repositories
Allow users to sync missing snapshots from the source repository to a
mirror. A new sync button per mirror opens a dialog showing which
snapshots are missing, with checkboxes to select which ones to copy.
- Add GET /:shortId/mirrors/:mirrorShortId/status endpoint to compare
snapshots between source and mirror repositories
- Add POST /:shortId/mirrors/:mirrorShortId/sync endpoint accepting
selected snapshotIds in the request body
- Extend restic copy command to accept multiple snapshotIds
- Add sync preview dialog with snapshot selection to the frontend
* refactor: stylistic changes
---------
Co-authored-by: Nicolas Meienberger <github@thisprops.com>
* feat(agent): add standalone agent runtime
* fix(backups): bridge local executor to Effect restic API
* fix(agent): add Bun and DOM types to agent tsconfig
* refactor: wrap backup error in a tagged effect error
* fix: pr feedbacks
* chore: migrate to vitest
* test: speed up some suites by sharing sessions and mocking expensive non-tested actions
* test: refactor some tests to verify behavior instead of implementation details
* chore: fix linting issues
Separate include patters and included path cleanly to avoid path with special characters to be expanded. Closes https://github.com/nicotsx/zerobyte/discussions/680
<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit
* **New Features**
* Added ability to select specific directories and paths for inclusion in backup schedules, separate from pattern-based rules.
* **Bug Fixes & Improvements**
* Automatically migrates existing backup configurations to work with the new path selection system.
* Enhanced backup restoration to properly handle both selected paths and pattern-based inclusions.
* **Chores**
* Updated database schema to support path selections in backup schedules.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Closes#478 The mode option of fs.writeFile does not reliably apply
permissions on all filesystems. On Synology NAS Docker volumes (btrfs),
the file ends up with 0755 permissions instead of 0600, causing SSH to
refuse the key.