@deepnote/database-integrations 1.7.1 → 2.1.0

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.
package/dist/index.cjs CHANGED
@@ -23,8 +23,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  //#endregion
24
24
  let zod = require("zod");
25
25
  zod = __toESM(zod, 1);
26
- let yaml = require("yaml");
27
26
  let _deepnote_blocks = require("@deepnote/blocks");
27
+ let yaml = require("yaml");
28
28
  //#region src/sql-integration-auth-methods.ts
29
29
  const AwsAuthMethods = {
30
30
  AccessKeys: "access-keys",
@@ -428,6 +428,73 @@ const databaseIntegrationConfigSchema = zod.default.discriminatedUnion("type", [
428
428
  })
429
429
  ]);
430
430
  //#endregion
431
+ //#region src/secret-field-paths.ts
432
+ /**
433
+ * All secret fields for each integration type.
434
+ * This includes all possible secret fields regardless of auth method.
435
+ *
436
+ * Note: For integrations with multiple auth methods (e.g., snowflake, bigquery),
437
+ * this includes all secret fields from all auth variants.
438
+ */
439
+ const SECRET_PATHS = {
440
+ alloydb: ["password", "caCertificateText"],
441
+ mariadb: ["password", "caCertificateText"],
442
+ materialize: ["password", "caCertificateText"],
443
+ mindsdb: ["password", "caCertificateText"],
444
+ mysql: ["password", "caCertificateText"],
445
+ pgsql: ["password", "caCertificateText"],
446
+ "sql-server": ["password"],
447
+ clickhouse: ["password", "caCertificateText"],
448
+ databricks: ["token"],
449
+ dremio: ["token"],
450
+ athena: ["secret_access_key"],
451
+ spanner: ["service_account"],
452
+ "cloud-sql": ["service_account"],
453
+ mongodb: [
454
+ "password",
455
+ "connection_string",
456
+ "rawConnectionString",
457
+ "caCertificateText"
458
+ ],
459
+ "pandas-dataframe": [],
460
+ "big-query": ["service_account", "clientSecret"],
461
+ snowflake: [
462
+ "password",
463
+ "clientSecret",
464
+ "privateKey",
465
+ "privateKeyPassphrase",
466
+ "dbtServiceToken"
467
+ ],
468
+ redshift: ["password", "caCertificateText"],
469
+ trino: [
470
+ "password",
471
+ "clientSecret",
472
+ "caCertificateText"
473
+ ]
474
+ };
475
+ /**
476
+ * Get the list of secret field paths for a given integration type.
477
+ *
478
+ * @param type - The integration type (e.g., 'pgsql', 'snowflake')
479
+ * @returns Array of field names that contain secrets
480
+ *
481
+ * @example
482
+ * getSecretFieldPaths('pgsql') // => ['password', 'caCertificateText']
483
+ * getSecretFieldPaths('snowflake') // => ['password', 'clientSecret', 'privateKey', 'privateKeyPassphrase', 'dbtServiceToken']
484
+ */
485
+ function getSecretFieldPaths(type) {
486
+ return SECRET_PATHS[type] ?? [];
487
+ }
488
+ /**
489
+ * Whether `key` is a secret field of an integration whose `metadata.authMethod` is federated.
490
+ * Such integrations authenticate each user with their own identity, so the value never needs
491
+ * to reach notebook code.
492
+ */
493
+ function isFederatedAuthSecretField(type, metadata, key) {
494
+ const { authMethod } = metadata;
495
+ return typeof authMethod === "string" && isFederatedAuthMethod(authMethod) && getSecretFieldPaths(type).includes(key);
496
+ }
497
+ //#endregion
431
498
  //#region src/snowflake-integration-env-vars.ts
