Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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: 1 addition & 1 deletion fiftyone_pipeline_did/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ same whichever language parsed the bytes.
| `UNEXPECTED_END` | The data stopped in the middle of an envelope field |
| `INVALID_DOMAIN_ENCODING` | The creator domain is not terminated or is longer than the OWID maximum |
| `BYTE_COUNT_MISMATCH` | The declared payload length disagrees with the bytes present |
| `IMPLEMENTATION_CAPACITY_EXCEEDED` | The envelope is consistent but larger than this runtime can hold |
| `IMPLEMENTATION_CAPACITY_EXCEEDED` | The envelope is consistent but larger than this runtime can hold, or dated past the end of the year 9999 where `datetime` stops. The four byte minute count runs to 15 February 10186, and the read answers with this status rather than raising on such a count |
| `ABSENT_NODE` | The version 0 marker, which stands for an absent envelope |
| `MALFORMED_ENVELOPE` | Malformed in a way none of the above describes |
| `PAYLOAD_TOO_SHORT` | The envelope was read but the payload is shorter than the 5 byte header, so the type cannot be read |
Expand Down
8 changes: 7 additions & 1 deletion fiftyone_pipeline_did/src/fiftyone_pipeline_did/fod_id.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,13 @@ class FodIdParseStatus(Enum):
INVALID_DOMAIN_ENCODING = "InvalidDomainEncoding"
#: The declared payload byte count disagrees with the bytes present.
BYTE_COUNT_MISMATCH = "ByteCountMismatch"
#: The envelope is consistent but larger than this runtime can hold.
#: The envelope is consistent but larger than this runtime can hold, or
#: dated past the end of the year 9999 where ``datetime`` stops. The
#: four byte minute count of OWID versions 2 and 3 runs to 15 February
#: 10186, and the OWID reader judges the count before the arithmetic,
#: so a read answers with this status rather than raising. The same
#: bytes read fine where the date type is wider, so the status is not a
#: fault in the data.
IMPLEMENTATION_CAPACITY_EXCEEDED = "ImplementationCapacityExceeded"
#: The version 0 marker, which stands for an absent envelope and never
#: produces a value.
Expand Down
45 changes: 45 additions & 0 deletions fiftyone_pipeline_did/tests/test_fodid.py
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,51 @@ def test_wrong_input_type_reports_invalid_input_type(self):
self.assert_failed(FodId.try_from_byte_array("AwB="),
FodIdParseStatus.INVALID_INPUT_TYPE)

# ----- A date the runtime cannot hold -----

def _dated_past_the_year_9999(self):
"""A signed envelope whose four byte minute count is 0xFFFFFFFF,
which the wire format allows and which lands on 15 February 10186,
past the end of the year 9999 where ``datetime`` stops. The bytes
are changed after signing, which is fine because the read refuses
the date before any signature is looked at."""
raw = bytearray(self.factory.signed_bytes(canonical_payload()))
# The four little endian date bytes sit after the version byte, the
# domain and its terminator.
at = 1 + raw.index(0, 1) + 1
raw[at:at + 4] = bytes([0xFF] * 4)
return bytes(raw)

def test_date_past_the_year_9999_is_implementation_capacity_exceeded(
self):
# The OWID reader judges the count before the arithmetic, so the
# read answers with a status instead of raising OverflowError, and
# the 51Did surface carries that status through unchanged on both
# the byte and the base64 surface. The same bytes read fine where
# the date type is wider, so the status is the runtime's limit and
# not a fault in the data.
raw = self._dated_past_the_year_9999()
self.assertIs(ParseStatus.IMPLEMENTATION_CAPACITY_EXCEEDED,
Owid.parse_bytes(raw).status)
self.assert_failed(
FodId.try_from_byte_array(raw),
FodIdParseStatus.IMPLEMENTATION_CAPACITY_EXCEEDED)
self.assert_failed(
FodId.try_from_base64(base64.b64encode(raw).decode()),
FodIdParseStatus.IMPLEMENTATION_CAPACITY_EXCEEDED)

def test_raising_readers_name_the_date_the_runtime_cannot_hold(self):
# The raising readers run the same walk, so the date is the
# documented OwidError with the status in the message, never the
# OverflowError the arithmetic would have raised.
raw = self._dated_past_the_year_9999()
with self.assertRaises(OwidError) as raised:
FodId.from_base64(base64.b64encode(raw).decode())
self.assertIn("ImplementationCapacityExceeded", str(raised.exception))
with self.assertRaises(OwidError) as raised:
FodId.from_byte_array(raw)
self.assertIn("ImplementationCapacityExceeded", str(raised.exception))

# ----- Parsing and verifying are separate -----

def test_tampered_signature_parses_then_verifies_as_invalid(self):
Expand Down
2 changes: 1 addition & 1 deletion owid-python
Loading