Skip to content

Commit 28237a4

Browse files
authored
dsse: add Envelope._from_json (#1039)
* dsse: add Envelope._from_json Signed-off-by: William Woodruff <william@trailofbits.com> * dsse: liskov Signed-off-by: William Woodruff <william@trailofbits.com> --------- Signed-off-by: William Woodruff <william@trailofbits.com>
1 parent ff8254c commit 28237a4

File tree

2 files changed

+56
-1
lines changed

2 files changed

+56
-1
lines changed

sigstore/dsse.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ class Envelope:
190190
"""
191191
Represents a DSSE envelope.
192192
193-
This class cannot be constructed directly; you must use `sign`.
193+
This class cannot be constructed directly; you must use `sign` or `from_json`.
194194
195195
See: <https://github.com/secure-systems-lab/dsse/blob/v1.0.0/envelope.md>
196196
"""
@@ -204,12 +204,26 @@ def __init__(self, inner: _Envelope) -> None:
204204

205205
self._inner = inner
206206

207+
@classmethod
208+
def _from_json(cls, contents: bytes | str) -> Envelope:
209+
"""Return a DSSE envelope from the given JSON representation."""
210+
inner = _Envelope().from_json(contents)
211+
return cls(inner)
212+
207213
def to_json(self) -> str:
208214
"""
209215
Return a JSON string with this DSSE envelope's contents.
210216
"""
211217
return self._inner.to_json()
212218

219+
def __eq__(self, other: object) -> bool:
220+
"""Equality for DSSE envelopes."""
221+
222+
if not isinstance(other, Envelope):
223+
return NotImplemented
224+
225+
return self._inner == other._inner
226+
213227

214228
def _pae(type_: str, body: bytes) -> bytes:
215229
"""

test/unit/test_dsse.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Copyright 2022 The Sigstore Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import base64
16+
import json
17+
18+
from sigstore import dsse
19+
20+
21+
class TestEnvelope:
22+
def test_roundtrip(self):
23+
raw = json.dumps(
24+
{
25+
"payload": base64.b64encode(b"foo").decode(),
26+
"payloadType": dsse.Envelope._TYPE,
27+
"signatures": [
28+
{"sig": base64.b64encode(b"lol").decode()},
29+
{"sig": base64.b64encode(b"lmao").decode()},
30+
],
31+
}
32+
)
33+
evp = dsse.Envelope._from_json(raw)
34+
35+
assert evp._inner.payload == b"foo"
36+
assert evp._inner.payload_type == dsse.Envelope._TYPE
37+
assert [b"lol", b"lmao"] == [s.sig for s in evp._inner.signatures]
38+
39+
serialized = evp.to_json()
40+
assert serialized == raw
41+
assert dsse.Envelope._from_json(serialized) == evp

0 commit comments

Comments
 (0)