Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
490682c
initial
SKairinos Jan 13, 2026
e5a0e88
quick save
SKairinos Jan 13, 2026
9f45022
quick save
SKairinos Jan 13, 2026
ce4f3de
bas encrypted model and field
SKairinos Jan 14, 2026
f9f300f
temp
SKairinos Jan 14, 2026
70749a0
encrypted model tests
SKairinos Jan 15, 2026
f8f9883
save tests
SKairinos Jan 15, 2026
a84b87e
contribute to class
SKairinos Jan 15, 2026
3235c34
EncryptedTextFieldTestCase
SKairinos Jan 15, 2026
a790b34
data encryption key field
SKairinos Jan 16, 2026
0577887
fix
SKairinos Jan 16, 2026
c4893a4
fix imports
SKairinos Jan 19, 2026
4dc7cb9
module docstring
SKairinos Jan 19, 2026
6366b77
fix tests
SKairinos Jan 19, 2026
5e31a60
quick save
SKairinos Jan 20, 2026
6d57ab4
fix tests
SKairinos Jan 20, 2026
c1b3289
get value tests
SKairinos Jan 20, 2026
d48e933
fix
SKairinos Jan 20, 2026
b083cab
fix pre_save
SKairinos Jan 20, 2026
35fd414
fix
SKairinos Jan 20, 2026
6b53f77
test pre_save pending encryption
SKairinos Jan 22, 2026
88e0698
more pre_save tests
SKairinos Jan 22, 2026
b1a38d2
house keeping
SKairinos Jan 22, 2026
2dc485e
fixes
SKairinos Jan 22, 2026
4e2b482
support fixtures
SKairinos Jan 22, 2026
c0138f9
DeferredAttribute
SKairinos Jan 22, 2026
02b7942
default get and set with type args
SKairinos Jan 22, 2026
b95c06a
dek model and field
SKairinos Jan 26, 2026
f5dc4aa
fixes
SKairinos Jan 26, 2026
4175fc9
local support
SKairinos Jan 26, 2026
0ed8221
final tweaks
SKairinos Jan 28, 2026
7643e93
cache dek aead
SKairinos Jan 29, 2026
72d4959
fix tests
SKairinos Jan 29, 2026
89fcd9d
rename
SKairinos Jan 29, 2026
e8e8509
enforce one dek per model
SKairinos Jan 29, 2026
cb49a6f
docs and fixes
SKairinos Feb 3, 2026
d99a9c0
merge from main
SKairinos Feb 3, 2026
2ec4ae9
fix types
SKairinos Feb 3, 2026
6d78a87
lazy create DEKs
SKairinos Feb 4, 2026
442d2dc
Encrypted Model and Field Initialization
SKairinos Feb 4, 2026
c052b29
DEK Field Initialization
SKairinos Feb 4, 2026
2851942
DEK AEAD Caching
SKairinos Feb 4, 2026
42ae7c7
house keeping
SKairinos Feb 4, 2026
5df9a28
feedback
SKairinos Feb 9, 2026
671a8ec
fix
SKairinos Feb 9, 2026
9fe135e
house keeping
SKairinos Feb 9, 2026
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
5 changes: 4 additions & 1 deletion Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ cfl-common = "==8.9.19" # TODO: remove
codeforlife-portal = "==8.9.19" # TODO: remove
rapid-router = "==7.6.18" # TODO: remove
phonenumbers = "==8.12.12" # TODO: remove
google-auth = "==2.40.3"
google-auth = "==2.48.0"
google-cloud-bigquery = "==3.38.0"
tink = {version = "==1.13.0", extras = ["gcpkms"]}
cachetools = "==6.2.6"

[dev-packages]
celery-types = "==0.23.0"
Expand All @@ -57,6 +59,7 @@ django-stubs = {version = "==5.1.3", extras = ["compatible-mypy"]}
djangorestframework-stubs = {version = "==3.15.3", extras = ["compatible-mypy"]}
types-regex = "==2024.11.6.*"
types-psutil = "==7.0.0.20250601"
types-cachetools = "==6.2.*"

