Browse Source

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

serve: add --permissions option as an alternative to BORG_REPO_PERMISSIONS env var
TW 1 day ago
parent
commit
dda9c445e1
4 changed files with 26 additions and 8 deletions
  1. 1 1
      src/borg/archiver/__init__.py
  2. 7 0
      src/borg/archiver/serve_cmd.py
  3. 6 4
      src/borg/remote.py
  4. 12 3
      src/borg/repository.py

+ 1 - 1
src/borg/archiver/__init__.py

@@ -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:

+ 7 - 0
src/borg/archiver/serve_cmd.py

@@ -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.",
+        )

+ 6 - 4
src/borg/remote.py

@@ -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
 

+ 12 - 3
src/borg/repository.py

@@ -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