forked from Georg/pyacl
Implement ACL building/writing
Add basic functionality for writing ACLs with user and group permissions to a file. Signed-off-by: Georg Pfuetzenreuter <mail@georg-pfuetzenreuter.net>
This commit is contained in:
parent
926b7e2c84
commit
18c3fefd1b
56
pyacl/acl.py
56
pyacl/acl.py
@ -8,7 +8,17 @@ An English copy of the Licence is shipped in a file called LICENSE along with th
|
||||
You may obtain copies of the Licence in any of the official languages at https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12.
|
||||
"""
|
||||
|
||||
import posix1e
|
||||
from pwd import getpwnam
|
||||
|
||||
from posix1e import (
|
||||
ACL,
|
||||
ACL_GROUP,
|
||||
ACL_GROUP_OBJ,
|
||||
ACL_MASK,
|
||||
ACL_OTHER,
|
||||
ACL_USER,
|
||||
ACL_USER_OBJ,
|
||||
)
|
||||
|
||||
DEFAULT_ENTRIES = [
|
||||
'u::rw-',
|
||||
@ -32,6 +42,15 @@ DEFAULT_ENTRYTYPES = [
|
||||
|
||||
MAX_PERMBITS = 3
|
||||
|
||||
LIBACL_TAGS = {
|
||||
'user': ACL_USER,
|
||||
'group': ACL_GROUP,
|
||||
'user_obj': ACL_USER_OBJ,
|
||||
'group_obj': ACL_GROUP_OBJ,
|
||||
'other': ACL_OTHER,
|
||||
'mask': ACL_MASK,
|
||||
}
|
||||
|
||||
|
||||
def reduce_entries(acl):
|
||||
entries = acl.to_any_text().decode().split()
|
||||
@ -108,8 +127,41 @@ def parse_entries(acl):
|
||||
return outmap
|
||||
|
||||
|
||||
def buildacl(target_name, target_type, read=False, write=False, execute=False):
|
||||
target_types = ['user', 'group']
|
||||
if target_type not in target_types or not isinstance(target_name, str):
|
||||
return ValueError('Invalid use of buildacl()')
|
||||
|
||||
myacl = ACL()
|
||||
mytags = [tag for tag in LIBACL_TAGS if tag == target_type or tag in [ltag for ltag in LIBACL_TAGS if ltag not in target_types]]
|
||||
|
||||
aclmap = {
|
||||
entry: myacl.append()
|
||||
for entry in mytags
|
||||
}
|
||||
|
||||
for entry, reference in aclmap.items():
|
||||
reference.tag_type = LIBACL_TAGS[entry]
|
||||
|
||||
aclmap[target_type].qualifier = getpwnam(target_name).pw_uid
|
||||
|
||||
for pentry in ['mask', target_type]:
|
||||
perms = aclmap[pentry].permset
|
||||
perms.read = read
|
||||
perms.write = write
|
||||
perms.execute = execute
|
||||
|
||||
return myacl
|
||||
|
||||
|
||||
def acltofile(acl, path):
|
||||
if acl.valid() is not True:
|
||||
return ValueError('ACL is not ready to be applied.')
|
||||
acl.applyto(path)
|
||||
|
||||
|
||||
def aclfromfile(path):
|
||||
return posix1e.ACL(file=path)
|
||||
return ACL(file=path)
|
||||
|
||||
|
||||
def entriesfromfile(path):
|
||||
|
@ -20,6 +20,7 @@ extend-select = [
|
||||
]
|
||||
ignore = [
|
||||
"E501", # line lengths
|
||||
"FBT002", # booleans as function arguments
|
||||
"S603", # https://github.com/astral-sh/ruff/issues/4045
|
||||
"S607", # makes subprocess calls in test suite more portable
|
||||
]
|
||||
@ -31,3 +32,6 @@ explicit-preview-rules = true
|
||||
|
||||
[lint.pydocstyle]
|
||||
convention = "pep257"
|
||||
|
||||
[lint.isort]
|
||||
force-wrap-aliases = true
|
||||
|
@ -14,9 +14,18 @@ from subprocess import run
|
||||
import pytest
|
||||
|
||||
|
||||
#@pytest.fixture(scope='session')
|
||||
@pytest.fixture
|
||||
def sample_file(tmp_path_factory, aclin):
|
||||
def sample_file(tmp_path_factory):
|
||||
directory = tmp_path_factory.mktemp('sample_files')
|
||||
file = directory / 'file_to_be_acled'
|
||||
file.touch()
|
||||
assert not file.read_text() # file should exist
|
||||
yield file
|
||||
rmtree(directory)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_file_with_acl(tmp_path_factory, aclin):
|
||||
directory = tmp_path_factory.mktemp('sample_files')
|
||||
file = directory / 'file_with_user_read_acl'
|
||||
file.touch()
|
||||
|
23
tests/matrix-apply.yaml
Normal file
23
tests/matrix-apply.yaml
Normal file
@ -0,0 +1,23 @@
|
||||
---
|
||||
user:user:r:
|
||||
args:
|
||||
target_name: user
|
||||
target_type: user
|
||||
read: true
|
||||
expect:
|
||||
user:
|
||||
user:
|
||||
read: true
|
||||
write: false
|
||||
execute: false
|
||||
group: &null_allfalse
|
||||
null:
|
||||
read: false
|
||||
write: false
|
||||
execute: false
|
||||
mask: &null_ro
|
||||
null:
|
||||
read: true
|
||||
write: false
|
||||
execute: false
|
||||
other: *null_allfalse
|
@ -24,6 +24,15 @@ def load_yaml(file):
|
||||
|
||||
|
||||
@mark.parametrize('aclin, aclout', load_yaml('matrix.yaml'))
|
||||
def test_parse_acl(sample_file, aclin, aclout):
|
||||
have = acl.parsefromfile(sample_file)
|
||||
def test_parse_acl(sample_file_with_acl, aclin, aclout):
|
||||
have = acl.parsefromfile(sample_file_with_acl)
|
||||
assert aclout == have
|
||||
|
||||
|
||||
@mark.parametrize('scenario, data', load_yaml('matrix-apply.yaml'))
|
||||
def test_build_and_apply_acl(sample_file, scenario, data):
|
||||
built_acl = acl.buildacl(**data['args'])
|
||||
assert len(list(built_acl)) == 5 # noqa PLR2004, this is the expected size of the built ACL
|
||||
assert acl.acltofile(built_acl, sample_file) is None
|
||||
read_acl = acl.parsefromfile(sample_file)
|
||||
assert read_acl == data['expect']
|
||||
|
Loading…
Reference in New Issue
Block a user