Skip to content
This repository has been archived by the owner on Nov 30, 2022. It is now read-only.

Commit

Permalink
GET Available Connectors [#706] (#768)
Browse files Browse the repository at this point in the history
* Adds Saas type to saas yaml config

* alter postman collection

* updates changelog

* lint fixes

* Add endpoint to surface all available connectors including database options and saas options.

* Exclude custom and manual types from list of available connectors.

- Add docs and postman collection.

* Update changelog.

* Remove committed ANALYTICS_ID.

* Import ClientDetail from fideslib instead of fidesops.

* Fix import order.

Co-authored-by: eastandwestwind <eastandwestwind@gmail.com>
  • Loading branch information
pattisdr and eastandwestwind committed Jul 6, 2022
1 parent f493e55 commit 509c641
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 2 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ The types of changes are:
* Add support for multiple statuses to be selected for filtering subject requests [#660](https://github.com/ethyca/fidesops/pull/802)
* Erasure support for Zendesk [#775](https://github.com/ethyca/fidesops/pull/775)
* Adds SaaS connection type to SaaS yaml config [748](https://github.com/ethyca/fidesops/pull/748)
* Adds endpoint to get available connectors (database and saas) [#768](https://github.com/ethyca/fidesops/pull/768)

### Fixed
* Resolve issue with MyPy seeing files in fidesops as missing imports [#719](https://github.com/ethyca/fidesops/pull/719)
Expand Down Expand Up @@ -56,7 +57,6 @@ The types of changes are:
* Fix no such container error with docker-compose [#758](https://github.com/ethyca/fidesops/pull/758)
* Fixed issue with extending the configuration [#721](https://github.com/ethyca/fidesops/pull/721)


## [1.6.0](https://github.com/ethyca/fidesops/compare/1.5.3...1.6.0)

### Added
Expand Down
33 changes: 33 additions & 0 deletions docs/fidesops/docs/guides/connection_types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Connection Types


## Available Connection Types

To view a list of all available connection types, visit `/api/v1/connection_type`.
This endpoint can be filtered with a `search` query param and is subject to change. We include
database options and third party API services with which Fidesops can communicate.

```json title="<code>GET /api/v1/connection_type</code>"
{
"items": [
"bigquery",
"hubspot",
"mailchimp",
"mariadb",
"mongodb",
"mssql",
"mysql",
"outreach",
"postgres",
"redshift",
"segment",
"sentry",
"snowflake",
"stripe",
"zendesk"
],
"total": 15,
"page": 1,
"size": 50
}
```
34 changes: 33 additions & 1 deletion docs/fidesops/docs/postman/Fidesops.postman_collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
"header": [],
"body": {
"mode": "raw",
"raw": "[\n \"client:create\",\n \"client:update\",\n \"client:read\",\n \"client:delete\",\n \"config:read\",\n \"connection:read\",\n \"connection:create_or_update\",\n \"connection:delete\",\n \"dataset:create_or_update\",\n \"dataset:delete\",\n \"dataset:read\",\n \"encryption:exec\",\n \"policy:create_or_update\",\n \"policy:read\",\n \"policy:delete\",\n \"privacy-request:read\",\n \"privacy-request:delete\",\n \"rule:create_or_update\",\n \"rule:read\",\n \"rule:delete\",\n \"scope:read\",\n \"storage:create_or_update\",\n \"storage:delete\",\n \"storage:read\",\n \"privacy-request:resume\",\n \"webhook:create_or_update\",\n \"webhook:read\",\n \"webhook:delete\",\n \"saas_config:create_or_update\",\n \"saas_config:read\",\n \"saas_config:delete\",\n \"privacy-request:review\",\n \"user:create\",\n \"user:delete\"\n]",
"raw": "[\n \"client:create\",\n \"client:update\",\n \"client:read\",\n \"client:delete\",\n \"config:read\",\n \"connection_type:read\",\n \"connection:read\",\n \"connection:create_or_update\",\n \"connection:delete\",\n \"dataset:create_or_update\",\n \"dataset:delete\",\n \"dataset:read\",\n \"encryption:exec\",\n \"policy:create_or_update\",\n \"policy:read\",\n \"policy:delete\",\n \"privacy-request:read\",\n \"privacy-request:delete\",\n \"rule:create_or_update\",\n \"rule:read\",\n \"rule:delete\",\n \"scope:read\",\n \"storage:create_or_update\",\n \"storage:delete\",\n \"storage:read\",\n \"privacy-request:resume\",\n \"webhook:create_or_update\",\n \"webhook:read\",\n \"webhook:delete\",\n \"saas_config:create_or_update\",\n \"saas_config:read\",\n \"saas_config:delete\",\n \"privacy-request:review\",\n \"user:create\",\n \"user:delete\"\n]",
"options": {
"raw": {
"language": "json"
Expand Down Expand Up @@ -3841,6 +3841,38 @@
"response": []
}
]
},
{
"name": "ConnectionType",
"item": [
{
"name": "Get available connectors",
"request": {
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "{{client_token}}",
"type": "string"
}
]
},
"method": "GET",
"header": [],
"url": {
"raw": "{{host}}/connection_type",
"host": [
"{{host}}"
],
"path": [
"connection_type"
]
}
},
"response": []
}
]
}
],
"event": [
Expand Down
2 changes: 2 additions & 0 deletions src/fidesops/api/v1/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from fidesops.api.v1.endpoints import (
config_endpoints,
connection_endpoints,
connection_type_endpoints,
dataset_endpoints,
drp_endpoints,
encryption_endpoints,
Expand All @@ -20,6 +21,7 @@

api_router = APIRouter()
api_router.include_router(config_endpoints.router)
api_router.include_router(connection_type_endpoints.router)
api_router.include_router(connection_endpoints.router)
api_router.include_router(dataset_endpoints.router)
api_router.include_router(drp_endpoints.router)
Expand Down
48 changes: 48 additions & 0 deletions src/fidesops/api/v1/endpoints/connection_type_endpoints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import logging
from typing import List, Optional

from fastapi import APIRouter, Depends
from fastapi.params import Security
from fastapi_pagination import Page, Params, paginate
from fastapi_pagination.bases import AbstractPage

from fidesops.api.v1.scope_registry import CONNECTION_TYPE_READ
from fidesops.api.v1.urn_registry import CONNECTION_TYPES, V1_URL_PREFIX
from fidesops.models.connectionconfig import ConnectionType
from fidesops.schemas.saas.saas_config import SaaSType
from fidesops.util.oauth_util import verify_oauth_client

router = APIRouter(tags=["Connection Types"], prefix=V1_URL_PREFIX)

logger = logging.getLogger(__name__)


@router.get(
CONNECTION_TYPES,
dependencies=[Security(verify_oauth_client, scopes=[CONNECTION_TYPE_READ])],
response_model=Page[str],
)
def get_all_connection_types(
*, params: Params = Depends(), search: Optional[str] = None
) -> AbstractPage[str]:
"""Returns a list of connection options in Fidesops - includes only database and saas options here."""

def is_match(elem: str) -> bool:
"""If a search query param was included, is it a substring of an available connector type?"""
return search in elem if search else True

database_types: List[str] = [
conn_type.value
for conn_type in ConnectionType
if conn_type
not in [ConnectionType.saas, ConnectionType.https, ConnectionType.manual]
and is_match(conn_type.value)
]
saas_types: List[str] = [
saas_type.value
for saas_type in SaaSType
if saas_type != SaaSType.custom and is_match(saas_type.value)
]
connection_types: List[str] = sorted(database_types + saas_types)

return paginate(connection_types, params)
3 changes: 3 additions & 0 deletions src/fidesops/api/v1/scope_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
POLICY_READ = "policy:read"
POLICY_DELETE = "policy:delete"

CONNECTION_TYPE_READ = "connection_type:read"

CONNECTION_CREATE_OR_UPDATE = "connection:create_or_update"
CONNECTION_READ = "connection:read"
CONNECTION_DELETE = "connection:delete"
Expand Down Expand Up @@ -65,6 +67,7 @@
CONNECTION_CREATE_OR_UPDATE,
CONNECTION_DELETE,
CONNECTION_AUTHORIZE,
CONNECTION_TYPE_READ,
DATASET_CREATE_OR_UPDATE,
DATASET_DELETE,
DATASET_READ,
Expand Down
3 changes: 3 additions & 0 deletions src/fidesops/api/v1/urn_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
"/policy/{policy_key}/webhook/post_execution/{post_webhook_key}"
)

# Connection Type URLs
CONNECTION_TYPES = "/connection_type"


# Connection Configurations URLs
CONNECTIONS = "/connection"
Expand Down
59 changes: 59 additions & 0 deletions tests/api/v1/endpoints/test_connection_template_endpoints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import pytest
from fastapi_pagination import Params
from fideslib.models.client import ClientDetail
from starlette.testclient import TestClient

from fidesops.api.v1.scope_registry import CONNECTION_READ, CONNECTION_TYPE_READ
from fidesops.api.v1.urn_registry import CONNECTION_TYPES, V1_URL_PREFIX


class TestGetConnections:
@pytest.fixture(scope="function")
def url(self, oauth_client: ClientDetail, policy) -> str:
return V1_URL_PREFIX + CONNECTION_TYPES

def test_get_connection_types_not_authenticated(self, api_client, url):
resp = api_client.get(url, headers={})
assert resp.status_code == 401

def test_get_connection_types_forbidden(
self, api_client, url, generate_auth_header
):
auth_header = generate_auth_header(scopes=[CONNECTION_READ])
resp = api_client.get(url, headers=auth_header)
assert resp.status_code == 403

def test_get_connection_types(
self, api_client: TestClient, generate_auth_header, url
) -> None:
auth_header = generate_auth_header(scopes=[CONNECTION_TYPE_READ])
resp = api_client.get(url, headers=auth_header)
data = resp.json()
assert resp.status_code == 200
assert "items" in data
assert "total" in data
assert "page" in data
assert data["size"] == Params().size

assert "postgres" in data["items"]
assert "stripe" in data["items"]

assert "saas" not in data["items"]
assert "https" not in data["items"]
assert "custom" not in data["items"]
assert "manual" not in data["items"]

def test_search_connection_types(self, api_client, generate_auth_header, url):
auth_header = generate_auth_header(scopes=[CONNECTION_TYPE_READ])

resp = api_client.get(url + "?search=str", headers=auth_header)
assert resp.status_code == 200
data = resp.json()
assert data["total"] == 1
assert data["items"][0] == "stripe"

resp = api_client.get(url + "?search=re", headers=auth_header)
assert resp.status_code == 200
data = resp.json()
assert data["total"] == 3
assert data["items"] == ["outreach", "postgres", "redshift"]

0 comments on commit 509c641

Please sign in to comment.