This commit is contained in:
David Paul Graham 2026-03-14 13:02:52 +00:00 committed by GitHub
commit 3f8b5400eb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 66 additions and 45 deletions

View file

@ -10,18 +10,22 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install ruff black
- uses: actions/checkout@v3
- name: Lint with Ruff
run: |
ruff check .
- name: "Set up Python"
uses: actions/setup-python@v6
- name: Lint with Black
run: |
black --check .
- name: "install Ruff"
uses: astral-sh/ruff-action@v3
with:
version: ">=0.15,<0.16"
# use args to avoid the default behavior of running ruff check automatically
args: "--version"
# ToDo: use pyrpoject.toml as version-file
# version-file: "pyproject.toml"
- name: "Check formatting"
run: ruff format --check --diff
test:
strategy:

3
.gitignore vendored
View file

@ -7,3 +7,6 @@ dist/
.ruff_cache
.venv
.venv_django_*
# Node
node_modules/

View file

@ -48,3 +48,11 @@ repos:
- id: pyupgrade
name: pyupgrade
args: [--py312-plus]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.6
hooks:
# uncomment after linting initially passes
# - id: ruff-check
# args: [ --fix ]
- id: ruff-format

View file

@ -24,9 +24,7 @@ class EncryptedFieldMixin:
def keys(self) -> list[bytes]:
keys = []
salt_keys = (
settings.SALT_KEY
if isinstance(settings.SALT_KEY, list)
else [settings.SALT_KEY]
settings.SALT_KEY if isinstance(settings.SALT_KEY, list) else [settings.SALT_KEY]
)
secret_keys = [settings.SECRET_KEY] + getattr(settings, "SECRET_KEY_FALLBACKS", list())
for secret_key in secret_keys:
@ -39,11 +37,7 @@ class EncryptedFieldMixin:
iterations=100_000,
backend=default_backend(),
)
keys.append(
base64.urlsafe_b64encode(
kdf.derive(secret_key.encode("utf-8"))
)
)
keys.append(base64.urlsafe_b64encode(kdf.derive(secret_key.encode("utf-8"))))
return keys
@cached_property
@ -85,11 +79,7 @@ class EncryptedFieldMixin:
return self.to_python(value)
def to_python(self, value: _TypeAny) -> _TypeAny:
if (
value is None
or not isinstance(value, str)
or hasattr(self, "_already_decrypted")
):
if value is None or not isinstance(value, str) or hasattr(self, "_already_decrypted"):
return value
try:
value = self.f.decrypt(bytes(value, "utf-8")).decode("utf-8")
@ -129,9 +119,7 @@ class EncryptedIntegerField(EncryptedFieldMixin, models.IntegerField):
# they're based on values retrieved from `connection`.
validators_ = [*self.default_validators, *self._validators]
internal_type = models.IntegerField().get_internal_type()
min_value, max_value = BaseDatabaseOperations.integer_field_ranges[
internal_type
]
min_value, max_value = BaseDatabaseOperations.integer_field_ranges[internal_type]
if min_value is not None and not any(
(
isinstance(validator, MinValueValidator)
@ -203,11 +191,7 @@ class EncryptedJSONField(EncryptedFieldMixin, models.JSONField):
return "JSONField"
def to_python(self, value: _TypeAny) -> _TypeAny:
if (
value is None
or not isinstance(value, str)
or hasattr(self, "_already_decrypted")
):
if value is None or not isinstance(value, str) or hasattr(self, "_already_decrypted"):
return value
try:
value = self._decrypt_values(value=json.loads(value))

View file

@ -13,9 +13,7 @@ from .models import TestModel
class FieldTest(TestCase):
def get_db_value(self, field: str, model_id: int) -> None:
cursor = connection.cursor()
cursor.execute(
f"select {field} from package_test_testmodel where id = {model_id};"
)
cursor.execute(f"select {field} from package_test_testmodel where id = {model_id};")
return cursor.fetchone()[0]
def test_char_field_encrypted(self) -> None:
@ -258,14 +256,13 @@ class RotatedSaltTestCase(TestCase):
class RotatedSecretKeyTestCase(TestCase):
@staticmethod
def clear_cached_properties():
# we have to clear the cached properties of EncryptedFieldMixin so we have the right encryption keys
text_field = TestModel._meta.get_field('text')
if hasattr(text_field, 'keys'):
text_field = TestModel._meta.get_field("text")
if hasattr(text_field, "keys"):
del text_field.keys
if hasattr(text_field, 'f'):
if hasattr(text_field, "f"):
del text_field.f
@classmethod
@ -308,4 +305,3 @@ class RotatedSecretKeyTestCase(TestCase):
assert old_record.text.endswith("=")
# assert that old record cannot be decrypted now
assert old_record.text != plaintext

View file

@ -3,12 +3,38 @@
##################
[tool.ruff]
fix = true
lint.fixable = ["ALL"]
lint.ignore = ["A003", "COM812", "D", "DJ008", "ERA001", "ISC001", "PLC2401", "PLC2403", "PT011", "RUF001", "S101", "S105", "S608", "SIM103", "TC001", "TC002", "TC003", "UP040"]
lint.select = ["ALL"]
lint.unfixable = ["ERA001", "F401"]
include = ["encrypted_fields/*.py", "package_test/*.py"]
target-version = "py312"
extend-include = ["package_test/**/*.py"]
target-version = "py310"
line-length = 100
[tool.ruff.lint]
fixable = ["ALL"]
extend-ignore = [
"RUF012",
"A003",
"COM812",
"D",
"DJ008",
"ERA001",
"ISC001",
"PLC2401",
"PLC2403",
"PT011",
"RUF001",
"S101",
"S105",
"S608",
"SIM103",
"TC001",
"TC002",
"TC003",
"UP040"
]
select = ["ALL"]
unfixable = [
"ERA001",
"F401"
]
##################
# mypy