Skip to content
Closed
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
2 changes: 2 additions & 0 deletions airbyte_cdk/models/airbyte_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ class OauthConnectorInputSpecification:
scope: Optional[str] = None
scopes: Optional[List[Dict[str, Any]]] = None
optional_scopes: Optional[List[Dict[str, Any]]] = None
# Stored as str (not ScopesJoinStrategy enum) because spec.py converts the enum
# to its .value before serialization. The protocol layer only sees plain strings.
scopes_join_strategy: Optional[str] = None
access_token_headers: Optional[Dict[str, Any]] = None
access_token_params: Optional[Dict[str, Any]] = None
Expand Down
44 changes: 44 additions & 0 deletions unit_tests/sources/declarative/spec/test_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# Copyright (c) 2025 Airbyte, Inc., all rights reserved.
#

import dataclasses

import pytest

from airbyte_cdk.models import (
Expand Down Expand Up @@ -271,3 +273,45 @@ def test_given_invalid_config_value_when_validating_then_exception_is_raised() -

with pytest.raises(Exception):
spec.validate_config(input_config)


@pytest.mark.parametrize(
"upstream_class_name, override_class_name",
[
("OauthConnectorInputSpecification", "OauthConnectorInputSpecification"),
("OAuthConfigSpecification", "OAuthConfigSpecification"),
("AdvancedAuth", "AdvancedAuth"),
("ConnectorSpecification", "ConnectorSpecification"),
],
ids=[
"OauthConnectorInputSpecification",
"OAuthConfigSpecification",
"AdvancedAuth",
"ConnectorSpecification",
],
)
def test_protocol_override_fields_in_sync(
upstream_class_name: str, override_class_name: str
) -> None:
"""Ensure protocol override dataclasses stay compatible with their upstream counterparts.

The airbyte_protocol.py file redeclares several dataclasses to add fields that the
upstream airbyte_protocol_dataclasses package does not yet include (e.g. scopes,
optional_scopes, scopes_join_strategy). If the upstream package adds new fields, this
test will fail to remind us to update the local overrides.
"""
import airbyte_protocol_dataclasses.models as upstream_models

import airbyte_cdk.models.airbyte_protocol as override_models

upstream_cls = getattr(upstream_models, upstream_class_name)
override_cls = getattr(override_models, override_class_name)

upstream_fields = {f.name for f in dataclasses.fields(upstream_cls)}
override_fields = {f.name for f in dataclasses.fields(override_cls)}

missing = upstream_fields - override_fields
assert not missing, (
f"Upstream protocol added fields {missing} to {upstream_class_name} "
f"that are missing from the airbyte_protocol.py override. Update the override to match."
)
Loading