mirror of
https://github.com/borgbackup/borg.git
synced 2026-06-11 01:41:57 -04:00
Merge pull request #8837 from ThomasWaldmann/store-permissions2
Store permissions
This commit is contained in:
commit
e0fd2af7bd
3 changed files with 162 additions and 2 deletions
|
|
@ -30,7 +30,7 @@ license = "BSD-3-Clause"
|
|||
license-files = ["LICENSE", "AUTHORS"]
|
||||
dependencies = [
|
||||
"borghash ~= 0.1.0",
|
||||
"borgstore ~= 0.2.0",
|
||||
"borgstore @ git+https://github.com/borgbackup/borgstore.git@master", # temporary until there is a release
|
||||
"msgpack >=1.0.3, <=1.1.0",
|
||||
"packaging",
|
||||
"platformdirs >=3.0.0, <5.0.0; sys_platform == 'darwin'", # for macOS: breaking changes in 3.0.0,
|
||||
|
|
|
|||
|
|
@ -115,8 +115,30 @@ class Repository:
|
|||
"keys/": [0],
|
||||
"locks/": [0],
|
||||
}
|
||||
# Get permissions from environment variable
|
||||
permissions = os.environ.get("BORG_REPO_PERMISSIONS", "all")
|
||||
|
||||
if permissions == "all":
|
||||
permissions = None # permissions system will not be used
|
||||
elif permissions == "no-delete": # mostly no delete, no overwrite
|
||||
permissions = {
|
||||
"": "lr",
|
||||
"archives": "lrw",
|
||||
"cache": "lrwWD", # WD for chunks.X
|
||||
"config": "lrWD", # W for manifest, D for last-key-checked
|
||||
"data": "lrw",
|
||||
"keys": "lr",
|
||||
"locks": "lrwD", # borg needs to create/delete a shared lock here
|
||||
}
|
||||
elif permissions == "read-only": # mostly r/o
|
||||
permissions = {"": "lr", "locks": "lrwD"}
|
||||
else:
|
||||
raise Error(
|
||||
f"Invalid BORG_REPO_PERMISSIONS value: {permissions}, should be one of: all, no-delete, read-only"
|
||||
)
|
||||
|
||||
try:
|
||||
self.store = Store(url, levels=levels_config)
|
||||
self.store = Store(url, levels=levels_config, permissions=permissions)
|
||||
except StoreBackendError as e:
|
||||
raise Error(str(e))
|
||||
self.store_opened = False
|
||||
|
|
|
|||
138
src/borg/testsuite/archiver/restricted_permissions_test.py
Normal file
138
src/borg/testsuite/archiver/restricted_permissions_test.py
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
import os
|
||||
import pytest
|
||||
|
||||
from borgstore.backends.errors import PermissionDenied
|
||||
|
||||
from ...constants import * # NOQA
|
||||
from .. import changedir
|
||||
from . import cmd, create_test_files, RK_ENCRYPTION, generate_archiver_tests
|
||||
|
||||
pytest_generate_tests = lambda metafunc: generate_archiver_tests(metafunc, kinds="local") # NOQA
|
||||
|
||||
|
||||
def test_repository_permissions_all(archivers, request, monkeypatch):
|
||||
"""Test repository with 'all' permissions setting"""
|
||||
archiver = request.getfixturevalue(archivers)
|
||||
|
||||
# Create a repository with unrestricted permissions.
|
||||
monkeypatch.setenv("BORG_REPO_PERMISSIONS", "all")
|
||||
cmd(archiver, "repo-create", RK_ENCRYPTION)
|
||||
|
||||
create_test_files(archiver.input_path)
|
||||
cmd(archiver, "create", "archive1", "input")
|
||||
|
||||
# Verify the archive was created.
|
||||
assert "archive1" in cmd(archiver, "repo-list")
|
||||
|
||||
# Delete the archive to verify unrestricted permissions.
|
||||
cmd(archiver, "delete", "archive1")
|
||||
|
||||
# Verify the archive was deleted.
|
||||
assert "archive1" not in cmd(archiver, "repo-list")
|
||||
|
||||
# Delete the repository to verify unrestricted permissions.
|
||||
cmd(archiver, "repo-delete")
|
||||
|
||||
|
||||
def test_repository_permissions_no_delete(archivers, request, monkeypatch):
|
||||
"""Test repository with 'no-delete' permissions setting"""
|
||||
archiver = request.getfixturevalue(archivers)
|
||||
create_test_files(archiver.input_path)
|
||||
|
||||
# Create a repository first (need unrestricted permissions for that).
|
||||
monkeypatch.setenv("BORG_REPO_PERMISSIONS", "all")
|
||||
cmd(archiver, "repo-create", RK_ENCRYPTION)
|
||||
cmd(archiver, "create", "archive1", "input")
|
||||
cmd(archiver, "delete", "archive1") # this is so that compact has some chunk to remove
|
||||
|
||||
# Switch to no-delete permissions.
|
||||
monkeypatch.setenv("BORG_REPO_PERMISSIONS", "no-delete")
|
||||
|
||||
# Creating new archives should work.
|
||||
cmd(archiver, "create", "archive2", "input")
|
||||
|
||||
# Verify the archive was created.
|
||||
assert "archive2" in cmd(archiver, "repo-list")
|
||||
|
||||
# Try to delete the archive, which should fail.
|
||||
with pytest.raises(PermissionDenied):
|
||||
cmd(archiver, "delete", "archive2")
|
||||
|
||||
# Verify the archive still exists.
|
||||
assert "archive2" in cmd(archiver, "repo-list")
|
||||
|
||||
# Try to rename an archive, which should fail.
|
||||
with pytest.raises(PermissionDenied):
|
||||
cmd(archiver, "rename", "archive2", "archive3")
|
||||
|
||||
# Verify the archive still exists.
|
||||
assert "archive2" in cmd(archiver, "repo-list")
|
||||
|
||||
# Try to delete the repo, which should fail.
|
||||
with pytest.raises(PermissionDenied):
|
||||
cmd(archiver, "repo-delete")
|
||||
|
||||
# Verify the archive still exists.
|
||||
assert "archive2" in cmd(archiver, "repo-list")
|
||||
|
||||
# Try to compact the repo, which should fail.
|
||||
with pytest.raises(PermissionDenied):
|
||||
cmd(archiver, "compact")
|
||||
|
||||
# Check without --repair should work.
|
||||
cmd(archiver, "check")
|
||||
|
||||
# Try to check --repair, which should fail.
|
||||
with pytest.raises(PermissionDenied):
|
||||
cmd(archiver, "check", "--repair")
|
||||
|
||||
# Try to repo-compress (and change compression from lz4 to zstd), which should fail.
|
||||
# It fails because it needs to overwrite existing chunks, which is also disallowed by no-delete.
|
||||
with pytest.raises(PermissionDenied):
|
||||
cmd(archiver, "repo-compress", "-C", "zstd")
|
||||
|
||||
|
||||
def test_repository_permissions_read_only(archivers, request, monkeypatch):
|
||||
"""Test repository with 'read-only' permissions setting"""
|
||||
archiver = request.getfixturevalue(archivers)
|
||||
|
||||
# Create a repository first (need unrestricted permissions for that).
|
||||
monkeypatch.setenv("BORG_REPO_PERMISSIONS", "all")
|
||||
cmd(archiver, "repo-create", RK_ENCRYPTION)
|
||||
|
||||
# Create an archive to test with.
|
||||
create_test_files(archiver.input_path)
|
||||
cmd(archiver, "create", "archive2", "input")
|
||||
|
||||
# Switch to read-only permissions.
|
||||
monkeypatch.setenv("BORG_REPO_PERMISSIONS", "read-only")
|
||||
|
||||
# Verify we can list archives.
|
||||
assert "archive2" in cmd(archiver, "repo-list")
|
||||
|
||||
# Verify we can list files in an archive.
|
||||
assert "input/" in cmd(archiver, "list", "archive2")
|
||||
|
||||
# Extract the archive.
|
||||
with changedir("output"):
|
||||
cmd(archiver, "extract", "archive2")
|
||||
|
||||
# Verify extraction worked.
|
||||
extracted_files = os.listdir("output")
|
||||
assert len(extracted_files) > 0
|
||||
|
||||
# Try to create a new archive, which should fail.
|
||||
with pytest.raises(PermissionDenied):
|
||||
cmd(archiver, "create", "archive3", "input")
|
||||
|
||||
# Try to delete an archive, which should fail.
|
||||
with pytest.raises(PermissionDenied):
|
||||
cmd(archiver, "delete", "archive2")
|
||||
|
||||
# Try to delete the repo, which should fail.
|
||||
with pytest.raises(PermissionDenied):
|
||||
cmd(archiver, "repo-delete")
|
||||
|
||||
# Try to compact the repo, which should fail.
|
||||
with pytest.raises(PermissionDenied):
|
||||
cmd(archiver, "compact")
|
||||
Loading…
Reference in a new issue