Skip to content

Encryption forbids the 'auto' serializer regardless of backend — local single-SDK FileBackend has no cross-SDK reader to protect #185

@27Bslash6

Description

@27Bslash6

Summary

CacheHandler rejects any non-cross-SDK serializer (notably auto) whenever encryption=True, gated purely on the encryption flag with no consideration of the backend. For a local, single-language FileBackend — read only by the Python SDK — the cross-SDK-interop rationale does not apply, yet auto + encryption is still a hard ConfigurationError. This conflates encrypted with cross-SDK-shared.

Where (source v0.9.0, installed 0.9.1)

src/cachekit/cache_handler.py:

# line 33
CROSS_SDK_SERIALIZER_NAMES = ("default", "std", "standard", "orjson", "arrow")

# line 348 — the guard's only enclosing condition is the encryption flag; no backend check
if self.encryption:
    ...
    if isinstance(serializer_name, str):
        if serializer_name not in CROSS_SDK_SERIALIZER_NAMES:
            raise ConfigurationError(
                "Encryption requires a cross-SDK-compatible serializer for cross-language "
                "interop, got serializer='...'. ... The 'auto' serializer emits "
                "Python-specific types that other SDKs cannot decode, so it cannot be used with encryption."
            )
    elif not getattr(type(serializer_name), "cross_sdk_compatible", False):
        raise ConfigurationError(...)

Why this is over-coupled

Serialization and encryption are already orthogonal in the implementation: EncryptionWrapper is a Decorator that composes any SerializerProtocol with the AES-256-GCM layer and threads the user's serializer through (it is not silently replaced, post-#134). So nothing technical forces encryption to constrain the serializer — the only coupling is this policy guard.

The guard's justification — "so the encrypted bytes remain decodable by other-language SDKs" — holds only when another-language SDK actually reads the cache. That is a property of the backend (SaaS CachekitIO / any shared store), not of encryption. A local FileBackend encrypted at rest and read solely by the Python process has no other-SDK reader, so requiring a cross-SDK wire format there buys nothing and costs auto's Python-type fidelity (sets, frozensets, datetime, UUID, Decimal, NumPy, pandas).

Impact

Anyone wanting an encrypted local cache that preserves rich Python types is forced onto std/orjson (JSON-ish types only), or must normalize/model_dump() every payload before the cache boundary. The only current escape is a custom serializer declaring cross_sdk_compatible=True — i.e. asserting a cross-SDK guarantee the cache does not actually need.

Proposed fix

Gate the cross-SDK serializer requirement on the backend's cross-SDK exposure, not on self.encryption:

  • SaaS / CachekitIO / any shared or cross-SDK backend → require a CROSS_SDK_SERIALIZER_NAMES serializer (current behavior).
  • Local single-SDK backend (FileBackend, in-process) → allow auto and other non-cross-SDK serializers with encryption; EncryptionWrapper still wraps the emitted bytes regardless.

Alternatively, an explicit opt-out (e.g. a backend capability flag / allow_local_serializer=True) for callers who know their encrypted cache is single-SDK.

Refs #134, which added this validation while wiring the user serializer through EncryptionWrapper.

Metadata

Metadata

Assignees

No one assigned

    Labels

    encryptionEncryption/cryptography relatedenhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions