Skip to content

Commit 8c193a4

Browse files
committed
More precise testing of plugins
Instead of relying on a count of the severity and confidence levels found within an example file, make use of Python's native unit testing to verify the results of a plugin. The existing method of confirming counts can be inaccurate. It's very easy to have a false positive simply because one issue extra was found and one issue was missed, thus giving the same count. It tells nothing of the validation of a particular line of problematic code. Relates to #352 Signed-off-by: Eric Brown <[email protected]>
1 parent 36fc7be commit 8c193a4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+8219
-535
lines changed

tests/functional/test_functional.py

+1-535
Large diffs are not rendered by default.
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
import testtools
3+
4+
from bandit.core import config
5+
from bandit.core import manager
6+
from bandit.core import meta_ast
7+
from bandit.core import metrics
8+
from bandit.core import node_visitor
9+
from bandit.core import test_set
10+
11+
12+
class BaseTestCase(testtools.TestCase):
13+
def setUp(self, test_ids):
14+
super().setUp()
15+
self.b_config = config.BanditConfig()
16+
self.b_manager = manager.BanditManager(self.b_config, "file")
17+
issue_metrics = metrics.Metrics()
18+
issue_metrics.begin("test.py")
19+
self.visitor = node_visitor.BanditNodeVisitor(
20+
"test.py",
21+
None,
22+
metaast=meta_ast.BanditMetaAst(),
23+
testset=test_set.BanditTestSet(
24+
self.b_config,
25+
profile={
26+
"include": test_ids,
27+
"exclude": [],
28+
},
29+
),
30+
debug=False,
31+
nosec_lines={},
32+
metrics=issue_metrics,
33+
)
+297
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
import textwrap
3+
4+
import bandit
5+
from bandit.core import issue as b_issue
6+
from tests.unit.blacklists import base_test_case
7+
8+
9+
class CipherCallTests(base_test_case.BaseTestCase):
10+
def setUp(self):
11+
super().setUp(["B304"])
12+
13+
def test_crypto_cipher_arc2_new(self):
14+
fdata = textwrap.dedent(
15+
"""
16+
from Crypto.Cipher import ARC2 as pycrypto_arc2
17+
from Crypto import Random
18+
key = b'Sixteen byte key'
19+
iv = Random.new().read(pycrypto_arc2.block_size)
20+
pycrypto_arc2.new(key, pycrypto_arc2.MODE_CFB, iv)
21+
"""
22+
)
23+
self.visitor.process(fdata)
24+
self.assertEqual(1, len(self.visitor.tester.results))
25+
issue = self.visitor.tester.results[0]
26+
self.assertEqual("B304", issue.test_id)
27+
self.assertEqual(bandit.HIGH, issue.severity)
28+
self.assertEqual(bandit.HIGH, issue.confidence)
29+
self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id)
30+
self.assertEqual(6, issue.lineno)
31+
self.assertEqual([6], issue.linerange)
32+
self.assertEqual(0, issue.col_offset)
33+
34+
def test_crypto_cipher_arc4_new(self):
35+
fdata = textwrap.dedent(
36+
"""
37+
from Crypto.Cipher import ARC4 as pycrypto_arc4
38+
from Crypto import Random
39+
key = b'Very long and confidential key'
40+
nonce = Random.new().read(16)
41+
tempkey = SHA.new(key+nonce).digest()
42+
pycrypto_arc4.new(tempkey)
43+
"""
44+
)
45+
self.visitor.process(fdata)
46+
self.assertEqual(1, len(self.visitor.tester.results))
47+
issue = self.visitor.tester.results[0]
48+
self.assertEqual("B304", issue.test_id)
49+
self.assertEqual(bandit.HIGH, issue.severity)
50+
self.assertEqual(bandit.HIGH, issue.confidence)
51+
self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id)
52+
self.assertEqual(7, issue.lineno)
53+
self.assertEqual([7], issue.linerange)
54+
self.assertEqual(0, issue.col_offset)
55+
56+
def test_crypto_cipher_blowfish_new(self):
57+
fdata = textwrap.dedent(
58+
"""
59+
from Crypto.Cipher import Blowfish as pycrypto_blowfish
60+
from Crypto import Random
61+
key = b'An arbitrarily long key'
62+
bs = pycrypto_blowfish.block_size
63+
iv = Random.new().read(bs)
64+
pycrypto_blowfish.new(key, pycrypto_blowfish.MODE_CBC, iv)
65+
"""
66+
)
67+
self.visitor.process(fdata)
68+
self.assertEqual(1, len(self.visitor.tester.results))
69+
issue = self.visitor.tester.results[0]
70+
self.assertEqual("B304", issue.test_id)
71+
self.assertEqual(bandit.HIGH, issue.severity)
72+
self.assertEqual(bandit.HIGH, issue.confidence)
73+
self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id)
74+
self.assertEqual(7, issue.lineno)
75+
self.assertEqual([7], issue.linerange)
76+
self.assertEqual(0, issue.col_offset)
77+
78+
def test_crypto_cipher_des_new(self):
79+
fdata = textwrap.dedent(
80+
"""
81+
from Crypto.Cipher import DES as pycrypto_des
82+
from Crypto import Random
83+
nonce = Random.new().read(pycrypto_des.block_size / 2)
84+
ctr = Counter.new(pycrypto_des.block_size * 8 / 2, prefix=nonce)
85+
pycrypto_des.new(key, pycrypto_des.MODE_CTR, counter=ctr)
86+
"""
87+
)
88+
self.visitor.process(fdata)
89+
self.assertEqual(1, len(self.visitor.tester.results))
90+
issue = self.visitor.tester.results[0]
91+
self.assertEqual("B304", issue.test_id)
92+
self.assertEqual(bandit.HIGH, issue.severity)
93+
self.assertEqual(bandit.HIGH, issue.confidence)
94+
self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id)
95+
self.assertEqual(6, issue.lineno)
96+
self.assertEqual([6], issue.linerange)
97+
self.assertEqual(0, issue.col_offset)
98+
99+
def test_crypto_cipher_xor_new(self):
100+
fdata = textwrap.dedent(
101+
"""
102+
from Crypto.Cipher import XOR as pycrypto_xor
103+
key = b'Super secret key'
104+
pycrypto_xor.new(key)
105+
"""
106+
)
107+
self.visitor.process(fdata)
108+
self.assertEqual(1, len(self.visitor.tester.results))
109+
issue = self.visitor.tester.results[0]
110+
self.assertEqual("B304", issue.test_id)
111+
self.assertEqual(bandit.HIGH, issue.severity)
112+
self.assertEqual(bandit.HIGH, issue.confidence)
113+
self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id)
114+
self.assertEqual(4, issue.lineno)
115+
self.assertEqual([4], issue.linerange)
116+
self.assertEqual(0, issue.col_offset)
117+
118+
def test_cryptodome_cipher_arc2_new(self):
119+
fdata = textwrap.dedent(
120+
"""
121+
from Cryptodome.Cipher import ARC2 as pycryptodomex_arc2
122+
from Crypto import Random
123+
key = b'Sixteen byte key'
124+
iv = Random.new().read(pycryptodomex_arc2.block_size)
125+
pycryptodomex_arc2.new(key, pycryptodomex_arc2.MODE_CFB, iv)
126+
"""
127+
)
128+
self.visitor.process(fdata)
129+
self.assertEqual(1, len(self.visitor.tester.results))
130+
issue = self.visitor.tester.results[0]
131+
self.assertEqual("B304", issue.test_id)
132+
self.assertEqual(bandit.HIGH, issue.severity)
133+
self.assertEqual(bandit.HIGH, issue.confidence)
134+
self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id)
135+
self.assertEqual(6, issue.lineno)
136+
self.assertEqual([6], issue.linerange)
137+
self.assertEqual(0, issue.col_offset)
138+
139+
def test_cryptodome_cipher_arc4_new(self):
140+
fdata = textwrap.dedent(
141+
"""
142+
from Cryptodome.Cipher import ARC4 as pycryptodomex_arc4
143+
from Cryptodome import Random
144+
key = b'Very long and confidential key'
145+
nonce = Random.new().read(16)
146+
tempkey = SHA.new(key + nonce).digest()
147+
pycryptodomex_arc4.new(tempkey)
148+
"""
149+
)
150+
self.visitor.process(fdata)
151+
self.assertEqual(1, len(self.visitor.tester.results))
152+
issue = self.visitor.tester.results[0]
153+
self.assertEqual("B304", issue.test_id)
154+
self.assertEqual(bandit.HIGH, issue.severity)
155+
self.assertEqual(bandit.HIGH, issue.confidence)
156+
self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id)
157+
self.assertEqual(7, issue.lineno)
158+
self.assertEqual([7], issue.linerange)
159+
self.assertEqual(0, issue.col_offset)
160+
161+
def test_cryptodome_cipher_blowfish_new(self):
162+
fdata = textwrap.dedent(
163+
"""
164+
from Cryptodome.Cipher import Blowfish as pycryptodomex_blowfish
165+
from Cryptodome import Random
166+
key = b'An arbitrarily long key'
167+
bs = pycryptodomex_blowfish.block_size
168+
iv = Random.new().read(bs)
169+
mode = pycryptodomex_blowfish.MODE_CBC
170+
pycryptodomex_blowfish.new(key, mode, iv)
171+
"""
172+
)
173+
self.visitor.process(fdata)
174+
self.assertEqual(1, len(self.visitor.tester.results))
175+
issue = self.visitor.tester.results[0]
176+
self.assertEqual("B304", issue.test_id)
177+
self.assertEqual(bandit.HIGH, issue.severity)
178+
self.assertEqual(bandit.HIGH, issue.confidence)
179+
self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id)
180+
self.assertEqual(8, issue.lineno)
181+
self.assertEqual([8], issue.linerange)
182+
self.assertEqual(0, issue.col_offset)
183+
184+
def test_cryptodome_cipher_des_new(self):
185+
fdata = textwrap.dedent(
186+
"""
187+
from Cryptodome.Cipher import DES as pycryptodomex_des
188+
from Cryptodome import Random
189+
nonce = Random.new().read(pycryptodomex_des.block_size / 2)
190+
ctr = Counter.new(pycryptodomex_des.block_size * 8/2, prefix=nonce)
191+
pycryptodomex_des.new(key, pycryptodomex_des.MODE_CTR, counter=ctr)
192+
"""
193+
)
194+
self.visitor.process(fdata)
195+
self.assertEqual(1, len(self.visitor.tester.results))
196+
issue = self.visitor.tester.results[0]
197+
self.assertEqual("B304", issue.test_id)
198+
self.assertEqual(bandit.HIGH, issue.severity)
199+
self.assertEqual(bandit.HIGH, issue.confidence)
200+
self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id)
201+
self.assertEqual(6, issue.lineno)
202+
self.assertEqual([6], issue.linerange)
203+
self.assertEqual(0, issue.col_offset)
204+
205+
def test_cryptodome_cipher_xor_new(self):
206+
fdata = textwrap.dedent(
207+
"""
208+
from Cryptodome.Cipher import XOR as pycryptodomex_xor
209+
key = b'Super secret key'
210+
pycryptodomex_xor.new(key)
211+
"""
212+
)
213+
self.visitor.process(fdata)
214+
self.assertEqual(1, len(self.visitor.tester.results))
215+
issue = self.visitor.tester.results[0]
216+
self.assertEqual("B304", issue.test_id)
217+
self.assertEqual(bandit.HIGH, issue.severity)
218+
self.assertEqual(bandit.HIGH, issue.confidence)
219+
self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id)
220+
self.assertEqual(4, issue.lineno)
221+
self.assertEqual([4], issue.linerange)
222+
self.assertEqual(0, issue.col_offset)
223+
224+
def test_cryptography_ciphers_algorithms_arc4(self):
225+
fdata = textwrap.dedent(
226+
"""
227+
from cryptography.hazmat.primitives.ciphers import Cipher
228+
from cryptography.hazmat.primitives.ciphers import algorithms
229+
from cryptography.hazmat.backends import default_backend
230+
key = b'Super secret key'
231+
Cipher(
232+
algorithms.ARC4(key),
233+
mode=None,
234+
backend=default_backend()
235+
)
236+
"""
237+
)
238+
self.visitor.process(fdata)
239+
self.assertEqual(1, len(self.visitor.tester.results))
240+
issue = self.visitor.tester.results[0]
241+
self.assertEqual("B304", issue.test_id)
242+
self.assertEqual(bandit.HIGH, issue.severity)
243+
self.assertEqual(bandit.HIGH, issue.confidence)
244+
self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id)
245+
self.assertEqual(7, issue.lineno)
246+
self.assertEqual([7], issue.linerange)
247+
self.assertEqual(4, issue.col_offset)
248+
249+
def test_cryptography_ciphers_algorithms_blowfish(self):
250+
fdata = textwrap.dedent(
251+
"""
252+
from cryptography.hazmat.primitives.ciphers import Cipher
253+
from cryptography.hazmat.primitives.ciphers import algorithms
254+
from cryptography.hazmat.backends import default_backend
255+
key = b'Super secret key'
256+
Cipher(
257+
algorithms.Blowfish(key),
258+
mode=None,
259+
backend=default_backend()
260+
)
261+
"""
262+
)
263+
self.visitor.process(fdata)
264+
self.assertEqual(1, len(self.visitor.tester.results))
265+
issue = self.visitor.tester.results[0]
266+
self.assertEqual("B304", issue.test_id)
267+
self.assertEqual(bandit.HIGH, issue.severity)
268+
self.assertEqual(bandit.HIGH, issue.confidence)
269+
self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id)
270+
self.assertEqual(7, issue.lineno)
271+
self.assertEqual([7], issue.linerange)
272+
self.assertEqual(4, issue.col_offset)
273+
274+
def test_cryptography_ciphers_algorithms_idea(self):
275+
fdata = textwrap.dedent(
276+
"""
277+
from cryptography.hazmat.primitives.ciphers import Cipher
278+
from cryptography.hazmat.primitives.ciphers import algorithms
279+
from cryptography.hazmat.backends import default_backend
280+
key = b'Super secret key'
281+
Cipher(
282+
algorithms.IDEA(key),
283+
mode=None,
284+
backend=default_backend(),
285+
)
286+
"""
287+
)
288+
self.visitor.process(fdata)
289+
self.assertEqual(1, len(self.visitor.tester.results))
290+
issue = self.visitor.tester.results[0]
291+
self.assertEqual("B304", issue.test_id)
292+
self.assertEqual(bandit.HIGH, issue.severity)
293+
self.assertEqual(bandit.HIGH, issue.confidence)
294+
self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id)
295+
self.assertEqual(7, issue.lineno)
296+
self.assertEqual([7], issue.linerange)
297+
self.assertEqual(4, issue.col_offset)
+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
import textwrap
3+
4+
import bandit
5+
from bandit.core import issue as b_issue
6+
from tests.unit.blacklists import base_test_case
7+
8+
9+
class CipherModesTests(base_test_case.BaseTestCase):
10+
def setUp(self):
11+
super().setUp(["B305"])
12+
13+
def test_cipher_mode_ecb(self):
14+
fdata = textwrap.dedent(
15+
"""
16+
import os
17+
from cryptography.hazmat.primitives.ciphers.modes import ECB
18+
iv = os.urandom(16)
19+
ECB(iv)
20+
"""
21+
)
22+
self.visitor.process(fdata)
23+
self.assertEqual(1, len(self.visitor.tester.results))
24+
issue = self.visitor.tester.results[0]
25+
self.assertEqual("B305", issue.test_id)
26+
self.assertEqual(bandit.MEDIUM, issue.severity)
27+
self.assertEqual(bandit.HIGH, issue.confidence)
28+
self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id)
29+
self.assertEqual(5, issue.lineno)
30+
self.assertEqual([5], issue.linerange)
31+
self.assertEqual(0, issue.col_offset)
32+
33+
def test_cipher_mode_ctr(self):
34+
fdata = textwrap.dedent(
35+
"""
36+
import os
37+
from cryptography.hazmat.primitives.ciphers import algorithms
38+
from cryptography.hazmat.primitives.ciphers import modes
39+
key = os.urandom(32)
40+
iv = os.urandom(16)
41+
algorithms.AES.new(key, modes.CTR, iv)
42+
"""
43+
)
44+
self.visitor.process(fdata)
45+
self.assertEqual(0, len(self.visitor.tester.results))
46+
47+
def test_cipher_mode_cbc(self):
48+
fdata = textwrap.dedent(
49+
"""
50+
import os
51+
from cryptography.hazmat.primitives.ciphers.modes import CBC
52+
iv = os.urandom(16)
53+
CBC(iv)
54+
"""
55+
)
56+
self.visitor.process(fdata)
57+
self.assertEqual(0, len(self.visitor.tester.results))

0 commit comments

Comments
 (0)