airbyte-cdk 7.1.1__py3-none-any.whl → 7.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- airbyte_cdk/cli/airbyte_cdk/_secrets.py +43 -8
- airbyte_cdk/sources/declarative/auth/jwt.py +29 -2
- airbyte_cdk/sources/declarative/declarative_component_schema.yaml +6 -0
- airbyte_cdk/sources/declarative/interpolation/macros.py +12 -0
- airbyte_cdk/sources/declarative/models/declarative_component_schema.py +6 -0
- airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py +1 -0
- {airbyte_cdk-7.1.1.dist-info → airbyte_cdk-7.2.1.dist-info}/METADATA +1 -1
- {airbyte_cdk-7.1.1.dist-info → airbyte_cdk-7.2.1.dist-info}/RECORD +12 -12
- {airbyte_cdk-7.1.1.dist-info → airbyte_cdk-7.2.1.dist-info}/LICENSE.txt +0 -0
- {airbyte_cdk-7.1.1.dist-info → airbyte_cdk-7.2.1.dist-info}/LICENSE_SHORT +0 -0
- {airbyte_cdk-7.1.1.dist-info → airbyte_cdk-7.2.1.dist-info}/WHEEL +0 -0
- {airbyte_cdk-7.1.1.dist-info → airbyte_cdk-7.2.1.dist-info}/entry_points.txt +0 -0
@@ -459,25 +459,60 @@ def _print_ci_secrets_masks(
|
|
459
459
|
_print_ci_secrets_masks_for_config(config=config_dict)
|
460
460
|
|
461
461
|
|
462
|
+
def _print_ci_secret_mask_for_string(secret: str) -> None:
|
463
|
+
"""Print GitHub CI mask for a single secret string.
|
464
|
+
|
465
|
+
We expect single-line secrets, but we also handle the case where the secret contains newlines.
|
466
|
+
For multi-line secrets, we must print a secret mask for each line separately.
|
467
|
+
"""
|
468
|
+
for line in secret.splitlines():
|
469
|
+
if line.strip(): # Skip empty lines
|
470
|
+
print(f"::add-mask::{line!s}")
|
471
|
+
|
472
|
+
|
473
|
+
def _print_ci_secret_mask_for_value(value: Any) -> None:
|
474
|
+
"""Print GitHub CI mask for a single secret value.
|
475
|
+
|
476
|
+
Call this function for any values identified as secrets, regardless of type.
|
477
|
+
"""
|
478
|
+
if isinstance(value, dict):
|
479
|
+
# For nested dicts, we call recursively on each value
|
480
|
+
for v in value.values():
|
481
|
+
_print_ci_secret_mask_for_value(v)
|
482
|
+
|
483
|
+
return
|
484
|
+
|
485
|
+
if isinstance(value, list):
|
486
|
+
# For lists, we call recursively on each list item
|
487
|
+
for list_item in value:
|
488
|
+
_print_ci_secret_mask_for_value(list_item)
|
489
|
+
|
490
|
+
return
|
491
|
+
|
492
|
+
# For any other types besides dict and list, we convert to string and mask each line
|
493
|
+
# separately to handle multi-line secrets (e.g. private keys).
|
494
|
+
for line in str(value).splitlines():
|
495
|
+
if line.strip(): # Skip empty lines
|
496
|
+
_print_ci_secret_mask_for_string(line)
|
497
|
+
|
498
|
+
|
462
499
|
def _print_ci_secrets_masks_for_config(
|
463
500
|
config: dict[str, str] | list[Any] | Any,
|
464
501
|
) -> None:
|
465
502
|
"""Print GitHub CI mask for secrets config, navigating child nodes recursively."""
|
466
503
|
if isinstance(config, list):
|
504
|
+
# Check each item in the list to look for nested dicts that may contain secrets:
|
467
505
|
for item in config:
|
468
506
|
_print_ci_secrets_masks_for_config(item)
|
469
507
|
|
470
|
-
|
508
|
+
elif isinstance(config, dict):
|
471
509
|
for key, value in config.items():
|
472
510
|
if _is_secret_property(key):
|
473
511
|
logger.debug(f"Masking secret for config key: {key}")
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
if isinstance(value, (dict, list)):
|
480
|
-
_print_ci_secrets_masks_for_config(config=value)
|
512
|
+
_print_ci_secret_mask_for_value(value)
|
513
|
+
elif isinstance(value, (dict, list)):
|
514
|
+
# Recursively check nested dicts and lists
|
515
|
+
_print_ci_secrets_masks_for_config(value)
|
481
516
|
|
482
517
|
|
483
518
|
def _is_secret_property(property_name: str) -> bool:
|
@@ -6,15 +6,26 @@ import base64
|
|
6
6
|
import json
|
7
7
|
from dataclasses import InitVar, dataclass
|
8
8
|
from datetime import datetime
|
9
|
-
from typing import Any, Mapping, Optional, Union
|
9
|
+
from typing import Any, Mapping, Optional, Union, cast
|
10
10
|
|
11
11
|
import jwt
|
12
|
+
from cryptography.hazmat.primitives import serialization
|
13
|
+
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateKey
|
14
|
+
from cryptography.hazmat.primitives.asymmetric.ed448 import Ed448PrivateKey
|
15
|
+
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
|
16
|
+
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
|
17
|
+
from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes
|
12
18
|
|
13
19
|
from airbyte_cdk.sources.declarative.auth.declarative_authenticator import DeclarativeAuthenticator
|
14
20
|
from airbyte_cdk.sources.declarative.interpolation.interpolated_boolean import InterpolatedBoolean
|
15
21
|
from airbyte_cdk.sources.declarative.interpolation.interpolated_mapping import InterpolatedMapping
|
16
22
|
from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString
|
17
23
|
|
24
|
+
# Type alias for keys that JWT library accepts
|
25
|
+
JwtKeyTypes = Union[
|
26
|
+
RSAPrivateKey, EllipticCurvePrivateKey, Ed25519PrivateKey, Ed448PrivateKey, str, bytes
|
27
|
+
]
|
28
|
+
|
18
29
|
|
19
30
|
class JwtAlgorithm(str):
|
20
31
|
"""
|
@@ -74,6 +85,7 @@ class JwtAuthenticator(DeclarativeAuthenticator):
|
|
74
85
|
aud: Optional[Union[InterpolatedString, str]] = None
|
75
86
|
additional_jwt_headers: Optional[Mapping[str, Any]] = None
|
76
87
|
additional_jwt_payload: Optional[Mapping[str, Any]] = None
|
88
|
+
passphrase: Optional[Union[InterpolatedString, str]] = None
|
77
89
|
|
78
90
|
def __post_init__(self, parameters: Mapping[str, Any]) -> None:
|
79
91
|
self._secret_key = InterpolatedString.create(self.secret_key, parameters=parameters)
|
@@ -103,6 +115,11 @@ class JwtAuthenticator(DeclarativeAuthenticator):
|
|
103
115
|
self._additional_jwt_payload = InterpolatedMapping(
|
104
116
|
self.additional_jwt_payload or {}, parameters=parameters
|
105
117
|
)
|
118
|
+
self._passphrase = (
|
119
|
+
InterpolatedString.create(self.passphrase, parameters=parameters)
|
120
|
+
if self.passphrase
|
121
|
+
else None
|
122
|
+
)
|
106
123
|
|
107
124
|
def _get_jwt_headers(self) -> dict[str, Any]:
|
108
125
|
"""
|
@@ -149,11 +166,21 @@ class JwtAuthenticator(DeclarativeAuthenticator):
|
|
149
166
|
payload["nbf"] = nbf
|
150
167
|
return payload
|
151
168
|
|
152
|
-
def _get_secret_key(self) ->
|
169
|
+
def _get_secret_key(self) -> JwtKeyTypes:
|
153
170
|
"""
|
154
171
|
Returns the secret key used to sign the JWT.
|
155
172
|
"""
|
156
173
|
secret_key: str = self._secret_key.eval(self.config, json_loads=json.loads)
|
174
|
+
|
175
|
+
if self._passphrase:
|
176
|
+
passphrase_value = self._passphrase.eval(self.config, json_loads=json.loads)
|
177
|
+
if passphrase_value:
|
178
|
+
private_key = serialization.load_pem_private_key(
|
179
|
+
secret_key.encode(),
|
180
|
+
password=passphrase_value.encode(),
|
181
|
+
)
|
182
|
+
return cast(JwtKeyTypes, private_key)
|
183
|
+
|
157
184
|
return (
|
158
185
|
base64.b64encode(secret_key.encode()).decode()
|
159
186
|
if self._base64_encode_secret_key
|
@@ -1270,6 +1270,12 @@ definitions:
|
|
1270
1270
|
title: Additional JWT Payload Properties
|
1271
1271
|
description: Additional properties to be added to the JWT payload.
|
1272
1272
|
additionalProperties: true
|
1273
|
+
passphrase:
|
1274
|
+
title: Passphrase
|
1275
|
+
description: A passphrase/password used to encrypt the private key. Only provide a passphrase if required by the API for JWT authentication. The API will typically provide the passphrase when generating the public/private key pair.
|
1276
|
+
type: string
|
1277
|
+
examples:
|
1278
|
+
- "{{ config['passphrase'] }}"
|
1273
1279
|
$parameters:
|
1274
1280
|
type: object
|
1275
1281
|
additionalProperties: true
|
@@ -6,6 +6,7 @@ import builtins
|
|
6
6
|
import datetime
|
7
7
|
import re
|
8
8
|
import typing
|
9
|
+
import uuid
|
9
10
|
from typing import Optional, Union
|
10
11
|
from urllib.parse import quote_plus
|
11
12
|
|
@@ -207,6 +208,16 @@ def camel_case_to_snake_case(value: str) -> str:
|
|
207
208
|
return re.sub(r"(?<!^)(?=[A-Z])", "_", value).lower()
|
208
209
|
|
209
210
|
|
211
|
+
def generate_uuid() -> str:
|
212
|
+
"""
|
213
|
+
Generates a UUID4
|
214
|
+
|
215
|
+
Usage:
|
216
|
+
`"{{ generate_uuid() }}"`
|
217
|
+
"""
|
218
|
+
return str(uuid.uuid4())
|
219
|
+
|
220
|
+
|
210
221
|
_macros_list = [
|
211
222
|
now_utc,
|
212
223
|
today_utc,
|
@@ -220,5 +231,6 @@ _macros_list = [
|
|
220
231
|
str_to_datetime,
|
221
232
|
sanitize_url,
|
222
233
|
camel_case_to_snake_case,
|
234
|
+
generate_uuid,
|
223
235
|
]
|
224
236
|
macros = {f.__name__: f for f in _macros_list}
|
@@ -448,6 +448,12 @@ class JwtAuthenticator(BaseModel):
|
|
448
448
|
description="Additional properties to be added to the JWT payload.",
|
449
449
|
title="Additional JWT Payload Properties",
|
450
450
|
)
|
451
|
+
passphrase: Optional[str] = Field(
|
452
|
+
None,
|
453
|
+
description="A passphrase/password used to encrypt the private key. Only provide a passphrase if required by the API for JWT authentication. The API will typically provide the passphrase when generating the public/private key pair.",
|
454
|
+
examples=["{{ config['passphrase'] }}"],
|
455
|
+
title="Passphrase",
|
456
|
+
)
|
451
457
|
parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
|
452
458
|
|
453
459
|
|
@@ -2705,6 +2705,7 @@ class ModelToComponentFactory:
|
|
2705
2705
|
aud=jwt_payload.aud,
|
2706
2706
|
additional_jwt_headers=model.additional_jwt_headers,
|
2707
2707
|
additional_jwt_payload=model.additional_jwt_payload,
|
2708
|
+
passphrase=model.passphrase,
|
2708
2709
|
)
|
2709
2710
|
|
2710
2711
|
def create_list_partition_router(
|
@@ -4,7 +4,7 @@ airbyte_cdk/cli/airbyte_cdk/__init__.py,sha256=8IoEcbdYr7CMAh97Xut5__uHH9vV4LKUt
|
|
4
4
|
airbyte_cdk/cli/airbyte_cdk/_connector.py,sha256=3AaKtp7QIuJcVrk7eHB9JokDyw2mTSBNiHCdpreL5no,6500
|
5
5
|
airbyte_cdk/cli/airbyte_cdk/_image.py,sha256=1Yu5CL5Eo07eY0OPBSgv1NfKoyNXualRr14KeGn0F0E,5773
|
6
6
|
airbyte_cdk/cli/airbyte_cdk/_manifest.py,sha256=aFdeeWgek7oXR3YfZPxk7kBZ64Blmsr0dAXN6BVGiIA,482
|
7
|
-
airbyte_cdk/cli/airbyte_cdk/_secrets.py,sha256=
|
7
|
+
airbyte_cdk/cli/airbyte_cdk/_secrets.py,sha256=RT0KQBIyHhXgSAgTRqoXr3AWbfCEzoJo46VLPMZfAYE,18898
|
8
8
|
airbyte_cdk/cli/airbyte_cdk/_version.py,sha256=ohZNIktLFk91sdzqFW5idaNrZAPX2dIRnz---_fcKOE,352
|
9
9
|
airbyte_cdk/cli/airbyte_cdk/exceptions.py,sha256=bsGmlWN6cXL2jCD1WYAZMqFmK1OLg2xLrcC_60KHSeA,803
|
10
10
|
airbyte_cdk/cli/source_declarative_manifest/README.md,sha256=aviNYFk1qKXGm33NQ2mJtJNyQ1MO0SPrm_fggUs0MVE,2460
|
@@ -115,7 +115,7 @@ airbyte_cdk/sources/declarative/async_job/status.py,sha256=mkExR-uOAO1ckUnclaUOa
|
|
115
115
|
airbyte_cdk/sources/declarative/async_job/timer.py,sha256=Fb8P72CQ7jIzJyzMSSNuBf2vt8bmrg9SrfmNxKwph2A,1242
|
116
116
|
airbyte_cdk/sources/declarative/auth/__init__.py,sha256=e2CRrcBWGhz3sQu3Oh34d1riEIwXipGS8hrSB1pu0Oo,284
|
117
117
|
airbyte_cdk/sources/declarative/auth/declarative_authenticator.py,sha256=nf-OmRUHYG4ORBwyb5CANzuHEssE-oNmL-Lccn41Td8,1099
|
118
|
-
airbyte_cdk/sources/declarative/auth/jwt.py,sha256=
|
118
|
+
airbyte_cdk/sources/declarative/auth/jwt.py,sha256=zZANSwaq-LkO22VbcdZloRrv5u7zTaC770xvWRtSKrE,9779
|
119
119
|
airbyte_cdk/sources/declarative/auth/oauth.py,sha256=bCwf3f3Td_CA8DZ6CXMVPNiImM9QEGDxkcLKzSo3-f0,14339
|
120
120
|
airbyte_cdk/sources/declarative/auth/selective_authenticator.py,sha256=qGwC6YsCldr1bIeKG6Qo-A9a5cTdHw-vcOn3OtQrS4c,1540
|
121
121
|
airbyte_cdk/sources/declarative/auth/token.py,sha256=2EnE78EhBOY9hbeZnQJ9AuFaM-G7dccU-oKo_LThRQk,11070
|
@@ -130,7 +130,7 @@ airbyte_cdk/sources/declarative/concurrent_declarative_source.py,sha256=z0AgJ6AZ
|
|
130
130
|
airbyte_cdk/sources/declarative/datetime/__init__.py,sha256=4Hw-PX1-VgESLF16cDdvuYCzGJtHntThLF4qIiULWeo,61
|
131
131
|
airbyte_cdk/sources/declarative/datetime/datetime_parser.py,sha256=_zGNGq31RNy_0QBLt_EcTvgPyhj7urPdx6oA3M5-r3o,3150
|
132
132
|
airbyte_cdk/sources/declarative/datetime/min_max_datetime.py,sha256=0BHBtDNQZfvwM45-tY5pNlTcKAFSGGNxemoi0Jic-0E,5785
|
133
|
-
airbyte_cdk/sources/declarative/declarative_component_schema.yaml,sha256=
|
133
|
+
airbyte_cdk/sources/declarative/declarative_component_schema.yaml,sha256=dWfbQUSNdW1HuY1NZslMNL8sTF-I3mKFXa9Fo3747-0,187551
|
134
134
|
airbyte_cdk/sources/declarative/decoders/__init__.py,sha256=JHb_0d3SE6kNY10mxA5YBEKPeSbsWYjByq1gUQxepoE,953
|
135
135
|
airbyte_cdk/sources/declarative/decoders/composite_raw_decoder.py,sha256=qB4lRUrCXLTE-a3VlpOLaazHiC7RIF_FIVJesuz7ebw,8078
|
136
136
|
airbyte_cdk/sources/declarative/decoders/decoder.py,sha256=1PeKwuMK8x9dsA2zqUjSVinEWVSEgYcUS6npiW3aC2c,855
|
@@ -159,20 +159,20 @@ airbyte_cdk/sources/declarative/interpolation/interpolated_nested_mapping.py,sha
|
|
159
159
|
airbyte_cdk/sources/declarative/interpolation/interpolated_string.py,sha256=CQkHqGlfa87G6VYMtBAQWin7ECKpfMdrDcg0JO5_rhc,3212
|
160
160
|
airbyte_cdk/sources/declarative/interpolation/interpolation.py,sha256=9IoeuWam3L6GyN10L6U8xNWXmkt9cnahSDNkez1OmFY,982
|
161
161
|
airbyte_cdk/sources/declarative/interpolation/jinja.py,sha256=oFGKs3oX0xO6DOL4E9x8rhxwbEoRcgx4HJVIL1RQ9c4,7269
|
162
|
-
airbyte_cdk/sources/declarative/interpolation/macros.py,sha256=
|
162
|
+
airbyte_cdk/sources/declarative/interpolation/macros.py,sha256=SgTnnFH6krDfFUuvZFEBQnhHjZNKar2t2ArElRPnQVU,6201
|
163
163
|
airbyte_cdk/sources/declarative/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
164
164
|
airbyte_cdk/sources/declarative/migrations/legacy_to_per_partition_state_migration.py,sha256=58MfDN0zD8M1Wv1jlgWIJ1jF3mbg7_jdS1glk_NFIaE,3962
|
165
165
|
airbyte_cdk/sources/declarative/migrations/state_migration.py,sha256=KWPjealMLKSMtajXgkdGgKg7EmTLR-CqqD7UIh0-eDU,794
|
166
166
|
airbyte_cdk/sources/declarative/models/__init__.py,sha256=nUFxNCiKeYRVXuZEKA7GD-lTHxsiKcQ8FitZjKhPIvE,100
|
167
167
|
airbyte_cdk/sources/declarative/models/base_model_with_deprecations.py,sha256=Imnj3yef0aqRdLfaUxkIYISUb8YkiPrRH_wBd-x8HjM,5999
|
168
|
-
airbyte_cdk/sources/declarative/models/declarative_component_schema.py,sha256=
|
168
|
+
airbyte_cdk/sources/declarative/models/declarative_component_schema.py,sha256=THYAUpV9dDO3n7nTshHrq9iMulGDy60QKM1_jy5t8Ak,131930
|
169
169
|
airbyte_cdk/sources/declarative/parsers/__init__.py,sha256=ZnqYNxHsKCgO38IwB34RQyRMXTs4GTvlRi3ImKnIioo,61
|
170
170
|
airbyte_cdk/sources/declarative/parsers/custom_code_compiler.py,sha256=nlVvHC511NUyDEEIRBkoeDTAvLqKNp-hRy8D19z8tdk,5941
|
171
171
|
airbyte_cdk/sources/declarative/parsers/custom_exceptions.py,sha256=wnRUP0Xeru9Rbu5OexXSDN9QWDo8YU4tT9M2LDVOgGA,802
|
172
172
|
airbyte_cdk/sources/declarative/parsers/manifest_component_transformer.py,sha256=la9Ulpc0lQewiBLKJ0FpsWxyU5XISv-ulmFRHJLJ1Pc,11292
|
173
173
|
airbyte_cdk/sources/declarative/parsers/manifest_normalizer.py,sha256=EtKjS9c94yNp3AwQC8KUCQaAYW5T3zvFYxoWYjc_buI,19729
|
174
174
|
airbyte_cdk/sources/declarative/parsers/manifest_reference_resolver.py,sha256=pJmg78vqE5VfUrF_KJnWjucQ4k9IWFULeAxHCowrHXE,6806
|
175
|
-
airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py,sha256=
|
175
|
+
airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py,sha256=1U2IMabGxODG9-sh2zNNHUBk3bkcWFssPisFL76vIVk,183420
|
176
176
|
airbyte_cdk/sources/declarative/partition_routers/__init__.py,sha256=TBC9AkGaUqHm2IKHMPN6punBIcY5tWGULowcLoAVkfw,1109
|
177
177
|
airbyte_cdk/sources/declarative/partition_routers/async_job_partition_router.py,sha256=VelO7zKqKtzMJ35jyFeg0ypJLQC0plqqIBNXoBW1G2E,3001
|
178
178
|
airbyte_cdk/sources/declarative/partition_routers/cartesian_product_stream_slicer.py,sha256=ocm4hZ4k-tEGs5HLrtI8ecWSK0hGqNH0Rvz2byx_HZk,6927
|
@@ -457,9 +457,9 @@ airbyte_cdk/utils/slice_hasher.py,sha256=EDxgROHDbfG-QKQb59m7h_7crN1tRiawdf5uU7G
|
|
457
457
|
airbyte_cdk/utils/spec_schema_transformations.py,sha256=9YDJmnIGFsT51CVQf2tSSvTapGimITjEFGbUTSZAGTI,963
|
458
458
|
airbyte_cdk/utils/stream_status_utils.py,sha256=ZmBoiy5HVbUEHAMrUONxZvxnvfV9CesmQJLDTAIWnWw,1171
|
459
459
|
airbyte_cdk/utils/traced_exception.py,sha256=C8uIBuCL_E4WnBAOPSxBicD06JAldoN9fGsQDp463OY,6292
|
460
|
-
airbyte_cdk-7.
|
461
|
-
airbyte_cdk-7.
|
462
|
-
airbyte_cdk-7.
|
463
|
-
airbyte_cdk-7.
|
464
|
-
airbyte_cdk-7.
|
465
|
-
airbyte_cdk-7.
|
460
|
+
airbyte_cdk-7.2.1.dist-info/LICENSE.txt,sha256=Wfe61S4BaGPj404v8lrAbvhjYR68SHlkzeYrg3_bbuM,1051
|
461
|
+
airbyte_cdk-7.2.1.dist-info/LICENSE_SHORT,sha256=aqF6D1NcESmpn-cqsxBtszTEnHKnlsp8L4x9wAh3Nxg,55
|
462
|
+
airbyte_cdk-7.2.1.dist-info/METADATA,sha256=KQgOHfblIbQ_fCnDFKgI8_dHYh4uxLKSS_wvefs1pqc,6798
|
463
|
+
airbyte_cdk-7.2.1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
464
|
+
airbyte_cdk-7.2.1.dist-info/entry_points.txt,sha256=eLZ2UYvJZGm1s07Pplcs--1Gim60YhZWTb53j_dghwU,195
|
465
|
+
airbyte_cdk-7.2.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|