mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-09-14 22:28:57 -04:00
daemon-exclude-namebased bound its daemon on 13010, and the setup_chroot_inner helper hashed into 12940-13139 -- both reach into 13000+, where ASUS Armoury Crate on the Cygwin CI host parks localhost listeners (13010, 13030-13032), making the port probe fail the test. The helper also used str hash(), which is per-process randomized (PYTHONHASHSEED), so its port wandered run to run. Move the fixed port to 12931 and the helper to a deterministic crc32-based slot in the otherwise-unused 12800-12859 band.
62 lines
2.6 KiB
Python
62 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
|
# The daemon exclude/filter matches the LOGICAL module-relative NAME, anchored at
|
|
# the module root -- it is a visibility/tamper filter, not a physical-path
|
|
# boundary. rsyncd.conf(5) (filter parameter) says a subtree must be excluded
|
|
# with a trailing-slash or "/***" pattern; a bare anchored name protects only an
|
|
# entry literally of that name, not paths under it. This test makes that
|
|
# documented, name-based behaviour executable (it matches stock rsync 3.2.7).
|
|
#
|
|
# A direct push of a FILE to <excluded>/x2.tx:
|
|
# exclude = /excluded (bare name) -> LANDS (subtree not protected)
|
|
# exclude = /excluded/ (dir form) -> refused
|
|
# exclude = /excluded/*** (subtree) -> refused
|
|
# One daemon serves three modules (one per pattern) so a single rsyncd handles
|
|
# all cases -- avoids multi-daemon port/pid churn on some platforms. Unprivileged.
|
|
|
|
import subprocess
|
|
|
|
from rsyncfns import (
|
|
SCRATCHDIR, rmtree, rsync_argv, start_test_daemon, test_fail, write_daemon_conf,
|
|
)
|
|
|
|
# Not 13000-13060: ASUS Armoury Crate on the Cygwin CI host parks localhost
|
|
# listeners there (13010 among them).
|
|
DAEMON_PORT = 12931
|
|
|
|
# (module name, exclude pattern, expect the pushed file to land)
|
|
CASES = [
|
|
('bare', '/excluded', True), # bare name: does NOT protect the subtree
|
|
('dir', '/excluded/', False), # dir form: protects the subtree
|
|
('triple', '/excluded/***', False), # documented subtree form: protects
|
|
]
|
|
|
|
base = SCRATCHDIR / 'daemon-exclude-namebased'
|
|
rmtree(base)
|
|
base.mkdir()
|
|
src = base / 'hosts'
|
|
src.write_text("127.0.0.1 localhost\n")
|
|
|
|
modules = []
|
|
for name, pattern, _ in CASES:
|
|
mod = base / name
|
|
(mod / 'excluded').mkdir(parents=True)
|
|
modules.append((name, {'path': str(mod), 'read only': 'no', 'exclude': pattern}))
|
|
|
|
url = start_test_daemon(write_daemon_conf(modules), DAEMON_PORT)
|
|
|
|
for name, pattern, expect_landed in CASES:
|
|
subprocess.run(
|
|
rsync_argv('-a', str(src), f'{url}{name}/excluded/x2.tx'),
|
|
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
landed = (base / name / 'excluded' / 'x2.tx').exists()
|
|
if landed != expect_landed:
|
|
verb = "did not land" if expect_landed else "landed"
|
|
test_fail(
|
|
f"exclude={pattern!r}: a file push to excluded/x2.tx {verb} "
|
|
f"(landed={landed}, expected {expect_landed}). A bare anchored name "
|
|
"protects only an entry of that exact name; a subtree needs a "
|
|
"trailing-slash or /*** pattern (rsyncd.conf(5)).")
|
|
|
|
print("daemon exclude is name-based: a bare-name pattern does not protect the "
|
|
"subtree; a /dir/ or /dir/*** pattern does (3.2.7-equivalent)")
|