Split FastSync's single use_metadata bundle into four independent rsync-parity attributes: preserve_perms, preserve_times, preserve_owner, preserve_group. use_metadata is now a derived transport bit (config_derived_use_metadata). CLI: real -p/--perms, -t/--times, -o/--owner, -g/--group plus --no-perms/--no-times/--no-owner/--no-group (short and long) and --no-preserve; -a is now rsync -rlptgoD; --preserve = -pt; -A implies -p; -X does not; --chmod implies -p; --usermap/--groupmap/--chown imply owner/group per side; --incremental/--delta still auto-preserve unless negated. Receiver: per-attribute FileAttrPolicy gating for files, dirs (modes applied at end of transfer), symlinks and specials; rsync -E read-bit rule; new files get source_mode & ~umask sanitized (no group/other write); per-side identity resolution; deferred directory metadata; batch dir-metadata replay; daemon modules without 'client owner = yes' no longer refuse plain -a but force super off (no ownership) with a warning. Wire: PROTOCOL_VERSION 2.21.0 -> 2.22.0 (four appended config bools, golden 653 / 95530566005420798). FileMetadata/chunk/batch framing unchanged. Docs/CHANGELOG/CMake updated to 2.22.0.
4.1 KiB
4.1 KiB
FastSync — Session Handoff (2026-09-14)
Current status
- Release
v2.21.0tagged (919a729, "Release v2.21.0"); full CI green (run 552: lint, build-and-test, ASan, UBSan, fuzz-build, coverage, valgrind).devhas the release commit plus later doc-only merges (a README refresh and this handoff). - Release PR #284 (
dev->main) open, CI green (run 553).mainis protected: it needs review/approval to merge. #284 PROTOCOL_VERSION="2.22.0"(src/shared/config.h); CMakeproject(FastFileTransfer VERSION 2.22.0).- Working tree clean; no wave worktrees remain.
What landed this session
- Wave 8 (refactors): Config X-macro wire table; single-owner
authorized_root; daemon per-module/per-host caps + cross-process auth lockout (daemon_limits.[ch]);Datacharge returns to its owningProtocolSession. - Wave 9 (protocol 2.21.0): optional
STATUS_ERROR_DETAILrejection reasons; server-contacting--dry-run(STATUS_DRY_RUN_TRANSFER, receiver mutates nothing). - Security wave: ran 5 parallel audits (wire parsing; daemon/transport/TLS/auth;
receiver confinement; client/CLI/SSH; crypto/memory/limits). Fixed all HIGH and the
confirmed MEDIUMs:
- SSH
-o ProxyCommand=…argument injection (RCE) — reject leading-, insert--. - Truncated zstd frame infinite CPU loop (remote DoS).
- FIFO receiver opens lacked
O_NONBLOCK(indefinite hang). --inplacecould write a FIFO/device (bypass of--write-devicesgate).--forcenot gated by server--allow-delete.- Privileged standalone server defaulted super activities on; added
--allow-super(never honored with--stdio). --dry-runcontent/hash oracle onread only/basis files removed.- Empty
hosts allow/deny/auth usersnow rejected. - TLS: AEAD-only 1.2 + server preference, TOCTOU-safe key load, IP-SAN verify,
CN-truncation guard. Glob backtracking bounded; line reads bounded; ACL xattrs
gated on
--acls; decompression/chunk memory charged; pre-authbasis_countNULL-deref fixed.
- SSH
- Tooling: benchmark accuracy (data mix, verification, percentiles,
tc,build-bench/,--warmmode);shell.nixfull toolchain and no build-on-entry; docs state push-only / remote-source unsupported. - Preserve-attribute split (protocol 2.22.0) landed on
feat/preserve-attr-split: per-attribute-p/-t/-o/-g+--no-*negations,-a=-rlptgoD, and the 2.21.0 → 2.22.0 wire bump.
Next steps
- Merge PR #284 (
dev->main) once reviewed (protected branch). - Deferred security items (documented, not implemented):
- Pre-auth config/daemon-auth handshake has no aggregate wall-clock deadline (per-message timeout only) — slowloris holds connection slots.
- Per-source registry fails open when the shared table is full (per-module/global caps and host ACLs still apply); consider fail-closed or larger/evicting table.
- SCRAM-like daemon auth has no TLS channel binding (and is not RFC 5802).
cleanup()signal handler calls non-async-signal-safe teardown; daemonumask(0).- Wire protocol assumes homogeneous word size/endianness (lengths are native
size_t) — document or move to fixed-width framing.
- Out of scope / intentional: pull (remote source) mode is not planned —
FastSync is push-only; see
RSYNC_COMPAT.md#direction.
Key facts / commands
- CI image:
gitea.tap-tap.win/taptap/fastsync-ci:v10(aliasfastsync-ci:local). - Build/test:
cmake -B build -S . -DSTRICT_WARNINGS=ON && cmake --build build -j$(nproc) && ./build/teststhenpython3 -m pytest tests/integration/ -n 4 --dist=load -m "not setpriv". - Dev shell:
nix-shell(provides clang-format, cppcheck, pytest-xdist, openssh, rsync, iproute2, valgrind, lcov; does not build on entry). - Gitea API token: supplied out-of-band via the
TOKENenvironment variable; it is intentionally not recorded in this file. - CI polling:
GET /api/v1/repos/TapTap/FastSync/actions/runs?limit=N, matchhead_sha, then/actions/runs/<id>/jobs.