Skip to content

Commit d289de1

Browse files
authored
Merge pull request #398 from chaoss/feat/keymasking
Improvements to masking of API keys in error messages
2 parents 115b4ee + 2b89108 commit d289de1

4 files changed

Lines changed: 69 additions & 4 deletions

File tree

collectoss/tasks/github/util/github_data_access.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ def make_request(self, url, method="GET", timeout=100):
169169
raise UrlNotFoundException(f"Could not find {url}")
170170

171171
if response.status_code == 401:
172-
raise NotAuthorizedException(f"Could not authorize with the github api")
172+
raise NotAuthorizedException(f"Could not authorize with the github api using key: {mask_key(self.key)}")
173173

174174
if response.status_code == 410:
175175
response_msg = response.json().get("message")

collectoss/util/keys.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
def mask_key(key: str, first: int = 6, last: int = 3, stars: int = 6) -> str:
22
"""Mask key except for the first and last few characters."""
3-
if not isinstance(key, str) or len(key) <= (first + last):
4-
return "*" * stars
5-
return f"{key[:first]}{'*' * stars}{key[-last:]}"
3+
if key is None:
4+
return None
5+
6+
if isinstance(key, str):
7+
if key == "":
8+
return "*" * stars + f" Type: empty string"
9+
if len(key) <= (first + last):
10+
return "*" * stars
11+
return f"{key[:first]}{'*' * stars}{key[-last:]}"
12+
else:
13+
return "*" * stars + f" Type: {str(type(key))}"

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ testpaths = [
149149
"tests/test_application/test_cli/test_csv_utils.py",
150150
"tests/test_tasks/test_task_utilities/test_util/",
151151
"tests/test_application/test_db/test_timestamp_utils.py",
152+
"tests/test_util/test_keys.py",
152153
# "tests/test_routes", # runs, but needs a fixture for connecting to the web interface of Augur
153154
# "tests/test_metrics",
154155
# "tests/test_tasks",

tests/test_util/test_keys.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import pytest
2+
3+
from collectoss.util.keys import mask_key
4+
5+
6+
def test_none():
7+
assert mask_key(None) is None
8+
9+
def test_empty_string():
10+
assert mask_key("") == "*" * 6 + " Type: empty string"
11+
12+
def test_non_string():
13+
result = mask_key(12345)
14+
assert "*" in result
15+
assert str(type(12345)) in result
16+
17+
18+
def test_non_string_list():
19+
result = mask_key([1, 2, 3])
20+
assert "*" in result
21+
assert str(type([])) in result
22+
23+
24+
def test_short_string():
25+
assert mask_key("short") == f"******"
26+
27+
28+
def test_long_string_masked_correctly():
29+
key = "ghp_abcdefghij" # 14 chars → first 6 + 6 stars + last 3
30+
assert mask_key(key) == "ghp_ab******hij"
31+
32+
33+
def test_exactly_one_over_boundary():
34+
# 10 chars: first 6 + 6 stars + last 3
35+
key = "1234567890"
36+
assert mask_key(key) == "123456******890"
37+
38+
39+
def test_default_star_count_is_six():
40+
key = "abcdefghijk" # 11 chars
41+
result = mask_key(key)
42+
middle = result[6:-3]
43+
assert middle == "******"
44+
45+
46+
def test_custom_first_last_stars():
47+
# first=2, last=2, stars=3 → boundary=4; "hello" is 5 chars → masked
48+
assert mask_key("hello", first=2, last=2, stars=3) == "he***lo"
49+
50+
51+
def test_custom_stars_count_in_output():
52+
key = "abcdefghijk"
53+
result = mask_key(key, stars=10)
54+
assert result == "abcdef**********ijk"
55+
56+

0 commit comments

Comments
 (0)