-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathmain.py
143 lines (128 loc) · 5.02 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
"""main.py for actions-security-analyzer"""
from argparse import ArgumentParser
from pathlib import Path
from os import sep
import sys
from yaml.resolver import Resolver
from yaml import safe_load
from analyzer.analyzer import Analyzer
from colors import Colors
FAILED = 1
SUCCESS = 0
# reference: https://stackoverflow.com/a/36470466
def _rewrite_pyyaml_boolean_recognition_rules():
for char in "OoYyNn":
if len(Resolver.yaml_implicit_resolvers[char]) == 1:
del Resolver.yaml_implicit_resolvers[char]
else:
Resolver.yaml_implicit_resolvers[char] = [
x for x in Resolver.yaml_implicit_resolvers[char] if x[0] != "tag:yaml.org,2002:bool"
]
def _parse_args():
parser = ArgumentParser()
parser.add_argument("--file", "-f", type=str, help="path to GitHub Action .yaml|.yml file")
parser.add_argument(
"--dir",
"-d",
type=str,
help="path to directory with GitHub Action .yaml|.yml files",
)
parser.add_argument(
"--list-checks",
"-l",
action="store_true",
help="list all checks performed against provided GitHub Action",
)
parser.add_argument("--verbose", "-v", action="store_true", help="increase tool verbosity")
parser.add_argument(
"--ignore-warnings",
"-i",
action="store_true",
help="ignore checks labeled as warning",
)
parser.add_argument(
"--ignore-checks",
"-k",
nargs="+",
metavar="CHECK",
help="specify checks to ignore",
)
parser.add_argument("--no-summary", "-n", action="store_true", help="don't show tool summary section")
return parser.parse_args()
def _main():
_rewrite_pyyaml_boolean_recognition_rules()
args = _parse_args()
file_ = args.file
dir_ = args.dir
list_checks = args.list_checks
verbose = args.verbose
ignore_warnings = args.ignore_warnings
ignore_checks = args.ignore_checks
no_summary = args.no_summary
analyzer = Analyzer(ignore_checks=ignore_checks, ignore_warnings=ignore_warnings, verbose=verbose)
errored = False
failed_actions = []
try:
if file_:
file_ = Path(file_)
if file_.exists():
print(f"FILE => {Colors.BOLD}{file_}{Colors.END}")
with file_.open("r") as action_file:
action_dict = safe_load(action_file)
if not analyzer.run_checks(action=action_dict):
failed_actions.append(file_)
else:
errored = True
print(f"[{Colors.RED}ERROR{Colors.END}]: the file '{str(file_)}' does not exist...")
print()
elif dir_:
dir_ = Path(dir_)
if dir_.is_dir() and dir_.exists():
if verbose:
print(
f"{Colors.LIGHT_GRAY}INFO{Colors.END} "
f"Scanning {Colors.UNDERLINE}{dir_}{Colors.END} directory..."
)
for action in dir_.iterdir():
print(
f"FILE => {Colors.BOLD}{Colors.UNDERLINE}{str(action).rsplit(sep, maxsplit=1)[-1]}{Colors.END}"
)
if action.is_file and action.suffix in (".yml", ".yaml"):
with action.open("r") as action_file:
action_dict = safe_load(action_file)
if not analyzer.run_checks(action=action_dict):
failed_actions.append(action)
else:
if verbose:
print(f"{Colors.LIGHT_GRAY}INFO{Colors.END} {str(action)} passed all checks")
print()
else:
errored = True
print(f"[{Colors.RED}ERROR{Colors.END}] the directory '{str(dir_)}' does not exist...")
elif list_checks:
for i, check in enumerate(analyzer.get_checks(), 1):
print(f"{i}. {check[1:]}")
else:
errored = True
print(f"[{Colors.LIGHT_GRAY}INFO{Colors.END}] must provide `--file` or `--dir`")
except Exception as exception:
errored = True
print(f"[{Colors.RED}ERROR{Colors.END}] {exception}")
finally:
if not no_summary:
if not errored and not list_checks:
if failed_actions:
print(
f"{Colors.PURPLE}{Colors.UNDERLINE}Summary{Colors.END}"
"\nThe following Actions failed to pass one or more checks:"
)
for action in failed_actions:
print(f" \u2022 {Colors.BOLD}{action}{Colors.END}")
sys.exit(FAILED)
else:
print(f"{Colors.PURPLE}Summary{Colors.END}: Passed all checks \U0001F44D")
sys.exit(SUCCESS)
if failed_actions:
sys.exit(FAILED)
if __name__ == "__main__":
_main()