mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-22 10:07:12 +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