Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add Github CI for waiver syntax check, fix waivers #138

Merged
merged 1 commit into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/sanity.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Sanity self-tests

on:
pull_request:

jobs:
waivers-syntax-check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Contest deps
run: sudo apt-get install -y python3-rpm
- name: Collect waivers
run: |
python3 <<'EOF'
import sys
from lib import waive
try:
list(waive.collect_waivers())
sys.exit(0)
except waive.WaiveParseError as e:
print(str(e))
sys.exit(1)
EOF
1 change: 1 addition & 0 deletions conf/waivers/30-permanent
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
# we don't control partitions on the host OS
/hardening/host-os/oscap/.+/mount_option_(home|opt|srv|var|var_log|var_log_audit|tmp)_(noexec|nosuid|nodev|usrquota|grpquota)
/hardening/host-os/oscap/.+/mount_option_boot_efi_nosuid
Match(True, sometimes=True)

# Beaker-specific, possibly;
# same for dnf-automatic and rsyslog (??), is this fully random?
Expand Down
23 changes: 13 additions & 10 deletions lib/waive.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ class WaiveParseError(SyntaxError):
Easy waiver file syntax error reporting, with line numbers derived
from _PushbackIterator style counter.
"""
def __init__(self, meta, msg):
super().__init__(f"waiver line {meta.counter}: {msg}")
def __init__(self, filedesc, msg):
file, line = filedesc
super().__init__(f"waiver {file}:{line}: {msg}")


def _compile_eval(meta, code):
Expand All @@ -59,7 +60,7 @@ def _compile_eval(meta, code):
raise WaiveParseError(meta, "compiling waiver python code failed")


def _parse_waiver_file(stream):
def _parse_waiver_file(stream, filename):
sections = []
regexes = set()
python_code = ''
Expand All @@ -70,6 +71,7 @@ def _parse_waiver_file(stream):
if line.startswith('#'):
continue
line = line.rstrip('\n')
filedesc = (filename, lines.counter)

# between regex+python blocks
if state == 'skipping_empty_lines':
Expand All @@ -82,19 +84,19 @@ def _parse_waiver_file(stream):
# collecting adjacent/subsequent regex lines
elif state == 'reading_regex':
if not line:
raise WaiveParseError(lines, "unexpected empty line between regexes")
raise WaiveParseError(filedesc, "unexpected empty line between regexes")

# until we see an indented line (beginning with space), just collect
# regex lines into a buffer
if not line.startswith((' ', '\t')):
try:
regexes.add(re.compile(line))
except re.error as e:
raise WaiveParseError(lines, f"regex failed: {e}")
raise WaiveParseError(filedesc, f"regex failed: {e}")
else:
# indented line found, which means it's a python code - parse it
if not regexes:
raise WaiveParseError(lines, "python block without a preceding regexp")
raise WaiveParseError(filedesc, "python block without a preceding regexp")
state = 'reading_python'
lines.pushback()

Expand All @@ -114,7 +116,7 @@ def _parse_waiver_file(stream):
lines.pushback()

if regexes and not python_code:
raise WaiveParseError(lines, "no python block follows the regexp")
raise WaiveParseError(filedesc, "no python block follows the regexp")

# still inside last python block - the append & cleanup section did not
# get to run because the iterator stopped because there was nothing left
Expand All @@ -126,7 +128,7 @@ def _parse_waiver_file(stream):
return sections


def _collect_waivers():
def collect_waivers():
"""
Recursively walk a directory of waiver files/directories,
yielding waiver sections.
Expand All @@ -148,8 +150,9 @@ def _collect_files(in_dir):
yield item

for file in _collect_files(dir_path):
relative = file.relative_to(dir_path)
with open(file) as f:
yield from _parse_waiver_file(f)
yield from _parse_waiver_file(f, str(relative))


class Match:
Expand All @@ -168,7 +171,7 @@ def __bool__(self):
def match_result(status, name, note):
global _sections_cache
if _sections_cache is None:
_sections_cache = list(_collect_waivers())
_sections_cache = list(collect_waivers())

# make sure "'someting' in name" always works
if name is None:
Expand Down