Skip to content

Commit 6ac3ea1

Browse files
edwarj2justineyster
authored andcommitted
Cloudant 2 (Yelp#207)
* clarify var names in test * help text * correcting account / pw test verification path * correcting validation error response * change detector vars & add cases * detection tests clean pending verification tests * all tests clean * added more key assignment tests * PR simplifications * fix capture group * fix capture group 2
1 parent b0cd34b commit 6ac3ea1

File tree

2 files changed

+70
-39
lines changed

2 files changed

+70
-39
lines changed

Diff for: detect_secrets/plugins/cloudant.py

+28-17
Original file line numberDiff line numberDiff line change
@@ -15,37 +15,48 @@ class CloudantDetector(RegexBasedDetector):
1515
opt_dashes = r'(?:--|)'
1616
opt_dot = r'(?:\.|)'
1717
dot = r'\.'
18-
cl_account = r'[0-9a-z\-\_]*'
19-
cl = r'(cloudant|cl|clou)'
18+
cl_account = r'[0-9a-z\-\_]+'
19+
cl = r'(?:cloudant|cl|clou)'
2020
opt_dash_undrscr = r'(?:_|-|)'
2121
opt_api = r'(?:api|)'
22-
cl_key_or_pass = cl + opt_dash_undrscr + r'(?:key|pwd|pw|password|pass|token)'
22+
cl_key_or_pass = opt_api + r'(?:key|pwd|pw|password|pass|token)'
2323
opt_space = r'(?: |)'
2424
assignment = r'(?:=|:|:=|=>)'
25-
cl_secret = r'[0-9a-f]{64}'
25+
cl_pw = r'([0-9a-f]{64})'
26+
cl_api_key = r'([a-z]{24})'
2627
colon = r'\:'
2728
at = r'\@'
28-
http = r'(?:http\:\/\/|https\:\/\/)'
29+
http = r'(?:https?\:\/\/)'
2930
cloudant_api_url = r'cloudant\.com'
3031
denylist = [
32+
RegexBasedDetector.assign_regex_generator(
33+
prefix_regex=cl,
34+
password_keyword_regex=cl_key_or_pass,
35+
password_regex=cl_pw,
36+
),
37+
RegexBasedDetector.assign_regex_generator(
38+
prefix_regex=cl,
39+
password_keyword_regex=cl_key_or_pass,
40+
password_regex=cl_api_key,
41+
),
3142
re.compile(
32-
r'{cl_key_or_pass}{opt_space}{assignment}{opt_space}{opt_quote}{cl_secret}'.format(
33-
cl_key_or_pass=cl_key_or_pass,
34-
opt_quote=opt_quote,
43+
r'{http}{cl_account}{colon}{cl_pw}{at}{cl_account}{dot}{cloudant_api_url}'.format(
44+
http=http,
45+
colon=colon,
3546
cl_account=cl_account,
36-
opt_dash_undrscr=opt_dash_undrscr,
37-
opt_api=opt_api,
38-
opt_space=opt_space,
39-
assignment=assignment,
40-
cl_secret=cl_secret,
41-
), flags=re.IGNORECASE,
47+
cl_pw=cl_pw,
48+
at=at,
49+
dot=dot,
50+
cloudant_api_url=cloudant_api_url,
51+
),
52+
flags=re.IGNORECASE,
4253
),
4354
re.compile(
44-
r'{http}{cl_account}{colon}{cl_secret}{at}{cl_account}{dot}{cloudant_api_url}'.format(
55+
r'{http}{cl_account}{colon}{cl_api_key}{at}{cl_account}{dot}{cloudant_api_url}'.format(
4556
http=http,
4657
colon=colon,
4758
cl_account=cl_account,
48-
cl_secret=cl_secret,
59+
cl_api_key=cl_api_key,
4960
at=at,
5061
dot=dot,
5162
cloudant_api_url=cloudant_api_url,
@@ -103,7 +114,7 @@ def verify_cloudant_key(hostname, token, potential_secret=None):
103114
request_url = 'https://{hostname}:' \
104115
'{token}' \
105116
'@{hostname}.' \
106-
'cloudant.com/_api/v2'.format(
117+
'cloudant.com'.format(
107118
hostname=hostname,
108119
token=token,
109120
)

Diff for: tests/plugins/cloudant_test.py

+42-22
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@
99
from detect_secrets.plugins.cloudant import get_host
1010

1111
CL_HOST = 'testy_test' # also called user
12-
# only detecting 64 hex
13-
CL_TOKEN = 'abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234'
12+
# only detecting 64 hex CL generated password
13+
CL_PW = 'abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234'
14+
15+
# detecting 24 alpha for CL generated API KEYS
16+
CL_API_KEY = 'abcdefghijabcdefghijabcd'
1417

1518

1619
class TestCloudantDetector:
@@ -19,25 +22,42 @@ class TestCloudantDetector:
1922
'payload, should_flag',
2023
[
2124
(
22-
'https://{cl_host}:{cl_token}@{cl_host}.cloudant.com"'.format(
23-
cl_host=CL_HOST, cl_token=CL_TOKEN,
25+
'https://{cl_host}:{cl_pw}@{cl_host}.cloudant.com"'.format(
26+
cl_host=CL_HOST, cl_pw=CL_PW,
27+
), True,
28+
),
29+
(
30+
'https://{cl_host}:{cl_pw}@{cl_host}.cloudant.com/_api/v2/'.format(
31+
cl_host=CL_HOST, cl_pw=CL_PW,
32+
), True,
33+
),
34+
(
35+
'https://{cl_host}:{cl_pw}@{cl_host}.cloudant.com/_api/v2/'.format(
36+
cl_host=CL_HOST, cl_pw=CL_PW,
37+
), True,
38+
),
39+
(
40+
'https://{cl_host}:{cl_pw}@{cl_host}.cloudant.com'.format(
41+
cl_host=CL_HOST, cl_pw=CL_PW,
2442
), True,
2543
),
2644
(
27-
'https://{cl_host}:{cl_token}@{cl_host}.cloudant.com/_api/v2/'.format(
28-
cl_host=CL_HOST, cl_token=CL_TOKEN,
45+
'https://{cl_host}:{cl_api_key}@{cl_host}.cloudant.com'.format(
46+
cl_host=CL_HOST, cl_api_key=CL_API_KEY,
2947
), True,
3048
),
3149
(
32-
'https://{cl_host}:{cl_token}.cloudant.com'.format(
33-
cl_host=CL_HOST, cl_token=CL_TOKEN,
50+
'https://{cl_host}:{cl_pw}.cloudant.com'.format(
51+
cl_host=CL_HOST, cl_pw=CL_PW,
3452
), False,
3553
),
36-
('cloudant_password=\'{cl_token}\''.format(cl_token=CL_TOKEN), True),
37-
('cloudant_pw=\'{cl_token}\''.format(cl_token=CL_TOKEN), True),
38-
('cloudant_pw="{cl_token}"'.format(cl_token=CL_TOKEN), True),
39-
('clou_pw = "{cl_token}"'.format(cl_token=CL_TOKEN), True),
54+
('cloudant_password=\'{cl_pw}\''.format(cl_pw=CL_PW), True),
55+
('cloudant_pw=\'{cl_pw}\''.format(cl_pw=CL_PW), True),
56+
('cloudant_pw="{cl_pw}"'.format(cl_pw=CL_PW), True),
57+
('clou_pw = "{cl_pw}"'.format(cl_pw=CL_PW), True),
58+
('cloudant_key = "{cl_api_key}"'.format(cl_api_key=CL_API_KEY), True),
4059
('cloudant_password = "a-fake-tooshort-key"', False),
60+
('cl_api_key = "a-fake-api-key"', False),
4161
],
4262
)
4363
def test_analyze_string(self, payload, should_flag):
@@ -48,31 +68,31 @@ def test_analyze_string(self, payload, should_flag):
4868

4969
@responses.activate
5070
def test_verify_invalid_secret(self):
51-
cl_api_url = 'https://{cl_host}:{cl_token}@{cl_host}.cloudant.com/_api/v2'.format(
52-
cl_host=CL_HOST, cl_token=CL_TOKEN,
71+
cl_api_url = 'https://{cl_host}:{cl_pw}@{cl_host}.cloudant.com'.format(
72+
cl_host=CL_HOST, cl_pw=CL_PW,
5373
)
5474
responses.add(
5575
responses.GET, cl_api_url,
56-
json={'error': 'Access denied. '}, status=401,
76+
json={'error': 'unauthorized'}, status=401,
5777
)
5878

5979
assert CloudantDetector().verify(
60-
CL_TOKEN,
80+
CL_PW,
6181
'cloudant_host={}'.format(CL_HOST),
6282
) == VerifiedResult.VERIFIED_FALSE
6383

6484
@responses.activate
6585
def test_verify_valid_secret(self):
66-
cl_api_url = 'https://{cl_host}:{cl_token}@{cl_host}.cloudant.com/_api/v2'.format(
67-
cl_host=CL_HOST, cl_token=CL_TOKEN,
86+
cl_api_url = 'https://{cl_host}:{cl_pw}@{cl_host}.cloudant.com'.format(
87+
cl_host=CL_HOST, cl_pw=CL_PW,
6888
)
6989
responses.add(
7090
responses.GET, cl_api_url,
7191
json={'id': 1}, status=200,
7292
)
73-
potential_secret = PotentialSecret('test cloudant', 'test filename', CL_TOKEN)
93+
potential_secret = PotentialSecret('test cloudant', 'test filename', CL_PW)
7494
assert CloudantDetector().verify(
75-
CL_TOKEN,
95+
CL_PW,
7696
'cloudant_host={}'.format(CL_HOST),
7797
potential_secret,
7898
) == VerifiedResult.VERIFIED_TRUE
@@ -81,13 +101,13 @@ def test_verify_valid_secret(self):
81101
@responses.activate
82102
def test_verify_unverified_secret(self):
83103
assert CloudantDetector().verify(
84-
CL_TOKEN,
104+
CL_PW,
85105
'cloudant_host={}'.format(CL_HOST),
86106
) == VerifiedResult.UNVERIFIED
87107

88108
def test_verify_no_secret(self):
89109
assert CloudantDetector().verify(
90-
CL_TOKEN,
110+
CL_PW,
91111
'no_un={}'.format(CL_HOST),
92112
) == VerifiedResult.UNVERIFIED
93113

0 commit comments

Comments
 (0)