Merge branch 'cboltz-profile-list' into 'master'

Replace "existing_profiles" & fix minitools for named profiles

See merge request apparmor/apparmor!249

Acked-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
Christian Boltz 2018-11-11 13:17:00 +00:00
commit 273e45a4af
8 changed files with 297 additions and 55 deletions

View file

@ -107,7 +107,7 @@ apparmor.check_qualifiers(program)
apparmor.loadincludes()
profile_filename = apparmor.get_profile_filename(program)
profile_filename = apparmor.get_profile_filename_from_attachment(program, True)
if os.path.exists(profile_filename):
apparmor.helpers[program] = apparmor.get_profile_flags(profile_filename, program)
else:

View file

@ -1,7 +1,7 @@
#! /usr/bin/python3
# ----------------------------------------------------------------------
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
# Copyright (C) 2014-2017 Christian Boltz <apparmor@cboltz.de>
# Copyright (C) 2014-2018 Christian Boltz <apparmor@cboltz.de>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public
@ -57,7 +57,7 @@ def reset_aa():
apparmor.aa.aa = apparmor.aa.hasher()
apparmor.aa.filelist = apparmor.aa.hasher()
apparmor.aa.include = dict()
apparmor.aa.existing_profiles = apparmor.aa.hasher()
apparmor.aa.active_profiles = apparmor.aa.ProfileList()
apparmor.aa.original_aa = apparmor.aa.hasher()
def find_profiles_from_files(files):
@ -75,7 +75,7 @@ def find_files_from_profiles(profiles):
apparmor.aa.read_profiles()
for profile_name in profiles:
profile_to_filename[profile_name] = apparmor.aa.get_profile_filename(profile_name)
profile_to_filename[profile_name] = apparmor.aa.get_profile_filename_from_profile_name(profile_name, True)
reset_aa()

View file

