Add a new module for better ensuring privacy of user data.

Review Request #9893 — Created April 25, 2018 and submitted

Information

Djblets
release-1.0.x
0f5c4fa...

Reviewers

This introduces djblets.privacy, a new module designed for more easily
ensuring protection of private user data, helping Django applications to
meet GDPR compliance and to otherwise help with the management and
safe-keeping of user data.

This initial version of the module focuses on consent tracking, giving
users control over operations or processing of data. It's designed to
allow applications (and even extensions) to dynamically register things
that require consent, to check if the user granted/denied that consent,
to (later) present options for consent, and to keep an audit log for
later proof. For now, only the backend is in place, with UI helpers
coming later.

This lives almost exclusively within the djblets.privacy.consent
module (with models living in djblets.privacy.models). There are a few
components:

  • Consent: An enum containing values to represent whether
    consent was given or denied, or simply not set yet.

  • ConsentRequirement: Represents a part of a product that requires
    consent. This can be instantiated with a unique ID, displayable name
    and description, and an optional URL for learning more about the
    requirement (useful for linking to privacy policies or documentation).

  • ConsentRequirementsRegistry: Used to register, track, and look up
    ConsentRequirement instances.

  • ConsentData: An object for store consent and consent-related
    information (timestamp, source of where the consent was given, and
    additional data to include), for serializing or deserializing.

  • BaseConsentTracker/DatabaseConsentTracker: Used to record if
    consent was given or denied for a requirement, check that consent on
    demand, and for keeping an audit log for helping to later document and
    prove when users set, denied, or revoked consent. By default,
    DatabaseConsentTracker (which stores the data in the database) is
    used, but projects can make use of custom ones for storing the audit
    data in other locations outside the database.

With this module, it will be very easy to start enforcing user control
of the processing of data without a lot of additional work.

Future changes will build on this to offer standard UI for consent
management and redacting of personal information before sending to
services.

Unit tests pass.

Built the docs and checked for build and generation errors.

Description From Last Updated

E501 line too long (80 > 79 characters)

reviewbotreviewbot

F401 'datetime.datetime' imported but unused

reviewbotreviewbot

F401 'django.contrib.auth.models.User' imported but unused

reviewbotreviewbot

F401 'django.test.utils.override_settings' imported but unused

reviewbotreviewbot

F401 'django.utils.timezone' imported but unused

reviewbotreviewbot

F401 'kgb.SpyAgency' imported but unused

reviewbotreviewbot

F401 'djblets.privacy.consent.Consent' imported but unused

reviewbotreviewbot

F401 'djblets.privacy.consent.BaseConsentTracker' imported but unused

reviewbotreviewbot

F401 'djblets.privacy.consent.ConsentData' imported but unused

reviewbotreviewbot

F401 'djblets.privacy.consent.errors.ConsentRequirementNotFoundError' imported but unused

reviewbotreviewbot

F401 'djblets.registries.errors.RegistrationError' imported but unused

reviewbotreviewbot

On Python2, UNSET will literally be 0, but using enum, it will be a Consent object with a value attribute …

brenniebrennie

Instead of doing this pattern (which I know I started), should we do the following? CONSENT_REQUIREMENT_DEFAULT_ERRORS = dict(DEFAULT_ERRORS, **{ 'key': …

brenniebrennie

Is it cool that we use PII here? Should this be hash(email)?

brenniebrennie

Needs a module docstring.

daviddavid

Let's say "EU" residents instead of "European"

daviddavid
Checks run (1 failed, 1 succeeded)
flake8 failed.
JSHint passed.

flake8

chipx86
brennie
  1. 
      
    1. Thanks for the review!

  2. djblets/privacy/consent/base.py (Diff revision 2)
     
     
    Show all issues

    On Python2, UNSET will literally be 0, but using enum, it will be a Consent object with a value attribute = 0.

    Is this difference in behaviour going to cause issues?

    enum.Enum also provides default __str__ etc impls, which this will lack.

    1. We're comparing the objects directly (we're not serializing the values) so I think it will be fine.

      I might introduce a dependency on enum34, but am hesitant to do it in this change.

  3. djblets/privacy/consent/registry.py (Diff revision 2)
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
    Show all issues

    Instead of doing this pattern (which I know I started), should we do the following?

    CONSENT_REQUIREMENT_DEFAULT_ERRORS = dict(DEFAULT_ERRORS, **{
        'key': 'value',
    })
    

    Also, should we just have this defined on the class (as default_errors)?

    1. Probably to both.

      I have some other thoughts on improving errors, but perhaps a topic for another day.

  4. djblets/privacy/consent/tracker.py (Diff revision 2)
     
     
    Show all issues

    Is it cool that we use PII here? Should this be hash(email)?

    1. It is cool because of consent audit tracking responsibilities, but I was thinking about this earlier and agree, we should use a hash. Planning to update this change later today with a few additional changes.

  5. 
      
chipx86
david
  1. 
      
  2. djblets/privacy/consent/registry.py (Diff revision 3)
     
     
    Show all issues

    Needs a module docstring.

  3. 
      
chipx86
chipx86
david
  1. 
      
  2. docs/djblets/glossary.rst (Diff revision 5)
     
     
    Show all issues

    Let's say "EU" residents instead of "European"

  3. 
      
chipx86
david
  1. Ship It!
  2. 
      
chipx86
Review request changed
Status:
Completed
Change Summary:
Pushed to release-1.0.x (e42d0d1)