Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ All versions prior to 0.9.0 are untracked.

### Fixed

* Avoid pydantic's instantiation issues with `TransparencyLogEntry` when `InclusionPromise` is not present.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is really related to pydantic (although I appreciate the neater handling in _to_rekor()). Isn't the issue that our code just won't work without an inclusion promise currently?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed mention of pydantic.

* TSA: Changed the Timestamp Authority requests to explicitly use sha256 for message digests.
[#1373](https://github.com/sigstore/sigstore-python/pull/1373)

Expand Down
26 changes: 14 additions & 12 deletions sigstore/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,18 +219,22 @@ def _from_dict_rekor(cls, dict_: dict[str, Any]) -> LogEntry:
tree_size=inclusion_proof.tree_size,
)

inclusion_promise: Optional[B64Str] = None
if tlog_entry.inclusion_promise:
inclusion_promise = B64Str(
base64.b64encode(
tlog_entry.inclusion_promise.signed_entry_timestamp
).decode()
)

return LogEntry(
uuid=None,
body=B64Str(base64.b64encode(tlog_entry.canonicalized_body).decode()),
integrated_time=tlog_entry.integrated_time,
log_id=tlog_entry.log_id.key_id.hex(),
log_index=tlog_entry.log_index,
inclusion_proof=parsed_inclusion_proof,
inclusion_promise=B64Str(
base64.b64encode(
tlog_entry.inclusion_promise.signed_entry_timestamp
).decode()
),
inclusion_promise=inclusion_promise,
)

def _to_rekor(self) -> rekor_v1.TransparencyLogEntry:
Expand All @@ -239,12 +243,6 @@ def _to_rekor(self) -> rekor_v1.TransparencyLogEntry:

@private
"""
inclusion_promise: rekor_v1.InclusionPromise | None = None
if self.inclusion_promise:
inclusion_promise = rekor_v1.InclusionPromise(
signed_entry_timestamp=base64.b64decode(self.inclusion_promise)
)

inclusion_proof = rekor_v1.InclusionProof(
log_index=self.inclusion_proof.log_index,
root_hash=bytes.fromhex(self.inclusion_proof.root_hash),
Expand All @@ -257,10 +255,14 @@ def _to_rekor(self) -> rekor_v1.TransparencyLogEntry:
log_index=self.log_index,
log_id=common_v1.LogId(key_id=bytes.fromhex(self.log_id)),
integrated_time=self.integrated_time,
inclusion_promise=inclusion_promise, # type: ignore[arg-type]
inclusion_proof=inclusion_proof,
canonicalized_body=base64.b64decode(self.body),
)
if self.inclusion_promise:
inclusion_promise = rekor_v1.InclusionPromise(
signed_entry_timestamp=base64.b64decode(self.inclusion_promise)
)
tlog_entry.inclusion_promise = inclusion_promise

# Fill in the appropriate kind
body_entry: ProposedEntry = TypeAdapter(ProposedEntry).validate_json(
Expand Down
2 changes: 1 addition & 1 deletion test/unit/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def _signing_materials(name: str, client: RekorClient) -> tuple[Path, Bundle]:


@pytest.fixture
def signing_bundle(asset):
def signing_bundle(asset) -> Callable[[str], tuple[Path, Bundle]]:
def _signing_bundle(name: str) -> tuple[Path, Bundle]:
file = asset(name)
bundle_path = asset(f"{name}.sigstore")
Expand Down
14 changes: 14 additions & 0 deletions test/unit/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@ def test_missing_inclusion_proof(self):
inclusion_promise=None,
)

def test_missing_inclusion_promise_round_trip(self, signing_bundle):
"""
Ensures that LogEntry._to_rekor() succeeds even without an inclusion_promise.
"""
bundle: Bundle
_, bundle = signing_bundle("bundle.txt")
_dict = bundle.log_entry._to_rekor().to_dict()
print(_dict)
del _dict["inclusionPromise"]
entry = LogEntry._from_dict_rekor(_dict)
assert entry.inclusion_promise is None
assert entry._to_rekor() is not None
assert LogEntry._from_dict_rekor(entry._to_rekor().to_dict()) == entry

def test_logentry_roundtrip(self, signing_bundle):
_, bundle = signing_bundle("bundle.txt")

Expand Down