@ -1,6 +1,6 @@
# ----------------------------------------------------------------------
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
# Copyright (C) 2014-2017 Christian Boltz <apparmor@cboltz.de>
# Copyright (C) 2014-2018 Christian Boltz <apparmor@cboltz.de>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public
@ -49,6 +49,8 @@ from apparmor.regex import (RE_PROFILE_START, RE_PROFILE_END, RE_PROFILE_LINK,
RE_PROFILE_UNIX, RE_RULE_HAS_COMMA, RE_HAS_COMMENT_SPLIT,
strip_quotes, parse_profile_start_line, re_match_include )
from apparmor.profile_list import ProfileList
from apparmor.profile_storage import (ProfileStorage, add_or_remove_flag, ruletypes, write_alias,
write_abi, write_includes, write_list_vars )
@ -89,7 +91,8 @@ extra_profile_dir = None
# To keep track of previously included profile fragments
include = dict()
existing_profiles = dict()
active_profiles = ProfileList()
extra_profiles = ProfileList()
# To store the globs entered by users so they can be provided again
# format: user_globs['/foo*'] = AARE('/foo*')
@ -217,11 +220,29 @@ def find_executable(bin_path):
return full_bin
return None
def get_profile_filename(profile):
"""Returns the full profile name"""
if existing_profiles.get(profile, False):
return existing_profiles[profile]
elif profile.startswith('/'):
def get_profile_filename_from_profile_name(profile, get_new=False):
"""Returns the full profile name for the given profile name"""
filename = active_profiles.filename_from_profile_name(profile)
if filename:
return filename
if get_new:
return get_new_profile_filename(profile)
def get_profile_filename_from_attachment(profile, get_new=False):
"""Returns the full profile name for the given attachment"""
filename = active_profiles.filename_from_attachment(profile)
if filename:
return filename
if get_new:
return get_new_profile_filename(profile)
def get_new_profile_filename(profile):
'''Compose filename for a new profile'''
if profile.startswith('/'):
# Remove leading /
profile = profile[1:]
else:
@ -238,7 +259,7 @@ def name_to_prof_filename(prof_filename):
else:
bin_path = find_executable(prof_filename)
if bin_path:
prof_filename = get_profile_filename(bin_path)
prof_filename = get_profile_filename_from_attachment(bin_path, True)
if os.path.isfile(prof_filename):
return (prof_filename, bin_path)
@ -464,7 +485,7 @@ def create_new_profile(localfile, is_stub=False):
def delete_profile(local_prof):
"""Deletes the specified file from the disk and remove it from our list"""
profile_file = get_profile_filename(local_prof)
profile_file = get_profile_filename_from_profile_name(local_prof, True)
if os.path.isfile(profile_file):
os.remove(profile_file)
if aa.get(local_prof, False):
@ -504,7 +525,8 @@ def get_profile(prof_name):
profile_hash[uname]['profile'] = serialize_profile(inactive_profile[prof_name], prof_name, {})
profile_hash[uname]['profile_data'] = inactive_profile
existing_profiles.pop(prof_name) # remove profile filename from list to force storing in /etc/apparmor.d/ instead of extra_profile_dir
# no longer necessary after splitting active and extra profiles
# existing_profiles.pop(prof_name) # remove profile filename from list to force storing in /etc/apparmor.d/ instead of extra_profile_dir
# If no profiles in repo and no inactive profiles
if not profile_hash.keys():
@ -560,7 +582,7 @@ def activate_repo_profiles(url, profiles, complain):
attach_profile_data(aa, profile_data)
write_profile(pname)
if complain:
fname = get_profile_filename(pname)
fname = get_profile_filename_from_profile_name(pname, True)
change_profile_flags(profile_dir + fname, None, 'complain', True)
aaui.UI_Info(_('Setting %s to complain mode.') % pname)
except Exception as e:
@ -592,7 +614,7 @@ def autodep(bin_name, pname=''):
# Create a new profile if no existing profile
if not profile_data:
profile_data = create_new_profile(pname)
file = get_profile_filename(pname)
file = get_profile_filename_from_profile_name(pname, True)
profile_data[pname][pname]['filename'] = None # will be stored in /etc/apparmor.d when saving, so it shouldn't carry the extra_profile_dir filename
attach_profile_data(aa, profile_data)
attach_profile_data(original_aa, profile_data)
@ -692,15 +714,16 @@ def profile_exists(program):
"""Returns True if profile exists, False otherwise"""
# Check cache of profiles
if existing_profiles.get(program, False):
if active_profiles.filename_from_attachment(program):
return True
# Check the disk for profile
prof_path = get_profile_filename(program)
prof_path = get_profile_filename_from_attachment(program, True)
#print(prof_path)
if os.path.isfile(prof_path):
# Add to cache of profile
existing_profiles[program] = prof_path
return True
raise AppArmorBug('Reached strange condition in profile_exists(), please open a bugreport!')
# active_profiles[program] = prof_path
# return True
return False
def sync_profile():
@ -1088,9 +1111,9 @@ def handle_children(profile, hat, root):
options += 'd'
# Define the default option
default = None
if 'p' in options and os.path.exists(get_profile_filename(exec_target)):
if 'p' in options and os.path.exists(get_profile_filename_from_attachment(exec_target, True)):
default = 'CMD_px'
sys.stdout.write(_('Target profile exists: %s\n') % get_profile_filename(exec_target))
sys.stdout.write(_('Target profile exists: %s\n') % get_profile_filename_from_attachment(exec_target, True))
elif 'i' in options:
default = 'CMD_ix'
elif 'c' in options:
@ -1104,7 +1127,7 @@ def handle_children(profile, hat, root):
parent_uses_ld_xxx = check_for_LD_XXX(profile)
sev_db.unload_variables()
sev_db.load_variables(get_profile_filename(profile))
sev_db.load_variables(get_profile_filename_from_profile_name(profile, True))
severity = sev_db.rank_path(exec_target, 'x')
# Prompt portion starts
@ -1228,7 +1251,7 @@ def handle_children(profile, hat, root):
profile_changes[pid] = '%s' % profile
# Check profile exists for px
if not os.path.exists(get_profile_filename(exec_target)):
if not os.path.exists(get_profile_filename_from_attachment(exec_target, True)):
ynans = 'y'
if 'i' in exec_mode:
ynans = aaui.UI_YesNo(_('A profile for %s does not exist.\nDo you want to create one?') % exec_target, 'n')
@ -1362,7 +1385,7 @@ def ask_the_questions(log_dict):
UI_SelectUpdatedRepoProfile(profile, p)
sev_db.unload_variables()
sev_db.load_variables(get_profile_filename(profile))
sev_db.load_variables(get_profile_filename_from_profile_name(profile, True))
# Sorted list of hats with the profile name coming first
hats = list(filter(lambda key: key != profile, sorted(log_dict[aamode][profile].keys())))
@ -1769,7 +1792,7 @@ def set_logfile(filename):
def do_logprof_pass(logmark='', passno=0, log_pid=log_pid):
# set up variables for this pass
# transitions = hasher()
global existing_profiles
global active_profiles
global sev_db
# aa = hasher()
# profile_changes = hasher()
@ -1786,13 +1809,13 @@ def do_logprof_pass(logmark='', passno=0, log_pid=log_pid):
if not sev_db:
sev_db = apparmor.severity.Severity(CONFDIR + '/severity.db', _('unknown'))
#print(pid)
#print(existing_profiles)
#print(active_profiles)
##if not repo_cf and cfg['repostory']['url']:
## repo_cfg = read_config('repository.conf')
## if not repo_cfg['repository'].get('enabled', False) or repo_cfg['repository]['enabled'] not in ['yes', 'no']:
## UI_ask_to_enable_repo()
log_reader = apparmor.logparser.ReadLog(log_pid, logfile, existing_profiles, profile_dir)
log_reader = apparmor.logparser.ReadLog(log_pid, logfile, active_profiles, profile_dir)
log = log_reader.read_log(logmark)
#read_log(logmark)
@ -1867,7 +1890,7 @@ def save_profiles():
if aa[which][which].get('filename', False):
oldprofile = aa[which][which]['filename']
else:
oldprofile = get_profile_filename(which)
oldprofile = get_profile_filename_from_attachment(which, True)
serialize_options = {'METADATA': True}
newprofile = serialize_profile(aa[which], which, serialize_options)
@ -2082,9 +2105,29 @@ def read_profile(file, active_profile):
if profile_data and active_profile:
attach_profile_data(aa, profile_data)
attach_profile_data(original_aa, profile_data)
for profile in profile_data: # TODO: also honor hats
name = profile_data[profile][profile]['name']
attachment = profile_data[profile][profile]['attachment']
filename = profile_data[profile][profile]['filename']
if not attachment and name.startswith('/'):
active_profiles.add(filename, name, name) # use name as name and attachment
else:
active_profiles.add(filename, name, attachment)
elif profile_data:
attach_profile_data(extras, profile_data)
for profile in profile_data: # TODO: also honor hats
name = profile_data[profile][profile]['name']
attachment = profile_data[profile][profile]['attachment']
filename = profile_data[profile][profile]['filename']
if not attachment and name.startswith('/'):
extra_profiles.add(filename, name, name) # use name as name and attachment
else:
extra_profiles.add(filename, name, attachment)
def attach_profile_data(profiles, profile_data):
# Make deep copy of data to avoid changes to
@ -2176,9 +2219,6 @@ def parse_profile_data(data, file, do_include):
if pps_set_hat_external:
profile_data[profile][hat]['external'] = True
# Profile stored
existing_profiles[profile] = file
# save profile name and filename
profile_data[profile][hat]['name'] = profile
profile_data[profile][hat]['filename'] = file
@ -2677,7 +2717,11 @@ def serialize_profile(profile_data, name, options):
# comment.replace('\\n', '\n')
# string += comment + '\n'
prof_filename = get_profile_filename(name)
if options.get('is_attachment'):
prof_filename = get_profile_filename_from_attachment(name, True)
else:
prof_filename = get_profile_filename_from_profile_name(name, True)
if filelist.get(prof_filename, False):
data += write_abi(filelist[prof_filename], 0)
data += write_alias(filelist[prof_filename], 0)
@ -2703,16 +2747,18 @@ def serialize_profile(profile_data, name, options):
return string + '\n'
def write_profile_ui_feedback(profile):
def write_profile_ui_feedback(profile, is_attachment=False):
aaui.UI_Info(_('Writing updated profile for %s.') % profile)
write_profile(profile)
write_profile(profile, is_attachment)
def write_profile(profile):
def write_profile(profile, is_attachment=False):
prof_filename = None
if aa[profile][profile].get('filename', False):
prof_filename = aa[profile][profile]['filename']
elif is_attachment:
prof_filename = get_profile_filename_from_attachment(profile, True)
else:
prof_filename = get_profile_filename(profile)
prof_filename = get_profile_filename_from_profile_name(profile, True)
newprof = tempfile.NamedTemporaryFile('w', suffix='~', delete=False, dir=profile_dir)
if os.path.exists(prof_filename):
@ -2722,7 +2768,7 @@ def write_profile(profile):
#os.chmod(newprof.name, permission_600)
pass
serialize_options = {'METADATA': True}
serialize_options = {'METADATA': True, 'is_attachment': is_attachment}
profile_string = serialize_profile(aa[profile], profile, serialize_options)
newprof.write(profile_string)
@ -2844,7 +2890,7 @@ def reload_base(bin_path):
if not check_for_apparmor():
return None
prof_filename = get_profile_filename(bin_path)
prof_filename = get_profile_filename_from_profile_name(bin_path, True)
# XXX use reload_profile() from tools.py instead (and don't hide output in /dev/null)
subprocess.call("cat '%s' | %s -I%s -r >/dev/null 2>&1" % (prof_filename, parser, profile_dir), shell=True)

