Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ on:
branches:
- main

env:
FORCE_COLOR: "1"

jobs:
build:
runs-on: ubuntu-latest
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ on:
- main
pull_request:

env:
FORCE_COLOR: "1"

jobs:
lint:
runs-on: ubuntu-latest
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ name: release

permissions: {}

env:
FORCE_COLOR: "1"

jobs:
build:
name: Build distributions 📦
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ on:
- main
pull_request:

env:
FORCE_COLOR: "1"
PYTHONDEVMODE: "1" # -X dev
PYTHONWARNDEFAULTENCODING: "1" # -X warn_default_encoding

jobs:
test:
strategy:
Expand Down
4 changes: 2 additions & 2 deletions src/pypi_attestations/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ def _inspect(args: argparse.Namespace) -> None:
_validate_files(args.files, should_exist=True)
for file_path in args.files:
try:
attestation = Attestation.model_validate_json(file_path.read_text())
attestation = Attestation.model_validate_json(file_path.read_bytes())
except ValidationError as validation_error:
_die(f"Invalid attestation ({file_path}): {validation_error}")

Expand Down Expand Up @@ -459,7 +459,7 @@ def _verify_attestation(args: argparse.Namespace) -> None:
for file_path, attestations in files_with_attestations.items():
for attestation_path in attestations:
try:
attestation = Attestation.model_validate_json(attestation_path.read_text())
attestation = Attestation.model_validate_json(attestation_path.read_bytes())
except ValidationError as validation_error:
_die(f"Invalid attestation ({attestation_path}): {validation_error}")

Expand Down
4 changes: 2 additions & 2 deletions test/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def test_sign_command(tmp_path: Path) -> None:
copied_artifact_attestation = Path(f"{copied_artifact}.publish.attestation")
assert copied_artifact_attestation.is_file()

attestation = Attestation.model_validate_json(copied_artifact_attestation.read_text())
attestation = Attestation.model_validate_json(copied_artifact_attestation.read_bytes())
assert attestation.version


Expand Down Expand Up @@ -544,7 +544,7 @@ def test_verify_pypi_validation_fails(
) -> None:
# Replace the actual wheel with another file
def _download_file(url: str, dest: Path) -> None:
with open(dest, "w") as f:
with open(dest, "w", encoding="utf-8") as f:
f.write("random wheel file")

monkeypatch.setattr(pypi_attestations._cli, "_download_file", _download_file)
Expand Down
26 changes: 13 additions & 13 deletions test/test_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def test_verify_from_gitlab_publisher(self) -> None:
workflow_filepath=".gitlab-ci.yml",
)

attestation = impl.Attestation.model_validate_json(gl_attestation_path.read_text())
attestation = impl.Attestation.model_validate_json(gl_attestation_path.read_bytes())
predicate_type, predicate = attestation.verify(publisher, gl_signed_dist)
assert predicate_type == "https://docs.pypi.org/attestations/publish/v1"
assert predicate is None
Expand All @@ -179,7 +179,7 @@ def test_verify_from_gitlab_publisher_wrong(self) -> None:
workflow_filepath="wrong.yml",
)

attestation = impl.Attestation.model_validate_json(gl_attestation_path.read_text())
attestation = impl.Attestation.model_validate_json(gl_attestation_path.read_bytes())
with pytest.raises(impl.VerificationError, match=r"Build Config URI .+ does not match"):
attestation.verify(publisher, gl_signed_dist)

Expand All @@ -189,7 +189,7 @@ def test_verify(self) -> None:
identity="william@yossarian.net", issuer="https://github.com/login/oauth"
)

attestation = impl.Attestation.model_validate_json(dist_attestation_path.read_text())
attestation = impl.Attestation.model_validate_json(dist_attestation_path.read_bytes())
predicate_type, predicate = attestation.verify(pol, dist, staging=True)

assert attestation.statement["_type"] == "https://in-toto.io/Statement/v1"
Expand All @@ -210,7 +210,7 @@ def test_verify_digest_mismatch(self, tmp_path: Path) -> None:
identity="william@yossarian.net", issuer="https://github.com/login/oauth"
)

attestation = impl.Attestation.model_validate_json(dist_attestation_path.read_text())
attestation = impl.Attestation.model_validate_json(dist_attestation_path.read_bytes())

