diff --git a/CHANGELOG.md b/CHANGELOG.md index 08b539597c0..c161a48f7d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ The types of changes are: ### Added - Additional consent reporting calls from `fides-js` [#3845](https://github.com/ethyca/fides/pull/3845) - Additional consent reporting calls from privacy center [#3847](https://github.com/ethyca/fides/pull/3847) +- Access support for Recurly [#3595](https://github.com/ethyca/fides/pull/3595) ### Fixed - Fix datamap zoom for low system counts [#3835](https://github.com/ethyca/fides/pull/3835) diff --git a/data/saas/config/recurly_config.yml b/data/saas/config/recurly_config.yml new file mode 100644 index 00000000000..443084cbccb --- /dev/null +++ b/data/saas/config/recurly_config.yml @@ -0,0 +1,77 @@ +saas_config: + fides_key: + name: Recurly + type: recurly + description: A sample schema representing the Recurly connector for Fides + version: 0.1.0 + + connector_params: + - name: domain + default_value: v3.recurly.com + - name: username + + client_config: + protocol: https + host: + authentication: + strategy: basic + configuration: + username: + + test_request: + method: GET + path: /accounts + headers: + - name: Accept + value: application/vnd.recurly.v2021-02-25 + + endpoints: + - name: accounts + requests: + read: + method: GET + path: /accounts + headers: + - name: Accept + value: application/vnd.recurly.v2021-02-25 + query_params: + - name: email + value: + data_path: data + param_values: + - name: email + identity: email + - name: billing_info + requests: + read: + method: GET + path: /accounts//billing_info + headers: + - name: Accept + value: application/vnd.recurly.v2021-02-25 + param_values: + - name: accounts_id + references: + - dataset: + field: accounts.id + direction: from + - name: shipping_address + requests: + read: + method: GET + path: /accounts//shipping_addresses + headers: + - name: Accept + value: application/vnd.recurly.v2021-02-25 + data_path: data + param_values: + - name: accounts_id + references: + - dataset: + field: accounts.id + direction: from + pagination: + strategy: link + configuration: + source: body + path: next diff --git a/data/saas/dataset/recurly_dataset.yml b/data/saas/dataset/recurly_dataset.yml new file mode 100644 index 00000000000..8162eec560a --- /dev/null +++ b/data/saas/dataset/recurly_dataset.yml @@ -0,0 +1,518 @@ +dataset: + - fides_key: + name: Recurly Dataset + description: A sample dataset representing the Recurly connector for Fides + collections: + - name: accounts + fields: + - name: address + fidesops_meta: + data_type: object + fields: + - name: street1 + data_categories: [user.contact.address.street] + fidesops_meta: + data_type: string + - name: street2 + data_categories: [user.contact.address.street] + fidesops_meta: + data_type: string + - name: city + data_categories: [user.contact.address.city] + fidesops_meta: + data_type: string + - name: region + data_categories: [user.contact.address.state] + fidesops_meta: + data_type: string + - name: postal_code + data_categories: [user.contact.address.postal_code] + fidesops_meta: + data_type: string + - name: country + data_categories: [user.contact.address.country] + fidesops_meta: + data_type: string + - name: phone + data_categories: [user.contact.phone_number] + fidesops_meta: + data_type: string + - name: bill_to + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: billing_info + fidesops_meta: + data_type: object + fields: + - name: id + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: object + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: account_id + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: primary_payment_method + data_categories: [system.operations] + fidesops_meta: + data_type: boolean + - name: backup_payment_method + data_categories: [system.operations] + fidesops_meta: + data_type: boolean + - name: first_name + data_categories: [user.name] + fidesops_meta: + data_type: string + - name: last_name + data_categories: [user.name] + fidesops_meta: + data_type: string + - name: company + - name: address + fidesops_meta: + data_type: object + fields: + - name: street1 + data_categories: [user.contact.address.street] + fidesops_meta: + data_type: string + - name: street2 + data_categories: [user.contact.address.street] + fidesops_meta: + data_type: string + - name: city + data_categories: [user.contact.address.city] + fidesops_meta: + data_type: string + - name: region + data_categories: [user.contact.address.state] + fidesops_meta: + data_type: string + - name: postal_code + data_categories: [user.contact.address.postal_code] + fidesops_meta: + data_type: string + - name: country + data_categories: [user.contact.address.country] + fidesops_meta: + data_type: string + - name: phone + data_categories: [user.contact.phone_number] + fidesops_meta: + data_type: string + - name: vat_number + - name: valid + data_categories: [system.operations] + fidesops_meta: + data_type: boolean + - name: payment_method + fidesops_meta: + data_type: object + fields: + - name: object + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: card_type + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: first_six + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: last_four + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: cc_bin_country + - name: exp_month + data_categories: [system.operations] + fidesops_meta: + data_type: integer + - name: exp_year + data_categories: [system.operations] + fidesops_meta: + data_type: integer + - name: fraud + - name: created_at + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: updated_at + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: updated_by + fidesops_meta: + data_type: object + fields: + - name: ip + - name: country + - name: cc_emails + data_categories: [user.contact.email] + fidesops_meta: + data_type: string + - name: code + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: company + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: created_at + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: custom_fields + - name: deleted_at + - name: dunning_campaign_id + - name: email + data_categories: [user.contact.email] + fidesops_meta: + data_type: string + - name: exemption_certificate + - name: external_accounts + - name: first_name + data_categories: [user.name] + fidesops_meta: + data_type: string + - name: has_active_subscription + data_categories: [system.operations] + fidesops_meta: + data_type: boolean + - name: has_canceled_subscription + data_categories: [system.operations] + fidesops_meta: + data_type: boolean + - name: has_future_subscription + data_categories: [system.operations] + fidesops_meta: + data_type: boolean + - name: has_live_subscription + data_categories: [system.operations] + fidesops_meta: + data_type: boolean + - name: has_past_due_invoice + data_categories: [system.operations] + fidesops_meta: + data_type: boolean + - name: has_paused_subscription + data_categories: [system.operations] + fidesops_meta: + data_type: boolean + - name: id + data_categories: [user.unique_id] + fidesops_meta: + data_type: string + primary_key: True + - name: last_name + data_categories: [user.name] + fidesops_meta: + data_type: string + - name: object + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: parent_account_id + - name: preferred_locale + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: preferred_time_zone + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: shipping_addresses + fidesops_meta: + data_type: "object[]" + fields: + - name: object + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: first_name + data_categories: [user.name] + fidesops_meta: + data_type: string + - name: last_name + data_categories: [user.name] + fidesops_meta: + data_type: string + - name: company + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: phone + data_categories: [user.contact.phone_number] + fidesops_meta: + data_type: string + - name: street1 + data_categories: [user.contact.address.street] + fidesops_meta: + data_type: string + - name: street2 + data_categories: [user.contact.address.street] + fidesops_meta: + data_type: string + - name: city + data_categories: [user.contact.address.city] + fidesops_meta: + data_type: string + - name: region + data_categories: [user.contact.address.state] + fidesops_meta: + data_type: string + - name: postal_code + data_categories: [user.contact.address.postal_code] + fidesops_meta: + data_type: string + - name: country + data_categories: [user.contact.address.country] + fidesops_meta: + data_type: string + - name: nickname + data_categories: [user.name] + fidesops_meta: + data_type: string + - name: email + data_categories: [user.contact.email] + fidesops_meta: + data_type: string + - name: vat_number + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: id + data_categories: [user.unique_id] + fidesops_meta: + data_type: string + - name: account_id + data_categories: [user.unique_id] + fidesops_meta: + data_type: string + - name: created_at + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: updated_at + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: state + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: tax_exempt + data_categories: [system.operations] + fidesops_meta: + data_type: boolean + - name: updated_at + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: username + data_categories: [user.name] + fidesops_meta: + data_type: string + - name: vat_number + - name: invoice_template_id + - name: override_business_entity_id + - name: billing_info + fields: + - name: id + data_categories: [user.unique_id] + fidesops_meta: + data_type: string + primary_key: True + - name: object + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: account_id + data_categories: [user.unique_id] + fidesops_meta: + data_type: string + - name: primary_payment_method + data_categories: [system.operations] + fidesops_meta: + data_type: boolean + - name: backup_payment_method + data_categories: [system.operations] + fidesops_meta: + data_type: boolean + - name: first_name + data_categories: [user.name] + fidesops_meta: + data_type: string + - name: last_name + data_categories: [user.name] + fidesops_meta: + data_type: string + - name: company + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: address + fidesops_meta: + data_type: object + fields: + - name: street1 + data_categories: [user.contact.address.street] + fidesops_meta: + data_type: string + - name: street2 + data_categories: [user.contact.address.street] + fidesops_meta: + data_type: string + - name: city + data_categories: [user.contact.address.city] + fidesops_meta: + data_type: string + - name: region + data_categories: [user.contact.address.state] + fidesops_meta: + data_type: string + - name: postal_code + data_categories: [user.contact.address.postal_code] + fidesops_meta: + data_type: string + - name: country + data_categories: [user.contact.address.country] + fidesops_meta: + data_type: string + - name: phone + data_categories: [user.contact.phone_number] + fidesops_meta: + data_type: string + - name: vat_number + - name: valid + data_categories: [system.operations] + fidesops_meta: + data_type: boolean + - name: payment_method + fidesops_meta: + data_type: object + fields: + - name: object + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: card_type + data_categories: [user.financial] + fidesops_meta: + data_type: string + - name: first_six + data_categories: [user.financial] + fidesops_meta: + data_type: string + - name: last_four + data_categories: [user.financial] + fidesops_meta: + data_type: string + - name: cc_bin_country + - name: exp_month + data_categories: [user.financial] + fidesops_meta: + data_type: integer + - name: exp_year + data_categories: [user.financial] + fidesops_meta: + data_type: integer + - name: fraud + - name: created_at + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: updated_at + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: updated_by + fidesops_meta: + data_type: object + fields: + - name: ip + - name: country + - name: shipping_address + fields: + - name: object + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: first_name + data_categories: [user.name] + fidesops_meta: + data_type: string + - name: last_name + data_categories: [user.name] + fidesops_meta: + data_type: string + - name: company + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: phone + data_categories: [user.contact.phone_number] + fidesops_meta: + data_type: string + - name: street1 + data_categories: [user.contact.address.street] + fidesops_meta: + data_type: string + - name: street2 + data_categories: [user.contact.address.street] + fidesops_meta: + data_type: string + - name: city + data_categories: [user.contact.address.city] + fidesops_meta: + data_type: string + - name: region + data_categories: [user.contact.address.state] + fidesops_meta: + data_type: string + - name: postal_code + data_categories: [user.contact.address.postal_code] + fidesops_meta: + data_type: string + - name: country + data_categories: [user.contact.address.country] + fidesops_meta: + data_type: string + - name: nickname + data_categories: [user.name] + fidesops_meta: + data_type: string + - name: email + data_categories: [user.contact.email] + fidesops_meta: + data_type: string + - name: vat_number + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: id + data_categories: [user.unique_id] + fidesops_meta: + data_type: string + primary_key: True + - name: account_id + data_categories: [user.unique_id] + fidesops_meta: + data_type: string + - name: created_at + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: updated_at + data_categories: [system.operations] + fidesops_meta: + data_type: string diff --git a/data/saas/icon/recurly.svg b/data/saas/icon/recurly.svg new file mode 100644 index 00000000000..a6e805656eb --- /dev/null +++ b/data/saas/icon/recurly.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/tests/fixtures/saas/recurly_fixtures.py b/tests/fixtures/saas/recurly_fixtures.py new file mode 100644 index 00000000000..0c7e60cbe74 --- /dev/null +++ b/tests/fixtures/saas/recurly_fixtures.py @@ -0,0 +1,29 @@ +from typing import Any, Dict + +import pydash +import pytest + +from tests.ops.integration_tests.saas.connector_runner import ConnectorRunner +from tests.ops.test_helpers.vault_client import get_secrets + +secrets = get_secrets("recurly") + + +@pytest.fixture(scope="session") +def recurly_secrets(saas_config) -> Dict[str, Any]: + return { + "domain": pydash.get(saas_config, "recurly.domain") or secrets["domain"], + "username": pydash.get(saas_config, "recurly.username") or secrets["username"], + } + + +@pytest.fixture(scope="session") +def recurly_identity_email(saas_config) -> str: + return ( + pydash.get(saas_config, "recurly.identity_email") or secrets["identity_email"] + ) + + +@pytest.fixture +def recurly_runner(db, cache, recurly_secrets) -> ConnectorRunner: + return ConnectorRunner(db, cache, "recurly", recurly_secrets) diff --git a/tests/ops/integration_tests/saas/test_recurly_task.py b/tests/ops/integration_tests/saas/test_recurly_task.py new file mode 100644 index 00000000000..77106294411 --- /dev/null +++ b/tests/ops/integration_tests/saas/test_recurly_task.py @@ -0,0 +1,26 @@ +import pytest + +from tests.ops.integration_tests.saas.connector_runner import ConnectorRunner + + +@pytest.mark.integration_saas +class TestRecurlyConnector: + def test_connection(self, recurly_runner: ConnectorRunner): + recurly_runner.test_connection() + + async def test_access_request( + self, recurly_runner: ConnectorRunner, policy, recurly_identity_email: str + ): + access_results = await recurly_runner.access_request( + access_policy=policy, identities={"email": recurly_identity_email} + ) + + assert len(access_results["recurly_instance:accounts"]) == 1 + account = access_results["recurly_instance:accounts"][0] + assert account["email"] == recurly_identity_email + + for billing_info in access_results["recurly_instance:billing_info"]: + assert billing_info["account_id"] == account["id"] + + for shipping_address in access_results["recurly_instance:shipping_address"]: + assert shipping_address["account_id"] == account["id"]