29
29
PROJECT_ID = "00000000-0000-1000-8000-000000000001"
30
30
USER_ID = "00000000-0000-1000-8000-000000000002"
31
31
BRANCH_ID = "00000000-0000-1000-8000-000000000003"
32
+ # This follows the format of the subject that ActiveState sends us. We don't
33
+ # validate the format when verifying the JWT. That should happen when the
34
+ # Publisher is configured. We just need to make sure that the subject matches
35
+ #
36
+ # Technically, the branch should only be present if a branch was provided in the JWT
37
+ # claims
38
+ SUBJECT = "org:fake_org_id:project:fake_project_id:branch_id:fake_branch_id"
32
39
33
40
34
41
def test_lookup_strategies ():
@@ -40,65 +47,63 @@ def test_lookup_strategies():
40
47
41
48
42
49
def new_signed_claims (
43
- sub : str = "fake:fake:fake:fake" ,
50
+ sub : str = SUBJECT ,
44
51
organization_id : str = ORG_ID ,
45
52
org_url_name : str = "fakeorg" ,
46
53
project_id : str = PROJECT_ID ,
47
54
project_name : str = "fakeproject" ,
48
55
project_path : str = "fakeorg/fakeproject" ,
49
- user_id : str = "00000000-0000-1000-8000-000000000002" ,
56
+ user_id : str = USER_ID ,
50
57
project_visibility : str = "public" ,
51
58
branch_id : str | None = None ,
52
59
) -> SignedClaims :
53
60
project_name = "fakeproject"
54
61
org_url_name = "fakeorg"
55
- claims : SignedClaims = {
56
- "sub" : sub ,
57
- "organization_id" : organization_id ,
58
- "organization_url_name" : org_url_name ,
59
- "project_id" : project_id ,
60
- "project_name" : project_name ,
61
- "project_path" : project_path ,
62
- "user_id" : user_id ,
63
- "project_visibility" : project_visibility ,
64
- }
62
+ claims = SignedClaims (
63
+ {
64
+ "sub" : sub ,
65
+ "organization_id" : organization_id ,
66
+ "organization_url_name" : org_url_name ,
67
+ "project_id" : project_id ,
68
+ "project_name" : project_name ,
69
+ "project_path" : project_path ,
70
+ "user_id" : user_id ,
71
+ "project_visibility" : project_visibility ,
72
+ }
73
+ )
65
74
if branch_id :
66
75
claims ["branch_id" ] = branch_id
67
76
return claims
68
77
69
78
70
79
class TestActiveStatePublisher :
71
80
def test_publisher_name (self ):
72
- publisher = ActiveStatePublisher (
73
- organization_id = ORG_ID ,
74
- project_id = PROJECT_ID ,
75
- user_id = USER_ID ,
76
- project_visibility = "public" ,
77
- )
81
+ publisher = ActiveStatePublisher ()
78
82
79
83
assert publisher .publisher_name == "ActiveState"
80
84
81
85
def test_publisher_url (self ):
86
+ org_name = "fakeorg"
87
+ project_name = "fakeproject"
82
88
publisher = ActiveStatePublisher (
83
- organization_id = ORG_ID ,
84
- project_id = PROJECT_ID ,
85
- user_id = USER_ID ,
86
- project_visibility = "public" ,
89
+ organization_url_name = org_name , activestate_project_name = project_name
87
90
)
88
91
89
- assert publisher .publisher_url == "https://platform.activestate.com/oauth/oidc"
92
+ assert (
93
+ publisher .publisher_url ()
94
+ == f"https://platform.activestate.com/{ org_name } /{ project_name } "
95
+ )
90
96
91
- def test_stringifies_as_email (self ):
97
+ def test_stringifies_as_project_url (self ):
98
+ org_name = "fakeorg"
99
+ project_name = "fakeproject"
92
100
publisher = ActiveStatePublisher (
93
- organization_id = ORG_ID ,
94
- project_id = PROJECT_ID ,
95
- user_id = USER_ID ,
96
- project_visibility = "public" ,
101
+ organization_url_name = org_name , activestate_project_name = project_name
97
102
)
98
103
99
104
assert (
100
105
str (publisher )
101
- == f"https://platform.activestate.com/{ publisher . project_path } "
106
+ == f"https://platform.activestate.com/{ org_name } / { project_name } "
102
107
)
103
108
104
109
def test_activestate_publisher_all_known_claims (self ):
@@ -107,7 +112,6 @@ def test_activestate_publisher_all_known_claims(self):
107
112
"organization_id" ,
108
113
"project_id" ,
109
114
"user_id" ,
110
- "project_visibility" ,
111
115
"sub" ,
112
116
# optional verifiable claims
113
117
"branch_id" ,
@@ -118,18 +122,15 @@ def test_activestate_publisher_all_known_claims(self):
118
122
"exp" ,
119
123
"aud" ,
120
124
# unchecked claims
125
+ "project_visibility" ,
121
126
"project_name" ,
122
127
"project_path" ,
123
128
"organization_url_name" ,
124
129
}
125
130
126
131
def test_activestate_publisher_unaccounted_claims (self , monkeypatch ):
127
132
publisher = ActiveStatePublisher (
128
- sub = "fake:fake:fake:fake:fake:fake" ,
129
- organization_id = ORG_ID ,
130
- project_id = PROJECT_ID ,
131
- user_id = USER_ID ,
132
- project_visibility = "public" ,
133
+ sub = SUBJECT ,
133
134
)
134
135
135
136
scope = pretend .stub ()
@@ -143,7 +144,6 @@ def test_activestate_publisher_unaccounted_claims(self, monkeypatch):
143
144
)
144
145
monkeypatch .setattr (_core , "sentry_sdk" , sentry_sdk )
145
146
146
- # We don't care if these actually verify, only that they're present.
147
147
signed_claims = {
148
148
claim_name : "fake" for claim_name in ActiveStatePublisher .all_known_claims ()
149
149
}
@@ -158,13 +158,27 @@ def test_activestate_publisher_unaccounted_claims(self, monkeypatch):
158
158
]
159
159
assert scope .fingerprint == ["another-fake-claim" , "fake-claim" ]
160
160
161
- def test_activestate_publisher_missing_claims (self , monkeypatch ):
161
+ @pytest .mark .parametrize (
162
+ ("claim_to_drop" , "valid" ),
163
+ [
164
+ ("organization_id" , False ),
165
+ ("project_id" , False ),
166
+ ("user_id" , False ),
167
+ ("branch_id" , True ),
168
+ ("organization_url_name" , True ),
169
+ ("project_visibility" , True ),
170
+ ("project_name" , True ),
171
+ ("project_path" , True ),
172
+ ],
173
+ )
174
+ def test_activestate_publisher_missing_claims (
175
+ self , monkeypatch , claim_to_drop : str , valid : bool
176
+ ):
162
177
publisher = ActiveStatePublisher (
163
- sub = "fake:fake:fake:fake:fake:fake" ,
164
- organization_id = "fake" ,
165
- project_id = "fake" ,
166
- user_id = "fake" ,
167
- project_visibility = "fake" ,
178
+ sub = SUBJECT ,
179
+ organization_id = ORG_ID ,
180
+ project_id = PROJECT_ID ,
181
+ user_id = USER_ID ,
168
182
)
169
183
170
184
scope = pretend .stub ()
@@ -178,21 +192,21 @@ def test_activestate_publisher_missing_claims(self, monkeypatch):
178
192
)
179
193
monkeypatch .setattr (_core , "sentry_sdk" , sentry_sdk )
180
194
181
- signed_claims = {
182
- claim_name : "fake" for claim_name in ActiveStatePublisher .all_known_claims ()
183
- }
184
- signed_claims ["sub" ] = "fake:fake:fake:fake:fake:fake"
185
- # Pop the first signed claim, so that it's the first one to fail.
186
- signed_claims .pop ("organization_id" )
187
- assert "organization_id" not in signed_claims
195
+ signed_claims = new_signed_claims ()
196
+ # I don't set branch_id in the claims by default, so no need to remove it
197
+ if claim_to_drop != "branch_id" :
198
+ # Remove a required claim to test that the code detects it's missing
199
+ signed_claims .pop (claim_to_drop )
200
+ assert claim_to_drop not in signed_claims
188
201
assert publisher .__required_verifiable_claims__
189
- assert not publisher .verify_claims (signed_claims = signed_claims )
190
- assert sentry_sdk .capture_message .calls == [
191
- pretend .call (
192
- "JWT for ActiveStatePublisher is missing claim: organization_id"
193
- )
194
- ]
195
- assert scope .fingerprint == ["organization_id" ]
202
+ assert publisher .verify_claims (signed_claims = signed_claims ) is valid
203
+ if not valid :
204
+ assert sentry_sdk .capture_message .calls == [
205
+ pretend .call (
206
+ "JWT for ActiveStatePublisher is missing claim: " + claim_to_drop
207
+ )
208
+ ]
209
+ assert scope .fingerprint == [claim_to_drop ]
196
210
197
211
@pytest .mark .parametrize (
198
212
("expect" , "actual" , "valid" ),
@@ -205,11 +219,10 @@ def test_activestate_publisher_org_id_verified(
205
219
self , expect : str , actual : str , valid : bool
206
220
):
207
221
publisher = ActiveStatePublisher (
208
- sub = "fake:fake:fake:fake" ,
222
+ sub = SUBJECT ,
209
223
organization_id = actual ,
210
224
project_id = PROJECT_ID ,
211
225
user_id = USER_ID ,
212
- project_visibility = "public" ,
213
226
)
214
227
215
228
signed_claims = new_signed_claims (organization_id = expect )
@@ -218,66 +231,64 @@ def test_activestate_publisher_org_id_verified(
218
231
@pytest .mark .parametrize (
219
232
("expect" , "actual" , "valid" ),
220
233
[
221
- (PROJECT_ID , PROJECT_ID , True ),
222
- (PROJECT_ID , ORG_ID , False ),
234
+ (BRANCH_ID , BRANCH_ID , True ),
235
+ (BRANCH_ID , PROJECT_ID , False ),
236
+ (None , None , True ),
237
+ (BRANCH_ID , None , False ),
223
238
],
224
239
)
225
- def test_activestate_publisher_project_id_verified (
240
+ def test_activestate_publisher_branch_id_verified (
226
241
self , expect : str , actual : str , valid : bool
227
242
):
228
243
publisher = ActiveStatePublisher (
229
- sub = "fake:fake:fake:fake" ,
244
+ sub = SUBJECT ,
230
245
organization_id = ORG_ID ,
231
- project_id = actual ,
246
+ project_id = PROJECT_ID ,
232
247
user_id = USER_ID ,
233
- project_visibility = "public" ,
248
+ branch_id = expect ,
234
249
)
235
250
236
- signed_claims = new_signed_claims (project_id = expect )
251
+ signed_claims = new_signed_claims (branch_id = actual )
237
252
assert publisher .verify_claims (signed_claims = signed_claims ) is valid
238
253
239
254
@pytest .mark .parametrize (
240
255
("expect" , "actual" , "valid" ),
241
256
[
242
- (USER_ID , USER_ID , True ),
243
- (USER_ID , ORG_ID , False ),
257
+ (PROJECT_ID , PROJECT_ID , True ),
258
+ (PROJECT_ID , ORG_ID , False ),
244
259
],
245
260
)
246
- def test_activestate_publisher_user_id_verified (
261
+ def test_activestate_publisher_project_id_verified (
247
262
self , expect : str , actual : str , valid : bool
248
263
):
249
264
publisher = ActiveStatePublisher (
250
- sub = "fake:fake:fake:fake" ,
265
+ sub = SUBJECT ,
251
266
organization_id = ORG_ID ,
252
- project_id = PROJECT_ID ,
253
- user_id = actual ,
254
- project_visibility = "public" ,
267
+ project_id = actual ,
268
+ user_id = USER_ID ,
255
269
)
256
270
257
- signed_claims = new_signed_claims (user_id = expect )
271
+ signed_claims = new_signed_claims (project_id = expect )
258
272
assert publisher .verify_claims (signed_claims = signed_claims ) is valid
259
273
260
274
@pytest .mark .parametrize (
261
275
("expect" , "actual" , "valid" ),
262
276
[
263
- ("public" , "public" , True ),
264
- ("private" , "private" , True ),
265
- ("public" , "private" , False ),
266
- ("private" , "public" , False ),
277
+ (USER_ID , USER_ID , True ),
278
+ (USER_ID , ORG_ID , False ),
267
279
],
268
280
)
269
- def test_activestate_publisher_project_vis_verified (
281
+ def test_activestate_publisher_user_id_verified (
270
282
self , expect : str , actual : str , valid : bool
271
283
):
272
284
publisher = ActiveStatePublisher (
273
- sub = "fake:fake:fake:fake" ,
285
+ sub = SUBJECT ,
274
286
organization_id = ORG_ID ,
275
287
project_id = PROJECT_ID ,
276
- user_id = USER_ID ,
277
- project_visibility = actual ,
288
+ user_id = actual ,
278
289
)
279
290
280
- signed_claims = new_signed_claims (project_visibility = expect )
291
+ signed_claims = new_signed_claims (user_id = expect )
281
292
assert publisher .verify_claims (signed_claims = signed_claims ) is valid
282
293
283
294
@pytest .mark .parametrize (
@@ -317,7 +328,6 @@ def test_activestate_publisher_project_vis_verified(
317
328
)
318
329
def test_activestate_publisher_sub (self , expected : str , actual : str , valid : bool ):
319
330
check = ActiveStatePublisher .__required_verifiable_claims__ ["sub" ]
320
- # claims: SignedClaims = new_signed_claims(sub=actual)
321
331
assert check (expected , actual , pretend .stub ()) is valid
322
332
323
333
@@ -337,8 +347,6 @@ def test_reify_does_not_exist_yet(self, db_request):
337
347
)
338
348
publisher = pending_publisher .reify (db_request .db )
339
349
340
- # If an OIDC publisher for this pending publisher does not already exist,
341
- # a new one is created and the pending publisher is marked for deletion.
342
350
assert isinstance (publisher , ActiveStatePublisher )
343
351
assert pending_publisher in db_request .db .deleted
344
352
assert publisher .organization_id == pending_publisher .organization_id
@@ -350,12 +358,9 @@ def test_reify_already_exists(self, db_request):
350
358
organization_id = existing_publisher .organization_id ,
351
359
project_id = existing_publisher .project_id ,
352
360
branch_id = existing_publisher .branch_id ,
353
- project_visibility = existing_publisher .project_visibility ,
354
361
sub = existing_publisher .sub ,
355
362
)
356
363
publisher = pending_publisher .reify (db_request .db )
357
364
358
- # If an OIDC publisher for this pending publisher already exists,
359
- # it is returned and the pending publisher is marked for deletion.
360
365
assert existing_publisher == publisher
361
366
assert pending_publisher in db_request .db .deleted
0 commit comments