Skip to content

Commit 317fe37

Browse files
authored
Merge pull request #29 from datamasque/feat/add-mongodb-tls-and-documentdb-connection
feat: MongoDB TLS CA fields + DocumentDB connection type
2 parents 5920210 + 4853ace commit 317fe37

7 files changed

Lines changed: 148 additions & 3 deletions

File tree

HISTORY.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22
History
33
=======
44

5+
1.1.3 (2026-06-26)
6+
------------------
7+
8+
* Added ``tls_ca_file`` and ``tls_allow_invalid_certificates`` to ``MongoConnectionConfig``,
9+
serialized only when TLS is enabled (``tls_ca_file`` only when set,
10+
``tls_allow_invalid_certificates`` only when ``True``).
11+
* Added ``DatabaseType.documentdb`` and ``DocumentDbConnectionConfig`` for AWS DocumentDB,
12+
which is MongoDB wire-compatible and reuses ``MongoConnectionConfig`` (differing only by ``db_type``).
13+
514
1.1.2 (2026-06-26)
615
------------------
716

datamasque/client/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
DatabaseConnectionConfig,
3434
DatabaseType,
3535
DatabricksConnectionConfig,
36+
DocumentDbConnectionConfig,
3637
DynamoConnectionConfig,
3738
FileConnectionConfig,
3839
MongoConnectionConfig,
@@ -150,6 +151,7 @@
150151
"DiscoveryConfigNotFoundError",
151152
"DiscoveryConfigType",
152153
"DiscoveryMatch",
154+
"DocumentDbConnectionConfig",
153155
"DynamoConnectionConfig",
154156
"FailedToStartError",
155157
"FileConnectionConfig",

datamasque/client/models/connection.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class DatabaseType(Enum):
4444
mssql_linked = "mssql_linked"
4545
snowflake = "snowflake"
4646
mongodb = "mongodb"
47+
documentdb = "documentdb"
4748
databricks_lakebase = "databricks_lakebase"
4849
databricks = "databricks"
4950
informix = "informix"
@@ -160,6 +161,8 @@ class MongoConnectionConfig(ConnectionConfig):
160161
password: Optional[str] = None
161162
auth_source: str = "admin"
162163
tls: bool = False
164+
tls_ca_file: str = ""
165+
tls_allow_invalid_certificates: bool = False
163166
direct_connection: bool = False
164167
replica_set: str = ""
165168
is_read_only: bool = False
@@ -180,6 +183,13 @@ def _serialize(self, handler: Callable) -> dict:
180183
d["dbpassword"] = password
181184
if not d.get("tls"):
182185
d.pop("tls", None)
186+
d.pop("tls_ca_file", None)
187+
d.pop("tls_allow_invalid_certificates", None)
188+
else:
189+
if not d.get("tls_ca_file"):
190+
d.pop("tls_ca_file", None)
191+
if not d.get("tls_allow_invalid_certificates"):
192+
d.pop("tls_allow_invalid_certificates", None)
183193
if not d.get("direct_connection"):
184194
d.pop("direct_connection", None)
185195
if not d.get("replica_set"):
@@ -197,6 +207,23 @@ def _strip_encrypted_password(cls, data: dict) -> dict:
197207
return data
198208

199209

210+
class DocumentDbConnectionConfig(MongoConnectionConfig):
211+
"""
212+
Connection configuration for an AWS DocumentDB cluster.
213+
214+
DocumentDB is MongoDB wire-compatible,
215+
so it reuses `MongoConnectionConfig` (including the TLS handling)
216+
and only differs by `db_type`/`database_type`.
217+
"""
218+
219+
# Narrowing the inherited Literal is a deliberate Pydantic discriminator override.
220+
db_type: Literal["documentdb"] = "documentdb" # type: ignore[assignment]
221+
222+
@property
223+
def database_type(self) -> DatabaseType:
224+
return DatabaseType.documentdb
225+
226+
200227
class SnowflakeConnectionConfig(ConnectionConfig):
201228
"""
202229
Connection configuration for a Snowflake database.
@@ -430,6 +457,7 @@ def _strip_encrypted_token(cls, data: dict) -> dict:
430457
DB_TYPE_MAP: dict[str, type[ConnectionConfig]] = {
431458
DatabaseType.dynamodb.value: DynamoConnectionConfig,
432459
DatabaseType.mongodb.value: MongoConnectionConfig,
460+
DatabaseType.documentdb.value: DocumentDbConnectionConfig,
433461
DatabaseType.snowflake.value: SnowflakeConnectionConfig,
434462
DatabaseType.mssql_linked.value: MssqlLinkedServerConnectionConfig,
435463
DatabaseType.databricks.value: DatabricksConnectionConfig,

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "datamasque-python"
3-
version = "1.1.2"
3+
version = "1.1.3"
44
description = "Official Python client for the DataMasque data-masking API."
55
authors = [
66
{ name = "DataMasque Ltd" },

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 1.1.2
2+
current_version = 1.1.3
33
commit = True
44
tag = True
55

tests/test_connections.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
DatabaseConnectionConfig,
1111
DatabaseType,
1212
DatabricksConnectionConfig,
13+
DocumentDbConnectionConfig,
1314
DynamoConnectionConfig,
1415
MongoConnectionConfig,
1516
MountedShareConnectionConfig,
@@ -1201,6 +1202,111 @@ def test_connection_config_dispatch_picks_mongo_subclass():
12011202
assert isinstance(validate_connection(payload), MongoConnectionConfig)
12021203

12031204

1205+
def test_mongo_tls_ca_fields_emitted_when_tls_enabled():
1206+
conn = MongoConnectionConfig(
1207+
name="mongo",
1208+
host="mongo.example",
1209+
database="people",
1210+
tls=True,
1211+
tls_ca_file="/certs/rds-ca.pem",
1212+
tls_allow_invalid_certificates=True,
1213+
)
1214+
d = conn.model_dump(exclude_none=True, by_alias=True, mode="json")
1215+
assert d["tls"] is True
1216+
assert d["tls_ca_file"] == "/certs/rds-ca.pem"
1217+
assert d["tls_allow_invalid_certificates"] is True
1218+
1219+
1220+
def test_mongo_tls_ca_fields_omitted_when_unset_but_tls_enabled():
1221+
conn = MongoConnectionConfig(name="mongo", host="mongo.example", database="people", tls=True)
1222+
d = conn.model_dump(exclude_none=True, by_alias=True, mode="json")
1223+
assert d["tls"] is True
1224+
assert "tls_ca_file" not in d
1225+
assert "tls_allow_invalid_certificates" not in d
1226+
1227+
1228+
def test_mongo_tls_ca_fields_omitted_when_tls_disabled():
1229+
"""Even when set, the TLS-dependent fields are not sent while TLS is disabled."""
1230+
conn = MongoConnectionConfig(
1231+
name="mongo",
1232+
host="mongo.example",
1233+
database="people",
1234+
tls=False,
1235+
tls_ca_file="/certs/rds-ca.pem",
1236+
tls_allow_invalid_certificates=True,
1237+
)
1238+
d = conn.model_dump(exclude_none=True, by_alias=True, mode="json")
1239+
for absent in ("tls", "tls_ca_file", "tls_allow_invalid_certificates"):
1240+
assert absent not in d
1241+
1242+
1243+
def test_mongo_tls_ca_fields_roundtrip():
1244+
payload = {
1245+
"id": "mongo-tls-1",
1246+
"name": "mongo",
1247+
"mask_type": "database",
1248+
"db_type": "mongodb",
1249+
"host": "mongo.example",
1250+
"database": "people",
1251+
"tls": True,
1252+
"tls_ca_file": "/certs/rds-ca.pem",
1253+
"tls_allow_invalid_certificates": True,
1254+
}
1255+
conn = MongoConnectionConfig.model_validate(payload)
1256+
assert conn.tls is True
1257+
assert conn.tls_ca_file == "/certs/rds-ca.pem"
1258+
assert conn.tls_allow_invalid_certificates is True
1259+
1260+
1261+
def test_mongo_tls_ca_fields_default_when_missing():
1262+
payload = {
1263+
"id": "mongo-tls-2",
1264+
"name": "mongo",
1265+
"mask_type": "database",
1266+
"db_type": "mongodb",
1267+
"host": "mongo.example",
1268+
"database": "people",
1269+
}
1270+
conn = MongoConnectionConfig.model_validate(payload)
1271+
assert conn.tls_ca_file == ""
1272+
assert conn.tls_allow_invalid_certificates is False
1273+
1274+
1275+
def test_documentdb_connection_model_dump():
1276+
conn = DocumentDbConnectionConfig(
1277+
name="docdb",
1278+
host="dtq-documentdb.cluster.example",
1279+
database="people",
1280+
user="dmadmin",
1281+
password="hunter2",
1282+
tls=True,
1283+
tls_ca_file="/certs/rds-ca.pem",
1284+
retry_writes=False,
1285+
)
1286+
d = conn.model_dump(exclude_none=True, by_alias=True, mode="json")
1287+
assert d["db_type"] == "documentdb"
1288+
assert d["mask_type"] == "database"
1289+
assert d["dbpassword"] == "hunter2"
1290+
assert d["tls"] is True
1291+
assert d["tls_ca_file"] == "/certs/rds-ca.pem"
1292+
assert d["retry_writes"] is False
1293+
assert conn.database_type is DatabaseType.documentdb
1294+
1295+
1296+
def test_connection_config_dispatch_picks_documentdb_subclass():
1297+
payload = {
1298+
"id": "docdb-id-1",
1299+
"name": "docdb",
1300+
"mask_type": "database",
1301+
"db_type": "documentdb",
1302+
"host": "dtq-documentdb.cluster.example",
1303+
"database": "people",
1304+
}
1305+
conn = validate_connection(payload)
1306+
assert isinstance(conn, DocumentDbConnectionConfig)
1307+
assert conn.database_type is DatabaseType.documentdb
1308+
1309+
12041310
def test_database_connection_config_rejects_mongodb_database_type():
12051311
"""`DatabaseConnectionConfig` is for SQL engines; MongoDB users must use `MongoConnectionConfig`."""
12061312
with pytest.raises(ValueError, match="For MongoDB"):

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)