Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
27 changes: 0 additions & 27 deletions airbyte-integrations/connectors/source-salesloft/components.py

This file was deleted.

14 changes: 12 additions & 2 deletions airbyte-integrations/connectors/source-salesloft/manifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1607,14 +1607,24 @@ definitions:
- auth_type
authenticators:
oauth2.0:
type: CustomAuthenticator
class_name: source_declarative_manifest.components.SingleUseOauth2Authenticator
type: OAuthAuthenticator
client_id: "{{ config['credentials']['client_id'] }}"
client_secret: "{{ config['credentials']['client_secret'] }}"
refresh_token: "{{ config['credentials']['refresh_token'] }}"
refresh_request_body: {}
token_refresh_endpoint: https://accounts.salesloft.com/oauth/token
grant_type: refresh_token
refresh_token_updater:
refresh_token_name: refresh_token
access_token_config_path:
- credentials
- access_token
refresh_token_config_path:
- credentials
- refresh_token
token_expiry_date_config_path:
- credentials
- token_expiry_date
api_key:
type: BearerAuthenticator
api_token: "{{ config['credentials']['api_key'] }}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ data:
connectorSubtype: api
connectorType: source
definitionId: 41991d12-d4b5-439e-afd0-260a31d4c53f
dockerImageTag: 1.5.2
dockerImageTag: 1.5.3
dockerRepository: airbyte/source-salesloft
githubIssueLabel: source-salesloft
icon: icon.svg
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copyright (c) 2026 Airbyte, Inc., all rights reserved.

from pathlib import Path

from airbyte_cdk.sources.declarative.yaml_declarative_source import YamlDeclarativeSource
from airbyte_cdk.test.catalog_builder import CatalogBuilder
from airbyte_cdk.test.state_builder import StateBuilder


def _get_manifest_path() -> Path:
ci_path = Path("/airbyte/integration_code/source_declarative_manifest")
if ci_path.exists():
return ci_path
return Path(__file__).parent.parent


_MANIFEST_PATH = _get_manifest_path() / "manifest.yaml"


def get_source(config, state=None) -> YamlDeclarativeSource:
catalog = CatalogBuilder().build()
state = state if state is not None else StateBuilder().build()
return YamlDeclarativeSource(
path_to_yaml=str(_MANIFEST_PATH),
catalog=catalog,
config=config,
state=state,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright (c) 2026 Airbyte, Inc., all rights reserved.

import os
import sys
from pathlib import Path


pytest_plugins = ["airbyte_cdk.test.utils.manifest_only_fixtures"]

os.environ.setdefault("REQUEST_CACHE_PATH", "REQUEST_CACHE_PATH")

_UNIT_TESTS_DIR = Path(__file__).parent
if str(_UNIT_TESTS_DIR) not in sys.path:
sys.path.insert(0, str(_UNIT_TESTS_DIR))
2,910 changes: 2,910 additions & 0 deletions airbyte-integrations/connectors/source-salesloft/unit_tests/poetry.lock

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "source-salesloft-tests"
version = "0.0.1"
description = "Unit tests for source-salesloft"
authors = ["Airbyte <contact@airbyte.io>"]

[tool.poetry.dependencies]
python = "^3.10,<3.13"
airbyte-cdk = "^7"
pytest = "^8"
requests-mock = "^1"

[tool.pytest.ini_options]
filterwarnings = [
"ignore:This class is experimental*",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Copyright (c) 2026 Airbyte, Inc., all rights reserved.

from urllib.parse import parse_qs

import requests_mock
from _helpers import get_source


def _oauth_config() -> dict:
return {
"start_date": "2024-01-01T00:00:00Z",
"credentials": {
"auth_type": "oauth2.0",
"client_id": "configured-client-id",
"client_secret": "configured-client-secret",
"refresh_token": "configured-refresh-token",
"access_token": "expired-access-token",
"token_expiry_date": "2000-01-01T00:00:00Z",
},
}


def _authenticator(config: dict):
source = get_source(config)
stream = source.streams(config)[0]
retriever = stream._stream_partition_generator._partition_factory._retriever
return retriever.requester.authenticator


def test_oauth_refresh_succeeds_with_form_body_and_updates_config():
config = _oauth_config()
authenticator = _authenticator(config)

with requests_mock.Mocker() as mocker:
mocker.post(
"https://accounts.salesloft.com/oauth/token",
json={
"access_token": "refreshed-access-token",
"refresh_token": "refreshed-refresh-token",
"expires_in": 3600,
},
)

assert authenticator.get_access_token() == "refreshed-access-token"

request = mocker.last_request
assert request is not None
assert request.url == "https://accounts.salesloft.com/oauth/token"
assert parse_qs(request.text) == {
"client_id": ["configured-client-id"],
"client_secret": ["configured-client-secret"],
"refresh_token": ["configured-refresh-token"],
"grant_type": ["refresh_token"],
}

assert config["credentials"]["access_token"] == "refreshed-access-token"
assert config["credentials"]["refresh_token"] == "refreshed-refresh-token"
assert config["credentials"]["token_expiry_date"] != "2000-01-01T00:00:00Z"


def test_api_key_authenticator_uses_configured_token():
config = {
"start_date": "2024-01-01T00:00:00Z",
"credentials": {"auth_type": "api_key", "api_key": "configured-api-key"},
}

authenticator = _authenticator(config)

assert authenticator.token == "Bearer configured-api-key"
1 change: 1 addition & 0 deletions docs/integrations/sources/salesloft.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ If you use Airbyte Cloud and your organization restricts access to specific IPs,

| Version | Date | Pull Request | Subject |
| :------ | :--------- | :------------------------------------------------------- | :------------------------------------------------------------- |
| 1.5.3 | 2026-08-12 | [84300](https://github.com/airbytehq/airbyte/pull/84300) | Fix OAuth token refresh by replacing the custom authenticator with the CDK's native OAuth authenticator |
| 1.5.2 | 2025-03-24 | [56365](https://github.com/airbytehq/airbyte/pull/56365) | Correct data types for email_scoped_fields |
| 1.5.1 | 2025-03-16 | [55779](https://github.com/airbytehq/airbyte/pull/55779) | Adding missing columns too emails_scoped_fields stream |
| 1.5.0 | 2025-03-06 | [55229](https://github.com/airbytehq/airbyte/pull/55229) | Add emails_scoped_fields stream. Remove body and subject fields from email stream |
Expand Down
Loading