Merge pull request #8893 from ThomasWaldmann/borg-serve-permissions

serve: add --permissions option as an alternative to BORG_REPO_PERMISSIONS env var
This commit is contained in:
TW 2025-05-30 13:08:29 +02:00 committed by GitHub
commit dda9c445e1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 26 additions and 8 deletions

View file

@ -401,7 +401,7 @@ class Archiver(
# client is allowed to specify the allowlisted options,
# everything else comes from the forced "borg serve" command (or the defaults).
# stuff from denylist must never be used from the client.
denylist = {"restrict_to_paths", "restrict_to_repositories", "umask"}
denylist = {"restrict_to_paths", "restrict_to_repositories", "umask", "permissions"}
allowlist = {"debug_topics", "lock_wait", "log_level"}
not_present = object()
for attr_name in allowlist:

View file

@ -15,6 +15,7 @@ class ServeMixIn:
restrict_to_paths=args.restrict_to_paths,
restrict_to_repositories=args.restrict_to_repositories,
use_socket=args.use_socket,
permissions=args.permissions,
).serve()
def build_parser_serve(self, subparsers, common_parser, mid_common_parser):
@ -71,3 +72,9 @@ class ServeMixIn:
"PATH may be an empty directory or the last element of PATH may not exist, in which case "
"the client may initialize a repository there.",
)
subparser.add_argument(
"--permissions",
dest="permissions",
choices=["all", "no-delete", "write-only", "read-only"],
help="Set repository permission mode. Equivalent to setting BORG_REPO_PERMISSIONS environment variable.",
)

View file

@ -164,12 +164,13 @@ class RepositoryServer: # pragma: no cover
"store_move",
)
def __init__(self, restrict_to_paths, restrict_to_repositories, use_socket):
def __init__(self, restrict_to_paths, restrict_to_repositories, use_socket, permissions=None):
self.repository = None
self.RepoCls = None
self.rpc_methods = ("open", "close", "negotiate")
self.restrict_to_paths = restrict_to_paths
self.restrict_to_repositories = restrict_to_repositories
self.permissions = permissions
# This flag is parsed from the serve command line via Archiver.do_serve,
# i.e. it reflects local system policy and generally ranks higher than
# whatever the client wants, except when initializing a new repository
@ -375,9 +376,10 @@ class RepositoryServer: # pragma: no cover
break
else:
raise PathNotAllowed(path)
self.repository = self.RepoCls(
path, create, lock_wait=lock_wait, lock=lock, exclusive=exclusive, send_log_cb=self.send_queued_log
)
kwargs = dict(lock_wait=lock_wait, lock=lock, exclusive=exclusive, send_log_cb=self.send_queued_log)
if not v1_or_v2:
kwargs["permissions"] = self.permissions
self.repository = self.RepoCls(path, create, **kwargs)
self.repository.__enter__() # clean exit handled by serve() method
return self.repository.id

View file

@ -92,7 +92,16 @@ class Repository:
exit_mcode = 21
def __init__(self, path_or_location, create=False, exclusive=False, lock_wait=1.0, lock=True, send_log_cb=None):
def __init__(
self,
path_or_location,
create=False,
exclusive=False,
lock_wait=1.0,
lock=True,
send_log_cb=None,
permissions=None,
):
if isinstance(path_or_location, Location):
location = path_or_location
if location.proto == "file":
@ -114,8 +123,8 @@ class Repository:
"keys/": [0],
"locks/": [0],
}
# Get permissions from environment variable
permissions = os.environ.get("BORG_REPO_PERMISSIONS", "all")
# Get permissions from parameter or environment variable
permissions = permissions if permissions is not None else os.environ.get("BORG_REPO_PERMISSIONS", "all")
if permissions == "all":
permissions = None # permissions system will not be used