From 149ba686ca34fafad42ac57ede04463d16681037 Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Mon, 5 Aug 2024 13:36:56 -0700 Subject: [PATCH] Add `SigstoreSignature` for storing Sigstore signatures Signed-off-by: Mihai Maruseac --- model_signing/signing/in_toto.py | 4 +- model_signing/signing/sigstore.py | 68 +++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 model_signing/signing/sigstore.py diff --git a/model_signing/signing/in_toto.py b/model_signing/signing/in_toto.py index 129fbaf7..055d3e09 100644 --- a/model_signing/signing/in_toto.py +++ b/model_signing/signing/in_toto.py @@ -132,7 +132,7 @@ def _convert_descriptors_to_hashed_statement( *, predicate_type: str, predicate_top_level_name: str, -): +) -> statement.Statement: """Converts manifest descriptors to an in-toto statement with payload. Args: @@ -359,7 +359,7 @@ def from_manifest(cls, manifest: manifest_module.Manifest) -> Self: def _convert_descriptors_to_direct_statement( manifest: manifest_module.Manifest, predicate_type: str -): +) -> statement.Statement: """Converts manifest descriptors to an in-toto statement, as subjects. Args: diff --git a/model_signing/signing/sigstore.py b/model_signing/signing/sigstore.py new file mode 100644 index 00000000..f30e5343 --- /dev/null +++ b/model_signing/signing/sigstore.py @@ -0,0 +1,68 @@ +# Copyright 2024 The Sigstore Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Sigstore based signature, signers and verifiers.""" + +import pathlib +from typing import Self + +from sigstore import models as sigstore_models +from typing_extensions import override + +from model_signing.signing import signing + + +class SigstoreSignature(signing.Signature): + """Sigstore signature support, wrapping around `sigstore_models.Bundle`.""" + + def __init__(self, bundle: sigstore_models.Bundle): + """Builds an instance of this signature. + + Args: + bundle: the Sigstore `Bundle` to wrap around. + """ + self.bundle = bundle + + @override + def write(self, path: pathlib.Path) -> None: + """Writes the signature to disk, to the given path. + + The Sigstore `Bundle` is written in JSON format, per the + canonicalization defined by the `sigstore-python` library. + + Args: + path: the path to write the signature to. + """ + path.write_text(self.bundle.to_json()) + + @classmethod + @override + def read(cls, path: pathlib.Path) -> Self: + """Reads the signature from disk. + + Does not perform any signature verification, except what is needed to + parse the signature file. + + Args: + path: the path to read the signature from. + + Returns: + A `SigstoreSignature` object wrapping a Sigstore `Bundle`. + + Raises: + ValueError: If the Sigstore `Bundle` could not be deserialized from + the contents of the file pointed to by `path`. + """ + content = path.read_text() + return cls(sigstore_models.Bundle.from_json(content))