mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-22 01:57:43 +00:00
test: rewrite test_profile.sh script in Python
test_profile.sh contained some bash-specific code and a bug in a regex that failed to flag some profiles where read access to their attachment path was not allowed. Replace it with a Python script, more robust and maintenable. Signed-off-by: Maxime Bélair <maxime.belair@canonical.com>
This commit is contained in:
parent
93c660e376
commit
d9dedcb51c
90
parser/tst/test_profile.py
Executable file
90
parser/tst/test_profile.py
Executable file
@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import subprocess
|
||||
import re
|
||||
import os
|
||||
|
||||
|
||||
VERBOSE = bool(os.environ.get('VERBOSE'))
|
||||
|
||||
NAME_RE = re.compile(r'^Name:\s*(\S+)')
|
||||
PERMS_ALL = re.compile(r'^Perms:.*r.*:.*:.*\(/\{?,?\*\*,?}?\)')
|
||||
ATTACH_RE = re.compile(r'^Attachment:\s*(.+)')
|
||||
|
||||
RED = '\033[0;31m'
|
||||
GREEN = '\033[0;32m'
|
||||
NORMAL = '\033[0m'
|
||||
|
||||
def die(msg):
|
||||
print(RED + msg + NORMAL, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
def check_profile(name, prof_file, skip, attachment, lines):
|
||||
if skip:
|
||||
if VERBOSE:
|
||||
print('Profile "{}" skipped: {}'.format(name, skip))
|
||||
return
|
||||
|
||||
pat = re.compile(r'^Perms:.*r.*:.*:.*\({}\)'.format(re.escape(attachment)))
|
||||
for l in lines:
|
||||
if pat.match(l):
|
||||
if VERBOSE:
|
||||
print(GREEN + 'Profile {} ({}): OK "{}" found'.format(prof_file, name, attachment) + NORMAL)
|
||||
return
|
||||
|
||||
die('Profile {} ({}): ERROR: no Perms rule for "{}".'.format(prof_file, name, attachment))
|
||||
|
||||
def process_profile(profile, extra_args):
|
||||
cmd = ['../parser/apparmor_parser'] + extra_args + ['-d', profile]
|
||||
proc = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
|
||||
if proc.returncode != 0:
|
||||
die('ERROR: Failed to parse "{}": {}'.format(profile, proc.stdout.strip()))
|
||||
|
||||
lines = proc.stdout.splitlines()
|
||||
curr_name = ''
|
||||
attachment = ''
|
||||
skip = None
|
||||
in_entries = False
|
||||
block = []
|
||||
|
||||
for line in lines:
|
||||
m = NAME_RE.match(line)
|
||||
if m:
|
||||
if curr_name:
|
||||
# check previously found profile
|
||||
check_profile(curr_name, profile, skip, attachment, block)
|
||||
|
||||
# remember newly found profile
|
||||
curr_name = m.group(1)
|
||||
attachment = ''
|
||||
skip = None
|
||||
in_entries = False
|
||||
block = []
|
||||
continue
|
||||
|
||||
if PERMS_ALL.match(line):
|
||||
skip = 'All files available'
|
||||
continue
|
||||
|
||||
m = ATTACH_RE.match(line)
|
||||
if m:
|
||||
attachment = m.group(1)
|
||||
if attachment == '<NULL>':
|
||||
skip = 'no attachment'
|
||||
continue
|
||||
|
||||
if line.strip() == '--- Entries ---':
|
||||
in_entries = True
|
||||
continue
|
||||
|
||||
if in_entries:
|
||||
block.append(line)
|
||||
|
||||
# Last profile
|
||||
check_profile(curr_name, profile, skip, attachment, block)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
print('Usage: {0} <profile-file> [parser_extra_args]'.format(sys.argv[0]))
|
||||
sys.exit(1)
|
||||
process_profile(sys.argv[1], sys.argv[2:])
|
@ -1,84 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Check if the current profile allow reading its attachment
|
||||
check_entry() {
|
||||
local prof_name="$1"
|
||||
local -n lines_ref="$2"
|
||||
local attachment="$3"
|
||||
local found=0
|
||||
|
||||
for line in "${lines_ref[@]}"; do
|
||||
if [[ $line == Perms:*r*:*"($attachment)"* ]]; then
|
||||
found=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $found -eq 0 ]]; then
|
||||
echo -e "\e[0;31mProfile $prof_name: ERROR: no Perms rule for '$attachment'.\e[0m"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[[ -n "${VERBOSE:-}" ]] && echo -e "\e[0;32mProfile $prof_name: OK '$attachment' found\e[0m" || true
|
||||
}
|
||||
|
||||
# Handle the end of a profile block: either skip it or check for the entry.
|
||||
finish_profile() {
|
||||
local name="$1"
|
||||
local prof_file="$2"
|
||||
local skip="$3"
|
||||
local attachment="$4"
|
||||
local arr_name="$5"
|
||||
|
||||
if [[ -n $name ]]; then
|
||||
if [[ $skip != 0 ]]; then
|
||||
[[ -n "${VERBOSE:-}" ]] && echo "Profile '$name' skipped: $skip" || true
|
||||
else
|
||||
check_entry "$prof_file ($name)" "$arr_name" "$attachment"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
process_profile() {
|
||||
local prof_file="$1"
|
||||
shift
|
||||
local dump curr_name="" attachment="" skip_profile=0 in_entries=0
|
||||
local block_lines=()
|
||||
|
||||
if ! dump=$(../parser/apparmor_parser $@ -d "$prof_file" 2>&1); then
|
||||
echo "\e[0;31mERROR: Failed to parse '$prof_file': $dump\e[0m" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IFS=$'\n' read -r -d '' -a lines < <(printf '%s\n' "$dump" && printf '\0')
|
||||
|
||||
for line in "${lines[@]}"; do
|
||||
if [[ $line =~ ^[[:space:]]*Name:[[:space:]]*([^[:space:]]+) ]]; then
|
||||
finish_profile "$curr_name" "$prof_file" "$skip_profile" "$attachment" block_lines
|
||||
curr_name="${BASH_REMATCH[1]}"
|
||||
attachment="" skip_profile=0 in_entries=0 block_lines=()
|
||||
elif [[ $line =~ ^[[:space:]]*Mode:[[:space:]]*unconfined ]]; then
|
||||
skip_profile="unconfined"
|
||||
elif [[ $line =~ ^Perms:.*r.*:.*:.*\(/(\{?,?\*\*,*\}?)\) ]]; then
|
||||
skip_profile="All files available"
|
||||
elif [[ $line =~ ^[[:space:]]*Attachment:[[:space:]]*(.+) ]]; then
|
||||
attachment="${BASH_REMATCH[1]}"
|
||||
[[ $attachment == "<NULL>" ]] && skip_profile="no attachment"
|
||||
elif [[ $line == ---\ Entries\ --- ]]; then
|
||||
in_entries=1
|
||||
elif [[ $in_entries -ne 0 ]]; then
|
||||
block_lines+=("$line")
|
||||
fi
|
||||
done
|
||||
|
||||
# Last profile
|
||||
finish_profile "$curr_name" "$prof_file" "$skip_profile" "$attachment" block_lines
|
||||
}
|
||||
|
||||
if (( $# < 1 )); then
|
||||
echo "Usage: $0 <profile-file> [parser_extra_args]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
process_profile $@
|
Loading…
x
Reference in New Issue
Block a user