Skip to content

Commit

Permalink
Merge branch 'main' into LA-164-Checking-Oauth-Access-token-regeneration
Browse files Browse the repository at this point in the history
  • Loading branch information
Vagoasdf authored Dec 6, 2024
2 parents 5ca7eb0 + 05cf5ef commit 657c940
Show file tree
Hide file tree
Showing 13 changed files with 238 additions and 55 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ The types of changes are:

## [Unreleased](https://github.com/ethyca/fides/compare/2.51.0...main)

### Added
- New page in the Cookie House sample app to demonstrate the use of embedding the FidesJS SDK on the page [#5564](https://github.com/ethyca/fides/pull/5564)

### Fixed
- SaaS integrations using `oauth_client_credentials` now properly update their access token when editing the secrets.


## [2.51.0](https://github.com/ethyca/fides/compare/2.50.0...2.51.0)

### Added
Expand All @@ -44,6 +45,7 @@ The types of changes are:
- Updating dataset PUT to allow deleting all datasets [#5524](https://github.com/ethyca/fides/pull/5524)
- Adds support for fides_key generation when parent_key is provided in Taxonomy create endpoints [#5542](https://github.com/ethyca/fides/pull/5542)
- An integration will no longer re-enable after saving the connection form [#5555](https://github.com/ethyca/fides/pull/5555)
- Fixed positioning of Fides brand link in privacy center [#5572](https://github.com/ethyca/fides/pull/5572)

### Removed
- Removed unnecessary debug logging from the load_file config helper [#5544](https://github.com/ethyca/fides/pull/5544)
Expand Down
40 changes: 28 additions & 12 deletions clients/privacy-center/components/BrandLink.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,32 @@
import { EthycaLogo, Link, LinkProps } from "fidesui";

const BrandLink = (props: LinkProps) => (
<Link
fontSize="8px"
color="gray.400"
isExternal
textDecoration="none"
_hover={{ textDecoration: "none" }}
{...props}
>
Powered by <EthycaLogo color="minos.500" h="20px" w="31px" />
</Link>
);
import { useSettings } from "~/features/common/settings.slice";

const BrandLink = ({
position = "absolute",
right = 6,
...props
}: LinkProps) => {
const { SHOW_BRAND_LINK } = useSettings();

if (!SHOW_BRAND_LINK) {
return null;
}

return (
<Link
fontSize="8px"
color="gray.400"
isExternal
position={position}
right={right}
textDecoration="none"
_hover={{ textDecoration: "none" }}
{...props}
>
Powered by <EthycaLogo color="minos.500" h="20px" w="31px" />
</Link>
);
};

export default BrandLink;
15 changes: 1 addition & 14 deletions clients/privacy-center/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,13 @@ import { Flex } from "fidesui";
import Head from "next/head";
import React, { ReactNode } from "react";

import BrandLink from "~/components/BrandLink";
import Logo from "~/components/Logo";
import { useConfig } from "~/features/common/config.slice";
import { useSettings } from "~/features/common/settings.slice";
import { useStyles } from "~/features/common/styles.slice";

const Layout = ({ children }: { children: ReactNode }) => {
const config = useConfig();
const styles = useStyles();
const { SHOW_BRAND_LINK } = useSettings();
return (
<>
<Head>
Expand All @@ -32,17 +29,7 @@ const Layout = ({ children }: { children: ReactNode }) => {
<Logo src={config.logo_path ?? ""} href={config.logo_url ?? ""} />
</Flex>
</header>
<div>
{children}
{SHOW_BRAND_LINK && (
<BrandLink
position="absolute"
bottom={16}
right={6}
href="https://fid.es/powered"
/>
)}
</div>
<div>{children}</div>
</>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useAppDispatch, useAppSelector } from "~/app/hooks";
import { inspectForBrowserIdentities } from "~/common/browser-identities";
import { useLocalStorage } from "~/common/hooks";
import { ErrorToastOptions, SuccessToastOptions } from "~/common/toast-options";
import BrandLink from "~/components/BrandLink";
import { useConfig } from "~/features/common/config.slice";
import {
changeConsent,
Expand Down Expand Up @@ -209,6 +210,7 @@ const ConfigDrivenConsent = ({
cancelLabel="Cancel"
saveLabel="Save"
/>
<BrandLink bottom={0} />
</Stack>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { inspectForBrowserIdentities } from "~/common/browser-identities";
import { useLocalStorage } from "~/common/hooks";
import useI18n from "~/common/hooks/useI18n";
import { ErrorToastOptions, SuccessToastOptions } from "~/common/toast-options";
import BrandLink from "~/components/BrandLink";
import { useProperty } from "~/features/common/property.slice";
import {
selectPrivacyExperience,
Expand Down Expand Up @@ -400,7 +401,10 @@ const NoticeDrivenConsent = ({ base64Cookie }: { base64Cookie: boolean }) => {
onCancel={handleCancel}
justifyContent="center"
/>
<PrivacyPolicyLink alignSelf="center" experience={experience} />
<Stack flexDirection="row" alignItems="center">
<PrivacyPolicyLink experience={experience} />
<BrandLink />
</Stack>
</Box>
);
};
Expand Down
42 changes: 28 additions & 14 deletions clients/privacy-center/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import React, { useEffect, useState } from "react";

import { useAppDispatch, useAppSelector } from "~/app/hooks";
import { ConfigErrorToastOptions } from "~/common/toast-options";
import BrandLink from "~/components/BrandLink";
import ConsentCard from "~/components/consent/ConsentCard";
import {
ConsentRequestModal,
Expand All @@ -25,7 +26,10 @@ import {
} from "~/components/modals/privacy-request-modal/PrivacyRequestModal";
import PrivacyCard from "~/components/PrivacyCard";
import { useConfig } from "~/features/common/config.slice";
import { selectIsNoticeDriven } from "~/features/common/settings.slice";
import {
selectIsNoticeDriven,
useSettings,
} from "~/features/common/settings.slice";
import {
clearLocation,
selectPrivacyExperience,
Expand Down Expand Up @@ -68,6 +72,10 @@ const Home: NextPage = () => {
let isConsentModalOpen = isConsentModalOpenConst;
const getIdVerificationConfigQuery = useGetIdVerificationConfigQuery();

const { SHOW_BRAND_LINK } = useSettings();
const showPrivacyPolicyLink =
!!config.privacy_policy_url && !!config.privacy_policy_url_text;

// Subscribe to experiences just to see if there are any notices.
// The subscription automatically handles skipping if overlay is not enabled
useSubscribeToPrivacyExperienceQuery();
Expand Down Expand Up @@ -214,19 +222,25 @@ const Home: NextPage = () => {
{paragraph}
</Text>
))}
{config.privacy_policy_url && config.privacy_policy_url_text ? (
<Link
fontSize={["small", "medium"]}
fontWeight="medium"
textAlign="center"
textDecoration="underline"
color="gray.600"
href={config.privacy_policy_url}
isExternal
>
{config.privacy_policy_url_text}
</Link>
) : null}

{(SHOW_BRAND_LINK || showPrivacyPolicyLink) && (
<Stack flexDirection="row">
{showPrivacyPolicyLink && (
<Link
fontSize={["small", "medium"]}
fontWeight="medium"
textAlign="center"
textDecoration="underline"
color="gray.600"
href={config.privacy_policy_url!}
isExternal
>
{config.privacy_policy_url_text}
</Link>
)}
<BrandLink />
</Stack>
)}
</Stack>
<PrivacyRequestModal
isOpen={isPrivacyModalOpen}
Expand Down
7 changes: 7 additions & 0 deletions clients/sample-app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ This will automatically bring up a Docker Compose project to create a sample app

Once running successfully, open http://localhost:3000 to see the Cookie House!

Note: If you are already running a database on port 5432 locally, you can override the default port by setting the `FIDES_SAMPLE_APP__DATABASE_PORT` environment variable and ALSO changing the **host** port number in the `docker-compose.yml` file. For example:

```yaml
ports:
- "5433:5432"
```
## Pre-commit
Before committing any changes, run the following:
Expand Down
99 changes: 99 additions & 0 deletions clients/sample-app/src/pages/embedded-consent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { GetServerSideProps } from "next";
import Head from "next/head";
import { useRouter } from "next/router";
import Script from "next/script";

interface Props {
gtmContainerId: string | null;
privacyCenterUrl: string;
}

// Regex to ensure the provided GTM container ID appears valid (e.g. "GTM-ABCD123")
// NOTE: this also protects against XSS since this ID is added to a script template
const VALID_GTM_REGEX = /^[0-9a-zA-Z-]+$/;

/**
* Pass the following server-side ENV variables to the page:
* - FIDES_SAMPLE_APP__GOOGLE_TAG_MANAGER_CONTAINER_ID: configure a GTM container, e.g. "GTM-ABCD123"
* - FIDES_SAMPLE_APP__PRIVACY_CENTER_URL: configure Privacy Center URL, e.g. "http://localhost:3001"
*/
export const getServerSideProps: GetServerSideProps<Props> = async () => {
// Check for a valid FIDES_SAMPLE_APP__GOOGLE_TAG_MANAGER_CONTAINER_ID
let gtmContainerId = null;
if (
process.env.FIDES_SAMPLE_APP__GOOGLE_TAG_MANAGER_CONTAINER_ID?.match(
VALID_GTM_REGEX,
)
) {
gtmContainerId =
process.env.FIDES_SAMPLE_APP__GOOGLE_TAG_MANAGER_CONTAINER_ID;
}

// Check for a valid FIDES_SAMPLE_APP__PRIVACY_CENTER_URL
const privacyCenterUrl =
process.env.FIDES_SAMPLE_APP__PRIVACY_CENTER_URL || "http://localhost:3001";

// Pass the server-side props to the page
return { props: { gtmContainerId, privacyCenterUrl } };
};

const IndexPage = ({ gtmContainerId, privacyCenterUrl }: Props) => {
// Load the fides.js script from the Fides Privacy Center, assumed to be
// running at http://localhost:3001
const fidesScriptTagUrl = new URL(`${privacyCenterUrl}/fides.js`);
const router = useRouter();
// eslint-disable-next-line @typescript-eslint/naming-convention
const { geolocation, property_id } = router.query;

// If `geolocation=` or `property_id` query params exists, pass those along to the fides.js fetch
if (geolocation && typeof geolocation === "string") {
fidesScriptTagUrl.searchParams.append("geolocation", geolocation);
}
if (typeof property_id === "string") {
fidesScriptTagUrl.searchParams.append("property_id", property_id);
}

return (
<>
<Head>
<title>Cookie House</title>
{/* Require FidesJS to "embed" it's UI onto the page, instead of as an overlay over the <body> itself. (see https://ethyca.com/docs/dev-docs/js/reference/interfaces/FidesOptions#fides_embed) */}
<script>{`window.fides_overrides = { fides_embed: true, fides_disable_banner: true }`}</script>
{/* Allow the embedded consent modal to fill the screen */}
<style>{`#fides-embed-container { --fides-overlay-width: 'auto' }`}</style>
</Head>
{/**
Insert the fides.js script and run the GTM integration once ready
DEFER: using "beforeInteractive" here triggers a lint warning from NextJS
as it should only be used in the _document.tsx file. This still works and
ensures that fides.js fires earlier than other scripts, but isn't a best
practice.
*/}
<Script
id="fides-js"
src={fidesScriptTagUrl.href}
onReady={() => {
// Enable the GTM integration, if GTM is configured
if (gtmContainerId) {
(window as any).Fides.gtm();
}
}}
/>
{/* Insert the GTM script, if a container ID was provided */}
{gtmContainerId ? (
<Script id="google-tag-manager" strategy="afterInteractive">
{`
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','${gtmContainerId}');
`}
</Script>
) : null}
<div id="fides-embed-container" />
</>
);
};

export default IndexPage;
9 changes: 8 additions & 1 deletion src/fides/api/api/v1/endpoints/privacy_request_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import csv
import io
import json
from collections import defaultdict
from datetime import datetime
from typing import (
Expand Down Expand Up @@ -148,6 +149,7 @@
from fides.api.util.enums import ColumnSort
from fides.api.util.fuzzy_search_utils import get_decrypted_identities_automaton
from fides.api.util.logger import Pii
from fides.api.util.storage_util import storage_json_encoder
from fides.common.api.scope_registry import (
PRIVACY_REQUEST_CALLBACK_RESUME,
PRIVACY_REQUEST_CREATE,
Expand Down Expand Up @@ -2657,8 +2659,13 @@ def get_test_privacy_request_results(
)
privacy_request.save(db=db)

# Escape datetime and ObjectId values
raw_data = privacy_request.get_raw_access_results()
escaped_json = json.dumps(raw_data, indent=2, default=storage_json_encoder)
escaped_data = json.loads(escaped_json)

return {
"privacy_request_id": privacy_request.id,
"status": privacy_request.status,
"results": privacy_request.get_raw_access_results(),
"results": escaped_data,
}
10 changes: 5 additions & 5 deletions tests/ctl/core/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1669,9 +1669,9 @@ def test_list_with_pagination_and_multiple_filters_2(
"vendor_deleted_date, expected_systems_count, show_deleted",
[
(datetime.now() - timedelta(days=1), 1, True),
(datetime.now() - timedelta(days=1), 0, None),
(datetime.now() + timedelta(days=1), 1, None),
(None, 1, None),
(datetime.now() - timedelta(days=1), 0, False),
(datetime.now() + timedelta(days=1), 1, False),
(None, 1, False),
],
)
def test_vendor_deleted_systems(
Expand All @@ -1691,13 +1691,13 @@ def test_vendor_deleted_systems(
url=test_config.cli.server_url,
headers=test_config.user.auth_header,
resource_type="system",
query_params={"show_deleted": True} if show_deleted else {},
query_params={"show_deleted": show_deleted, "size": 50},
)

assert result.status_code == 200
result_json = result.json()

assert len(result_json) == expected_systems_count
assert len(result_json["items"]) == expected_systems_count


@pytest.mark.unit
Expand Down
2 changes: 1 addition & 1 deletion tests/ops/api/v1/endpoints/test_dataset_test_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ def test_dataset_reachability(
assert set(response.json().keys()) == {"reachable", "details"}


@pytest.mark.integration_external
@pytest.mark.integration
@pytest.mark.integration_postgres
class TestDatasetTest:
@pytest.fixture(scope="function")
Expand Down
Loading

0 comments on commit 657c940

Please sign in to comment.