Skip to content
This repository was archived by the owner on Nov 1, 2023. It is now read-only.

Commit 5f72cc2

Browse files
authored
Fix issue when deserializing GithubIssueTemplate with hidden secret (#1008)
1 parent 4c9a9f2 commit 5f72cc2

File tree

3 files changed

+101
-32
lines changed

3 files changed

+101
-32
lines changed

src/api-service/tests/test_secrets.py

+85-27
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
JobTemplateNotification,
1515
)
1616
from onefuzztypes.models import (
17+
ADOTemplate,
18+
GithubAuth,
19+
GithubIssueTemplate,
1720
JobConfig,
1821
Notification,
1922
NotificationConfig,
@@ -27,13 +30,14 @@
2730
from __app__.onefuzzlib.orm import hide_secrets
2831

2932

33+
def hider(secret_data: SecretData) -> SecretData:
34+
if not isinstance(secret_data.secret, SecretAddress):
35+
secret_data.secret = SecretAddress(url="blah blah")
36+
return secret_data
37+
38+
3039
class TestSecret(unittest.TestCase):
3140
def test_hide(self) -> None:
32-
def hider(secret_data: SecretData) -> SecretData:
33-
if not isinstance(secret_data.secret, SecretAddress):
34-
secret_data.secret = SecretAddress(url="blah blah")
35-
return secret_data
36-
3741
notification = Notification(
3842
container=Container("data"),
3943
config=TeamsTemplate(url=SecretData(secret="http://test")),
@@ -47,11 +51,6 @@ def hider(secret_data: SecretData) -> SecretData:
4751
self.fail(f"Invalid config type {type(notification.config)}")
4852

4953
def test_hide_nested_list(self) -> None:
50-
def hider(secret_data: SecretData) -> SecretData:
51-
if not isinstance(secret_data.secret, SecretAddress):
52-
secret_data.secret = SecretAddress(url="blah blah")
53-
return secret_data
54-
5554
job_template_index = JobTemplateIndex(
5655
name="test",
5756
template=JobTemplate(
@@ -100,12 +99,33 @@ def test_roundtrip_github_issue(self) -> None:
10099
f"{current_path}"
101100
+ "/../../../contrib/onefuzz-job-github-actions/github-issues.json"
102101
) as json_file:
103-
b = json.load(json_file)
104-
b["container"] = "testing"
105-
c = NotificationCreate.parse_obj(b)
106-
d = c.json()
107-
e = json.loads(d)
108-
NotificationCreate.parse_obj(e)
102+
notification_dict = json.load(json_file)
103+
notification_dict["container"] = "testing"
104+
notification1 = NotificationCreate.parse_obj(notification_dict)
105+
106+
assert isinstance(notification1.config, GithubIssueTemplate)
107+
self.assertIsInstance(
108+
notification1.config.auth.secret, GithubAuth, "Invalid secret type"
109+
)
110+
111+
notification2 = NotificationCreate.parse_obj(
112+
json.loads(notification1.json())
113+
)
114+
115+
assert isinstance(notification2.config, GithubIssueTemplate)
116+
self.assertIsInstance(
117+
notification2.config.auth.secret, GithubAuth, "Invalid secret type"
118+
)
119+
120+
hide_secrets(notification2, hider)
121+
122+
notification3 = NotificationCreate.parse_obj(
123+
json.loads(notification2.json())
124+
)
125+
assert isinstance(notification3.config, GithubIssueTemplate)
126+
self.assertIsInstance(
127+
notification3.config.auth.secret, SecretAddress, "Invalid secret type"
128+
)
109129

110130
def test_roundtrip_team_issue(self) -> None:
111131
a = """
@@ -115,21 +135,59 @@ def test_roundtrip_team_issue(self) -> None:
115135
}
116136
117137
""" # noqa
118-
b = json.loads(a)
119-
c = NotificationCreate.parse_obj(b)
120-
d = c.json()
121-
e = json.loads(d)
122-
NotificationCreate.parse_obj(e)
138+
notification_dict = json.loads(a)
139+
notification_dict["container"] = "testing"
140+
notification1 = NotificationCreate.parse_obj(notification_dict)
141+
142+
assert isinstance(notification1.config, TeamsTemplate)
143+
self.assertIsInstance(
144+
notification1.config.url.secret, str, "Invalid secret type"
145+
)
146+
147+
notification2 = NotificationCreate.parse_obj(json.loads(notification1.json()))
148+
assert isinstance(notification2.config, TeamsTemplate)
149+
self.assertIsInstance(
150+
notification2.config.url.secret, str, "Invalid secret type"
151+
)
152+
153+
hide_secrets(notification2, hider)
154+
155+
notification3 = NotificationCreate.parse_obj(json.loads(notification2.json()))
156+
assert isinstance(notification3.config, TeamsTemplate)
157+
self.assertIsInstance(
158+
notification3.config.url.secret, SecretAddress, "Invalid secret type"
159+
)
123160

124161
def test_roundtrip_ado(self) -> None:
125162
current_path = pathlib.Path(__file__).parent.absolute()
126163
with open(
127164
f"{current_path}"
128165
+ "/../../../contrib/onefuzz-job-azure-devops-pipeline/ado-work-items.json" # noqa
129166
) as json_file:
130-
b = json.load(json_file)
131-
b["container"] = "testing"
132-
c = NotificationCreate.parse_obj(b)
133-
d = c.json()
134-
e = json.loads(d)
135-
NotificationCreate.parse_obj(e)
167+
notification_dict = json.load(json_file)
168+
notification_dict["container"] = "testing"
169+
notification1 = NotificationCreate.parse_obj(notification_dict)
170+
assert isinstance(notification1.config, ADOTemplate)
171+
self.assertIsInstance(
172+
notification1.config.auth_token.secret, str, "Invalid secret type"
173+
)
174+
175+
notification2 = NotificationCreate.parse_obj(
176+
json.loads(notification1.json())
177+
)
178+
assert isinstance(notification2.config, ADOTemplate)
179+
self.assertIsInstance(
180+
notification2.config.auth_token.secret, str, "Invalid secret type"
181+
)
182+
183+
hide_secrets(notification2, hider)
184+
185+
notification3 = NotificationCreate.parse_obj(
186+
json.loads(notification2.json())
187+
)
188+
assert isinstance(notification3.config, ADOTemplate)
189+
self.assertIsInstance(
190+
notification3.config.auth_token.secret,
191+
SecretAddress,
192+
"Invalid secret type",
193+
)

src/pytypes/onefuzztypes/models.py

+15-4
Original file line numberDiff line numberDiff line change
@@ -511,15 +511,26 @@ class GithubIssueTemplate(BaseModel):
511511
# validator needed for backward compatibility
512512
@validator("auth", pre=True, always=True)
513513
def validate_auth(cls, v: Any) -> SecretData:
514+
def try_parse_GithubAuth(x: dict) -> Optional[GithubAuth]:
515+
try:
516+
return GithubAuth.parse_obj(x)
517+
except Exception:
518+
return None
519+
514520
if isinstance(v, GithubAuth):
515521
return SecretData(secret=v)
516522
elif isinstance(v, SecretData):
517523
return v
518524
elif isinstance(v, dict):
519-
try:
520-
return SecretData(GithubAuth.parse_obj(v))
521-
except Exception:
522-
return SecretData(GithubAuth.parse_obj(v["secret"]))
525+
githubAuth = try_parse_GithubAuth(v)
526+
if githubAuth:
527+
return SecretData(secret=githubAuth)
528+
529+
githubAuth = try_parse_GithubAuth(v["secret"])
530+
if githubAuth:
531+
return SecretData(secret=githubAuth)
532+
533+
return SecretData(secret=v["secret"])
523534
else:
524535
raise TypeError(f"invalid datatype {type(v)}")
525536

src/pytypes/tests/test_models.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
import unittest
77

88
from onefuzztypes.models import Scaleset, SecretData, TeamsTemplate
9-
from onefuzztypes.requests import NotificationCreate
109
from onefuzztypes.primitives import PoolName, Region
10+
from onefuzztypes.requests import NotificationCreate
1111
from pydantic import ValidationError
1212

1313

0 commit comments

Comments
 (0)