Skip to content

Commit

Permalink
add signing test using public OIDC beacon
Browse files Browse the repository at this point in the history
Signed-off-by: Spencer Schrock <[email protected]>
  • Loading branch information
spencerschrock committed Nov 19, 2024
1 parent ff4e73d commit afe1223
Showing 1 changed file with 84 additions and 1 deletion.
85 changes: 84 additions & 1 deletion tests/signing/sigstore_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,15 @@

"""Tests for signing and verification with Sigstore."""

from base64 import b64decode
from datetime import datetime
from datetime import timedelta
import json
import pathlib
import sys
import time
from unittest import mock
from urllib import request

import pytest

Expand Down Expand Up @@ -189,6 +194,39 @@ def mocked_sigstore(
return True # keep in scope


class DangerousPublicOIDCBeacon:
"""Fetches and validates tokens from Sigstore's testing beacon repo."""

def __init__(self):
self._token_url = "https://raw.githubusercontent.com/sigstore-conformance/extremely-dangerous-public-oidc-beacon/refs/heads/current-token/oidc-token.txt"

def _fetch(self) -> None:
filename, headers = request.urlretrieve(self._token_url)
with open(filename) as f:
self._token = f.read().rstrip()
request.urlcleanup()

def _expiration(self) -> datetime:
payload = self._token.split(".")[1]
payload += "=" * (4 - len(payload) % 4)
payload_json = json.loads(b64decode(payload))
return datetime.fromtimestamp(payload_json["exp"])


@pytest.fixture
def sigstore_oidc_beacon_token():
beacon = DangerousPublicOIDCBeacon()
while True:
now = datetime.now()
print("fetching token: ", now) # DO NOT SUBMIT
deadline = now + timedelta(minutes=2)
beacon._fetch()
exp = beacon._expiration()
if deadline < exp:
return beacon._token
time.sleep(30) # DO NOT SUBMIT


class TestSigstoreSigning:
def _file_hasher_factory(self, path: pathlib.Path) -> file.FileHasher:
return file.SimpleFileHasher(path, memory.SHA256())
Expand All @@ -208,9 +246,14 @@ def _sign_manifest(
signer_type,
use_staging=True,
oidc_issuer=None,
identity_token=None,
):
payload = payload_type.from_manifest(manifest)
signer = signer_type(use_staging=use_staging, oidc_issuer=oidc_issuer)
signer = signer_type(
use_staging=use_staging,
oidc_issuer=oidc_issuer,
identity_token=identity_token,
)
signature = signer.sign(payload)
signature.write(signature_path)

Expand All @@ -226,6 +269,18 @@ def _verify_artifact_signature(
)
return verifier.verify(signature)

def _verify_artifact_signature_integration(
self, manifest, signature_path, use_staging=True
):
signature = sigstore.SigstoreSignature.read(signature_path)
verifier = sigstore.SigstoreArtifactVerifier(
expected_digest=manifest.digest.digest_value,
identity="https://github.com/sigstore-conformance/extremely-dangerous-public-oidc-beacon/.github/workflows/extremely-dangerous-oidc-beacon.yml@refs/heads/main",
oidc_issuer="https://token.actions.githubusercontent.com",
use_staging=use_staging,
)
return verifier.verify(signature)

def _verify_dsse_signature(self, signature_path, use_staging=True):
signature = sigstore.SigstoreSignature.read(signature_path)
verifier = sigstore.SigstoreDSSEVerifier(
Expand Down Expand Up @@ -485,6 +540,34 @@ def test_sign_identity_token_precedence(self, mocked_oidc_provider):
token = signer._get_identity_token()
assert token == "fake_token"

@pytest.mark.integration
def test_sign_staging(
self, sigstore_oidc_beacon_token, sample_model_folder, tmp_path
):
# Serialize and sign model
file_hasher = file.SimpleFileHasher(
pathlib.Path("unused"), memory.SHA256()
)
serializer = serialize_by_file.DigestSerializer(
file_hasher, memory.SHA256, allow_symlinks=True
)
manifest = serializer.serialize(sample_model_folder)
signature_path = tmp_path / "model.sig"
self._sign_manifest(
manifest,
signature_path,
as_bytes.BytesPayload,
sigstore.SigstoreArtifactSigner,
identity_token=sigstore_oidc_beacon_token,
)

# Read signature and check against expected serialization
local_manifest = serializer.serialize(sample_model_folder)
expected_manifest = self._verify_artifact_signature_integration(
local_manifest, signature_path
)
assert expected_manifest == manifest

def test_verify_artifact_signature_not_sigstore(self, mocked_sigstore):
signature = empty_signing.EmptySignature()
verifier = sigstore.SigstoreArtifactVerifier(
Expand Down

0 comments on commit afe1223

Please sign in to comment.