2121 get_identity_token ,
2222 main ,
2323)
24- from pypi_attestations ._impl import Attestation
24+ from pypi_attestations ._impl import Attestation , AttestationError
2525
2626ONLINE_TESTS = "CI" in os .environ or "TEST_INTERACTIVE" in os .environ
2727online = pytest .mark .skipif (not ONLINE_TESTS , reason = "online tests not enabled" )
@@ -101,9 +101,7 @@ def test_sign_command(tmp_path: Path) -> None:
101101
102102
103103@online
104- def test_sign_command_failures (
105- tmp_path : Path , monkeypatch : pytest .MonkeyPatch , caplog : pytest .LogCaptureFixture
106- ) -> None :
104+ def test_sign_missing_file (caplog : pytest .LogCaptureFixture ) -> None :
107105 # Missing file
108106 with pytest .raises (SystemExit ):
109107 run_main_with_command (
@@ -115,9 +113,10 @@ def test_sign_command_failures(
115113 )
116114
117115 assert "not_exist.txt is not a file" in caplog .text
118- caplog .clear ()
119116
120- # Signature already exists
117+
118+ @online
119+ def test_sign_signature_already_exists (tmp_path : Path , caplog : pytest .LogCaptureFixture ) -> None :
121120 artifact = tmp_path / artifact_path .with_suffix (".copy2.whl" ).name
122121 artifact .touch (exist_ok = False )
123122
@@ -135,7 +134,11 @@ def test_sign_command_failures(
135134 assert "already exists" in caplog .text
136135 caplog .clear ()
137136
138- # Invalid token
137+
138+ @online
139+ def test_sign_invalid_token (
140+ monkeypatch : pytest .MonkeyPatch , caplog : pytest .LogCaptureFixture
141+ ) -> None :
139142 def return_invalid_token () -> str :
140143 return "invalid-token"
141144
@@ -146,14 +149,39 @@ def return_invalid_token() -> str:
146149 [
147150 "sign" ,
148151 "--staging" ,
149- artifact .as_posix (),
152+ artifact_path .as_posix (),
150153 ]
151154 )
152155
153156 assert "Failed to detect identity" in caplog .text
154157
155158
156- def test_inspect_command (caplog : pytest .LogCaptureFixture , monkeypatch : pytest .MonkeyPatch ) -> None :
159+ @online
160+ def test_sign_invalid_artifact (caplog : pytest .LogCaptureFixture , tmp_path : Path ) -> None :
161+ artifact = tmp_path / "pkg-1.0.0.exe"
162+ artifact .touch (exist_ok = False )
163+
164+ with pytest .raises (SystemExit ):
165+ run_main_with_command (["sign" , "--staging" , artifact .as_posix ()])
166+
167+ assert "Invalid Python package distribution" in caplog .text
168+
169+
170+ @online
171+ def test_sign_fail_to_sign (
172+ monkeypatch : pytest .MonkeyPatch , caplog : pytest .LogCaptureFixture , tmp_path : Path
173+ ) -> None :
174+ monkeypatch .setattr (pypi_attestations ._cli , "Attestation" , stub (sign = raiser (AttestationError )))
175+ copied_artifact = tmp_path / artifact_path .with_suffix (".copy.whl" ).name
176+ shutil .copy (artifact_path , copied_artifact )
177+
178+ with pytest .raises (SystemExit ):
179+ run_main_with_command (["sign" , "--staging" , copied_artifact .as_posix ()])
180+
181+ assert "Failed to sign:" in caplog .text
182+
183+
184+ def test_inspect_command (caplog : pytest .LogCaptureFixture ) -> None :
157185 # Happy path
158186 run_main_with_command (["inspect" , attestation_path .as_posix ()])
159187 assert attestation_path .as_posix () in caplog .text
@@ -183,9 +211,7 @@ def test_inspect_command(caplog: pytest.LogCaptureFixture, monkeypatch: pytest.M
183211 assert "not_a_file.txt is not a file." in caplog .text
184212
185213
186- def test_verify_attestation_command (
187- caplog : pytest .LogCaptureFixture , monkeypatch : pytest .MonkeyPatch
188- ) -> None :
214+ def test_verify_attestation_command (caplog : pytest .LogCaptureFixture ) -> None :
189215 # Happy path
190216 run_main_with_command (
191217 [
@@ -219,7 +245,7 @@ def test_verify_attestation_command(
219245 assert "OK:" not in caplog .text
220246
221247
222- def test_verify_attestation_command_failures (caplog : pytest .LogCaptureFixture ) -> None :
248+ def test_verify_attestation_invalid_attestation (caplog : pytest .LogCaptureFixture ) -> None :
223249 # Failure because not an attestation
224250 with pytest .raises (SystemExit ):
225251 with tempfile .NamedTemporaryFile (suffix = ".publish.attestation" ) as f :
@@ -238,8 +264,9 @@ def test_verify_attestation_command_failures(caplog: pytest.LogCaptureFixture) -
238264 )
239265 assert "Invalid attestation" in caplog .text
240266
267+
268+ def test_verify_attestation_missing_artifact (caplog : pytest .LogCaptureFixture ) -> None :
241269 # Failure because missing package file
242- caplog .clear ()
243270 with pytest .raises (SystemExit ):
244271 run_main_with_command (
245272 [
@@ -254,8 +281,9 @@ def test_verify_attestation_command_failures(caplog: pytest.LogCaptureFixture) -
254281
255282 assert "not_a_file.txt is not a file." in caplog .text
256283
284+
285+ def test_verify_attestation_missing_attestation (caplog : pytest .LogCaptureFixture ) -> None :
257286 # Failure because missing attestation file
258- caplog .clear ()
259287 with pytest .raises (SystemExit ):
260288 with tempfile .NamedTemporaryFile () as f :
261289 run_main_with_command (
@@ -272,6 +300,28 @@ def test_verify_attestation_command_failures(caplog: pytest.LogCaptureFixture) -
272300 assert "is not a file." in caplog .text
273301
274302
303+ def test_verify_attestation_invalid_artifact (
304+ caplog : pytest .LogCaptureFixture , tmp_path : Path
305+ ) -> None :
306+ copied_artifact = tmp_path / artifact_path .with_suffix (".whl2" ).name
307+ shutil .copy (artifact_path , copied_artifact )
308+ copied_attestation = tmp_path / artifact_path .with_suffix (".whl2.publish.attestation" ).name
309+ shutil .copy (attestation_path , copied_attestation )
310+
311+ with pytest .raises (SystemExit ):
312+ run_main_with_command (
313+ [
314+ "verify" ,
315+ "attestation" ,
316+ "--staging" ,
317+ "--identity" ,
318+ "william@yossarian.net" ,
319+ copied_artifact .as_posix (),
320+ ]
321+ )
322+ assert "Invalid Python package distribution" in caplog .text
323+
324+
275325def test_get_identity_token_oauth_flow (monkeypatch : pytest .MonkeyPatch ) -> None :
276326 # If no ambient credential is available, default to the OAuth2 flow
277327 monkeypatch .setattr (sigstore .oidc , "detect_credential" , lambda : None )
0 commit comments