Skip to content

Commit 9a2c241

Browse files
committed
Add validation of AutoPkg processor input variables (arguments)
1 parent 70c5e22 commit 9a2c241

2 files changed

Lines changed: 82 additions & 2 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ After adding a hook to your pre-commit config, it's not a bad idea to run `pre-c
5252

5353
- __check-autopkg-recipes__
5454

55-
This hook checks AutoPkg recipes to ensure they meet various requirements.
55+
This hook checks AutoPkg recipes to ensure they meet various requirements and conventions.
5656

5757
- Optionally specify your preferred AutoPkg recipe and/or override prefix, if you wish to enforce them:
5858
`args: ['--override-prefix=com.yourcompany.autopkg.']`
@@ -65,7 +65,7 @@ After adding a hook to your pre-commit config, it's not a bad idea to run `pre-c
6565
(default: `1.0.0`)
6666
Specifying `0.1.0` will not ignore any MinimumVersion mismatches.
6767

68-
- If you're a purist, you can also enable strict mode. This enforces recipe type conventions, all processor/MinimumVersion mismatches, and forbids `<!-- -->` style comments.
68+
- If you're a purist, you can also enable strict mode. This enforces recipe type conventions, all processor/MinimumVersion mismatches, forbids `<!-- -->` style comments, and ensures all processor input variables (arguments) are valid.
6969
`args: ['--strict']`
7070
(default: False)
7171

pre_commit_hooks/check_autopkg_recipes.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
requirements."""
55

66
import argparse
7+
import os
78
import plistlib
9+
import sys
10+
from contextlib import contextmanager
811
from distutils.version import LooseVersion
912
from xml.parsers.expat import ExpatError
1013

@@ -15,6 +18,29 @@
1518
)
1619

1720

21+
# Import AutoPkg libraries, but ignore any warnings generated by the import.
22+
@contextmanager
23+
def suppress_stdout():
24+
with open(os.devnull, "w") as devnull:
25+
old_stdout = sys.stdout
26+
sys.stdout = devnull
27+
try:
28+
yield
29+
finally:
30+
sys.stdout = old_stdout
31+
32+
33+
sys.path.append("/Library/AutoPkg")
34+
try:
35+
with suppress_stdout():
36+
from autopkglib import get_processor, processor_names
37+
38+
HAS_AUTOPKGLIB = True
39+
except ImportError:
40+
# Silently skip checks that require autopkglib.
41+
HAS_AUTOPKGLIB = False
42+
43+
1844
def build_argument_parser():
1945
"""Build and return the argument parser."""
2046

@@ -388,6 +414,56 @@ def validate_required_proc_for_types(process, filename):
388414
return passed
389415

390416

417+
def validate_proc_args(process, filename):
418+
"""Warn if invalid processor arguments are used."""
419+
420+
passed = True
421+
422+
# List of argument names (lowercase) that will not be flagged as invalid.
423+
ignored_args = ("note", "notes", "comment", "comments")
424+
425+
# Create dictionary of AutoPkg core processors and their inputs.
426+
core_procs = {}
427+
for proc in processor_names():
428+
if hasattr(get_processor(proc), "input_variables"):
429+
core_procs[proc] = get_processor(proc).input_variables
430+
else:
431+
core_procs[proc] = {}
432+
433+
for proc in process:
434+
if proc["Processor"] not in core_procs:
435+
# Skip input variable validation for non-core processors.
436+
continue
437+
for arg in proc.get("Arguments", {}):
438+
if arg.lower() in ignored_args:
439+
# Skip args in ignored list above.
440+
continue
441+
442+
if not core_procs[proc["Processor"]]:
443+
print(
444+
"{}: Unknown argument {} for processor {}, "
445+
"which does not accept any arguments.".format(
446+
filename,
447+
arg,
448+
proc["Processor"],
449+
)
450+
)
451+
passed = False
452+
elif arg not in core_procs[proc["Processor"]]:
453+
print(
454+
"{}: Unknown argument {} for processor {}. "
455+
"Allowed arguments are: {}".format(
456+
filename,
457+
arg,
458+
proc["Processor"],
459+
", ".join(core_procs[proc["Processor"]]),
460+
)
461+
)
462+
passed = False
463+
464+
return passed
465+
466+
391467
def main(argv=None):
392468
"""Main process."""
393469

@@ -507,6 +583,10 @@ def main(argv=None):
507583
if not validate_required_proc_for_types(process, filename):
508584
retval = 1
509585

586+
if HAS_AUTOPKGLIB:
587+
if not validate_proc_args(process, filename):
588+
retval = 1
589+
510590
return retval
511591

512592

0 commit comments

Comments
 (0)