Skip to content

Commit 991915f

Browse files
kronnkpre-commit-ci[bot]edgarrmondragon
authored
feat: Support for Base64 String Private key (#341)
This pull request includes significant updates to the Meltano configuration and enhancements to the Snowflake connector. The changes improve configuration management and add new functionality for handling private keys. ### Meltano Configuration Updates: * Added `default_environment` and `environments` to specify deployment environments. (`meltano.yml`: [meltano.ymlL3-R114](diffhunk://#diff-6d0acc7374df2a40ec960634f967ae63128eac507abd089a68b8787e9433ddf2L3-R114)) * Updated `target-snowflake` loader settings to include new validation groups and reorganized settings for better readability. (`meltano.yml`: [meltano.ymlL3-R114](diffhunk://#diff-6d0acc7374df2a40ec960634f967ae63128eac507abd089a68b8787e9433ddf2L3-R114)) ### Snowflake Connector Enhancements: * Added imports for `base64`, `binascii`, and `warn` to handle private key formats and deprecations. (`target_snowflake/connector.py`: [target_snowflake/connector.pyR3-R10](diffhunk://#diff-9d2a86f3e673ca747a3f08bc77045ce73dbe3ead0713d3292a622091e7060cc8R3-R10)) * Introduced `SingerSDKDeprecationWarning` to warn users about using private key pem formats. (`target_snowflake/connector.py`: [target_snowflake/connector.pyR19](diffhunk://#diff-9d2a86f3e673ca747a3f08bc77045ce73dbe3ead0713d3292a622091e7060cc8R19)) * Enhanced `get_private_key` method to support both PEM and base64 encoded private keys, with appropriate logging and error handling. (`target_snowflake/connector.py`: [target_snowflake/connector.pyL131-R151](diffhunk://#diff-9d2a86f3e673ca747a3f08bc77045ce73dbe3ead0713d3292a622091e7060cc8L131-R151)) --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Edgar Ramírez Mondragón <[email protected]>
1 parent 1d10cd4 commit 991915f

File tree

2 files changed

+92
-62
lines changed

2 files changed

+92
-62
lines changed

meltano.yml

+72-60
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,114 @@
11
version: 1
22
send_anonymous_usage_stats: true
3-
project_id: "target-snowflake"
3+
project_id: target-snowflake
4+
default_environment: dev
5+
environments:
6+
- name: dev
47
plugins:
5-
extractors: []
68
loaders:
7-
- name: "target-snowflake"
8-
namespace: "target_snowflake"
9+
- name: target-snowflake
10+
namespace: target_snowflake
911
pip_url: -e .
1012
capabilities:
1113
- about
1214
- schema-flattening
1315
- stream-maps
14-
config:
15-
start_date: '2010-01-01T00:00:00Z'
16+
settings_group_validation:
17+
- - account
18+
- database
19+
- password
20+
- user
21+
- - account
22+
- database
23+
- private_key_path
24+
- user
25+
- - account
26+
- database
27+
- private_key
28+
- user
29+
- - account
30+
- database
31+
- use_browser_authentication
32+
- user
1633
settings:
17-
- description: Your account identifier. See [Account Identifiers](https://docs.snowflake.com/en/user-guide/admin-account-identifier.html).
34+
- name: account
1835
kind: string
1936
label: Account
20-
name: account
21-
- description: Whether to add metadata columns.
37+
description: Your account identifier. See [Account
38+
Identifiers](https://docs.snowflake.com/en/user-guide/admin-account-identifier.html).
39+
- name: add_record_metadata
2240
kind: boolean
23-
label: Add Record Metadata
24-
name: add_record_metadata
2541
value: true
26-
- description: Whether to remove batch files after processing.
42+
label: Add Record Metadata
43+
description: Whether to add metadata columns.
44+
- name: clean_up_batch_files
2745
kind: boolean
28-
label: Clean Up Batch Files
29-
name: clean_up_batch_files
3046
value: true
31-
- description: The initial database for the Snowflake session.
47+
label: Clean Up Batch Files
48+
description: Whether to remove batch files after processing.
49+
- name: database
3250
kind: string
3351
label: Database
34-
name: database
35-
- description: The default target database schema name to use for all streams.
52+
description: The initial database for the Snowflake session.
53+
- name: default_target_schema
3654
kind: string
3755
label: Default Target Schema
38-
name: default_target_schema
39-
- description: "'True' to enable schema flattening and automatically expand nested\
40-
\ properties."
56+
description: The default target database schema name to use for all streams.
57+
- name: flattening_enabled
4158
kind: boolean
4259
label: Flattening Enabled
43-
name: flattening_enabled
44-
- description: The max depth to flatten schemas.
60+
description: "'True' to enable schema flattening and automatically expand nested
61+
properties."
62+
- name: flattening_max_depth
4563
kind: integer
4664
label: Flattening Max Depth
47-
name: flattening_max_depth
48-
- description: The password for your Snowflake user.
49-
kind: password
65+
description: The max depth to flatten schemas.
66+
- name: password
67+
kind: string
5068
label: Password
51-
name: password
52-
- description: Path to file containing private key
69+
description: The password for your Snowflake user.
70+
sensitive: true
71+
- name: private_key_path
5372
kind: string
5473
label: Private Key Path
55-
name: private_key_path
56-
- description: Passphrase to decrypt private key if encrypted
74+
description: Path to file containing private key
75+
- name: private_key
76+
kind: string
77+
label: Private Key
78+
description: The private key for your Snowflake user.
79+
- name: private_key_passphrase
80+
kind: string
5781
label: Private Key Passphrase
58-
kind: password
59-
name: private_key_passphrase
60-
- description: The initial role for the session.
82+
description: Passphrase to decrypt private key if encrypted
83+
sensitive: true
84+
- name: role
6185
kind: string
6286
label: Role
63-
name: role
64-
- description: The initial schema for the Snowflake session.
87+
description: The initial role for the session.
88+
- name: schema
6589
kind: string
6690
label: Schema
67-
name: schema
68-
- description: User-defined config values to be used within map expressions.
91+
description: The initial schema for the Snowflake session.
92+
- name: stream_map_config
6993
kind: object
7094
label: Stream Map Config
71-
name: stream_map_config
72-
- description: Config object for stream maps capability. For more information check
73-
out [Stream Maps](https://sdk.meltano.com/en/latest/stream_maps.html).
95+
description: User-defined config values to be used within map expressions.
96+
- name: stream_maps
7497
kind: object
7598
label: Stream Maps
76-
name: stream_maps
77-
- description: If browser based SSO authentication should be used. See [SSO browser authentication](https://docs.snowflake.com/en/developer-guide/node-js/nodejs-driver-authenticate#using-single-sign-on-sso-through-a-web-browser).
99+
description: Config object for stream maps capability. For more information
100+
check out [Stream Maps](https://sdk.meltano.com/en/latest/stream_maps.html).
101+
- name: use_browser_authentication
78102
kind: boolean
79-
label: Use browser authentication
80-
name: use_browser_authentication
81103
value: false
82-
- description: The login name for your Snowflake user.
104+
label: Use browser authentication
105+
description: If browser based SSO authentication should be used. See [SSO browser
106+
authentication](https://docs.snowflake.com/en/developer-guide/node-js/nodejs-driver-authenticate#using-single-sign-on-sso-through-a-web-browser).
107+
- name: user
83108
kind: string
84109
label: User
85-
name: user
86-
- description: The initial warehouse for the session.
110+
description: The login name for your Snowflake user.
111+
- name: warehouse
87112
kind: string
88113
label: Warehouse
89-
name: warehouse
90-
settings_group_validation:
91-
- - account
92-
- database
93-
- password
94-
- user
95-
- - account
96-
- database
97-
- private_key_path
98-
- user
99-
- - account
100-
- database
101-
- use_browser_authentication
102-
- user
114+
description: The initial warehouse for the session.

target_snowflake/connector.py

+20-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
from __future__ import annotations
22

3+
import base64
4+
import binascii
35
import urllib.parse
46
from enum import Enum
57
from functools import cached_property
68
from pathlib import Path
79
from typing import TYPE_CHECKING, Any
10+
from warnings import warn
811

912
import snowflake.sqlalchemy.custom_types as sct
1013
import sqlalchemy
@@ -128,8 +131,23 @@ def get_private_key(self):
128131
with key_path.open("rb") as key_file:
129132
key_content = key_file.read()
130133
else:
131-
key_content = self.config["private_key"].encode()
132-
134+
private_key = self.config["private_key"]
135+
self.logger.debug("Reading private key from config")
136+
if "-----BEGIN " in private_key:
137+
warn(
138+
"Use base64 encoded private key instead of PEM format",
139+
DeprecationWarning,
140+
stacklevel=2,
141+
)
142+
self.logger.info("Private key is in PEM format")
143+
key_content = private_key.encode()
144+
else:
145+
try:
146+
self.logger.debug("Private key is in base64 format")
147+
key_content = base64.b64decode(private_key)
148+
except binascii.Error as e:
149+
error_message = f"Invalid private key format: {e}"
150+
raise ValueError(error_message) from e
133151
p_key = serialization.load_pem_private_key(
134152
key_content,
135153
password=encoded_passphrase,

0 commit comments

Comments
 (0)