Add ability to globally mask fields by name on all models. (#702)

* Add ability to globally mask fields by name on all models.

Fixes https://github.com/jazzband/django-auditlog/issues/701

* Add feature explanation in `usage.rst` file.

* Add a record to CHANGELOG.md file.

* Add test coverage.
This commit is contained in:
Amirreza Ashouri 2025-02-24 12:05:04 +03:30 committed by GitHub
parent fb3fac5cce
commit c4907bcd52
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 82 additions and 0 deletions

View file

@ -4,6 +4,8 @@
#### Improvements
- feat: Support masking field names globally when ```AUDITLOG_INCLUDE_ALL_MODELS``` is enabled
via `AUDITLOG_MASK_TRACKING_FIELDS` setting. ([#702](https://github.com/jazzband/django-auditlog/pull/702))
- feat: Added 'LogEntry.actor_email` field. ([#641](https://github.com/jazzband/django-auditlog/pull/641))
- Add Python 3.13 support. ([#671](https://github.com/jazzband/django-auditlog/pull/671))
- feat: Added `LogEntry.remote_port` field. ([#671](https://github.com/jazzband/django-auditlog/pull/671))

View file

@ -21,6 +21,11 @@ settings.AUDITLOG_EXCLUDE_TRACKING_FIELDS = getattr(
settings, "AUDITLOG_EXCLUDE_TRACKING_FIELDS", ()
)
# Mask named fields across all models
settings.AUDITLOG_MASK_TRACKING_FIELDS = getattr(
settings, "AUDITLOG_MASK_TRACKING_FIELDS", ()
)
# Disable on raw save to avoid logging imports and similar
settings.AUDITLOG_DISABLE_ON_RAW_SAVE = getattr(
settings, "AUDITLOG_DISABLE_ON_RAW_SAVE", False

View file

@ -107,6 +107,9 @@ class AuditlogModelRegistry:
for fld in settings.AUDITLOG_EXCLUDE_TRACKING_FIELDS:
exclude_fields.append(fld)
for fld in settings.AUDITLOG_MASK_TRACKING_FIELDS:
mask_fields.append(fld)
def registrar(cls):
"""Register models for a given class."""
if not issubclass(cls, Model):
@ -300,6 +303,15 @@ class AuditlogModelRegistry:
"setting 'AUDITLOG_INCLUDE_ALL_MODELS' must be set to 'True'"
)
if (
settings.AUDITLOG_MASK_TRACKING_FIELDS
and not settings.AUDITLOG_INCLUDE_ALL_MODELS
):
raise ValueError(
"In order to use 'AUDITLOG_MASK_TRACKING_FIELDS', "
"setting 'AUDITLOG_INCLUDE_ALL_MODELS' must be set to 'True'"
)
if not isinstance(settings.AUDITLOG_INCLUDE_TRACKING_MODELS, (list, tuple)):
raise TypeError(
"Setting 'AUDITLOG_INCLUDE_TRACKING_MODELS' must be a list or tuple"
@ -310,6 +322,11 @@ class AuditlogModelRegistry:
"Setting 'AUDITLOG_EXCLUDE_TRACKING_FIELDS' must be a list or tuple"
)
if not isinstance(settings.AUDITLOG_MASK_TRACKING_FIELDS, (list, tuple)):
raise TypeError(
"Setting 'AUDITLOG_MASK_TRACKING_FIELDS' must be a list or tuple"
)
for item in settings.AUDITLOG_INCLUDE_TRACKING_MODELS:
if not isinstance(item, (str, dict)):
raise TypeError(

View file

@ -1347,6 +1347,24 @@ class RegisterModelSettingsTest(TestCase):
):
self.test_auditlog.register_from_settings()
with override_settings(
AUDITLOG_INCLUDE_ALL_MODELS=True,
AUDITLOG_MASK_TRACKING_FIELDS="badvalue",
):
with self.assertRaisesMessage(
TypeError,
"Setting 'AUDITLOG_MASK_TRACKING_FIELDS' must be a list or tuple",
):
self.test_auditlog.register_from_settings()
with override_settings(AUDITLOG_MASK_TRACKING_FIELDS=("token", "otp_secret")):
with self.assertRaisesMessage(
ValueError,
"In order to use 'AUDITLOG_MASK_TRACKING_FIELDS', "
"setting 'AUDITLOG_INCLUDE_ALL_MODELS' must be set to 'True'",
):
self.test_auditlog.register_from_settings()
with override_settings(AUDITLOG_INCLUDE_TRACKING_MODELS="str"):
with self.assertRaisesMessage(
TypeError,
@ -1424,6 +1442,24 @@ class RegisterModelSettingsTest(TestCase):
["datetime"],
)
@override_settings(
AUDITLOG_INCLUDE_ALL_MODELS=True,
AUDITLOG_MASK_TRACKING_FIELDS=("secret",),
)
def test_register_from_settings_register_all_models_with_mask_tracking_fields(
self,
):
self.test_auditlog.register_from_settings()
self.assertEqual(
self.test_auditlog.get_model_fields(SimpleModel)["mask_fields"],
["secret"],
)
self.assertEqual(
self.test_auditlog.get_model_fields(AltPrimaryKeyModel)["mask_fields"],
["secret"],
)
@override_settings(
AUDITLOG_INCLUDE_ALL_MODELS=True,
AUDITLOG_EXCLUDE_TRACKING_MODELS=["auditlog_tests.SimpleExcludeModel"],

View file

@ -235,6 +235,28 @@ It will be considered when ``AUDITLOG_DISABLE_REMOTE_ADDR`` is `True`.
.. versionadded:: 3.0.0
**AUDITLOG_MASK_TRACKING_FIELDS**
You can use this setting to mask specific field values in all tracked models
while still logging changes. This is useful when models contain sensitive fields
like `password`, `api_key`, or `secret_token`` that should not be logged
in plain text but need to be auditable.
When a masked field changes, its value will be replaced with a masked
representation (e.g., `****`) in the audit log instead of storing the actual value.
This setting will be applied only when `AUDITLOG_INCLUDE_ALL_MODELS`` is `True`.
.. code-block:: python
AUDITLOG_MASK_TRACKING_FIELDS = (
"password",
"api_key",
"secret_token"
)
.. versionadded:: 3.1.0
**AUDITLOG_EXCLUDE_TRACKING_MODELS**
You can use this setting to exclude models in registration process.