View file

@ -1,6 +1,6 @@
# ----------------------------------------------------------------------
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
# Copyright (C) 2015-2016 Christian Boltz <apparmor@cboltz.de>
# Copyright (C) 2015-2018 Christian Boltz <apparmor@cboltz.de>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public
@ -44,11 +44,11 @@ class ReadLog:
# used to pre-filter log lines so that we hand over only relevant lines to LibAppArmor parsing
RE_LOG_ALL = re.compile('(' + '|'.join(RE_log_parts) + ')')
def __init__(self, pid, filename, existing_profiles, profile_dir):
def __init__(self, pid, filename, active_profiles, profile_dir):
self.filename = filename
self.profile_dir = profile_dir
self.pid = pid
self.existing_profiles = existing_profiles
self.active_profiles = active_profiles
self.log = []
self.debug_logger = DebugLogger('ReadLog')
self.LOG = None
@ -447,15 +447,16 @@ class ReadLog:
def profile_exists(self, program):
"""Returns True if profile exists, False otherwise"""
# Check cache of profiles
if self.existing_profiles.get(program, False):
if self.active_profiles.filename_from_profile_name(program):
return True
# Check the disk for profile
prof_path = self.get_profile_filename(program)
#print(prof_path)
if os.path.isfile(prof_path):
# Add to cache of profile
self.existing_profiles[program] = prof_path
return True
raise AppArmorBug('This should never happen, please open a bugreport!')
# self.active_profiles[program] = prof_path
# return True
return False
def get_profile_filename(self, profile):

