Skip to content

Add support for DecryptedField in nested dict fields#2

Draft
Copilot wants to merge 4 commits intomasterfrom
copilot/add-support-nested-decrypted-field
Draft

Add support for DecryptedField in nested dict fields#2
Copilot wants to merge 4 commits intomasterfrom
copilot/add-support-nested-decrypted-field

Conversation

Copy link
Copy Markdown

Copilot AI commented Dec 4, 2025

DecryptedField uses Python descriptors (__get__/__set__) which only work at class level. When placed inside a nested dict field schema, the descriptor protocol isn't invoked and encryption/decryption fails.

Changes

  • ming/encryption.py:
    • Added EncryptedObject class extending Object that intercepts attribute/item access to handle DecryptedField pairs within nested dicts
    • Enhanced encrypt_some_fields() to recursively handle nested dicts with EncryptedObjectSchema, enabling make_encr() to automatically encrypt nested fields
  • ming/schema.py:
    • Added EncryptedObjectSchema to detect DecryptedField instances in dict schemas and produce EncryptedObject results
    • Updated SchemaItem.make() to route dicts containing DecryptedField to EncryptedObjectSchema
    • Extended Document._validate() to inject encryption functions into nested EncryptedObject instances post-validation

Example

class MyDocument(Document):
    profile = Field(dict(
        first_name=DecryptedField(str, 'first_name_encrypted'),
        first_name_encrypted=S.Binary,
        age=int
    ))

# Using make_encr() with unencrypted field names - encryption happens automatically
doc = MyDocument.make_encr(dict(
    profile=dict(
        first_name='Jerome',
        age=30
    )
))

doc.profile.first_name  # 'Jerome' (decrypted)
doc.profile.first_name = 'Jane'  # auto-encrypts to first_name_encrypted

# Only encrypted fields are stored in the database
# Decrypted fields act as virtual fields for get/set operations
Original prompt

The DecryptedField class works by automatically referencing its encrypted field counterpart to set and get the value. It works for top level fields, due to the __get__ and __set__ methods in DecryptedField. But if I define, for example:

profile = Field(dict(first_name=DecryptedField(str, 'first_name_encrypted'), first_name_encrypted=ming.schema.Binary))

it doesn't work. add support for getting and setting encrypted values in nested dict fields using DecryptedField and its encrypted field counterpart


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits December 4, 2025 22:47
Co-authored-by: jcarlosdev <8920902+jcarlosdev@users.noreply.github.com>
…ility

Co-authored-by: jcarlosdev <8920902+jcarlosdev@users.noreply.github.com>
Copilot AI changed the title [WIP] Add support for nested dict fields in DecryptedField Add support for DecryptedField in nested dict fields Dec 4, 2025
Copilot AI requested a review from jcarlosdev December 4, 2025 22:51
@jcarlosdev
Copy link
Copy Markdown
Owner

@copilot In the tests, I see that you create a new encrypted object document and encrypt the fields manually in

doc = TestDocNested.make(dict(
_id=1,
profile=dict(
first_name_encrypted=TestDocNested.encr('Jerome'),
last_name_encrypted=TestDocNested.encr('Smith'),
age=30
)
))
doc.m.save()

it would be better if the document could be created using make_encr(), like this

doc = TestDocNested.make_encr(dict(
_id=1,
profile=dict(
first_name='Jerome',
last_name='Smith',
age=30
)
))
doc.m.save()

under the hood it will encrypt the values and set them to the corresponding encrypted fields. Also, only save the encrypted fields to the db, the unencrypted fields will stay as a virtual field to get and set encrypted values

…fields

Co-authored-by: jcarlosdev <8920902+jcarlosdev@users.noreply.github.com>
Copy link
Copy Markdown
Author

Copilot AI commented Dec 8, 2025

@copilot In the tests, I see that you create a new encrypted object document and encrypt the fields manually in

doc = TestDocNested.make(dict(...

Updated in commit b880cb8. The test now uses make_encr() with unencrypted field names as you requested:

doc = TestDocNested.make_encr(dict(
    _id=1,
    profile=dict(
        first_name='Jerome',
        last_name='Smith',
        age=30
    )
))

The encrypt_some_fields() method has been enhanced to recursively handle nested EncryptedObjectSchema fields, automatically encrypting the values and storing them in the corresponding _encrypted fields. The test also verifies that only encrypted fields are stored in the underlying dict (virtual decrypted fields are not persisted).

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.

2 participants