Closed
Description
As I was writing up the keyring examples for #221, I realized that while the keyring trace is exposed in the keyring results, it is not exposed in the actual encrypt/decrypt results.
There are two places where we need to expose this:
- Streaming APIs
We can do this simply by adding the keyring trace as an attribute on the stream object.
- One-step APIs
This one is a bit more complicated. Because we currently return (bytes, MessageHeader)
rather than a return object, our options are limited. There are two ways I can think to approach this:
- Add a
keyring_trace
attribute toMessageHeader
. This is the simplest option, and the least likely to break people, but is a bit messy because the header doesn't really contain the keyring trace. - Change the one-step APIs to return a results object that is structured like the one-step return values from the other ESDK implementations but also quacks like a two-member sequence. This would let us be more flexible in the future when adding other return data but would also let us avoid breaking existing users who expect a two-member tuple. [PREFERRED]
One-step APIs
The current interface of the one-step APIs is that they return a 2-member tuple containing the result bytes (plaintext for decrypt and encrypted message for encrypt) and the MessageHeader
instance for that message.
my_ciphertext, encryptor_header = aws_encryption_sdk.encrypt(
source=my_plaintext,
keyring=my_keyring,
)
Option 1 : Modify MessageHeader
Pros:
- This would be the simplest change.
- Basically guaranteed to not break anyone.
Cons:
- This would mix unrelated concepts. The message header does not include the keyring trace and adding it to that structure would confuse concepts and relationships.
- If we ever need to add something else to the output, we would find ourselves in a similar situation again, having to put even more unrelated stuff into
MessageHeader
.
my_ciphertext, encryptor_header = aws_encryption_sdk.encrypt(
source=my_plaintext,
keyring=my_keyring,
)
encryptor_header.keyring_trace
Option 2 : Result object that quacks like a 2-member tuple [PREFERRED]
# Legacy interaction: compatible but no access to keyring trace
my_ciphertext, encryptor_header = aws_encryption_sdk.encrypt(
source=my_plaintext,
keyring=my_keyring,
)
# New interaction: provides access to keyring trace
encryption_result = aws_encryption_sdk.encrypt(
source=my_plaintext,
keyring=my_keyring,
)
# ciphertext
encryption_result.result
# header
encryption_result.header
# keyring trace
encryption_result.keyring_trace
Pros:
- This would let us expose the keyring trace without combining unrelated concepts.
- If we need to add another output value in the future, this gives us a simple and consistent way to do it.
- This is very unlikely to break any customers. We can make the output value behave like a 2-member tuple so that anyone interacting with it as if it were a tuple will not be surprised.
- This would let us align the Python client's one-step interface with the one-step interfaces in the other language implementations.
Cons:
- If anyone is relying on the output value actually being an instance of the
tuple
class, this would break. Relying on implicit types in this way is generally considered an antipattern.
Discarded options
- Output a 3-member tuple
(bytes, MessageHeader, Sequence[KeyringTrace])
. This is a non-starter because the most common way that we expect people to be using these APIs is to unpack the output values on call. Adding another member to the output tuple would result in an error when they attempt to unpack just two members from a three-member tuple.
>>> a,b = (1,2,3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)
- Subclass
tuple
for result object. Subclassing built-in classes is generally considered an anti-pattern. Additionally, if we were to add access to the stored values by attribute names, which would be the best way to expose these values while also not breaking compatibility with the previous output value, we would end up with something that says that it is atuple
but behaves very differently than an actualtuple
.
Metadata
Metadata
Assignees
Labels
No labels