Skip to content

Commit db4832b

Browse files
committed
add CLI support for vulntotal
Signed-off-by: Keshav Priyadarshi <git@keshav.space>
1 parent 1542377 commit db4832b

File tree

1 file changed

+177
-0
lines changed

1 file changed

+177
-0
lines changed

vulntotal/vulntotal-cli.py

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
#!/usr/bin/env python
2+
#
3+
# Copyright (c) nexB Inc. and others. All rights reserved.
4+
# http://nexb.com and https://github.com/nexB/vulnerablecode/
5+
# The VulnTotal software is licensed under the Apache License version 2.0.
6+
# Data generated with VulnTotal require an acknowledgment.
7+
#
8+
# You may not use this software except in compliance with the License.
9+
# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
10+
# Unless required by applicable law or agreed to in writing, software distributed
11+
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12+
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
13+
# specific language governing permissions and limitations under the License.
14+
#
15+
# When you publish or redistribute any data created with VulnTotal or any VulnTotal
16+
# derivative work, you must accompany this data with the following acknowledgment:
17+
#
18+
# Generated with VulnTotal and provided on an "AS IS" BASIS, WITHOUT WARRANTIES
19+
# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
20+
# VulnTotal should be considered or used as legal advice. Consult an Attorney
21+
# for any legal advice.
22+
# VulnTotal is a free software code scanning tool from nexB Inc. and others.
23+
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
24+
25+
import argparse
26+
import pydoc
27+
28+
from packageurl import PackageURL
29+
from texttable import Texttable
30+
31+
from vulntotal.validators import VALIDATORS_REGISTRY
32+
33+
34+
def get_help():
35+
return """
36+
██╗░░░██╗██╗░░░██╗██╗░░░░░███╗░░██╗████████╗░█████╗░████████╗░█████╗░██╗░░░░░
37+
██║░░░██║██║░░░██║██║░░░░░████╗░██║╚══██╔══╝██╔══██╗╚══██╔══╝██╔══██╗██║░░░░░
38+
╚██╗░██╔╝██║░░░██║██║░░░░░██╔██╗██║░░░██║░░░██║░░██║░░░██║░░░███████║██║░░░░░
39+
░╚████╔╝░██║░░░██║██║░░░░░██║╚████║░░░██║░░░██║░░██║░░░██║░░░██╔══██║██║░░░░░
40+
░░╚██╔╝░░╚██████╔╝███████╗██║░╚███║░░░██║░░░╚█████╔╝░░░██║░░░██║░░██║███████╗
41+
░░░╚═╝░░░░╚═════╝░╚══════╝╚═╝░░╚══╝░░░╚═╝░░░░╚════╝░░░░╚═╝░░░╚═╝░░╚═╝╚══════╝
42+
43+
Usage: vulntotal-cli.py [-h] [-p PURL] [-l] [-d validator [validator ...]]
44+
[-e validator [validator ...]]
45+
46+
Discription:
47+
When no -e/-d flag is provided CLI will run the PURL through
48+
all the available validators.
49+
50+
51+
Optional arguments:
52+
-h, --help Show this help message and exit
53+
-p PURL, --purl PURL PackageURL to run through validator/s
54+
-l, --list Lists all the available validators
55+
56+
-e validator [validator ...] Enable these validator/s only
57+
--enable validator [validator ...]
58+
59+
-d validator [validator ...] Disable these validator/s
60+
--disable validator [validator ...]
61+
62+
Examples:
63+
python vultotal-cli.py --list
64+
python vultotal-cli.py -p 'pkg:pypi/jinja2@2.4.1'
65+
python vultotal-cli.py -e osv vulnerablecode -p 'pkg:pypi/jinja2@2.4.1'
66+
python vultotal-cli.py -d osv -p 'pkg:pypi/jinja2@2.4.1'
67+
"""
68+
69+
70+
def get_valid_validators(validators):
71+
valid_validators = {}
72+
unknown_validators = []
73+
for validator in validators:
74+
try:
75+
valid_validators[validator] = VALIDATORS_REGISTRY[validator]
76+
except KeyError:
77+
unknown_validators.append(validator)
78+
if unknown_validators:
79+
raise CommandError(f"Unknown validator: {unknown_validators}")
80+
return valid_validators
81+
82+
83+
def get_undisabled_validator(validators):
84+
disabled = get_valid_validators(validators)
85+
return {key: value for key, value in VALIDATORS_REGISTRY.items() if key not in disabled}
86+
87+
88+
def get_enabled_validator(validators):
89+
return get_valid_validators(validators)
90+
91+
92+
def list_validators():
93+
validators = list(VALIDATORS_REGISTRY)
94+
print("Currently supported validators:")
95+
print("\n".join(validators))
96+
97+
98+
def formatted_row(validator, advisory):
99+
aliases = "\n".join(advisory.aliases)
100+
affected = " ".join(advisory.affected_versions)
101+
fixed = " ".join(advisory.fixed_versions)
102+
return [validator.upper(), aliases, affected, fixed]
103+
104+
105+
def run_validators(purl, validators):
106+
if not validators:
107+
print("No validators available!")
108+
return
109+
print("PURL: ", purl)
110+
print("Active Validators: ", ", ".join(validators.keys()))
111+
table = Texttable()
112+
table.set_cols_dtype(["t", "t", "t", "t"])
113+
table.set_cols_align(["c", "l", "l", "l"])
114+
table.set_cols_valign(["t", "t", "a", "t"])
115+
table.header(["VALIDATOR", "ALIASES", "AFFECTED", "FIXED"])
116+
for key, validator in validators.items():
117+
vendor = validator()
118+
vendor_advisories = vendor.validator_advisory(PackageURL.from_string(purl))
119+
not_vulnerable_in_vendor_advisory = True
120+
121+
for advisory in vendor_advisories:
122+
if not_vulnerable_in_vendor_advisory:
123+
not_vulnerable_in_vendor_advisory = False
124+
table.add_row(formatted_row(key, advisory))
125+
126+
if not_vulnerable_in_vendor_advisory:
127+
table.add_row([key.upper(), "None", "None", "None"])
128+
129+
pydoc.pager(table.draw())
130+
131+
132+
def handler():
133+
parser = argparse.ArgumentParser(
134+
add_help=False,
135+
)
136+
parser.add_argument("-h", "--help", action="store_true", help="Show this help message and exit")
137+
parser.add_argument("-p", "--purl", help="PackageURL to run through validator/s")
138+
parser.add_argument(
139+
"-l", "--list", action="store_true", help="Lists all the available validators"
140+
)
141+
parser.add_argument(
142+
"-e", "--enable", metavar="validator", nargs="+", help="Enable these validator/s only"
143+
)
144+
parser.add_argument(
145+
"-d",
146+
"--disable",
147+
metavar="validator",
148+
nargs="+",
149+
help="Disable these validator/s",
150+
)
151+
152+
args = parser.parse_args()
153+
154+
if not any(vars(args).values()) or args.help:
155+
print(get_help())
156+
157+
elif args.list:
158+
list_validators()
159+
160+
elif args.purl:
161+
if args.enable:
162+
run_validators(args.purl, get_enabled_validator(args.enable))
163+
164+
elif args.disable:
165+
run_validators(args.purl, get_undisabled_validator(args.disable))
166+
167+
else:
168+
# Run on all the validators
169+
run_validators(args.purl, VALIDATORS_REGISTRY)
170+
171+
172+
def main():
173+
handler()
174+
175+
176+
if __name__ == "__main__":
177+
main()

0 commit comments

Comments
 (0)