View file

@ -0,0 +1,73 @@
# ----------------------------------------------------------------------
# Copyright (C) 2018 Christian Boltz <apparmor@cboltz.de>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public
# License as published by the Free Software Foundation.
#
# 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
# GNU General Public License for more details.
#
# ----------------------------------------------------------------------
from apparmor.aare import AARE
from apparmor.common import AppArmorBug, AppArmorException
# setup module translations
from apparmor.translations import init_translation
_ = init_translation()
class ProfileList:
''' Stores the list of profiles (both name and attachment) and in which files they live '''
def __init__(self):
self.profile_names = {} # profile name -> filename
self.attachments = {} # attachment -> filename
self.attachments_AARE = {} # AARE(attachment) -> filename
def add(self, filename, profile_name, attachment):
''' Add the given profile and attachment to the list '''
if not filename:
raise AppArmorBug('Empty filename given to ProfileList')
if not profile_name and not attachment:
raise AppArmorBug('Neither profile name or attachment given')
if profile_name in self.profile_names:
raise AppArmorException(_('Profile %(profile_name)s exists in %(filename)s and %(filename2)s' % {'profile_name': profile_name, 'filename': filename, 'filename2': self.profile_names[profile_name]}))
if attachment in self.attachments:
raise AppArmorException(_('Profile for %(profile_name)s exists in %(filename)s and %(filename2)s' % {'profile_name': attachment, 'filename': filename, 'filename2': self.attachments[attachment]}))
if profile_name:
self.profile_names[profile_name] = filename
if attachment:
self.attachments[attachment] = filename
self.attachments_AARE[attachment] = AARE(attachment, True)
def filename_from_profile_name(self, name):
''' Return profile filename for the given profile name, or None '''
return self.profile_names.get(name, None)
def filename_from_attachment(self, attachment):
''' Return profile filename for the given attachment/executable path, or None '''
if not attachment.startswith( ('/', '@', '{') ):
raise AppArmorBug('Called filename_from_attachment with non-path attachment: %s' % attachment)
# plain path
if self.attachments.get(attachment):
return self.attachments[attachment]
# try AARE matches to cover profile names with alternations and wildcards
for path in self.attachments.keys():
if self.attachments_AARE[path].match(attachment):
return self.attachments[path] # XXX this returns the first match, not necessarily the best one
return None # nothing found