[requires]
python_version = "3.12"
290 changes: 182 additions & 108 deletions Pipfile.lock

Large diffs are not rendered by default.

124 changes: 0 additions & 124 deletions codeforlife/caches.py

This file was deleted.

8 changes: 8 additions & 0 deletions codeforlife/caches/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""
© Ocado Group
Created on 28/01/2026 at 16:52:19(+00:00).
"""

from .base import BaseCache
from .base_dynamic_key import BaseDynamicKeyCache
from .base_fixed_key import BaseFixedKeyCache
67 changes: 67 additions & 0 deletions codeforlife/caches/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""
© Ocado Group
Created on 28/01/2026 at 16:52:19(+00:00).
"""

import typing as t

from django.core.cache import cache

V = t.TypeVar("V")


class BaseCache(t.Generic[V]):
"""Base class which helps to get and set cache values."""

timeout: int | None = None

@classmethod
def get(
cls,
key: str,
default: t.Optional[V] = None,
version: t.Optional[int] = None,
) -> t.Optional[V]:
"""
Fetch a given key from the cache. If the key does not exist, return
default, which itself defaults to None.
"""
return cache.get(
key=key,
default=default,
version=version,
)

@classmethod
def set(
cls,
key: str,
value: V,
timeout: t.Optional[int] = None,
version: t.Optional[int] = None,
):
"""
Set a value in the cache. If timeout is given, use that timeout for the
key; otherwise use the default cache timeout.
"""
cache.set(
key=key,
value=value,
timeout=timeout or cls.timeout,
version=version,
)

@classmethod
def delete(
cls,
key: str,
version: t.Optional[int] = None,
):
"""
Delete a key from the cache and return whether it succeeded, failing
silently.
"""
cache.delete(
key=key,
version=version,
)
59 changes: 59 additions & 0 deletions codeforlife/caches/base_dynamic_key.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""
© Ocado Group
Created on 28/01/2026 at 16:52:19(+00:00).
"""

import typing as t

from .base import BaseCache

V = t.TypeVar("V")
K = t.TypeVar("K")


class BaseDynamicKeyCache(BaseCache[V], t.Generic[K, V]):
"""Base class which helps to get and set cache values with a dynamic key."""

@staticmethod
def make_key(key: K) -> str:
"""Make the cache key from the key's data."""
raise NotImplementedError()

@classmethod
def get( # type: ignore[override]
cls,
key: K,
default: t.Optional[V] = None,
version: t.Optional[int] = None,
) -> t.Optional[V]:
return super().get(
key=cls.make_key(key),
default=default,
version=version,
)

@classmethod
def set( # type: ignore[override]
cls,
key: K,
value: V,
timeout: t.Optional[int] = None,
version: t.Optional[int] = None,
):
super().set(
key=cls.make_key(key),
value=value,
timeout=timeout,
version=version,
)

@classmethod
def delete( # type: ignore[override]
cls,
key: K,
version: t.Optional[int] = None,
):
super().delete(
key=cls.make_key(key),
version=version,
)
56 changes: 56 additions & 0 deletions codeforlife/caches/base_fixed_key.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"""
© Ocado Group
Created on 28/01/2026 at 16:52:19(+00:00).
"""

import typing as t

from .base import BaseCache

V = t.TypeVar("V")


class BaseFixedKeyCache(BaseCache[V], t.Generic[V]):
"""Base class which helps to get and set cache values with a fixed key."""

key: str

# pylint: disable=arguments-differ

@classmethod
def get( # type: ignore[override]
cls,
default: t.Optional[V] = None,
version: t.Optional[int] = None,
) -> t.Optional[V]:
return super().get(
key=cls.key,
default=default,
version=version,
)

@classmethod
def set( # type: ignore[override]
cls,
value: V,
timeout: t.Optional[int] = None,
version: t.Optional[int] = None,
):
super().set(
key=cls.key,
value=value,
timeout=timeout,
version=version,
)

@classmethod
def delete( # type: ignore[override]
cls,
version: t.Optional[int] = None,
):
super().delete(
key=cls.key,
version=version,
)

# pylint: enable=arguments-differ
Loading
Loading