permissions: add permission configuration to packages.yaml (#8773)
Spack can now be configured to assign permissions to the files installed by a package. In the `packages.yaml` file under `permissions`, the attributes `read`, `write`, and `group` control the package permissions. These attributes can be set per-package, or for all packages under `all`. If permissions are set under `all` and for a specific package, the package-specific settings take precedence. The `read` and `write` attributes take one of `user`, `group`, and `world`. packages: all: permissions: write: group group: spack my_app: permissions: read: group group: my_team
This commit is contained in:
parent
91fbc59f22
commit
d1a5113cfe
10 changed files with 338 additions and 9 deletions
|
@ -40,4 +40,6 @@ packages:
|
||||||
szip: [libszip, libaec]
|
szip: [libszip, libaec]
|
||||||
tbb: [intel-tbb]
|
tbb: [intel-tbb]
|
||||||
unwind: [libunwind]
|
unwind: [libunwind]
|
||||||
|
permissions:
|
||||||
|
read: world
|
||||||
|
write: user
|
||||||
|
|
|
@ -166,3 +166,52 @@ The syntax for the ``provider`` section differs slightly from other
|
||||||
concretization rules. A provider lists a value that packages may
|
concretization rules. A provider lists a value that packages may
|
||||||
``depend_on`` (e.g, mpi) and a list of rules for fulfilling that
|
``depend_on`` (e.g, mpi) and a list of rules for fulfilling that
|
||||||
dependency.
|
dependency.
|
||||||
|
|
||||||
|
.. _package_permissions:
|
||||||
|
|
||||||
|
-------------------
|
||||||
|
Package Permissions
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Spack can be configured to assign permissions to the files installed
|
||||||
|
by a package.
|
||||||
|
|
||||||
|
In the ``packages.yaml`` file under ``permissions``, the attributes
|
||||||
|
``read``, ``write``, and ``group`` control the package
|
||||||
|
permissions. These attributes can be set per-package, or for all
|
||||||
|
packages under ``all``. If permissions are set under ``all`` and for a
|
||||||
|
specific package, the package-specific settings take precedence.
|
||||||
|
|
||||||
|
The ``read`` and ``write`` attributes take one of ``user``, ``group``,
|
||||||
|
and ``world``.
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
packages:
|
||||||
|
all:
|
||||||
|
permissions:
|
||||||
|
write: group
|
||||||
|
group: spack
|
||||||
|
my_app:
|
||||||
|
permissions:
|
||||||
|
read: group
|
||||||
|
group: my_team
|
||||||
|
|
||||||
|
The permissions settings describe the broadest level of access to
|
||||||
|
installations of the specified packages. The execute permissions of
|
||||||
|
the file are set to the same level as read permissions for those files
|
||||||
|
that are executable. The default setting for ``read`` is ``world``,
|
||||||
|
and for ``write`` is ``user``. In the example above, installations of
|
||||||
|
``my_app`` will be installed with user and group permissions but no
|
||||||
|
world permissions, and owned by the group ``my_team``. All other
|
||||||
|
packages will be installed with user and group write privileges, and
|
||||||
|
world read privileges. Those packages will be owned by the group
|
||||||
|
``spack``.
|
||||||
|
|
||||||
|
The ``group`` attribute assigns a unix-style group to a package. All
|
||||||
|
files installed by the package will be owned by the assigned group,
|
||||||
|
and the sticky group bit will be set on the install prefix and all
|
||||||
|
directories inside the install prefix. This will ensure that even
|
||||||
|
manually placed files within the install prefix are owned by the
|
||||||
|
assigned group. If no group is assigned, Spack will allow the OS
|
||||||
|
default behavior to go as expected.
|
||||||
|
|
|
@ -242,6 +242,25 @@ def group_ids(uid=None):
|
||||||
return [g.gr_gid for g in grp.getgrall() if user in g.gr_mem]
|
return [g.gr_gid for g in grp.getgrall() if user in g.gr_mem]
|
||||||
|
|
||||||
|
|
||||||
|
def chgrp(path, group):
|
||||||
|
"""Implement the bash chgrp function on a single path"""
|
||||||
|
gid = grp.getgrnam(group).gr_gid
|
||||||
|
os.chown(path, -1, gid)
|
||||||
|
|
||||||
|
|
||||||
|
def chmod_x(entry, perms):
|
||||||
|
"""Implements chmod, treating all executable bits as set using the chmod
|
||||||
|
utility's `+X` option.
|
||||||
|
"""
|
||||||
|
mode = os.stat(entry).st_mode
|
||||||
|
if os.path.isfile(entry):
|
||||||
|
if not mode & (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH):
|
||||||
|
perms &= ~stat.S_IXUSR
|
||||||
|
perms &= ~stat.S_IXGRP
|
||||||
|
perms &= ~stat.S_IXOTH
|
||||||
|
os.chmod(entry, perms)
|
||||||
|
|
||||||
|
|
||||||
def copy_mode(src, dest):
|
def copy_mode(src, dest):
|
||||||
"""Set the mode of dest to that of src unless it is a link.
|
"""Set the mode of dest to that of src unless it is a link.
|
||||||
"""
|
"""
|
||||||
|
@ -413,12 +432,14 @@ def get_filetype(path_name):
|
||||||
return output.strip()
|
return output.strip()
|
||||||
|
|
||||||
|
|
||||||
def mkdirp(*paths):
|
def mkdirp(*paths, **kwargs):
|
||||||
"""Creates a directory, as well as parent directories if needed."""
|
"""Creates a directory, as well as parent directories if needed."""
|
||||||
|
mode = kwargs.get('mode', stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
|
||||||
for path in paths:
|
for path in paths:
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
try:
|
try:
|
||||||
os.makedirs(path)
|
os.makedirs(path, mode)
|
||||||
|
os.chmod(path, mode) # For systems that ignore makedirs mode
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
if e.errno != errno.EEXIST or not os.path.isdir(path):
|
if e.errno != errno.EEXIST or not os.path.isdir(path):
|
||||||
raise e
|
raise e
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
|
|
||||||
import ruamel.yaml as yaml
|
import ruamel.yaml as yaml
|
||||||
|
|
||||||
from llnl.util.filesystem import mkdirp
|
from llnl.util.filesystem import mkdirp, chgrp
|
||||||
|
|
||||||
import spack.config
|
import spack.config
|
||||||
import spack.spec
|
import spack.spec
|
||||||
|
@ -263,7 +263,19 @@ def create_install_directory(self, spec):
|
||||||
if prefix:
|
if prefix:
|
||||||
raise InstallDirectoryAlreadyExistsError(prefix)
|
raise InstallDirectoryAlreadyExistsError(prefix)
|
||||||
|
|
||||||
mkdirp(self.metadata_path(spec))
|
# Create install directory with properly configured permissions
|
||||||
|
# Cannot import at top of file
|
||||||
|
from spack.package_prefs import get_package_dir_permissions
|
||||||
|
from spack.package_prefs import get_package_group
|
||||||
|
group = get_package_group(spec)
|
||||||
|
perms = get_package_dir_permissions(spec)
|
||||||
|
mkdirp(spec.prefix, mode=perms)
|
||||||
|
if group:
|
||||||
|
chgrp(spec.prefix, group)
|
||||||
|
# Need to reset the sticky group bit after chgrp
|
||||||
|
os.chmod(spec.prefix, perms)
|
||||||
|
|
||||||
|
mkdirp(self.metadata_path(spec), mode=perms)
|
||||||
self.write_spec(spec, self.spec_file_path(spec))
|
self.write_spec(spec, self.spec_file_path(spec))
|
||||||
|
|
||||||
def check_installed(self, spec):
|
def check_installed(self, spec):
|
||||||
|
|
64
lib/spack/spack/hooks/permissions_setters.py
Normal file
64
lib/spack/spack/hooks/permissions_setters.py
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
##############################################################################
|
||||||
|
# Copyright (c) 2013-2018, Lawrence Livermore National Security, LLC.
|
||||||
|
# Produced at the Lawrence Livermore National Laboratory.
|
||||||
|
#
|
||||||
|
# This file is part of Spack.
|
||||||
|
# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
|
||||||
|
# LLNL-CODE-647188
|
||||||
|
#
|
||||||
|
# For details, see https://github.com/spack/spack
|
||||||
|
# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License (as
|
||||||
|
# published by the Free Software Foundation) version 2.1, February 1999.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but
|
||||||
|
# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
|
||||||
|
# conditions of the GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
##############################################################################
|
||||||
|
import os
|
||||||
|
|
||||||
|
from llnl.util.filesystem import chmod_x, chgrp
|
||||||
|
|
||||||
|
from spack.package_prefs import get_package_permissions, get_package_group
|
||||||
|
from spack.package_prefs import get_package_dir_permissions
|
||||||
|
|
||||||
|
|
||||||
|
def forall_files(path, fn, args, dir_args=None):
|
||||||
|
"""Apply function to all files in directory, with file as first arg.
|
||||||
|
|
||||||
|
Does not apply to the root dir. Does not apply to links"""
|
||||||
|
for root, dirs, files in os.walk(path):
|
||||||
|
for d in dirs:
|
||||||
|
if not os.path.islink(os.path.join(root, d)):
|
||||||
|
if dir_args:
|
||||||
|
fn(os.path.join(root, d), *dir_args)
|
||||||
|
else:
|
||||||
|
fn(os.path.join(root, d), *args)
|
||||||
|
for f in files:
|
||||||
|
if not os.path.islink(os.path.join(root, d)):
|
||||||
|
fn(os.path.join(root, f), *args)
|
||||||
|
|
||||||
|
|
||||||
|
def chmod_real_entries(path, perms):
|
||||||
|
# Don't follow links so we don't change things outside the prefix
|
||||||
|
if not os.path.islink(path):
|
||||||
|
chmod_x(path, perms)
|
||||||
|
|
||||||
|
|
||||||
|
def post_install(spec):
|
||||||
|
if not spec.external:
|
||||||
|
perms = get_package_permissions(spec)
|
||||||
|
dir_perms = get_package_dir_permissions(spec)
|
||||||
|
group = get_package_group(spec)
|
||||||
|
|
||||||
|
forall_files(spec.prefix, chmod_real_entries, [perms], [dir_perms])
|
||||||
|
|
||||||
|
if group:
|
||||||
|
forall_files(spec.prefix, chgrp, [group])
|
|
@ -66,7 +66,7 @@
|
||||||
import spack.multimethod
|
import spack.multimethod
|
||||||
import spack.binary_distribution as binary_distribution
|
import spack.binary_distribution as binary_distribution
|
||||||
|
|
||||||
from llnl.util.filesystem import mkdirp, touch
|
from llnl.util.filesystem import mkdirp, touch, chgrp
|
||||||
from llnl.util.filesystem import working_dir, install_tree, install
|
from llnl.util.filesystem import working_dir, install_tree, install
|
||||||
from llnl.util.lang import memoized
|
from llnl.util.lang import memoized
|
||||||
from llnl.util.link_tree import LinkTree
|
from llnl.util.link_tree import LinkTree
|
||||||
|
@ -78,6 +78,7 @@
|
||||||
from spack.util.environment import dump_environment
|
from spack.util.environment import dump_environment
|
||||||
from spack.util.package_hash import package_hash
|
from spack.util.package_hash import package_hash
|
||||||
from spack.version import Version
|
from spack.version import Version
|
||||||
|
from spack.package_prefs import get_package_dir_permissions, get_package_group
|
||||||
|
|
||||||
"""Allowed URL schemes for spack packages."""
|
"""Allowed URL schemes for spack packages."""
|
||||||
_ALLOWED_URL_SCHEMES = ["http", "https", "ftp", "file", "git"]
|
_ALLOWED_URL_SCHEMES = ["http", "https", "ftp", "file", "git"]
|
||||||
|
@ -1527,6 +1528,18 @@ def build_process():
|
||||||
# Create the install prefix and fork the build process.
|
# Create the install prefix and fork the build process.
|
||||||
if not os.path.exists(self.prefix):
|
if not os.path.exists(self.prefix):
|
||||||
spack.store.layout.create_install_directory(self.spec)
|
spack.store.layout.create_install_directory(self.spec)
|
||||||
|
else:
|
||||||
|
# Set the proper group for the prefix
|
||||||
|
group = get_package_group(self.spec)
|
||||||
|
if group:
|
||||||
|
chgrp(self.prefix, group)
|
||||||
|
# Set the proper permissions.
|
||||||
|
# This has to be done after group because changing groups blows
|
||||||
|
# away the sticky group bit on the directory
|
||||||
|
mode = os.stat(self.prefix).st_mode
|
||||||
|
perms = get_package_dir_permissions(self.spec)
|
||||||
|
if mode != perms:
|
||||||
|
os.chmod(self.prefix, perms)
|
||||||
|
|
||||||
# Fork a child to do the actual installation
|
# Fork a child to do the actual installation
|
||||||
# we preserve verbosity settings across installs.
|
# we preserve verbosity settings across installs.
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
# License along with this program; if not, write to the Free Software
|
# License along with this program; if not, write to the Free Software
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
import stat
|
||||||
from six import string_types
|
from six import string_types
|
||||||
from six import iteritems
|
from six import iteritems
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@
|
||||||
import spack.error
|
import spack.error
|
||||||
from spack.util.path import canonicalize_path
|
from spack.util.path import canonicalize_path
|
||||||
from spack.version import VersionList
|
from spack.version import VersionList
|
||||||
|
from spack.config import ConfigError
|
||||||
|
|
||||||
_lesser_spec_types = {'compiler': spack.spec.CompilerSpec,
|
_lesser_spec_types = {'compiler': spack.spec.CompilerSpec,
|
||||||
'version': VersionList}
|
'version': VersionList}
|
||||||
|
@ -252,5 +253,79 @@ def is_spec_buildable(spec):
|
||||||
return allpkgs[spec.name]['buildable']
|
return allpkgs[spec.name]['buildable']
|
||||||
|
|
||||||
|
|
||||||
|
def get_package_dir_permissions(spec):
|
||||||
|
"""Return the permissions configured for the spec.
|
||||||
|
|
||||||
|
Include the GID bit if group permissions are on. This makes the group
|
||||||
|
attribute sticky for the directory. Package-specific settings take
|
||||||
|
precedent over settings for ``all``"""
|
||||||
|
perms = get_package_permissions(spec)
|
||||||
|
if perms & stat.S_IRWXG:
|
||||||
|
perms |= stat.S_ISGID
|
||||||
|
return perms
|
||||||
|
|
||||||
|
|
||||||
|
def get_package_permissions(spec):
|
||||||
|
"""Return the permissions configured for the spec.
|
||||||
|
|
||||||
|
Package-specific settings take precedence over settings for ``all``"""
|
||||||
|
|
||||||
|
# Get read permissions level
|
||||||
|
for name in (spec.name, 'all'):
|
||||||
|
try:
|
||||||
|
readable = spack.config.get('packages:%s:permissions:read' % name,
|
||||||
|
'')
|
||||||
|
if readable:
|
||||||
|
break
|
||||||
|
except AttributeError:
|
||||||
|
readable = 'world'
|
||||||
|
|
||||||
|
# Get write permissions level
|
||||||
|
for name in (spec.name, 'all'):
|
||||||
|
try:
|
||||||
|
writable = spack.config.get('packages:%s:permissions:write' % name,
|
||||||
|
'')
|
||||||
|
if writable:
|
||||||
|
break
|
||||||
|
except AttributeError:
|
||||||
|
writable = 'user'
|
||||||
|
|
||||||
|
perms = stat.S_IRWXU
|
||||||
|
if readable in ('world', 'group'): # world includes group
|
||||||
|
perms |= stat.S_IRGRP | stat.S_IXGRP
|
||||||
|
if readable == 'world':
|
||||||
|
perms |= stat.S_IROTH | stat.S_IXOTH
|
||||||
|
|
||||||
|
if writable in ('world', 'group'):
|
||||||
|
if readable == 'user':
|
||||||
|
raise ConfigError('Writable permissions may not be more' +
|
||||||
|
' permissive than readable permissions.\n' +
|
||||||
|
' Violating package is %s' % spec.name)
|
||||||
|
perms |= stat.S_IWGRP
|
||||||
|
if writable == 'world':
|
||||||
|
if readable != 'world':
|
||||||
|
raise ConfigError('Writable permissions may not be more' +
|
||||||
|
' permissive than readable permissions.\n' +
|
||||||
|
' Violating package is %s' % spec.name)
|
||||||
|
perms |= stat.S_IWOTH
|
||||||
|
|
||||||
|
return perms
|
||||||
|
|
||||||
|
|
||||||
|
def get_package_group(spec):
|
||||||
|
"""Return the unix group associated with the spec.
|
||||||
|
|
||||||
|
Package-specific settings take precedence over settings for ``all``"""
|
||||||
|
for name in (spec.name, 'all'):
|
||||||
|
try:
|
||||||
|
group = spack.config.get('packages:%s:permissions:group' % name,
|
||||||
|
'')
|
||||||
|
if group:
|
||||||
|
break
|
||||||
|
except AttributeError:
|
||||||
|
group = ''
|
||||||
|
return group
|
||||||
|
|
||||||
|
|
||||||
class VirtualInPackagesYAMLError(spack.error.SpackError):
|
class VirtualInPackagesYAMLError(spack.error.SpackError):
|
||||||
"""Raised when a disallowed virtual is found in packages.yaml"""
|
"""Raised when a disallowed virtual is found in packages.yaml"""
|
||||||
|
|
|
@ -59,6 +59,23 @@
|
||||||
'type': 'boolean',
|
'type': 'boolean',
|
||||||
'default': True,
|
'default': True,
|
||||||
},
|
},
|
||||||
|
'permissions': {
|
||||||
|
'type': 'object',
|
||||||
|
'additionalProperties': False,
|
||||||
|
'properties': {
|
||||||
|
'read': {
|
||||||
|
'type': 'string',
|
||||||
|
'enum': ['user', 'group', 'world'],
|
||||||
|
},
|
||||||
|
'write': {
|
||||||
|
'type': 'string',
|
||||||
|
'enum': ['user', 'group', 'world'],
|
||||||
|
},
|
||||||
|
'group': {
|
||||||
|
'type': 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
'modules': {
|
'modules': {
|
||||||
'type': 'object',
|
'type': 'object',
|
||||||
'default': {},
|
'default': {},
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
##############################################################################
|
##############################################################################
|
||||||
import os
|
import os
|
||||||
|
import stat
|
||||||
import sys
|
import sys
|
||||||
import errno
|
import errno
|
||||||
import hashlib
|
import hashlib
|
||||||
|
@ -488,11 +489,13 @@ def create(self):
|
||||||
if self._need_to_create_path():
|
if self._need_to_create_path():
|
||||||
tmp_root = get_tmp_root()
|
tmp_root = get_tmp_root()
|
||||||
if tmp_root is not None:
|
if tmp_root is not None:
|
||||||
|
# tempfile.mkdtemp already sets mode 0700
|
||||||
tmp_dir = tempfile.mkdtemp('', _stage_prefix, tmp_root)
|
tmp_dir = tempfile.mkdtemp('', _stage_prefix, tmp_root)
|
||||||
tty.debug('link %s -> %s' % (self.path, tmp_dir))
|
tty.debug('link %s -> %s' % (self.path, tmp_dir))
|
||||||
os.symlink(tmp_dir, self.path)
|
os.symlink(tmp_dir, self.path)
|
||||||
else:
|
else:
|
||||||
mkdirp(self.path)
|
# emulate file permissions for tempfile.mkdtemp
|
||||||
|
mkdirp(self.path, mode=stat.S_IRWXU)
|
||||||
# Make sure we can actually do something with the stage we made.
|
# Make sure we can actually do something with the stage we made.
|
||||||
ensure_access(self.path)
|
ensure_access(self.path)
|
||||||
self.created = True
|
self.created = True
|
||||||
|
|
|
@ -23,11 +23,12 @@
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
##############################################################################
|
##############################################################################
|
||||||
import pytest
|
import pytest
|
||||||
|
import stat
|
||||||
|
|
||||||
import spack.package_prefs
|
import spack.package_prefs
|
||||||
import spack.repo
|
import spack.repo
|
||||||
import spack.util.spack_yaml as syaml
|
import spack.util.spack_yaml as syaml
|
||||||
from spack.config import ConfigScope
|
from spack.config import ConfigScope, ConfigError
|
||||||
from spack.spec import Spec
|
from spack.spec import Spec
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,6 +46,31 @@ def concretize_scope(config, tmpdir):
|
||||||
spack.repo.path._provider_index = None
|
spack.repo.path._provider_index = None
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def configure_permissions():
|
||||||
|
conf = syaml.load("""\
|
||||||
|
all:
|
||||||
|
permissions:
|
||||||
|
read: group
|
||||||
|
write: group
|
||||||
|
group: all
|
||||||
|
mpich:
|
||||||
|
permissions:
|
||||||
|
read: user
|
||||||
|
write: user
|
||||||
|
mpileaks:
|
||||||
|
permissions:
|
||||||
|
write: user
|
||||||
|
group: mpileaks
|
||||||
|
callpath:
|
||||||
|
permissions:
|
||||||
|
write: world
|
||||||
|
""")
|
||||||
|
spack.config.set('packages', conf, scope='concretize')
|
||||||
|
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
def concretize(abstract_spec):
|
def concretize(abstract_spec):
|
||||||
return Spec(abstract_spec).concretized()
|
return Spec(abstract_spec).concretized()
|
||||||
|
|
||||||
|
@ -174,3 +200,50 @@ def test_external_mpi(self):
|
||||||
spec = Spec('mpi')
|
spec = Spec('mpi')
|
||||||
spec.concretize()
|
spec.concretize()
|
||||||
assert spec['mpich'].external_path == '/dummy/path'
|
assert spec['mpich'].external_path == '/dummy/path'
|
||||||
|
|
||||||
|
def test_config_permissions_from_all(self, configure_permissions):
|
||||||
|
# Although these aren't strictly about concretization, they are
|
||||||
|
# configured in the same file and therefore convenient to test here.
|
||||||
|
# Make sure we can configure readable and writable
|
||||||
|
|
||||||
|
# Test inheriting from 'all'
|
||||||
|
spec = Spec('zmpi')
|
||||||
|
perms = spack.package_prefs.get_package_permissions(spec)
|
||||||
|
assert perms == stat.S_IRWXU | stat.S_IRWXG
|
||||||
|
|
||||||
|
dir_perms = spack.package_prefs.get_package_dir_permissions(spec)
|
||||||
|
assert dir_perms == stat.S_IRWXU | stat.S_IRWXG | stat.S_ISGID
|
||||||
|
|
||||||
|
group = spack.package_prefs.get_package_group(spec)
|
||||||
|
assert group == 'all'
|
||||||
|
|
||||||
|
def test_config_permissions_from_package(self, configure_permissions):
|
||||||
|
# Test overriding 'all'
|
||||||
|
spec = Spec('mpich')
|
||||||
|
perms = spack.package_prefs.get_package_permissions(spec)
|
||||||
|
assert perms == stat.S_IRWXU
|
||||||
|
|
||||||
|
dir_perms = spack.package_prefs.get_package_dir_permissions(spec)
|
||||||
|
assert dir_perms == stat.S_IRWXU
|
||||||
|
|
||||||
|
group = spack.package_prefs.get_package_group(spec)
|
||||||
|
assert group == 'all'
|
||||||
|
|
||||||
|
def test_config_permissions_differ_read_write(self, configure_permissions):
|
||||||
|
# Test overriding group from 'all' and different readable/writable
|
||||||
|
spec = Spec('mpileaks')
|
||||||
|
perms = spack.package_prefs.get_package_permissions(spec)
|
||||||
|
assert perms == stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP
|
||||||
|
|
||||||
|
dir_perms = spack.package_prefs.get_package_dir_permissions(spec)
|
||||||
|
expected = stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_ISGID
|
||||||
|
assert dir_perms == expected
|
||||||
|
|
||||||
|
group = spack.package_prefs.get_package_group(spec)
|
||||||
|
assert group == 'mpileaks'
|
||||||
|
|
||||||
|
def test_config_perms_fail_write_gt_read(self, configure_permissions):
|
||||||
|
# Test failure for writable more permissive than readable
|
||||||
|
spec = Spec('callpath')
|
||||||
|
with pytest.raises(ConfigError):
|
||||||
|
spack.package_prefs.get_package_permissions(spec)
|
||||||
|
|
Loading…
Reference in a new issue