Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fides adyen erasure integration #4735

Merged
merged 27 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f9bef7e
init commit
MarcGEthyca Mar 21, 2024
d152224
Quick initial changes
MarcGEthyca Mar 21, 2024
a62638d
First pass
MarcGEthyca Mar 22, 2024
cf84328
replaced adyen icon with proper exported icon
MarcGEthyca Mar 25, 2024
326124f
Initial PR - test pass erasure not
MarcGEthyca Mar 27, 2024
a88ba6d
Added a skip to get this test to pass for now
MarcGEthyca Mar 27, 2024
1dbfefd
pause
MarcGEthyca Mar 28, 2024
3bb6f5d
testing
MarcGEthyca Mar 28, 2024
fcfd575
Added a _ to the task trying to get it to pass
MarcGEthyca Mar 28, 2024
dab0fc9
Merge branch 'main' into fides-Adyen-Erasure-integration
galvana Mar 28, 2024
fe584a5
Adding skip for integrations without access requests
galvana Mar 28, 2024
1c4128b
Changed note
MarcGEthyca Mar 29, 2024
b51b61d
Fixing Adyen tests
galvana Mar 29, 2024
4893c16
First fixes
MarcGEthyca Mar 29, 2024
c897673
clean 1
MarcGEthyca Mar 29, 2024
4d93b80
Various fixes
MarcGEthyca Mar 29, 2024
41ed4ef
Changes
MarcGEthyca Mar 29, 2024
1227a7b
Added entry for changelog
MarcGEthyca Mar 30, 2024
3a3f421
Merge branch 'main' into fides-Adyen-Erasure-integration
MarcGEthyca Mar 30, 2024
48ebee7
Merge branch 'main' into fides-Adyen-Erasure-integration
MarcGEthyca Apr 1, 2024
dd12428
Text Correction
MarcGEthyca Apr 1, 2024
c8cb08d
Black pass
MarcGEthyca Apr 1, 2024
0c88362
Update CHANGELOG.md
MarcGEthyca Apr 1, 2024
0faf437
Update data/saas/config/adyen_config.yml
MarcGEthyca Apr 2, 2024
d0efcce
Update data/saas/config/adyen_config.yml
MarcGEthyca Apr 2, 2024
3433d24
Merge branch 'main' into fides-Adyen-Erasure-integration
MarcGEthyca Apr 2, 2024
1fd76ef
Merge branch 'main' into fides-Adyen-Erasure-integration
MarcGEthyca Apr 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ The types of changes are:
- Added language switching support to the FidesJS UI based on configured translations [#4737](https://github.com/ethyca/fides/pull/4737)
- Added ability to override some experience language and primary color [#4743](https://github.com/ethyca/fides/pull/4743)
- Generate FidesJS SDK Reference Docs from tsdoc comments [#4736](https://github.com/ethyca/fides/pull/4736)
- Added erasure support for Adyen [#4735](https://github.com/ethyca/fides/pull/4735)

### Changed

Expand Down
76 changes: 76 additions & 0 deletions data/saas/config/adyen_config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
saas_config:
fides_key: <instance_fides_key>
name: Adyen
type: adyen
description: A sample schema representing the Adyen integrations for Fides
user_guide: https://docs.ethyca.com/user-guides/integrations/saas-integrations/adyen
version: 0.1.0

connector_params:
- name: domain_management
label: Management domain
description: Please note that Adyen has both TEST and LIVE environments. E.g. management-test.adyen.com or management-live.adyen.com, and that API keys for live and test will not be the same.
- name: domain_ca
label: CA domain
description: Please note that Adyen has both TEST and LIVE environments. E.g. ca-test.adyen.com or ca-live.adyen.com, and that API keys for live and test will not be the same.
- name: merchant_account
label: Merchant account
MarcGEthyca marked this conversation as resolved.
Show resolved Hide resolved
description: Your merchant account.
- name: api_key
label: API key
description: See Adyen's documentation for me details about creating API keys, and how to assign roles for the key here (https://docs.adyen.com/development-resources/api-credentials/).
sensitive: True

external_references:
- name: adyen_user_id
label: PSP reference
description: The dataset reference to the PSP reference of the original payment authorization which maps to the desired user.

client_config:
protocol: https
host: <domain_management>
authentication:
strategy: api_key
configuration:
headers:
- name: x-API-key
value: <api_key>
test_request:
method: GET
path: /v3/me

endpoints:
- name: user
requests:
read:
request_override: adyen_user_read
param_values:
- name: user_id
references:
- adyen_user_id
delete:
method: POST
path: /ca/services/DataProtectionService/v1/requestSubjectErasure
client_config:
protocol: https
host: <domain_ca>
authentication:
strategy: api_key
configuration:
headers:
- name: x-API-key
value: <api_key>
body: |
{
"merchantAccount": "<merchant_account>",
"pspReference": "<psp_reference>",
"forceErasure": "True"
}
param_values:
- name: merchant_account
connector_param: merchant_account
- name: psp_reference
references:
- dataset: <instance_fides_key>
field: user.psp_reference
direction: from
MarcGEthyca marked this conversation as resolved.
Show resolved Hide resolved
12 changes: 12 additions & 0 deletions data/saas/dataset/adyen_dataset.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
dataset:
- fides_key: <instance_fides_key>
name: adyen
description: A sample dataset representing the Adyen integration for Fides
collections:
- name: user
fields:
- name: id
data_categories: [system.operations]
fidesops_meta:
primary_key: True
data_type: string
7 changes: 7 additions & 0 deletions data/saas/icon/adyen.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""Notes for this particular override
For more details consult the Adyen documentation for their Data Protection API
The gist is that like some other vendors we do not get an email directly for this integration. The data protection endpoint in this case has two main requirements, called merchantAccount and pspReference.
"""

from typing import Any, Dict, List

from fides.api.graph.traversal import TraversalNode
from fides.api.models.policy import Policy
from fides.api.models.privacy_request import PrivacyRequest
from fides.api.service.connectors.saas.authenticated_client import AuthenticatedClient
from fides.api.service.saas_request.saas_request_override_factory import (
SaaSRequestType,
register,
)
from fides.api.util.collection_util import Row


@register("adyen_user_read", [SaaSRequestType.READ])
def adyen_user_read(
client: AuthenticatedClient,
node: TraversalNode,
policy: Policy,
privacy_request: PrivacyRequest,
input_data: Dict[str, List[Any]],
secrets: Dict[str, Any],
) -> List[Row]:
adyen_user_ids = input_data.get("user_id", [])
results = []

Check warning on line 29 in src/fides/api/service/saas_request/override_implementations/adyen_request_overrides.py

View check run for this annotation

Codecov / codecov/patch

src/fides/api/service/saas_request/override_implementations/adyen_request_overrides.py#L28-L29

Added lines #L28 - L29 were not covered by tests
for adyen_user_id in adyen_user_ids:
results.append({"psp_reference": adyen_user_id})
MarcGEthyca marked this conversation as resolved.
Show resolved Hide resolved
return results

Check warning on line 32 in src/fides/api/service/saas_request/override_implementations/adyen_request_overrides.py

View check run for this annotation

Codecov / codecov/patch

src/fides/api/service/saas_request/override_implementations/adyen_request_overrides.py#L31-L32

Added lines #L31 - L32 were not covered by tests
71 changes: 71 additions & 0 deletions tests/fixtures/saas/adyen_fixtures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"""Notes on the particulars for this Adyen integration
In this case, we aren't passing an identity email as Adyen's data protection endpoint requires a different value, the pspReference value which will be provided to us by our customer.
The pspReference value itself will be provided by the customer
For reference this is the name of the value in the Adyen API data erasure endpoint
While we have hardcoded a value in this instance, it should be fairly straight-forward to make that a random value.
Naming considerations
adyen_external_references() & adyen_erasure_external_references()
both will need to use naming consistent with that in the config.yml
"""
from typing import Any, Dict, Generator

import pydash
import pytest

from tests.ops.integration_tests.saas.connector_runner import (
ConnectorRunner,
generate_random_email,
)
from tests.ops.test_helpers.vault_client import get_secrets

secrets = get_secrets("adyen")


@pytest.fixture(scope="session")
def adyen_secrets(saas_config) -> Dict[str, Any]:
return {
"domain_management": pydash.get(saas_config, "adyen.domain_management")
or secrets["domain_management"],
"domain_ca": pydash.get(saas_config, "adyen.domain_ca") or secrets["domain_ca"],
"api_key": pydash.get(saas_config, "adyen.api_key") or secrets["adyen.api_key"],
"merchant_account": pydash.get(saas_config, "adyen.merchant_account")
or secrets["adyen.merchant_account"],
MarcGEthyca marked this conversation as resolved.
Show resolved Hide resolved
"psp_reference": pydash.get(saas_config, "adyen.psp_reference")
or secrets["adyen.pspReference"],
"adyen_user_id": pydash.get(saas_config, "adyen.user_id")
or secrets["adyen.user_id"],
# add the rest of your secrets here
}


@pytest.fixture
def adyen_erasure_identity_email() -> str:
return generate_random_email()


@pytest.fixture
def adyen_external_references() -> Dict[str, Any]:
return {"adyen_user_id": "852617375522786K"}
MarcGEthyca marked this conversation as resolved.
Show resolved Hide resolved


@pytest.fixture
def adyen_erasure_external_references() -> Dict[str, Any]:
return {"adyen_user_id": "852617375522786K"}


@pytest.fixture
def adyen_runner(
db,
cache,
adyen_secrets,
adyen_external_references,
adyen_erasure_external_references,
) -> ConnectorRunner:
return ConnectorRunner(
db,
cache,
"adyen",
adyen_secrets,
external_references=adyen_external_references,
erasure_external_references=adyen_erasure_external_references,
)
34 changes: 20 additions & 14 deletions tests/ops/integration_tests/saas/connector_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
ProvidedIdentity,
)
from fides.api.models.sql_models import Dataset as CtlDataset
from fides.api.schemas.policy import ActionType
from fides.api.schemas.redis_cache import Identity
from fides.api.schemas.saas.saas_config import SaaSConfig
from fides.api.service.connectors import get_connector
from fides.api.service.privacy_request.request_runner_service import (
build_consent_dataset_graph,
Expand Down Expand Up @@ -291,20 +293,24 @@ async def _base_erasure_request(
_process_external_references(self.db, graph_list, connection_config_list)
dataset_graph = DatasetGraph(*graph_list)

access_results = await graph_task.run_access_request(
privacy_request,
access_policy,
dataset_graph,
connection_config_list,
identities,
self.db,
)
if (
ActionType.access
in SaaSConfig(**self.connection_config.saas_config).supported_actions
):
access_results = await graph_task.run_access_request(
privacy_request,
access_policy,
dataset_graph,
connection_config_list,
identities,
self.db,
)

# verify we returned at least one row for each collection in the dataset
for collection in self.dataset["collections"]:
assert len(
access_results[f"{fides_key}:{collection['name']}"]
), f"No rows returned for collection '{collection['name']}'"
# verify we returned at least one row for each collection in the dataset
for collection in self.dataset["collections"]:
assert len(
access_results[f"{fides_key}:{collection['name']}"]
), f"No rows returned for collection '{collection['name']}'"

erasure_results = await graph_task.run_erasure(
privacy_request,
Expand All @@ -316,7 +322,7 @@ async def _base_erasure_request(
self.db,
)

return access_results, erasure_results
return access_results or {}, erasure_results


def _config(connector_type: str) -> Dict[str, Any]:
Expand Down
30 changes: 30 additions & 0 deletions tests/ops/integration_tests/saas/test_adyen_task.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import pytest

from fides.api.models.policy import Policy
from tests.ops.integration_tests.saas.connector_runner import ConnectorRunner


@pytest.mark.integration_saas
class TestAdyenConnector:
def test_connection(self, adyen_runner: ConnectorRunner):
adyen_runner.test_connection()

async def test_non_strict_erasure_request(
self,
adyen_runner: ConnectorRunner,
policy: Policy,
erasure_policy_string_rewrite: Policy,
adyen_erasure_identity_email: str,
):
(
_,
erasure_results,
) = await adyen_runner.non_strict_erasure_request(
access_policy=policy,
erasure_policy=erasure_policy_string_rewrite,
identities={"email": adyen_erasure_identity_email},
)
assert erasure_results == {
"adyen_external_dataset:adyen_external_collection": 0,
"adyen_instance:user": 1,
}
Loading