From 62f9fe0d21cdb669334f8a0a72861adf02d5da85 Mon Sep 17 00:00:00 2001 From: Roger Plotz <115798183+Roger-Ethyca@users.noreply.github.com> Date: Wed, 12 Mar 2025 16:04:52 -0400 Subject: [PATCH 1/5] empty commit to start release 2.57.0 From a829a9a6081153574cfa9e75bb1f07a95b01d787 Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Thu, 13 Mar 2025 17:11:06 -0300 Subject: [PATCH 2/5] Fix hover/selecter colors in main menu (#5887) --- clients/admin-ui/src/theme/global.scss | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/clients/admin-ui/src/theme/global.scss b/clients/admin-ui/src/theme/global.scss index ec9922fd07..6598d66050 100644 --- a/clients/admin-ui/src/theme/global.scss +++ b/clients/admin-ui/src/theme/global.scss @@ -53,10 +53,12 @@ h6 { } } - &:hover, - &:focus-within { + &:focus-within:not(.ant-menu-item-selected) { background-color: var(--fidesui-neutral-800); } + &:hover { + --ant-menu-dark-item-hover-bg: var(--fidesui-neutral-800); + } } // The selected submenu item should be dark, because the background is light From 9343e91639e610092fdafebbce16a42c8c2d3888 Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Thu, 13 Mar 2025 17:16:12 -0300 Subject: [PATCH 3/5] Fix extra space in subject email (#5889) --- .../admin-ui/src/features/privacy-requests/RequestDetails.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/admin-ui/src/features/privacy-requests/RequestDetails.tsx b/clients/admin-ui/src/features/privacy-requests/RequestDetails.tsx index 98349aca62..ef5292ac54 100644 --- a/clients/admin-ui/src/features/privacy-requests/RequestDetails.tsx +++ b/clients/admin-ui/src/features/privacy-requests/RequestDetails.tsx @@ -59,7 +59,7 @@ const RequestDetails = ({ subjectRequest }: RequestDetailsProps) => { {Object.entries(identity) .filter(([, { value }]) => value !== null) .map(([key, { value = "", label }]) => { - const text = `${value} ${!identityVerifiedAt ? "(Unverified)" : ""}`; + const text = `${value}${!identityVerifiedAt ? " (Unverified)" : ""}`; return ( Date: Thu, 13 Mar 2025 17:58:55 -0300 Subject: [PATCH 4/5] Use gpp_settings.cmp_api_required to determine if GPP should be included (#5883) --- CHANGELOG.md | 1 + clients/fides-js/src/lib/gpp/types.ts | 4 ++++ clients/privacy-center/pages/api/fides-js.ts | 4 +++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b3d378a5b..9a2f3d0af7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ Changes can also be flagged with a GitHub label for tracking purposes. The URL o - Updated privacy request handling to still succeed if not all identities are provided [#5836](https://github.com/ethyca/fides/pull/5836) - Refactored privacy request processing to never re-use sessions [#5862](https://github.com/ethyca/fides/pull/5862) - Updated hover state of menu items to be more visible [#5868](https://github.com/ethyca/fides/pull/5868) +- Use `gpp_settings.cmp_api_required` to determine if GPP CMP API should be included in bundle [#5883](https://github.com/ethyca/fides/pull/5883) ### Developer Experience - Moved non-prod Admin UI dependencies to devDependencies [#5832](https://github.com/ethyca/fides/pull/5832) diff --git a/clients/fides-js/src/lib/gpp/types.ts b/clients/fides-js/src/lib/gpp/types.ts index fac850fdfa..7d13b6b2a4 100644 --- a/clients/fides-js/src/lib/gpp/types.ts +++ b/clients/fides-js/src/lib/gpp/types.ts @@ -44,6 +44,10 @@ export type GPPSettings = { * Whether TC string should be included as a section in GPP */ enable_tcfeu_string?: boolean; + /** + * Whether the GPP CMP API is required for the experience + */ + cmp_api_required?: boolean; }; export type GPPMechanismMapping = { diff --git a/clients/privacy-center/pages/api/fides-js.ts b/clients/privacy-center/pages/api/fides-js.ts index 0ed6c38cfb..4f2996ad0c 100644 --- a/clients/privacy-center/pages/api/fides-js.ts +++ b/clients/privacy-center/pages/api/fides-js.ts @@ -227,8 +227,10 @@ export default async function handler( if (forcedGppQuery === "true" && experience === undefined) { experience = {}; } + const gppEnabled = - (!!experience?.gpp_settings?.enabled || forcedGppQuery === "true") && + (!!experience?.gpp_settings?.cmp_api_required || + forcedGppQuery === "true") && forcedGppQuery !== "debug"; // Create the FidesConfig JSON that will be used to initialize fides.js unless in E2E mode (see below) From 42bbb179d4841773d0942a517f207b22db405e6d Mon Sep 17 00:00:00 2001 From: Jason Gill Date: Thu, 13 Mar 2025 15:46:18 -0600 Subject: [PATCH 5/5] fix vendor override handling (#5886) --- CHANGELOG.md | 2 +- clients/fides-js/src/lib/tcf.ts | 24 ++++++- .../cypress/e2e/consent-banner-tcf.cy.ts | 72 +++++++++++++++++++ .../fixtures/consent/experience_tcf.json | 28 ++++++++ 4 files changed, 124 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a2f3d0af7..49f3d055df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,6 @@ Changes can also be flagged with a GitHub label for tracking purposes. The URL o - ## [2.57.0](https://github.com/ethyca/fides/compare/2.56.2...2.57.0) ### Added @@ -59,6 +58,7 @@ Changes can also be flagged with a GitHub label for tracking purposes. The URL o - Fixed an issue with the update payloads for select SaaS integrations [#5860](https://github.com/ethyca/fides/pull/5860) - Fixed `/privacy-request//resubmit` endpoint so it doesn't queue the request twice [#5870](https://github.com/ethyca/fides/pull/5870) - Fixed the system assets table being the wrong width [#5879](https://github.com/ethyca/fides/pull/5879) +- Fixed vendor override handling in FidesJS CMP [#5886](https://github.com/ethyca/fides/pull/5886) ## [2.56.2](https://github.com/ethyca/fides/compare/2.56.1...2.56.2) diff --git a/clients/fides-js/src/lib/tcf.ts b/clients/fides-js/src/lib/tcf.ts index 9ca4497264..8a105dc8b3 100644 --- a/clients/fides-js/src/lib/tcf.ts +++ b/clients/fides-js/src/lib/tcf.ts @@ -6,7 +6,14 @@ */ import { CmpApi, TCData } from "@iabtechlabtcf/cmpapi"; -import { GVL, Segment, TCModel, TCString } from "@iabtechlabtcf/core"; +import { + GVL, + PurposeRestriction, + RestrictionType, + Segment, + TCModel, + TCString, +} from "@iabtechlabtcf/core"; import { PrivacyExperience, PrivacyExperienceMinimal } from "./consent-types"; import { ETHYCA_CMP_ID, FIDES_SEPARATOR } from "./tcf/constants"; @@ -96,6 +103,21 @@ export const generateFidesString = async ({ if (vendorGvlEntry(vendorId, experience.gvl)) { const { id } = decodeVendorId(vendorId); tcModel.vendorConsents.set(+id); + + // look up each vendor in the GVL vendors list to see if they have a purpose list. + // If they do not it means they have been set in Admin UI as Vendor Overrides to + // require consent. In that case we need to set a publisher restriction for the + // vendor's flexible purposes. + const vendor = experience.gvl?.vendors[id]; + if (vendor && !vendor?.purposes?.length) { + vendor.flexiblePurposes.forEach((purpose) => { + const purposeRestriction = new PurposeRestriction(); + purposeRestriction.purposeId = purpose; + purposeRestriction.restrictionType = + RestrictionType.REQUIRE_CONSENT; + tcModel.publisherRestrictions.add(+id, purposeRestriction); + }); + } } }); tcStringPreferences.vendorsLegint.forEach((vendorId) => { diff --git a/clients/privacy-center/cypress/e2e/consent-banner-tcf.cy.ts b/clients/privacy-center/cypress/e2e/consent-banner-tcf.cy.ts index 3c0a08b695..fd865e277e 100644 --- a/clients/privacy-center/cypress/e2e/consent-banner-tcf.cy.ts +++ b/clients/privacy-center/cypress/e2e/consent-banner-tcf.cy.ts @@ -1486,6 +1486,78 @@ describe("Fides-js TCF", () => { }); }); }); + + describe("Vendor overrides", () => { + it("adds Legitimate Interest vendors to Preferences list when overriden", () => { + cy.fixture("consent/experience_tcf.json").then((payload) => { + const experience = payload.items[0]; + // mimics behavior of a vendor override, where DoubleVerify is added to the + // preferences list instead of Legitimate Interest vendor + experience.tcf_vendor_consents = [ + { + id: "gvl.3", + name: "DoubleVerify", + default_preference: "opt_out", + purpose_consents: [ + { + id: 2, + name: "Use limited data to select advertising", + retention_period: "45", + }, + ], + }, + ]; + experience.tcf_vendor_legitimate_interests = []; + experience.tcf_vendor_relationships = [ + { + id: "gvl.3", + has_vendor_id: true, + name: "DoubleVerify", + special_purposes: [ + { + id: 1, + name: "Ensure security, prevent and detect fraud, and fix errors", + retention_period: "45", + }, + { + id: 2, + name: "Deliver and present advertising and content", + retention_period: "45", + }, + ], + }, + ]; + stubTCFExperience({ + experienceFullOverride: experience, + }); + cy.waitUntilFidesInitialized().then(() => { + cy.get("#fides-modal-link").click(); + cy.get("#fides-tab-vendors").click(); + cy.get("#fides-panel-vendors").within(() => { + // should exist in the Consent list and not be checked yet + cy.getByTestId("toggle-DoubleVerify") + .find("input") + .should("exist"); + cy.getByTestId("toggle-DoubleVerify") + .find("input") + .should("not.be.checked"); + }); + cy.getByTestId("fides-modal-content").within(() => { + cy.getByTestId("Opt in to all-btn").click(); + }); + // Verify the TCF String has the vendor override + cy.getCookie(CONSENT_COOKIE_NAME).then((cookie) => { + const cookieKeyConsent: FidesCookie = JSON.parse( + decodeURIComponent(cookie!.value), + ); + expect(cookieKeyConsent.fides_string).to.contain( + "GXABBENArEoABaAAEAAAAAAABiAAAAMJABAAGOgAgADKQAQABgA", // excludes date information for testing + ); + }); + }); + }); + }); + }); }); describe("when fides_embed is true", () => { diff --git a/clients/privacy-center/cypress/fixtures/consent/experience_tcf.json b/clients/privacy-center/cypress/fixtures/consent/experience_tcf.json index 75660b614e..501ecc015d 100644 --- a/clients/privacy-center/cypress/fixtures/consent/experience_tcf.json +++ b/clients/privacy-center/cypress/fixtures/consent/experience_tcf.json @@ -955,6 +955,34 @@ ], "dataDeclaration": [1, 2, 4, 6, 11], "deviceStorageDisclosureUrl": "https://static.cpx.to/gvl/deviceStorageDisclosure.json" + }, + "3": { + "id": 3, + "name": "DoubleVerify Inc.​", + "purposes": [], + "legIntPurposes": [2, 7, 10], + "flexiblePurposes": [2, 7, 10], + "specialPurposes": [1, 2], + "features": [], + "specialFeatures": [], + "cookieMaxAgeSeconds": null, + "usesCookies": false, + "cookieRefresh": false, + "urls": [ + { + "langId": "en", + "privacy": "https://doubleverify.com/privacy-notice/solutions-privacy-notice", + "legIntClaim": "https://doubleverify.com/privacy-notice/solutions-privacy-notice" + } + ], + "usesNonCookieAccess": false, + "dataRetention": { + "stdRetention": 45, + "purposes": {}, + "specialPurposes": {} + }, + "dataDeclaration": [1, 2, 4, 6, 8, 11], + "deviceStorageDisclosureUrl": "https://cdn.doubleverify.com/static/Doubleverify_TCF.json" } } },