View file

@ -1,5 +1,6 @@
# ----------------------------------------------------------------------
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
# Copyright (C) 2015-2018 Christian Boltz <apparmor@cboltz.de>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public
@ -66,12 +67,12 @@ class aa_tools:
profile = fq_path
else:
program = fq_path
profile = apparmor.get_profile_filename(fq_path)
profile = apparmor.get_profile_filename_from_attachment(fq_path, True)
else:
which = apparmor.which(p)
if which is not None:
program = apparmor.get_full_path(which)
profile = apparmor.get_profile_filename(program)
profile = apparmor.get_profile_filename_from_attachment(program, True)
elif os.path.exists(os.path.join(apparmor.profile_dir, p)):
program = None
profile = apparmor.get_full_path(os.path.join(apparmor.profile_dir, p)).strip()
@ -190,7 +191,7 @@ class aa_tools:
apparmor.check_qualifiers(program)
if os.path.exists(apparmor.get_profile_filename(program)) and not self.force:
if os.path.exists(apparmor.get_profile_filename_from_attachment(program, True)) and not self.force:
aaui.UI_Info(_('Profile for %s already exists - skipping.') % program)
else:
apparmor.autodep(program)
@ -198,7 +199,7 @@ class aa_tools:
apparmor.reload(program)
def clean_profile(self, program):
filename = apparmor.get_profile_filename(program)
filename = apparmor.get_profile_filename_from_attachment(program, True)
import apparmor.cleanprofile as cleanprofile
prof = cleanprofile.Prof(filename)
cleanprof = cleanprofile.CleanProf(True, prof, prof)
@ -220,14 +221,14 @@ class aa_tools:
while ans != 'CMD_SAVE_CHANGES':
ans, arg = q.promptUser()
if ans == 'CMD_SAVE_CHANGES':
apparmor.write_profile_ui_feedback(program)
apparmor.write_profile_ui_feedback(program, True)
self.reload_profile(filename)
elif ans == 'CMD_VIEW_CHANGES':
#oldprofile = apparmor.serialize_profile(apparmor.original_aa[program], program, {})
newprofile = apparmor.serialize_profile(apparmor.aa[program], program, {})
newprofile = apparmor.serialize_profile(apparmor.aa[program], program, {'is_attachment': True})
aaui.UI_Changes(filename, newprofile, comments=True)
else:
apparmor.write_profile_ui_feedback(program)
apparmor.write_profile_ui_feedback(program, True)
self.reload_profile(filename)
else:
raise apparmor.AppArmorException(_('The profile for %s does not exists. Nothing to clean.') % program)

View file

@ -1,7 +1,7 @@
#! /usr/bin/python3
# ------------------------------------------------------------------
#
# Copyright (C) 2015 Christian Boltz <apparmor@cboltz.de>
# Copyright (C) 2015-2018 Christian Boltz <apparmor@cboltz.de>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public
@ -18,6 +18,7 @@ from apparmor.common import open_file_read
import apparmor.aa
from apparmor.logparser import ReadLog
from apparmor.profile_list import ProfileList
class TestLibapparmorTestMulti(AATest):
'''Parse all libraries/libapparmor/testsuite/test_multi tests and compare the result with the *.out files'''
@ -249,9 +250,15 @@ def logfile_to_profile(logfile):
if '//' in profile:
profile, hat = profile.split('//')
apparmor.aa.existing_profiles = {profile: profile_dummy_file}
apparmor.aa.active_profiles = ProfileList()
log_reader = ReadLog(dict(), logfile, apparmor.aa.existing_profiles, '')
# optional for now, might be needed one day
# if profile.startswith('/'):
# apparmor.aa.active_profiles.add(profile_dummy_file, profile, profile)
# else:
apparmor.aa.active_profiles.add(profile_dummy_file, profile, '')
log_reader = ReadLog(dict(), logfile, apparmor.aa.active_profiles, '')
log = log_reader.read_log('')
for root in log:

View file

@ -0,0 +1,114 @@
#! /usr/bin/python3
# ------------------------------------------------------------------
#
# Copyright (C) 2018 Christian Boltz <apparmor@cboltz.de>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public
# License published by the Free Software Foundation.
#
# ------------------------------------------------------------------
import unittest
from common_test import AATest, setup_all_loops
from apparmor.common import AppArmorBug, AppArmorException
from apparmor.profile_list import ProfileList
class TestAdd(AATest):
def AASetup(self):
self.pl = ProfileList()
def testEmpty(self):
self.assertEqual(self.pl.profile_names, {})
self.assertEqual(self.pl.attachments, {})
def testAdd_1(self):
self.pl.add('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo')
self.assertEqual(self.pl.profile_names, {'foo': '/etc/apparmor.d/bin.foo'})
self.assertEqual(self.pl.attachments, {'/bin/foo': '/etc/apparmor.d/bin.foo'})
def testAdd_2(self):
self.pl.add('/etc/apparmor.d/bin.foo', None, '/bin/foo')
self.assertEqual(self.pl.profile_names, {})
self.assertEqual(self.pl.attachments, {'/bin/foo': '/etc/apparmor.d/bin.foo'})
def testAdd_3(self):
self.pl.add('/etc/apparmor.d/bin.foo', 'foo', None)
self.assertEqual(self.pl.profile_names, {'foo': '/etc/apparmor.d/bin.foo'})
self.assertEqual(self.pl.attachments, {})
def testAddError_1(self):
with self.assertRaises(AppArmorBug):
self.pl.add('', 'foo', '/bin/foo') # no filename
def testAddError_2(self):
with self.assertRaises(AppArmorBug):
self.pl.add('/etc/apparmor.d/bin.foo', None, None) # neither attachment or profile name
def testAddError_twice_1(self):
self.pl.add('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo')
with self.assertRaises(AppArmorException):
self.pl.add('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo')
def testAddError_twice_2(self):
self.pl.add('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo')
with self.assertRaises(AppArmorException):
self.pl.add('/etc/apparmor.d/bin.foo', 'foo', None)
def testAddError_twice_3(self):
self.pl.add('/etc/apparmor.d/bin.foo', None, '/bin/foo')
with self.assertRaises(AppArmorException):
self.pl.add('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo')
def testAddError_twice_4(self):
self.pl.add('/etc/apparmor.d/bin.foo', None, '/bin/foo')
with self.assertRaises(AppArmorException):
self.pl.add('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo')
def testAddError_twice_5(self):
self.pl.add('/etc/apparmor.d/bin.foo', 'foo', None)
with self.assertRaises(AppArmorException):
self.pl.add('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo')
class TestFilename_from_profile_name(AATest):
tests = [
('foo', '/etc/apparmor.d/bin.foo'),
('/bin/foo', None),
('bar', None),
]
def AASetup(self):
self.pl = ProfileList()
self.pl.add('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo')
def _run_test(self, params, expected):
self.assertEqual(self.pl.filename_from_profile_name(params), expected)
class TestFilename_from_attachment(AATest):
tests = [
('/bin/foo', '/etc/apparmor.d/bin.foo'),
('/bin/baz', '/etc/apparmor.d/bin.baz'),
('/bin/foobar', '/etc/apparmor.d/bin.foobar'),
('@{foo}', None), # XXX variables not supported yet (and @{foo} isn't defined in this test)
('/bin/404', None),
]
def AASetup(self):
self.pl = ProfileList()
self.pl.add('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo')
self.pl.add('/etc/apparmor.d/bin.baz', 'baz', '/bin/ba*')
self.pl.add('/etc/apparmor.d/bin.foobar', 'foobar', '/bin/foo{bar,baz}')
def _run_test(self, params, expected):
self.assertEqual(self.pl.filename_from_attachment(params), expected)
def test_non_path_attachment(self):
with self.assertRaises(AppArmorBug):
self.pl.filename_from_attachment('foo')
setup_all_loops(__name__)
if __name__ == '__main__':
unittest.main(verbosity=1)