Skip to content

ENG-3515: BE: new custom privacy center field types (checkbox, checkbox_group, textarea)#7977

Open
mikeGarifullin wants to merge 4 commits intomainfrom
ENG-3515
Open

ENG-3515: BE: new custom privacy center field types (checkbox, checkbox_group, textarea)#7977
mikeGarifullin wants to merge 4 commits intomainfrom
ENG-3515

Conversation

@mikeGarifullin
Copy link
Copy Markdown

@mikeGarifullin mikeGarifullin commented Apr 21, 2026

Ticket ENG-3515

Description Of Changes

Adds three new custom privacy center form field types — checkbox, checkbox_group, and textarea — to the public privacy-center config schema. Also widens MultiValue to accept StrictBool so boolean checkbox values round-trip through identity caching and persistence without being coerced to int.

Key subtlety: StrictBool must precede StrictInt in the MultiValue union because bool is a subclass of int in Python — if the order were reversed, pydantic would accept True/False on the int branch and silently drop the bool type. An inline comment and regression tests pin this.

Two latent if item.value: / if not value: guards on the persist and hash paths would have swallowed legitimate False checkbox values. Switched to is None/is not None checks with matching comments.

Code Changes

  • src/fides/api/schemas/privacy_center_config.py — add checkbox, checkbox_group, textarea to CustomPrivacyRequestField.field_type. Extend validate_field_type_constraints:
    • checkbox_group requires options
    • checkbox and textarea reject options
    • multiselect and checkbox_group reject hidden=True (default_value is str-only, can't represent a list)
  • src/fides/api/schemas/redis_cache.pyMultiValue accepts StrictBool (union order: StrictBool, StrictInt, StrictStr, List[...]). Inline comment explains the ordering rationale.
  • src/fides/api/schemas/privacy_request.py — update IdentityValue docstring to include bool.
  • src/fides/api/models/privacy_preference.pybcrypt_hash_value / hash_value switched from if not value: to if value is None: so False hashes rather than being treated as "no value".
  • src/fides/api/models/privacy_request/privacy_request.py and .../consent.pypersist_custom_privacy_request_fields switched from if item.value: to if item.value is not None: for the same reason on both PrivacyRequest and ConsentRequest paths.
  • tests/ops/schemas/test_identity_schema.py — parametrized bool round-trip tests on LabeledIdentity + CustomPrivacyRequestField pinning StrictBool ordering; replaced brittle "4 validation errors" count assertion with a loc-based one.
  • tests/ops/schemas/test_privacy_center_config.py — parametrized valid/invalid tests for new field types and the new validator rules.
  • changelog/7977-new-custom-privacy-center-field-types.yaml — added.

Steps to Confirm

  1. Schema acceptance — run pytest tests/ops/schemas/test_privacy_center_config.py tests/ops/schemas/test_identity_schema.py and confirm all pass.
  2. Privacy Center config accepts new types — POST a privacy-center config to PUT /api/v1/plus/privacy-center-config with an action whose custom_privacy_request_fields includes each new type:
    {
      "agree": {"label": "I confirm", "field_type": "checkbox", "required": true},
      "data_types": {"label": "Which data?", "field_type": "checkbox_group", "options": ["Profile", "Orders"]},
      "context": {"label": "Notes", "field_type": "textarea"}
    }
    Expect 200. GET the config back and verify the fields survive unchanged.
  3. Validation rejects invalid configs — confirm PUT returns 4xx for:
    • checkbox_group without options
    • checkbox or textarea with options
    • multiselect or checkbox_group with hidden=True
  4. Boolean round-trip — submit a privacy request (POST to /api/v1/privacy-request) containing a checkbox custom field with value: false. Confirm the value persists as False in the CustomPrivacyRequestField table (SELECT encrypted_value FROM customprivacyrequestfield WHERE field_name=...) and is not dropped.

Pre-Merge Checklist

  • Issue requirements met
  • All CI pipelines succeeded
  • CHANGELOG.md updated
    • Add a db-migration label to the entry if your change includes a DB migration
    • Add a high-risk label to the entry if your change includes a high-risk change
    • Updates unreleased work already in Changelog, no new entry necessary
  • UX feedback:
    • All UX related changes have been reviewed by a designer
    • No UX review needed
  • Followup issues:
    • Followup issues created
    • No followup issues
  • Database migrations:
    • Ensure that your downrev is up to date with the latest revision on main
    • Ensure that your downgrade() migration is correct and works
      • If a downgrade migration is not possible for this change, please call this out in the PR description!
    • No migrations
  • Documentation:
    • Documentation complete, PR opened in fidesdocs
    • Documentation issue created in fidesdocs
    • If there are any new client scopes created as part of the pull request, remember to update public-facing documentation that references our scope registry
    • No documentation updates required

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Actions Updated (UTC)
fides-plus-nightly Ignored Ignored Preview Apr 22, 2026 3:02pm
fides-privacy-center Ignored Ignored Apr 22, 2026 3:02pm

Request Review

@mikeGarifullin mikeGarifullin marked this pull request as ready for review April 21, 2026 14:14
@mikeGarifullin mikeGarifullin requested a review from a team as a code owner April 21, 2026 14:14
@mikeGarifullin mikeGarifullin requested review from erosselli and removed request for a team April 21, 2026 14:14
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 21, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 84.98%. Comparing base (a533969) to head (09ede77).
⚠️ Report is 3 commits behind head on main.

❌ Your project check has failed because the head coverage (84.98%) is below the target coverage (85.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7977      +/-   ##
==========================================
+ Coverage   84.95%   84.98%   +0.02%     
==========================================
  Files         631      632       +1     
  Lines       41185    41256      +71     
  Branches     4781     4786       +5     
==========================================
+ Hits        34989    35061      +72     
- Misses       5110     5112       +2     
+ Partials     1086     1083       -3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

mikeGarifullin and others added 2 commits April 22, 2026 14:03
Fix two failing tests that pass value=None / value="" to exercise the
persist path's drop-None-and-empty filter. Pydantic was rejecting None
at construction time (4 validation errors against every MultiValue
union branch) before persist could run.

Making value Optional lets "no value supplied" be expressed; the
existing persist filter (`if item.value or isinstance(item.value, bool)`)
already drops None and empty strings before writing to the DB, and
cache_custom_privacy_request_fields already skips None entries.

Fixes:
  tests/ops/models/privacy_request/test_consent.py::
    TestConsentRequestCustomFieldFunctions::
    test_persist_custom_privacy_request_fields_preserves_bool_and_drops_empty
  tests/ops/models/privacy_request/test_privacy_request.py::
    TestPrivacyRequestCustomFieldFunctions::
    test_persist_custom_privacy_request_fields_preserves_bool_and_drops_empty

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread changelog/7977-new-custom-privacy-center-field-types.yaml Outdated
Comment thread src/fides/api/models/privacy_request/privacy_request.py Outdated
Comment thread src/fides/api/models/privacy_preference.py Outdated
Comment thread src/fides/api/schemas/privacy_center_config.py Outdated
Comment thread src/fides/api/models/privacy_request/consent.py Dismissed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants