Skip to content

chore: refactor to make S3EC install itself as plugins#138

Merged
kessplas merged 10 commits into
stagingfrom
plugin
Feb 17, 2026
Merged

chore: refactor to make S3EC install itself as plugins#138
kessplas merged 10 commits into
stagingfrom
plugin

Conversation

@kessplas

Copy link
Copy Markdown
Contributor

Issue #, if available: #130

Description of changes: The main reason to do this is that we don't need to worry about how the data is serialized. It will already have been serialized by the time the S3EC needs to encrypt/decrypt it.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@kessplas kessplas marked this pull request as ready for review February 13, 2026 18:46
Comment thread src/s3_encryption/__init__.py Outdated
# Re-raise our own exceptions without wrapping
raise
except Exception as e:
raise S3EncryptionClientError(f"Failed to encryption object: {str(e)}") from e

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

fail

Suggested change
raise S3EncryptionClientError(f"Failed to encryption object: {str(e)}") from e
raise S3EncryptionClientError(f"Failed to encrypt object: {str(e)}") from e

header_key = f"{S3_METADATA_PREFIX}{key}"
headers[header_key] = value

params["headers"] = headers

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't understand enough of the business logic to know if this was intentional or not, but you may wind up overwriting existing headers here

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hmm... is the ask to check for header key collision?
That is a reasonable ask, and it might prevent double wrapping of the pipeline.
i.e: a user manages to wrap a encryption client with a encryption client.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It's not an ask - it's me not understanding. If you want to override it, it's great as is :)

If you're concerned with users setting custom headers, you can always just update the above to

if header_key not in headers:
     headers[header_key] = value

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The headers set by the encryption client are reserved and should not be set by the customer. If the customer does this, those values must be overwritten. This is not explicitly specified, but this is how Java behaves.

@texastony texastony left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think checking for header key collision is worth refactoring this PR for.
Also, for TODOs, if we can create GHI issues for them, that would be groovy; though we can punt on that until pre-launch and triage for launch blockers if you would prefer.

body_bytes = body.read()
else:
# Unexpected body type - should not happen as boto3 validates before this point
raise S3EncryptionClientError("Unexpected type of body parameter!")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Question: any chance the request ID is in scope here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Not sure if this answers you're question:

If you're asking if we have access to the x-amz-request-id or x-amz-id-2 headers, those come from the service as a part of the response. Since the request hasn't been sent yet at this point in code execution, so those values don't exist yet. You'd need to wait until we have sent the request and the service has responded.

If you only need it for client side tracking, you can delay this to the request-created event and take a look at the amz-sdk-invocation-id header. If you're looking to add any sort of logic around the request id that's connected with the server's request id, you'll need to hook into after-call or later.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I was asking to improve the error message.
I frequent customer ask is for request IDs to be in error messages,
but since the request ID is not in scope,
let it roll.

header_key = f"{S3_METADATA_PREFIX}{key}"
headers[header_key] = value

params["headers"] = headers

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hmm... is the ask to check for header key collision?
That is a reasonable ask, and it might prevent double wrapping of the pipeline.
i.e: a user manages to wrap a encryption client with a encryption client.

}

# Create a pipeline and decrypt the data
pipeline = GetEncryptedObjectPipeline(self.config.cmm)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Issue: To handle instruction files, we are going to need the S3EC client to be passed to the GetEncryptedObjectPipeline.

Is there an S3 Client in scope here?

Note: This does not have to be resolved for this PR, but I am asking @kessplas about this, as Kess has context on the plugin nature that I do not.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Short answer, no.

Long answer, there can be. I think the easiest way to deal with this is to make the original wrapped client an instance variable of the plugin so that the plugin can call out to get_object for the instruction file if needed. IIRC Python uses references everywhere so it should be too heavy, and the client should be thread safe enough to reuse.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Praise: I love this.

@texastony texastony dismissed their stale review February 16, 2026 21:03

Key collision is not a concern.

@kessplas kessplas merged commit 4c9a1e9 into staging Feb 17, 2026
4 checks passed
@kessplas kessplas deleted the plugin branch February 17, 2026 17:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants