Skip to content

Commit f88b169

Browse files
committed
Add tests for missing coverage
Signed-off-by: Facundo Tuesca <facundo.tuesca@trailofbits.com>
1 parent cb55411 commit f88b169

File tree

2 files changed

+66
-24
lines changed

2 files changed

+66
-24
lines changed

src/pypi_attestations/_cli.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ def _verify_attestation(args: argparse.Namespace) -> None:
385385
"""Verify the files passed as argument."""
386386
pol = policy.Identity(identity=args.identity)
387387

388-
# Validate that both the attestations and files exists
388+
# Validate that both the attestations and files exist
389389
_validate_files(args.files, should_exist=True)
390390
_validate_files(
391391
(Path(f"{file_path}.publish.attestation") for file_path in args.files),
@@ -394,16 +394,8 @@ def _verify_attestation(args: argparse.Namespace) -> None:
394394

395395
inputs: list[Path] = []
396396
for file_path in args.files:
397-
# Collect only the inputs themselves, not their attestations.
398-
# Attestation paths are inferred subsequently.
399-
if file_path.name.endswith(".publish.attestation"):
400-
_logger.warning(f"skipping attestation path while collecting file inputs: {file_path}")
401-
continue
402397
inputs.append(file_path)
403398

404-
if not inputs:
405-
_die("No inputs given; make sure you passed distributions and not attestations as inputs")
406-
407399
for input in inputs:
408400
attestation_path = Path(f"{input}.publish.attestation")
409401
try:

test/test_cli.py

Lines changed: 65 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
get_identity_token,
2222
main,
2323
)
24-
from pypi_attestations._impl import Attestation
24+
from pypi_attestations._impl import Attestation, AttestationError
2525

2626
ONLINE_TESTS = "CI" in os.environ or "TEST_INTERACTIVE" in os.environ
2727
online = 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+
275325
def 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

Comments
 (0)