modified_dist_path = tmp_path / dist_path.name
modified_dist_path.write_bytes(b"nothing")
Expand All @@ -229,7 +229,7 @@ def test_verify_filename_mismatch(self, tmp_path: Path) -> None:
identity="william@yossarian.net", issuer="https://github.com/login/oauth"
)

attestation = impl.Attestation.model_validate_json(dist_attestation_path.read_text())
attestation = impl.Attestation.model_validate_json(dist_attestation_path.read_bytes())

modified_dist_path = tmp_path / "wrong_name-0.1.2-py3-none-any.whl"
modified_dist_path.write_bytes(dist_path.read_bytes())
Expand All @@ -246,7 +246,7 @@ def test_verify_policy_mismatch(self) -> None:
# Wrong identity.
pol = policy.Identity(identity="fake@example.com", issuer="https://github.com/login/oauth")

attestation = impl.Attestation.model_validate_json(dist_attestation_path.read_text())
attestation = impl.Attestation.model_validate_json(dist_attestation_path.read_bytes())

with pytest.raises(impl.VerificationError, match=r"Certificate's SANs do not match"):
attestation.verify(pol, dist, staging=True)
Expand All @@ -260,7 +260,7 @@ def test_verify_wrong_envelope(self, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(impl.Verifier, "staging", staging)
pol = pretend.stub()

attestation = impl.Attestation.model_validate_json(dist_attestation_path.read_text())
attestation = impl.Attestation.model_validate_json(dist_attestation_path.read_bytes())

with pytest.raises(impl.VerificationError, match="expected JSON envelope, got fake-type"):
attestation.verify(pol, dist, staging=True)
Expand All @@ -276,7 +276,7 @@ def test_verify_bad_payload(self, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(impl.Verifier, "staging", staging)
pol = pretend.stub()

attestation = impl.Attestation.model_validate_json(dist_attestation_path.read_text())
attestation = impl.Attestation.model_validate_json(dist_attestation_path.read_bytes())

with pytest.raises(impl.VerificationError, match="invalid statement"):
attestation.verify(pol, dist, staging=True)
Expand Down Expand Up @@ -308,7 +308,7 @@ def test_verify_too_many_subjects(self, monkeypatch: pytest.MonkeyPatch) -> None
monkeypatch.setattr(impl.Verifier, "staging", staging)
pol = pretend.stub()

attestation = impl.Attestation.model_validate_json(dist_attestation_path.read_text())
attestation = impl.Attestation.model_validate_json(dist_attestation_path.read_bytes())

with pytest.raises(impl.VerificationError, match="too many subjects in statement"):
attestation.verify(pol, dist, staging=True)
Expand Down Expand Up @@ -339,7 +339,7 @@ def test_verify_subject_missing_name(self, monkeypatch: pytest.MonkeyPatch) -> N
monkeypatch.setattr(impl.Verifier, "staging", staging)
pol = pretend.stub()

attestation = impl.Attestation.model_validate_json(dist_attestation_path.read_text())
attestation = impl.Attestation.model_validate_json(dist_attestation_path.read_bytes())

with pytest.raises(impl.VerificationError, match="invalid subject: missing name"):
attestation.verify(pol, dist, staging=True)
Expand Down Expand Up @@ -373,7 +373,7 @@ def test_verify_subject_invalid_name(self, monkeypatch: pytest.MonkeyPatch) -> N
monkeypatch.setattr(impl.Verifier, "staging", staging)
pol = pretend.stub()

attestation = impl.Attestation.model_validate_json(dist_attestation_path.read_text())
attestation = impl.Attestation.model_validate_json(dist_attestation_path.read_bytes())

with pytest.raises(impl.VerificationError, match="invalid subject: Invalid wheel filename"):
attestation.verify(pol, dist, staging=True)
Expand Down Expand Up @@ -413,14 +413,14 @@ def test_verify_unknown_attestation_type(self, monkeypatch: pytest.MonkeyPatch)
monkeypatch.setattr(impl.Verifier, "staging", staging)
pol = pretend.stub()

attestation = impl.Attestation.model_validate_json(dist_attestation_path.read_text())
attestation = impl.Attestation.model_validate_json(dist_attestation_path.read_bytes())

with pytest.raises(impl.VerificationError, match="unknown attestation type: foo"):
attestation.verify(pol, dist, staging=True)

def test_certificate_claims(self) -> None:
attestation = impl.Attestation.model_validate_json(
pypi_attestations_attestation.read_text()
pypi_attestations_attestation.read_bytes()
)

results = {
Expand Down