diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index d1d24d6..e46d704 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -5,6 +5,9 @@ on: branches: - main +env: + FORCE_COLOR: "1" + jobs: build: runs-on: ubuntu-latest diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 938b48a..e921117 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -6,6 +6,9 @@ on: - main pull_request: +env: + FORCE_COLOR: "1" + jobs: lint: runs-on: ubuntu-latest diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 623f930..c29e9c3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,6 +7,9 @@ name: release permissions: {} +env: + FORCE_COLOR: "1" + jobs: build: name: Build distributions 📦 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e191aa0..e1f8601 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -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: diff --git a/src/pypi_attestations/_cli.py b/src/pypi_attestations/_cli.py index 67512e2..08073c3 100644 --- a/src/pypi_attestations/_cli.py +++ b/src/pypi_attestations/_cli.py @@ -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}") @@ -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}") diff --git a/test/test_cli.py b/test/test_cli.py index df559f8..57061b7 100644 --- a/test/test_cli.py +++ b/test/test_cli.py @@ -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 @@ -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) diff --git a/test/test_impl.py b/test/test_impl.py index b817bbd..ba8fa3d 100644 --- a/test/test_impl.py +++ b/test/test_impl.py @@ -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 @@ -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) @@ -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" @@ -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") @@ -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()) @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) @@ -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 = {