From 821a3495e24a100e99025fda06bd7168149cbcf2 Mon Sep 17 00:00:00 2001 From: Jason Gill Date: Fri, 8 Nov 2024 12:09:46 -0700 Subject: [PATCH 1/2] Support new "All" GPP approach --- .../consent-settings/GppConfiguration.tsx | 6 + .../admin-ui/src/pages/settings/consent.tsx | 1 + .../src/types/api/models/GPPUSApproach.ts | 1 + .../fides-js/__tests__/lib/gpp/us-notices.ts | 112 ++++++++++++++++++ clients/fides-js/src/fides-ext-gpp.ts | 13 +- clients/fides-js/src/lib/gpp/types.ts | 1 + clients/fides-js/src/lib/gpp/us-notices.ts | 20 +++- .../types/api/models/GPPUSApproach.ts | 1 + 8 files changed, 149 insertions(+), 6 deletions(-) diff --git a/clients/admin-ui/src/features/consent-settings/GppConfiguration.tsx b/clients/admin-ui/src/features/consent-settings/GppConfiguration.tsx index 304c77d8471..692bc4f1406 100644 --- a/clients/admin-ui/src/features/consent-settings/GppConfiguration.tsx +++ b/clients/admin-ui/src/features/consent-settings/GppConfiguration.tsx @@ -61,6 +61,12 @@ const GppConfiguration = () => { tooltip: "When state-by-state is selected, Fides will only present consent to consumers and save their preferences if they are located in a state that is supported by the GPP. The consent options presented to consumers will vary depending on the regulations in each state.", }, + { + label: "Enable US National and State-by-State notices", + value: GPPUSApproach.ALL, + tooltip: + "When enabled, Fides can be configured to serve the National and U.S. state notices. This mode is intended to provide consent coverage to U.S. states with new privacy laws where GPP support lags behind the effective date of state laws.", + }, ]} /> diff --git a/clients/admin-ui/src/pages/settings/consent.tsx b/clients/admin-ui/src/pages/settings/consent.tsx index f422d23182c..695e4da52fa 100644 --- a/clients/admin-ui/src/pages/settings/consent.tsx +++ b/clients/admin-ui/src/pages/settings/consent.tsx @@ -301,6 +301,7 @@ const ConsentConfigPage: NextPage = () => { disabled={!dirty || !isValid} loading={isSubmitting} data-testid="save-btn" + className="self-start" > Save diff --git a/clients/admin-ui/src/types/api/models/GPPUSApproach.ts b/clients/admin-ui/src/types/api/models/GPPUSApproach.ts index fe2e01534ae..a4382393750 100644 --- a/clients/admin-ui/src/types/api/models/GPPUSApproach.ts +++ b/clients/admin-ui/src/types/api/models/GPPUSApproach.ts @@ -5,4 +5,5 @@ export enum GPPUSApproach { NATIONAL = "national", STATE = "state", + ALL = "all", } diff --git a/clients/fides-js/__tests__/lib/gpp/us-notices.ts b/clients/fides-js/__tests__/lib/gpp/us-notices.ts index 4b5d4c47111..105dc06f415 100644 --- a/clients/fides-js/__tests__/lib/gpp/us-notices.ts +++ b/clients/fides-js/__tests__/lib/gpp/us-notices.ts @@ -681,4 +681,116 @@ describe("setGppOptOutsFromCookieAndExperience", () => { expect(cmpApi.getSection("usnatv1")).toBe(null); expect(cmpApi.getSection("usnyv1")).toBe(null); }); + + it("can use US gpp fields when gpp is set to all", () => { + const cmpApi = new CmpApi(1, 1); + const cookie = mockFidesCookie({ + consent: { + data_sales_and_sharing: false, + targeted_advertising: false, + sensitive_personal_data_sharing: false, + known_child_sensitive_data_consents: false, + personal_data_consents: false, + }, + }); + const notices = [ + DATA_SALES_SHARING_NOTICE, + TARGETED_ADVERTISING_NOTICE, + SENSITIVE_PERSONAL_SHARING_NOTICE, + KNOWN_CHILD_SENSITIVE_NOTICE, + PERSONAL_DATA_NOTICE, + ]; + const experience = mockPrivacyExperience({ + region: "us_mt", // Set to a non-supported state + privacy_notices: notices, + gpp_settings: { + enabled: true, + us_approach: GPPUSApproach.ALL, // Set to all + mspa_covered_transactions: true, + mspa_opt_out_option_mode: true, + mspa_service_provider_mode: false, + enable_tcfeu_string: true, + }, + }); + setGppOptOutsFromCookieAndExperience({ + cmpApi, + cookie, + experience, + }); + const section = cmpApi.getSection("usnatv1"); + expect(section).toEqual({ + Version: 1, + SharingNotice: 0, + SaleOptOutNotice: 0, + SharingOptOutNotice: 0, + TargetedAdvertisingOptOutNotice: 0, + SensitiveDataProcessingOptOutNotice: 0, + SensitiveDataLimitUseNotice: 0, + SaleOptOut: 1, + SharingOptOut: 1, + TargetedAdvertisingOptOut: 1, + SensitiveDataProcessing: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + KnownChildSensitiveDataConsents: [1, 1], + PersonalDataConsents: 1, + MspaCoveredTransaction: 1, + MspaOptOutOptionMode: 1, + MspaServiceProviderMode: 2, + GpcSegmentType: 1, + Gpc: false, + }); + expect(cmpApi.getGppString()).toEqual("DBABLA~BAAVVVVVVWA.QA"); + }); + + it("can use state gpp fields when gpp is set to all", () => { + const cmpApi = new CmpApi(1, 1); + const cookie = mockFidesCookie({ + consent: { + data_sales_and_sharing: false, + targeted_advertising: false, + sensitive_personal_data_sharing: false, + known_child_sensitive_data_consents: false, + personal_data_consents: false, + }, + }); + const notices = [ + DATA_SALES_SHARING_NOTICE, + TARGETED_ADVERTISING_NOTICE, + SENSITIVE_PERSONAL_SHARING_NOTICE, + KNOWN_CHILD_SENSITIVE_NOTICE, + PERSONAL_DATA_NOTICE, + ]; + const experience = mockPrivacyExperience({ + region: "us_ut", // Set to a supported state + privacy_notices: notices, + gpp_settings: { + enabled: true, + us_approach: GPPUSApproach.ALL, // Set to all + mspa_covered_transactions: true, + mspa_opt_out_option_mode: true, + mspa_service_provider_mode: false, + enable_tcfeu_string: true, + }, + }); + setGppOptOutsFromCookieAndExperience({ + cmpApi, + cookie, + experience, + }); + const section = cmpApi.getSection("usutv1"); + expect(section).toEqual({ + Version: 1, + SharingNotice: 0, + SaleOptOutNotice: 0, + TargetedAdvertisingOptOutNotice: 0, + SensitiveDataProcessingOptOutNotice: 0, + SaleOptOut: 0, + TargetedAdvertisingOptOut: 0, + SensitiveDataProcessing: [0, 0, 0, 0, 0, 0, 0, 0], + KnownChildSensitiveDataConsents: 0, + MspaCoveredTransaction: 1, + MspaOptOutOptionMode: 1, + MspaServiceProviderMode: 2, + }); + expect(cmpApi.getGppString()).toEqual("DBABFg~BAAAAAWA"); + }); }); diff --git a/clients/fides-js/src/fides-ext-gpp.ts b/clients/fides-js/src/fides-ext-gpp.ts index d63783427de..ab7df5f3c78 100644 --- a/clients/fides-js/src/fides-ext-gpp.ts +++ b/clients/fides-js/src/fides-ext-gpp.ts @@ -115,10 +115,19 @@ const getSupportedApis = () => { if (window.Fides.options.tcfEnabled && gppSettings.enable_tcfeu_string) { supportedApis.push(`${TcfEuV2.ID}:${TcfEuV2.NAME}`); } - if (gppSettings.us_approach === GPPUSApproach.NATIONAL) { + fidesDebugger("GPP settings", gppSettings); + if ( + gppSettings.us_approach === GPPUSApproach.NATIONAL || + gppSettings.us_approach === GPPUSApproach.ALL + ) { + fidesDebugger("setting US National"); supportedApis.push(`${UsNatV1.ID}:${UsNatV1.NAME}`); } - if (gppSettings.us_approach === GPPUSApproach.STATE) { + if ( + gppSettings.us_approach === GPPUSApproach.STATE || + gppSettings.us_approach === GPPUSApproach.ALL + ) { + fidesDebugger("setting US State"); // TODO: include the states based off of locations/regulations. // For now, hard code all of them. https://ethyca.atlassian.net/browse/PROD-1595 [UsCaV1, UsCoV1, UsCtV1, UsUtV1, UsVaV1].forEach((state) => { diff --git a/clients/fides-js/src/lib/gpp/types.ts b/clients/fides-js/src/lib/gpp/types.ts index 3b0e201baf7..1e0d824b8f1 100644 --- a/clients/fides-js/src/lib/gpp/types.ts +++ b/clients/fides-js/src/lib/gpp/types.ts @@ -15,6 +15,7 @@ export type GppFunction = ( export enum GPPUSApproach { NATIONAL = "national", STATE = "state", + ALL = "all", } export type GPPSettings = { diff --git a/clients/fides-js/src/lib/gpp/us-notices.ts b/clients/fides-js/src/lib/gpp/us-notices.ts index 6f807eb1755..f7f6edd871b 100644 --- a/clients/fides-js/src/lib/gpp/us-notices.ts +++ b/clients/fides-js/src/lib/gpp/us-notices.ts @@ -85,11 +85,17 @@ export const setGppNoticesProvidedFromExperience = ({ gpp_settings: gppSettings, } = experience; const usApproach = gppSettings?.us_approach; - const gppRegion = deriveGppFieldRegion({ + let gppRegion = deriveGppFieldRegion({ experienceRegion, usApproach, }); - const gppSection = FIDES_REGION_TO_GPP_SECTION[gppRegion]; + let gppSection = FIDES_REGION_TO_GPP_SECTION[gppRegion]; + + if (!gppSection && usApproach === GPPUSApproach.ALL) { + // if we're using the "all" approach, and the user's state isn't supported yet, we should default to national. + gppRegion = US_NATIONAL_REGION; + gppSection = FIDES_REGION_TO_GPP_SECTION[gppRegion]; + } if ( !gppSection || @@ -142,11 +148,17 @@ export const setGppOptOutsFromCookieAndExperience = ({ gpp_settings: gppSettings, } = experience; const usApproach = gppSettings?.us_approach; - const gppRegion = deriveGppFieldRegion({ + let gppRegion = deriveGppFieldRegion({ experienceRegion, usApproach, }); - const gppSection = FIDES_REGION_TO_GPP_SECTION[gppRegion]; + let gppSection = FIDES_REGION_TO_GPP_SECTION[gppRegion]; + + if (!gppSection && usApproach === GPPUSApproach.ALL) { + // if we're using the all approach, and the current state isn't supported, we should default to national + gppRegion = US_NATIONAL_REGION; + gppSection = FIDES_REGION_TO_GPP_SECTION[gppRegion]; + } if ( !gppSection || diff --git a/clients/privacy-center/types/api/models/GPPUSApproach.ts b/clients/privacy-center/types/api/models/GPPUSApproach.ts index fe2e01534ae..a4382393750 100644 --- a/clients/privacy-center/types/api/models/GPPUSApproach.ts +++ b/clients/privacy-center/types/api/models/GPPUSApproach.ts @@ -5,4 +5,5 @@ export enum GPPUSApproach { NATIONAL = "national", STATE = "state", + ALL = "all", } From 593b7c8ad194665d8098fd7b70695d57c3016327 Mon Sep 17 00:00:00 2001 From: Jason Gill Date: Fri, 8 Nov 2024 12:14:45 -0700 Subject: [PATCH 2/2] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3537c4668f..73ebddeacd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,9 @@ The types of changes are: ## [Unreleased](https://github.com/ethyca/fidesplus/compare/2.49.0...main) +### Added +- Added support for GPP national string to be used alongside state-by-state using a new approach option [#5480](https://github.com/ethyca/fides/pull/5480) + ## [2.49.0](https://github.com/ethyca/fidesplus/compare/2.48.2...2.49.0)