432
499
  /**
433
500
  * Build a URL with path and query parameters using native URL API
@@ -498,9 +565,9 @@ function getEnvironmentVariablesForIntegrations(integrations, params) {
498
565
  const envVars = [];
499
566
  const errors = [];
500
567
  integrations.forEach((integration) => {
501
- const namePrefix = convertToEnvironmentVariableName(integration.name);
568
+ const namePrefix = (0, _deepnote_blocks.convertToEnvironmentVariableName)(integration.name);
502
569
  const envVarsForThisIntegration = Object.entries(integration.metadata).filter(([key]) => {
503
- return key !== "caCertificateText";
570
+ return key !== "caCertificateText" && !isFederatedAuthSecretField(integration.type, integration.metadata, key);
504
571
  }).map(([key, rawValue]) => {
505
572
  const name = `${namePrefix}_${key.toUpperCase()}`;
506
573
  const value = String(rawValue);
@@ -798,6 +865,21 @@ const getBigQuerySqlAlchemyInput = (metadata) => {
798
865
  throw new BigQueryServiceAccountParseError("Failed to parse bigquery service account, returning empty environment variable.", { cause: error instanceof Error ? error : new Error(String(error)) });
799
866
  }
800
867
  };
868
+ /**
869
+ * @returns sql alchemy input for a BigQuery integration authenticated via Google OAuth, given an
870
+ * access token minted by the caller. `user_supplied_client=true` tells the runtime to build its
871
+ * BigQuery client from `access_token` / `project` instead of a service account.
872
+ */
873
+ function getBigQueryOAuthSqlAlchemyInput(metadata, accessToken) {
874
+ return {
875
+ url: "bigquery://?user_supplied_client=true",
876
+ params: {
877
+ access_token: accessToken,
878
+ project: metadata.project
879
+ },
880
+ param_style: "pyformat"
881
+ };
882
+ }
801
883
  var SpannerServiceAccountParseError = class extends Error {
802
884
  cause;
803
885
  constructor(message, params) {
@@ -847,11 +929,8 @@ const getMySqlSqlAlchemyInput = (integrationId, projectRootDirectory, { user, pa
847
929
  function getCACertificatePath({ projectRoot, integrationId, caCertificateName }) {
848
930
  return `${projectRoot}/.deepnote/${integrationId}/${caCertificateName}`;
849
931
  }
850
- function convertToEnvironmentVariableName(str) {
851
- return (/^\d/.test(str) ? `_${str}` : str).toUpperCase().replace(/[^\w]/g, "_");
852
- }
853
932
  function getSqlEnvVarName(integrationId) {
854
- return convertToEnvironmentVariableName(`SQL_${integrationId}`);
933
+ return (0, _deepnote_blocks.convertToEnvironmentVariableName)(`SQL_${integrationId}`);
855
934
  }
856
935
  function assertNever(value) {
857
936
  throw new Error(`Unexpected value: ${value}`);
@@ -1018,7 +1097,7 @@ const apiIntegrationSchema = zod.z.object({
1018
1097
  id: zod.z.string(),
1019
1098
  name: zod.z.string(),
1020
1099
  type: zod.z.string(),
1021
- metadata: zod.z.unknown(),
1100
+ metadata: zod.z.unknown().optional(),
1022
1101
  is_public: zod.z.boolean().nullish(),
1023
1102
  created_at: zod.z.string().nullish(),
1024
1103
  updated_at: zod.z.string().nullish(),
@@ -1127,67 +1206,9 @@ function serializeIntegrationsDocument(doc) {
1127
1206
  * ...
1128
1207
  * ```
1129
1208
  */
1130
- const baseIntegrationsFileSchema = zod.z.object({ integrations: zod.z.array(zod.z.record(zod.z.unknown())).optional().default([]) });
1209
+ const baseIntegrationsFileSchema = zod.z.object({ integrations: zod.z.array(zod.z.record(zod.z.string(), zod.z.unknown())).optional().default([]) });
1131
1210
  const integrationsFileSchema = zod.z.object({ integrations: zod.z.array(databaseIntegrationConfigSchema) });
1132
1211
  //#endregion
1133
- //#region src/secret-field-paths.ts
1134
- /**
1135
- * All secret fields for each integration type.
1136
- * This includes all possible secret fields regardless of auth method.
1137
- *
1138
- * Note: For integrations with multiple auth methods (e.g., snowflake, bigquery),
1139
- * this includes all secret fields from all auth variants.
1140
- */
1141
- const SECRET_PATHS = {
1142
- alloydb: ["password", "caCertificateText"],
1143
- mariadb: ["password", "caCertificateText"],
1144
- materialize: ["password", "caCertificateText"],
1145
- mindsdb: ["password", "caCertificateText"],
1146
- mysql: ["password", "caCertificateText"],
1147
- pgsql: ["password", "caCertificateText"],
1148
- "sql-server": ["password"],
1149
- clickhouse: ["password", "caCertificateText"],
1150
- databricks: ["token"],
1151
- dremio: ["token"],
1152
- athena: ["secret_access_key"],
1153
- spanner: ["service_account"],
1154
- "cloud-sql": ["service_account"],
1155
- mongodb: [
1156
- "password",
1157
- "connection_string",
1158
- "rawConnectionString",
1159
- "caCertificateText"
1160
- ],
1161
- "pandas-dataframe": [],
1162
- "big-query": ["service_account", "clientSecret"],
1163
- snowflake: [
1164
- "password",
1165
- "clientSecret",
1166
- "privateKey",
1167
- "privateKeyPassphrase",
1168
- "dbtServiceToken"
1169
- ],
1170
- redshift: ["password", "caCertificateText"],
1171
- trino: [
1172
- "password",
1173
- "clientSecret",
1174
- "caCertificateText"
1175
- ]
1176
- };
1177
- /**
1178
- * Get the list of secret field paths for a given integration type.
1179
- *
1180
- * @param type - The integration type (e.g., 'pgsql', 'snowflake')
1181
- * @returns Array of field names that contain secrets
1182
- *
1183
- * @example
1184
- * getSecretFieldPaths('pgsql') // => ['password', 'caCertificateText']
1185
- * getSecretFieldPaths('snowflake') // => ['password', 'clientSecret', 'privateKey', 'privateKeyPassphrase', 'dbtServiceToken']
1186
- */
1187
- function getSecretFieldPaths(type) {
1188
- return SECRET_PATHS[type] ?? [];
1189
- }
1190
- //#endregion
1191
1212
  //#region src/loading/merge-integrations.ts
1192
1213
  /**
1193
1214
  * JSON schema URL for the integrations file.
@@ -1562,6 +1583,7 @@ exports.extractEnvVarName = extractEnvVarName;
1562
1583
  exports.federatedAuthMethods = federatedAuthMethods;
1563
1584
  exports.fetchIntegrations = fetchIntegrations;
1564
1585
  exports.generateEnvVarName = generateEnvVarName;
1586
+ exports.getBigQueryOAuthSqlAlchemyInput = getBigQueryOAuthSqlAlchemyInput;
1565
1587
  exports.getEnvironmentVariablesForIntegrations = getEnvironmentVariablesForIntegrations;
1566
1588
  exports.getOrCreateIntegrationMetadata = getOrCreateIntegrationMetadata;
1567
1589
  exports.getOrCreateIntegrationsFromDocument = getOrCreateIntegrationsFromDocument;
@@ -1576,6 +1598,7 @@ exports.isDatabaseIntegrationTypeWithSslSupport = isDatabaseIntegrationTypeWithS
1576
1598
  exports.isEnvVarRef = isEnvVarRef;
1577
1599
  exports.isFederatedAuthMetadata = isFederatedAuthMetadata;
1578
1600
  exports.isFederatedAuthMethod = isFederatedAuthMethod;
1601
+ exports.isFederatedAuthSecretField = isFederatedAuthSecretField;
1579
1602
  exports.isSqlIntegrationType = isSqlIntegrationType;
1580
1603
  exports.mergeApiIntegrationsIntoDocument = mergeApiIntegrationsIntoDocument;
1581
1604
  exports.mergeApiIntegrationsIntoYaml = mergeApiIntegrationsIntoYaml;