@backstage/backend-defaults 0.17.7 → 0.17.9-next.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/config.schema.json +1 -1
  3. package/dist/alpha/entrypoints/actionsRegistry/DefaultActionsRegistryService.cjs.js +34 -9
  4. package/dist/alpha/entrypoints/actionsRegistry/DefaultActionsRegistryService.cjs.js.map +1 -1
  5. package/dist/alpha/entrypoints/actionsRegistry/actionFilters.cjs.js +67 -0
  6. package/dist/alpha/entrypoints/actionsRegistry/actionFilters.cjs.js.map +1 -0
  7. package/dist/alpha/entrypoints/actionsRegistry/actionsRegistryServiceFactory.cjs.js +3 -0
  8. package/dist/alpha/entrypoints/actionsRegistry/actionsRegistryServiceFactory.cjs.js.map +1 -1
  9. package/dist/entrypoints/auth/DefaultAuthService.cjs.js +18 -2
  10. package/dist/entrypoints/auth/DefaultAuthService.cjs.js.map +1 -1
  11. package/dist/entrypoints/auth/JwksClient.cjs.js +61 -32
  12. package/dist/entrypoints/auth/JwksClient.cjs.js.map +1 -1
  13. package/dist/entrypoints/auth/external/ExternalAuthTokenHandler.cjs.js +2 -1
  14. package/dist/entrypoints/auth/external/ExternalAuthTokenHandler.cjs.js.map +1 -1
  15. package/dist/entrypoints/auth/helpers.cjs.js +7 -1
  16. package/dist/entrypoints/auth/helpers.cjs.js.map +1 -1
  17. package/dist/entrypoints/auth/plugin/PluginTokenHandler.cjs.js +0 -1
  18. package/dist/entrypoints/auth/plugin/PluginTokenHandler.cjs.js.map +1 -1
  19. package/dist/entrypoints/auth/user/UserTokenHandler.cjs.js +0 -1
  20. package/dist/entrypoints/auth/user/UserTokenHandler.cjs.js.map +1 -1
  21. package/dist/entrypoints/database/DatabaseManager.cjs.js +12 -0
  22. package/dist/entrypoints/database/DatabaseManager.cjs.js.map +1 -1
  23. package/dist/entrypoints/database/connectors/postgres.cjs.js +216 -59
  24. package/dist/entrypoints/database/connectors/postgres.cjs.js.map +1 -1
  25. package/dist/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.cjs.js +4 -0
  26. package/dist/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.cjs.js.map +1 -1
  27. package/dist/entrypoints/urlReader/lib/AwsS3UrlReader.cjs.js +8 -1
  28. package/dist/entrypoints/urlReader/lib/AwsS3UrlReader.cjs.js.map +1 -1
  29. package/dist/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.cjs.js +8 -1
  30. package/dist/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.cjs.js.map +1 -1
  31. package/dist/entrypoints/urlReader/lib/FetchUrlReader.cjs.js +8 -4
  32. package/dist/entrypoints/urlReader/lib/FetchUrlReader.cjs.js.map +1 -1
  33. package/dist/entrypoints/urlReader/lib/GitlabUrlReader.cjs.js +19 -12
  34. package/dist/entrypoints/urlReader/lib/GitlabUrlReader.cjs.js.map +1 -1
  35. package/dist/entrypoints/urlReader/lib/GoogleGcsUrlReader.cjs.js +2 -1
  36. package/dist/entrypoints/urlReader/lib/GoogleGcsUrlReader.cjs.js.map +1 -1
  37. package/dist/entrypoints/urlReader/lib/HarnessUrlReader.cjs.js +58 -25
  38. package/dist/entrypoints/urlReader/lib/HarnessUrlReader.cjs.js.map +1 -1
  39. package/dist/entrypoints/urlReader/lib/util.cjs.js +30 -0
  40. package/dist/entrypoints/urlReader/lib/util.cjs.js.map +1 -1
  41. package/dist/package.json.cjs.js +1 -1
  42. package/dist/urlReader.d.ts +7 -1
  43. package/package.json +17 -17
@@ -16,6 +16,115 @@ var limiterFactory__default = /*#__PURE__*/_interopDefaultCompat(limiterFactory)
16
16
  var format__default = /*#__PURE__*/_interopDefaultCompat(format);
17
17
 
18
18
  const ddlLimiter = limiterFactory__default.default(1);
19
+ class PgAdminPool {
20
+ constructor(createClient, idleTimeoutMillis) {
21
+ this.createClient = createClient;
22
+ this.idleTimeoutMillis = idleTimeoutMillis;
23
+ }
24
+ client;
25
+ destruction;
26
+ destructionErrors = [];
27
+ idleTimer;
28
+ operations = /* @__PURE__ */ new Set();
29
+ isShutdown = false;
30
+ async run(operation) {
31
+ if (this.isShutdown) {
32
+ throw new Error("PostgreSQL admin pool is shut down");
33
+ }
34
+ clearTimeout(this.idleTimer);
35
+ this.idleTimer = void 0;
36
+ const operationPromise = this.runOperation(operation);
37
+ this.operations.add(operationPromise);
38
+ try {
39
+ return await operationPromise;
40
+ } finally {
41
+ this.operations.delete(operationPromise);
42
+ this.scheduleIdleDestroy();
43
+ }
44
+ }
45
+ async shutdown() {
46
+ this.isShutdown = true;
47
+ clearTimeout(this.idleTimer);
48
+ this.idleTimer = void 0;
49
+ await Promise.allSettled(this.operations);
50
+ await this.destroyClient().catch(() => {
51
+ });
52
+ if (this.destructionErrors.length > 0) {
53
+ throw new AggregateError(
54
+ this.destructionErrors,
55
+ "Failed to destroy PostgreSQL admin pool clients"
56
+ );
57
+ }
58
+ }
59
+ async invalidate() {
60
+ clearTimeout(this.idleTimer);
61
+ this.idleTimer = void 0;
62
+ await Promise.allSettled(this.operations);
63
+ await this.destroyClient();
64
+ }
65
+ async runOperation(operation) {
66
+ if (this.destruction) {
67
+ await this.destruction;
68
+ }
69
+ if (this.isShutdown) {
70
+ throw new Error("PostgreSQL admin pool is shut down");
71
+ }
72
+ let clientPromise = this.client;
73
+ if (!clientPromise) {
74
+ clientPromise = this.createClient();
75
+ this.client = clientPromise;
76
+ void clientPromise.catch(() => {
77
+ if (this.client === clientPromise) {
78
+ this.client = void 0;
79
+ }
80
+ });
81
+ }
82
+ return operation(await clientPromise);
83
+ }
84
+ scheduleIdleDestroy() {
85
+ if (this.isShutdown || this.operations.size > 0) {
86
+ return;
87
+ }
88
+ const timer = setTimeout(() => {
89
+ if (this.idleTimer === timer) {
90
+ this.idleTimer = void 0;
91
+ void this.destroyClient().catch(() => {
92
+ });
93
+ }
94
+ }, this.idleTimeoutMillis);
95
+ timer.unref();
96
+ this.idleTimer = timer;
97
+ }
98
+ destroyClient() {
99
+ if (this.destruction) {
100
+ return this.destruction;
101
+ }
102
+ const clientPromise = this.client;
103
+ this.client = void 0;
104
+ if (!clientPromise) {
105
+ return Promise.resolve();
106
+ }
107
+ const destruction = clientPromise.then(
108
+ (client) => client.destroy(),
109
+ () => void 0
110
+ );
111
+ this.destruction = destruction;
112
+ void destruction.then(
113
+ () => {
114
+ if (this.destruction === destruction) {
115
+ this.destruction = void 0;
116
+ }
117
+ },
118
+ (error) => {
119
+ if (this.destruction === destruction) {
120
+ this.destruction = void 0;
121
+ this.destructionErrors.push(error);
122
+ }
123
+ }
124
+ );
125
+ return destruction;
126
+ }
127
+ }
19
128
  async function createPgDatabaseClient(dbConfig, overrides) {
20
129
  const knexConfig = await buildPgDatabaseConfig(dbConfig, overrides);
21
130
  const database = knexFactory__default.default(knexConfig);
@@ -236,64 +345,40 @@ function requirePgConnectionString() {
236
345
  throw new errors.ForwardedError("Postgres: Install 'pg-connection-string'", e);
237
346
  }
238
347
  }
239
- async function ensurePgDatabaseExists(dbConfig, ...databases) {
240
- const ensureDatabase = async (database) => {
241
- const admin = await createPgDatabaseClient(dbConfig, {
242
- connection: {
243
- database: "postgres"
244
- },
245
- pool: {
246
- min: 0,
247
- max: 1,
248
- acquireTimeoutMillis: 1e4
249
- }
250
- });
348
+ const PG_DATABASE_ADMIN_OVERRIDES = {
349
+ connection: { database: "postgres" },
350
+ pool: { min: 0, max: 1, acquireTimeoutMillis: 1e4 }
351
+ };
352
+ const PG_SCHEMA_ADMIN_OVERRIDES = {
353
+ pool: { min: 0, max: 1, acquireTimeoutMillis: 1e4 }
354
+ };
355
+ async function ensurePgDatabase(admin, database) {
356
+ const result = await admin.from("pg_database").where("datname", database).count();
357
+ if (parseInt(result[0].count, 10) === 0) {
358
+ await admin.raw(`CREATE DATABASE ??`, [database]);
359
+ }
360
+ }
361
+ async function retryPgAdminOperation(operation) {
362
+ const maxAttempts = 3;
363
+ for (let attempt = 1; ; attempt++) {
251
364
  try {
252
- const result = await admin.from("pg_database").where("datname", database).count();
253
- if (parseInt(result[0].count, 10) > 0) {
254
- return;
365
+ return await operation();
366
+ } catch (error) {
367
+ if (attempt >= maxAttempts) {
368
+ throw error;
255
369
  }
256
- await admin.raw(`CREATE DATABASE ??`, [database]);
257
- } finally {
258
- await admin.destroy();
370
+ await new Promise((resolve) => setTimeout(resolve, 100));
259
371
  }
260
- };
261
- await Promise.all(
262
- databases.map(async (database) => {
263
- const maxAttempts = 3;
264
- for (let attempt = 1; ; attempt++) {
265
- try {
266
- return await ddlLimiter(() => ensureDatabase(database));
267
- } catch (err) {
268
- if (attempt >= maxAttempts) {
269
- throw err;
270
- } else {
271
- await new Promise((resolve) => setTimeout(resolve, 100));
272
- }
273
- }
274
- }
275
- })
276
- );
372
+ }
277
373
  }
278
- async function ensurePgSchemaExists(dbConfig, ...schemas) {
279
- const admin = await createPgDatabaseClient(dbConfig);
280
- const role = dbConfig.getOptionalString("role");
281
- try {
282
- const ensureSchema = async (database) => {
283
- if (role) {
284
- await admin.raw(`CREATE SCHEMA IF NOT EXISTS ?? AUTHORIZATION ??`, [
285
- database,
286
- role
287
- ]);
288
- } else {
289
- await admin.raw(`CREATE SCHEMA IF NOT EXISTS ??`, [database]);
290
- }
291
- };
292
- await Promise.all(
293
- schemas.map((database) => ddlLimiter(() => ensureSchema(database)))
294
- );
295
- } finally {
296
- await admin.destroy();
374
+ async function ensurePgSchema(admin, role, schema) {
375
+ if (role) {
376
+ await admin.raw(`CREATE SCHEMA IF NOT EXISTS ?? AUTHORIZATION ??`, [
377
+ schema,
378
+ role
379
+ ]);
380
+ } else {
381
+ await admin.raw(`CREATE SCHEMA IF NOT EXISTS ??`, [schema]);
297
382
  }
298
383
  }
299
384
  function pluginPath(pluginId) {
@@ -375,9 +460,73 @@ function computePgPluginConfig(config, pluginId, prefix) {
375
460
  class PgConnector {
376
461
  config;
377
462
  prefix;
378
- constructor(config, prefix) {
463
+ databaseEnsureCache = /* @__PURE__ */ new Map();
464
+ customEnsureDatabaseExists;
465
+ databaseAdminPool;
466
+ schemaAdminPool;
467
+ constructor(config, prefix, options = {}) {
379
468
  this.config = config;
380
469
  this.prefix = prefix;
470
+ this.customEnsureDatabaseExists = options.ensureDatabaseExists;
471
+ const createAdminClient = options.createAdminClient ?? ((overrides) => createPgDatabaseClient(this.config, overrides));
472
+ const idleTimeoutMillis = options.adminPoolIdleTimeoutMillis ?? 1e4;
473
+ this.databaseAdminPool = new PgAdminPool(
474
+ () => createAdminClient(PG_DATABASE_ADMIN_OVERRIDES),
475
+ idleTimeoutMillis
476
+ );
477
+ this.schemaAdminPool = new PgAdminPool(
478
+ () => createAdminClient(PG_SCHEMA_ADMIN_OVERRIDES),
479
+ idleTimeoutMillis
480
+ );
481
+ }
482
+ async ensureDatabase(databaseName) {
483
+ let promise = this.databaseEnsureCache.get(databaseName);
484
+ if (!promise) {
485
+ promise = this.customEnsureDatabaseExists ? this.customEnsureDatabaseExists(this.config, databaseName) : retryPgAdminOperation(
486
+ () => ddlLimiter(
487
+ () => this.runAdminOperation(
488
+ this.databaseAdminPool,
489
+ (admin) => ensurePgDatabase(admin, databaseName)
490
+ )
491
+ )
492
+ );
493
+ this.databaseEnsureCache.set(databaseName, promise);
494
+ }
495
+ try {
496
+ await promise;
497
+ } catch (error) {
498
+ if (this.databaseEnsureCache.get(databaseName) === promise) {
499
+ this.databaseEnsureCache.delete(databaseName);
500
+ }
501
+ throw error;
502
+ }
503
+ }
504
+ async runAdminOperation(pool, operation) {
505
+ try {
506
+ return await pool.run(operation);
507
+ } catch (error) {
508
+ await pool.invalidate().catch(() => {
509
+ });
510
+ throw error;
511
+ }
512
+ }
513
+ async shutdown() {
514
+ const results = await Promise.allSettled([
515
+ this.databaseAdminPool.shutdown(),
516
+ this.schemaAdminPool.shutdown()
517
+ ]);
518
+ const errors = results.filter(
519
+ (result) => result.status === "rejected"
520
+ ).map((result) => result.reason);
521
+ if (errors.length === 1) {
522
+ throw errors[0];
523
+ }
524
+ if (errors.length > 1) {
525
+ throw new AggregateError(
526
+ errors,
527
+ "Failed to shut down PostgreSQL admin pools"
528
+ );
529
+ }
381
530
  }
382
531
  async getClient(pluginId, _deps) {
383
532
  const pluginDbConfig = computePgPluginConfig(
@@ -387,7 +536,7 @@ class PgConnector {
387
536
  );
388
537
  if (pluginDbConfig.databaseName && pluginDbConfig.ensureExists) {
389
538
  try {
390
- await ensurePgDatabaseExists(this.config, pluginDbConfig.databaseName);
539
+ await this.ensureDatabase(pluginDbConfig.databaseName);
391
540
  } catch (error) {
392
541
  throw new Error(
393
542
  `Failed to connect to the database to make sure that '${pluginDbConfig.databaseName}' exists, ${error}`
@@ -397,7 +546,16 @@ class PgConnector {
397
546
  if (pluginDbConfig.pluginDivisionMode === "schema") {
398
547
  if (pluginDbConfig.ensureSchemaExists || pluginDbConfig.ensureExists) {
399
548
  try {
400
- await ensurePgSchemaExists(this.config, pluginId);
549
+ await ddlLimiter(
550
+ () => this.runAdminOperation(
551
+ this.schemaAdminPool,
552
+ (admin) => ensurePgSchema(
553
+ admin,
554
+ this.config.getOptionalString("role"),
555
+ pluginId
556
+ )
557
+ )
558
+ );
401
559
  } catch (error) {
402
560
  throw new Error(
403
561
  `Failed to connect to the database to make sure that schema for plugin '${pluginId}' exists, ${error}`
@@ -416,6 +574,7 @@ class PgConnector {
416
574
  }
417
575
  }
418
576
 
577
+ exports.PgAdminPool = PgAdminPool;
419
578
  exports.PgConnector = PgConnector;
420
579
  exports.buildAzurePgConfig = buildAzurePgConfig;
421
580
  exports.buildCloudSqlConfig = buildCloudSqlConfig;
@@ -423,8 +582,6 @@ exports.buildPgDatabaseConfig = buildPgDatabaseConfig;
423
582
  exports.buildRdsPgConfig = buildRdsPgConfig;
424
583
  exports.computePgPluginConfig = computePgPluginConfig;
425
584
  exports.createPgDatabaseClient = createPgDatabaseClient;
426
- exports.ensurePgDatabaseExists = ensurePgDatabaseExists;
427
- exports.ensurePgSchemaExists = ensurePgSchemaExists;
428
585
  exports.getPgConnectionConfig = getPgConnectionConfig;
429
586
  exports.parsePgConnectionString = parsePgConnectionString;
430
587
  //# sourceMappingURL=postgres.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"postgres.cjs.js","sources":["../../../../src/entrypoints/database/connectors/postgres.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LifecycleService, LoggerService } from '@backstage/backend-plugin-api';\nimport {\n Config,\n ConfigReader,\n readDurationFromConfig,\n} from '@backstage/config';\nimport { ForwardedError } from '@backstage/errors';\nimport {\n durationToMilliseconds,\n HumanDuration,\n JsonObject,\n} from '@backstage/types';\nimport knexFactory, { Knex } from 'knex';\nimport { merge, omit } from 'lodash';\nimport limiterFactory from 'p-limit';\nimport { Client } from 'pg';\nimport { Connector } from '../types';\nimport { mergeDatabaseConfig } from './mergeDatabaseConfig';\nimport format from 'pg-format';\nimport { TokenCredential } from '@azure/identity';\n\n// Limits the number of concurrent DDL operations to 1\nconst ddlLimiter = limiterFactory(1);\n\n/**\n * Creates a knex postgres database connection\n *\n * @param dbConfig - The database config\n * @param overrides - Additional options to merge with the config\n */\nexport async function createPgDatabaseClient(\n dbConfig: Config,\n overrides?: Knex.Config,\n) {\n const knexConfig = await buildPgDatabaseConfig(dbConfig, overrides);\n const database = knexFactory(knexConfig);\n\n const role = dbConfig.getOptionalString('role');\n\n if (role) {\n database.client.pool.on(\n 'createSuccess',\n async (_event: number, pgClient: Client) => {\n const query = format('SET ROLE %I', role);\n await pgClient.query(query);\n },\n );\n }\n return database;\n}\n\n/**\n * Builds a knex postgres database connection\n *\n * @param dbConfig - The database config\n * @param overrides - Additional options to merge with the config\n */\nexport async function buildPgDatabaseConfig(\n dbConfig: Config,\n overrides?: Knex.Config,\n) {\n const config = mergeDatabaseConfig(\n dbConfig.get(),\n {\n connection: getPgConnectionConfig(dbConfig, !!overrides),\n useNullAsDefault: true,\n },\n overrides,\n );\n const mergedConfigReader = new ConfigReader(config);\n\n if (config.connection.type === 'default' || !config.connection.type) {\n const connectionValue = config.connection;\n const sanitizedConnection =\n typeof connectionValue === 'string' || connectionValue instanceof String\n ? connectionValue\n : // connection is an object, omit config-only props\n omit(connectionValue as Record<string, unknown>, [\n 'type',\n 'instance',\n 'tokenCredential',\n ]);\n\n return {\n ...config,\n connection: sanitizedConnection,\n };\n }\n\n switch (config.connection.type) {\n case 'azure':\n return buildAzurePgConfig(mergedConfigReader);\n case 'cloudsql':\n return buildCloudSqlConfig(mergedConfigReader);\n case 'rds':\n return buildRdsPgConfig(mergedConfigReader);\n default:\n throw new Error(`Unknown connection type: ${config.connection.type}`);\n }\n}\n\n/* Note: the following type definition is intentionally duplicated in\n * /packages/backend-defaults/config.d.ts so the clientSecret property\n * can be annotated with \"@visibility secret\" there.\n */\nexport type AzureTokenCredentialConfig = {\n /**\n * How early before an access token expires to refresh it with a new one.\n * Defaults to 5 minutes\n * Supported formats:\n * - A string in the format of '1d', '2 seconds' etc. as supported by the `ms`\n * library.\n * - A standard ISO formatted duration string, e.g. 'P2DT6H' or 'PT1M'.\n * - An object with individual units (in plural) as keys, e.g. `{ days: 2, hours: 6 }`.\n */\n tokenRenewableOffsetTime?: string | HumanDuration;\n /**\n * The client ID of a user-assigned managed identity.\n * If not provided, the system-assigned managed identity is used.\n */\n clientId?: string;\n clientSecret?: string;\n tenantId?: string;\n};\n\nexport async function buildAzurePgConfig(config: Config): Promise<Knex.Config> {\n const {\n DefaultAzureCredential,\n ManagedIdentityCredential,\n ClientSecretCredential,\n } = require('@azure/identity');\n\n const tokenConfig = config.getOptionalConfig('connection.tokenCredential');\n\n const tokenRenewableOffsetTime = durationToMilliseconds(\n tokenConfig?.has('tokenRenewableOffsetTime')\n ? readDurationFromConfig(tokenConfig, { key: 'tokenRenewableOffsetTime' })\n : { minutes: 5 },\n );\n\n const clientId = tokenConfig?.getOptionalString('clientId');\n const tenantId = tokenConfig?.getOptionalString('tenantId');\n const clientSecret = tokenConfig?.getOptionalString('clientSecret');\n let credential: TokenCredential;\n\n /**\n * Determine which TokenCredential to use based on provided config\n * 1. If clientId, tenantId and clientSecret are provided, use ClientSecretCredential\n * 2. If only clientId is provided, use ManagedIdentityCredential with user-assigned identity\n * 3. Otherwise, use DefaultAzureCredential (which may use system-assigned identity among other methods)\n */\n if (clientId && tenantId && clientSecret) {\n credential = new ClientSecretCredential(tenantId, clientId, clientSecret);\n } else if (clientId) {\n credential = new ManagedIdentityCredential(clientId);\n } else {\n credential = new DefaultAzureCredential();\n }\n\n const rawConfig = config.get() as Record<string, unknown>;\n\n const normalized = normalizeConnection(rawConfig.connection as any);\n const sanitizedConnection = omit(normalized, [\n 'type',\n 'instance',\n 'tokenCredential',\n ]) as Partial<Knex.StaticConnectionConfig>;\n\n async function getConnectionConfig() {\n const token = await credential.getToken(\n 'https://ossrdbms-aad.database.windows.net/.default',\n );\n\n if (!token) {\n throw new Error(\n 'Failed to acquire Azure access token for database authentication',\n );\n }\n\n const connectionConfig = {\n ...sanitizedConnection,\n password: token.token,\n expirationChecker: () =>\n /* return true if the token is within the renewable offset time */\n token.expiresOnTimestamp - tokenRenewableOffsetTime <= Date.now(),\n };\n\n return connectionConfig;\n }\n\n return {\n ...(rawConfig as Record<string, unknown>),\n connection: getConnectionConfig,\n };\n}\n\nexport async function buildCloudSqlConfig(\n config: Config,\n): Promise<Knex.Config> {\n const client = config.getOptionalString('client');\n\n if (client && client !== 'pg') {\n throw new Error('Cloud SQL only supports the pg client');\n }\n\n const instance = config.getOptionalString('connection.instance');\n if (!instance) {\n throw new Error('Missing instance connection name for Cloud SQL');\n }\n\n const {\n Connector: CloudSqlConnector,\n IpAddressTypes,\n AuthTypes,\n } = require('@google-cloud/cloud-sql-connector') as typeof import('@google-cloud/cloud-sql-connector');\n const connector = new CloudSqlConnector();\n\n type IpType = (typeof IpAddressTypes)[keyof typeof IpAddressTypes];\n const ipTypeRaw = config.getOptionalString('connection.ipAddressType');\n\n let ipType: IpType | undefined;\n if (ipTypeRaw !== undefined) {\n if (\n !(Object.values(IpAddressTypes) as Array<string | number>).includes(\n ipTypeRaw as any,\n )\n ) {\n throw new Error(\n `Invalid connection.ipAddressType: ${ipTypeRaw}; valid values: ${Object.values(\n IpAddressTypes,\n ).join(', ')}`,\n );\n }\n ipType = ipTypeRaw as unknown as IpType;\n }\n\n const clientOpts = await connector.getOptions({\n instanceConnectionName: instance,\n ipType: ipType ?? IpAddressTypes.PUBLIC,\n authType: AuthTypes.IAM,\n });\n\n const rawConfig = config.get() as Record<string, unknown>;\n const normalized = normalizeConnection(rawConfig.connection as any);\n const sanitizedConnection = omit(normalized, [\n 'type',\n 'instance',\n ]) as Partial<Knex.StaticConnectionConfig>;\n\n return {\n ...(rawConfig as Record<string, unknown>),\n client: 'pg',\n connection: {\n ...sanitizedConnection,\n ...clientOpts,\n },\n };\n}\n\nexport async function buildRdsPgConfig(config: Config): Promise<Knex.Config> {\n const { Signer } =\n require('@aws-sdk/rds-signer') as typeof import('@aws-sdk/rds-signer');\n\n let hostname: string;\n let port: number;\n let username: string;\n try {\n hostname = config.getString('connection.host');\n port = config.getNumber('connection.port');\n username = config.getString('connection.user');\n } catch (err) {\n throw new ForwardedError(\n 'AWS RDS IAM auth: missing required database connection config — make sure connection.host, connection.port, and connection.user are set and any environment variables they reference are set',\n err,\n );\n }\n const region =\n config.getOptionalString('connection.region') ??\n process.env.AWS_REGION ??\n process.env.AWS_DEFAULT_REGION;\n if (!region) {\n throw new Error(\n 'Missing region for AWS RDS IAM auth: set connection.region or the AWS_REGION environment variable',\n );\n }\n\n const rawConfig = config.get() as Record<string, unknown>;\n const sanitizedConnection = omit(\n config.get('connection') as Record<string, unknown>,\n ['type', 'region'],\n ) as Partial<Knex.StaticConnectionConfig>;\n\n const signer = new Signer({ hostname, port, username, region });\n\n // RDS IAM auth tokens are valid for 15 minutes. Renew 1 minute early so\n // that pooled connections are refreshed before the token actually expires.\n const tokenTtlMs = 15 * 60 * 1000;\n const renewalOffsetMs = 60 * 1000;\n\n async function getConnectionConfig() {\n try {\n const password = await signer.getAuthToken();\n const tokenExpiration = Date.now() + tokenTtlMs - renewalOffsetMs;\n return {\n ...sanitizedConnection,\n password,\n expirationChecker: () => tokenExpiration <= Date.now(),\n };\n } catch (err) {\n throw new ForwardedError(\n `AWS RDS IAM auth token acquisition failed for ${username}@${hostname}:${port}`,\n err,\n );\n }\n }\n\n return {\n ...(rawConfig as Record<string, unknown>),\n connection: getConnectionConfig,\n };\n}\n\n/**\n * Gets the postgres connection config\n *\n * @param dbConfig - The database config\n * @param parseConnectionString - Flag to explicitly control connection string parsing\n */\nexport function getPgConnectionConfig(\n dbConfig: Config,\n parseConnectionString?: boolean,\n): Knex.PgConnectionConfig | string {\n const connection = dbConfig.get('connection') as any;\n const isConnectionString =\n typeof connection === 'string' || connection instanceof String;\n const autoParse = typeof parseConnectionString !== 'boolean';\n\n const shouldParseConnectionString = autoParse\n ? isConnectionString\n : parseConnectionString && isConnectionString;\n\n return shouldParseConnectionString\n ? parsePgConnectionString(connection as string)\n : connection;\n}\n\n/**\n * Parses a connection string using pg-connection-string\n *\n * @param connectionString - The postgres connection string\n */\nexport function parsePgConnectionString(connectionString: string) {\n const parse = requirePgConnectionString();\n return parse(connectionString);\n}\n\nfunction requirePgConnectionString() {\n try {\n return require('pg-connection-string').parse;\n } catch (e) {\n throw new ForwardedError(\"Postgres: Install 'pg-connection-string'\", e);\n }\n}\n\n/**\n * Creates the missing Postgres database if it does not exist\n *\n * @param dbConfig - The database config\n * @param databases - The name of the databases to create\n */\nexport async function ensurePgDatabaseExists(\n dbConfig: Config,\n ...databases: Array<string>\n) {\n // Implements a single existence check attempt\n const ensureDatabase = async (database: string) => {\n const admin = await createPgDatabaseClient(dbConfig, {\n connection: {\n database: 'postgres',\n },\n pool: {\n min: 0,\n max: 1,\n acquireTimeoutMillis: 10000,\n },\n });\n\n try {\n const result = await admin\n .from('pg_database')\n .where('datname', database)\n .count<Record<string, { count: string }>>();\n\n if (parseInt(result[0].count, 10) > 0) {\n return;\n }\n\n await admin.raw(`CREATE DATABASE ??`, [database]);\n } finally {\n await admin.destroy();\n }\n };\n\n await Promise.all(\n databases.map(async database => {\n // For initial setup we use a smaller timeout but several retries. Given that this\n // is a separate connection pool we should never really run into issues with connection\n // acquisition timeouts, but we do anyway. This might be a bug in knex or some other dependency.\n const maxAttempts = 3;\n for (let attempt = 1; ; attempt++) {\n try {\n return await ddlLimiter(() => ensureDatabase(database));\n } catch (err) {\n if (attempt >= maxAttempts) {\n throw err;\n } else {\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n }\n }\n }),\n );\n}\n\n/**\n * Creates the missing Postgres schema if it does not exist\n *\n * @param dbConfig - The database config\n * @param schemas - The name of the schemas to create\n */\nexport async function ensurePgSchemaExists(\n dbConfig: Config,\n ...schemas: Array<string>\n): Promise<void> {\n const admin = await createPgDatabaseClient(dbConfig);\n const role = dbConfig.getOptionalString('role');\n\n try {\n const ensureSchema = async (database: string) => {\n if (role) {\n await admin.raw(`CREATE SCHEMA IF NOT EXISTS ?? AUTHORIZATION ??`, [\n database,\n role,\n ]);\n } else {\n await admin.raw(`CREATE SCHEMA IF NOT EXISTS ??`, [database]);\n }\n };\n\n await Promise.all(\n schemas.map(database => ddlLimiter(() => ensureSchema(database))),\n );\n } finally {\n await admin.destroy();\n }\n}\n\n/**\n * Drops the Postgres databases.\n *\n * @param dbConfig - The database config\n * @param databases - The name of the databases to drop\n */\nexport async function dropPgDatabase(\n dbConfig: Config,\n ...databases: Array<string>\n) {\n const admin = await createPgDatabaseClient(dbConfig);\n try {\n await Promise.all(\n databases.map(async database => {\n await ddlLimiter(() => admin.raw(`DROP DATABASE ??`, [database]));\n }),\n );\n } finally {\n await admin.destroy();\n }\n}\n\n/**\n * Provides a config lookup path for a plugin's config block.\n */\nfunction pluginPath(pluginId: string): string {\n return `plugin.${pluginId}`;\n}\n\nfunction normalizeConnection(\n connection: Knex.StaticConnectionConfig | JsonObject | string | undefined,\n): Partial<Knex.StaticConnectionConfig> {\n if (typeof connection === 'undefined' || connection === null) {\n return {};\n }\n\n return typeof connection === 'string' || connection instanceof String\n ? parsePgConnectionString(connection as string)\n : connection;\n}\n\n/**\n * The computed configuration for a plugin's postgres database connection.\n */\nexport interface PgPluginDatabaseConfig {\n /** The database client type (e.g. 'pg') */\n client: string;\n /** Whether the client type was overridden at the plugin level */\n clientOverridden: boolean;\n /** The optional role to set on connections */\n role: string | undefined;\n /** Additional knex configuration merged from base and plugin config */\n additionalKnexConfig: JsonObject | undefined;\n /** Whether to ensure the database exists */\n ensureExists: boolean;\n /** Whether to ensure the schema exists */\n ensureSchemaExists: boolean;\n /** The plugin division mode ('database' or 'schema') */\n pluginDivisionMode: string;\n /** The connection configuration */\n connection: Knex.PgConnectionConfig;\n /** The database name, if any */\n databaseName: string | undefined;\n /** Database client overrides including schema overrides if applicable */\n databaseClientOverrides: Knex.Config;\n /** The full knex config for the plugin */\n knexConfig: Knex.Config;\n}\n\n/**\n * Computes all postgres database configuration for a plugin from the provided config.\n *\n * @param config - The database config object\n * @param pluginId - The plugin ID to compute config for\n * @param prefix - The database name prefix (e.g. 'backstage_plugin_')\n * @returns All computed configuration values for the plugin\n */\nexport function computePgPluginConfig(\n config: Config,\n pluginId: string,\n prefix: string,\n): PgPluginDatabaseConfig {\n // Client type\n const pluginClient = config.getOptionalString(\n `${pluginPath(pluginId)}.client`,\n );\n const baseClient = config.getString('client');\n const client = pluginClient ?? baseClient;\n const clientOverridden = client !== baseClient;\n\n // Role\n const role =\n config.getOptionalString(`${pluginPath(pluginId)}.role`) ??\n config.getOptionalString('role');\n\n // Additional knex config\n const pluginKnexConfig = config\n .getOptionalConfig(`${pluginPath(pluginId)}.knexConfig`)\n ?.get<JsonObject>();\n const baseKnexConfig = config\n .getOptionalConfig('knexConfig')\n ?.get<JsonObject>();\n const additionalKnexConfig = merge(baseKnexConfig, pluginKnexConfig);\n\n // Ensure exists flags\n const baseEnsureExists = config.getOptionalBoolean('ensureExists') ?? true;\n const ensureExists =\n config.getOptionalBoolean(`${pluginPath(pluginId)}.ensureExists`) ??\n baseEnsureExists;\n\n const baseEnsureSchemaExists =\n config.getOptionalBoolean('ensureSchemaExists') ?? false;\n const ensureSchemaExists =\n config.getOptionalBoolean(\n `${pluginPath(pluginId)}.getEnsureSchemaExistsConfig`,\n ) ?? baseEnsureSchemaExists;\n\n // Plugin division mode\n const pluginDivisionMode =\n config.getOptionalString('pluginDivisionMode') ?? 'database';\n\n // Connection config\n let baseConnection = normalizeConnection(config.get('connection'));\n\n // Databases cannot be shared unless the `pluginDivisionMode` is set to `schema`.\n // The `database` property from the base connection is omitted unless\n // `pluginDivisionMode` is set to `schema`.\n if (pluginDivisionMode !== 'schema') {\n baseConnection = omit(baseConnection, 'database');\n }\n\n // Get and normalize optional plugin specific database connection\n const pluginConnection = normalizeConnection(\n config.getOptional(`${pluginPath(pluginId)}.connection`),\n );\n\n (\n baseConnection as Knex.PgConnectionConfig\n ).application_name ||= `backstage_plugin_${pluginId}`;\n\n const connection = {\n // Include base connection if client type has not been overridden\n ...(clientOverridden ? {} : baseConnection),\n ...pluginConnection,\n } as Knex.PgConnectionConfig;\n\n // Database name\n const connectionDatabaseName = (connection as Knex.ConnectionConfig)\n ?.database;\n let databaseName: string | undefined;\n\n if (pluginDivisionMode === 'schema') {\n // `pluginDivisionMode` as `schema` should use overridden databaseName if supplied\n // or fallback to default knex database\n databaseName = connectionDatabaseName;\n } else {\n // All other supported databases should fallback to an auto-prefixed name\n databaseName = connectionDatabaseName ?? `${prefix}${pluginId}`;\n }\n\n // Database client overrides\n let databaseClientOverrides: Knex.Config = {};\n if (databaseName) {\n databaseClientOverrides = { connection: { database: databaseName } };\n }\n if (pluginDivisionMode === 'schema') {\n databaseClientOverrides = mergeDatabaseConfig({}, databaseClientOverrides, {\n searchPath: [pluginId],\n });\n }\n\n // Full knex config for plugin\n const knexConfig: Knex.Config = {\n ...additionalKnexConfig,\n client,\n connection,\n ...(role && { role }),\n };\n\n return {\n client,\n clientOverridden,\n role,\n additionalKnexConfig,\n ensureExists,\n ensureSchemaExists,\n pluginDivisionMode,\n connection,\n databaseName,\n databaseClientOverrides,\n knexConfig,\n };\n}\n\nexport class PgConnector implements Connector {\n private readonly config: Config;\n private readonly prefix: string;\n\n constructor(config: Config, prefix: string) {\n this.config = config;\n this.prefix = prefix;\n }\n\n async getClient(\n pluginId: string,\n _deps: {\n logger: LoggerService;\n lifecycle: LifecycleService;\n },\n ): Promise<Knex> {\n const pluginDbConfig = computePgPluginConfig(\n this.config,\n pluginId,\n this.prefix,\n );\n\n if (pluginDbConfig.databaseName && pluginDbConfig.ensureExists) {\n try {\n await ensurePgDatabaseExists(this.config, pluginDbConfig.databaseName);\n } catch (error) {\n throw new Error(\n `Failed to connect to the database to make sure that '${pluginDbConfig.databaseName}' exists, ${error}`,\n );\n }\n }\n\n if (pluginDbConfig.pluginDivisionMode === 'schema') {\n if (pluginDbConfig.ensureSchemaExists || pluginDbConfig.ensureExists) {\n try {\n await ensurePgSchemaExists(this.config, pluginId);\n } catch (error) {\n throw new Error(\n `Failed to connect to the database to make sure that schema for plugin '${pluginId}' exists, ${error}`,\n );\n }\n }\n }\n\n const client = createPgDatabaseClient(\n this.config,\n mergeDatabaseConfig(\n pluginDbConfig.knexConfig,\n pluginDbConfig.databaseClientOverrides,\n ),\n );\n\n return client;\n }\n}\n"],"names":["limiterFactory","knexFactory","format","config","mergeDatabaseConfig","ConfigReader","omit","durationToMilliseconds","readDurationFromConfig","ForwardedError","merge"],"mappings":"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"}
1
+ {"version":3,"file":"postgres.cjs.js","sources":["../../../../src/entrypoints/database/connectors/postgres.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LifecycleService, LoggerService } from '@backstage/backend-plugin-api';\nimport {\n Config,\n ConfigReader,\n readDurationFromConfig,\n} from '@backstage/config';\nimport { ForwardedError } from '@backstage/errors';\nimport {\n durationToMilliseconds,\n HumanDuration,\n JsonObject,\n} from '@backstage/types';\nimport knexFactory, { Knex } from 'knex';\nimport { merge, omit } from 'lodash';\nimport limiterFactory from 'p-limit';\nimport { Client } from 'pg';\nimport { Connector } from '../types';\nimport { mergeDatabaseConfig } from './mergeDatabaseConfig';\nimport format from 'pg-format';\nimport { TokenCredential } from '@azure/identity';\n\n// Limits the number of concurrent DDL operations to 1\nconst ddlLimiter = limiterFactory(1);\n\nexport class PgAdminPool {\n private client?: Promise<Knex>;\n private destruction?: Promise<void>;\n private readonly destructionErrors: unknown[] = [];\n private idleTimer?: NodeJS.Timeout;\n private readonly operations = new Set<Promise<unknown>>();\n private isShutdown = false;\n\n constructor(\n private readonly createClient: () => Promise<Knex>,\n private readonly idleTimeoutMillis: number,\n ) {}\n\n async run<T>(operation: (client: Knex) => Promise<T> | T): Promise<T> {\n if (this.isShutdown) {\n throw new Error('PostgreSQL admin pool is shut down');\n }\n\n clearTimeout(this.idleTimer);\n this.idleTimer = undefined;\n\n const operationPromise = this.runOperation(operation);\n this.operations.add(operationPromise);\n try {\n return await operationPromise;\n } finally {\n this.operations.delete(operationPromise);\n this.scheduleIdleDestroy();\n }\n }\n\n async shutdown(): Promise<void> {\n this.isShutdown = true;\n clearTimeout(this.idleTimer);\n this.idleTimer = undefined;\n\n await Promise.allSettled(this.operations);\n await this.destroyClient().catch(() => {});\n if (this.destructionErrors.length > 0) {\n throw new AggregateError(\n this.destructionErrors,\n 'Failed to destroy PostgreSQL admin pool clients',\n );\n }\n }\n\n async invalidate(): Promise<void> {\n clearTimeout(this.idleTimer);\n this.idleTimer = undefined;\n\n await Promise.allSettled(this.operations);\n await this.destroyClient();\n }\n\n private async runOperation<T>(\n operation: (client: Knex) => Promise<T> | T,\n ): Promise<T> {\n if (this.destruction) {\n await this.destruction;\n }\n if (this.isShutdown) {\n throw new Error('PostgreSQL admin pool is shut down');\n }\n\n let clientPromise = this.client;\n if (!clientPromise) {\n clientPromise = this.createClient();\n this.client = clientPromise;\n void clientPromise.catch(() => {\n if (this.client === clientPromise) {\n this.client = undefined;\n }\n });\n }\n return operation(await clientPromise);\n }\n\n private scheduleIdleDestroy(): void {\n if (this.isShutdown || this.operations.size > 0) {\n return;\n }\n\n const timer = setTimeout(() => {\n if (this.idleTimer === timer) {\n this.idleTimer = undefined;\n void this.destroyClient().catch(() => {});\n }\n }, this.idleTimeoutMillis);\n timer.unref();\n this.idleTimer = timer;\n }\n\n private destroyClient(): Promise<void> {\n if (this.destruction) {\n return this.destruction;\n }\n\n const clientPromise = this.client;\n this.client = undefined;\n if (!clientPromise) {\n return Promise.resolve();\n }\n\n const destruction = clientPromise.then(\n client => client.destroy(),\n () => undefined,\n );\n this.destruction = destruction;\n void destruction.then(\n () => {\n if (this.destruction === destruction) {\n this.destruction = undefined;\n }\n },\n error => {\n if (this.destruction === destruction) {\n this.destruction = undefined;\n this.destructionErrors.push(error);\n }\n },\n );\n return destruction;\n }\n}\n\n/**\n * Creates a knex postgres database connection\n *\n * @param dbConfig - The database config\n * @param overrides - Additional options to merge with the config\n */\nexport async function createPgDatabaseClient(\n dbConfig: Config,\n overrides?: Knex.Config,\n) {\n const knexConfig = await buildPgDatabaseConfig(dbConfig, overrides);\n const database = knexFactory(knexConfig);\n\n const role = dbConfig.getOptionalString('role');\n\n if (role) {\n database.client.pool.on(\n 'createSuccess',\n async (_event: number, pgClient: Client) => {\n const query = format('SET ROLE %I', role);\n await pgClient.query(query);\n },\n );\n }\n return database;\n}\n\n/**\n * Builds a knex postgres database connection\n *\n * @param dbConfig - The database config\n * @param overrides - Additional options to merge with the config\n */\nexport async function buildPgDatabaseConfig(\n dbConfig: Config,\n overrides?: Knex.Config,\n) {\n const config = mergeDatabaseConfig(\n dbConfig.get(),\n {\n connection: getPgConnectionConfig(dbConfig, !!overrides),\n useNullAsDefault: true,\n },\n overrides,\n );\n const mergedConfigReader = new ConfigReader(config);\n\n if (config.connection.type === 'default' || !config.connection.type) {\n const connectionValue = config.connection;\n const sanitizedConnection =\n typeof connectionValue === 'string' || connectionValue instanceof String\n ? connectionValue\n : // connection is an object, omit config-only props\n omit(connectionValue as Record<string, unknown>, [\n 'type',\n 'instance',\n 'tokenCredential',\n ]);\n\n return {\n ...config,\n connection: sanitizedConnection,\n };\n }\n\n switch (config.connection.type) {\n case 'azure':\n return buildAzurePgConfig(mergedConfigReader);\n case 'cloudsql':\n return buildCloudSqlConfig(mergedConfigReader);\n case 'rds':\n return buildRdsPgConfig(mergedConfigReader);\n default:\n throw new Error(`Unknown connection type: ${config.connection.type}`);\n }\n}\n\n/* Note: the following type definition is intentionally duplicated in\n * /packages/backend-defaults/config.d.ts so the clientSecret property\n * can be annotated with \"@visibility secret\" there.\n */\nexport type AzureTokenCredentialConfig = {\n /**\n * How early before an access token expires to refresh it with a new one.\n * Defaults to 5 minutes\n * Supported formats:\n * - A string in the format of '1d', '2 seconds' etc. as supported by the `ms`\n * library.\n * - A standard ISO formatted duration string, e.g. 'P2DT6H' or 'PT1M'.\n * - An object with individual units (in plural) as keys, e.g. `{ days: 2, hours: 6 }`.\n */\n tokenRenewableOffsetTime?: string | HumanDuration;\n /**\n * The client ID of a user-assigned managed identity.\n * If not provided, the system-assigned managed identity is used.\n */\n clientId?: string;\n clientSecret?: string;\n tenantId?: string;\n};\n\nexport async function buildAzurePgConfig(config: Config): Promise<Knex.Config> {\n const {\n DefaultAzureCredential,\n ManagedIdentityCredential,\n ClientSecretCredential,\n } = require('@azure/identity');\n\n const tokenConfig = config.getOptionalConfig('connection.tokenCredential');\n\n const tokenRenewableOffsetTime = durationToMilliseconds(\n tokenConfig?.has('tokenRenewableOffsetTime')\n ? readDurationFromConfig(tokenConfig, { key: 'tokenRenewableOffsetTime' })\n : { minutes: 5 },\n );\n\n const clientId = tokenConfig?.getOptionalString('clientId');\n const tenantId = tokenConfig?.getOptionalString('tenantId');\n const clientSecret = tokenConfig?.getOptionalString('clientSecret');\n let credential: TokenCredential;\n\n /**\n * Determine which TokenCredential to use based on provided config\n * 1. If clientId, tenantId and clientSecret are provided, use ClientSecretCredential\n * 2. If only clientId is provided, use ManagedIdentityCredential with user-assigned identity\n * 3. Otherwise, use DefaultAzureCredential (which may use system-assigned identity among other methods)\n */\n if (clientId && tenantId && clientSecret) {\n credential = new ClientSecretCredential(tenantId, clientId, clientSecret);\n } else if (clientId) {\n credential = new ManagedIdentityCredential(clientId);\n } else {\n credential = new DefaultAzureCredential();\n }\n\n const rawConfig = config.get() as Record<string, unknown>;\n\n const normalized = normalizeConnection(rawConfig.connection as any);\n const sanitizedConnection = omit(normalized, [\n 'type',\n 'instance',\n 'tokenCredential',\n ]) as Partial<Knex.StaticConnectionConfig>;\n\n async function getConnectionConfig() {\n const token = await credential.getToken(\n 'https://ossrdbms-aad.database.windows.net/.default',\n );\n\n if (!token) {\n throw new Error(\n 'Failed to acquire Azure access token for database authentication',\n );\n }\n\n const connectionConfig = {\n ...sanitizedConnection,\n password: token.token,\n expirationChecker: () =>\n /* return true if the token is within the renewable offset time */\n token.expiresOnTimestamp - tokenRenewableOffsetTime <= Date.now(),\n };\n\n return connectionConfig;\n }\n\n return {\n ...(rawConfig as Record<string, unknown>),\n connection: getConnectionConfig,\n };\n}\n\nexport async function buildCloudSqlConfig(\n config: Config,\n): Promise<Knex.Config> {\n const client = config.getOptionalString('client');\n\n if (client && client !== 'pg') {\n throw new Error('Cloud SQL only supports the pg client');\n }\n\n const instance = config.getOptionalString('connection.instance');\n if (!instance) {\n throw new Error('Missing instance connection name for Cloud SQL');\n }\n\n const {\n Connector: CloudSqlConnector,\n IpAddressTypes,\n AuthTypes,\n } = require('@google-cloud/cloud-sql-connector') as typeof import('@google-cloud/cloud-sql-connector');\n const connector = new CloudSqlConnector();\n\n type IpType = (typeof IpAddressTypes)[keyof typeof IpAddressTypes];\n const ipTypeRaw = config.getOptionalString('connection.ipAddressType');\n\n let ipType: IpType | undefined;\n if (ipTypeRaw !== undefined) {\n if (\n !(Object.values(IpAddressTypes) as Array<string | number>).includes(\n ipTypeRaw as any,\n )\n ) {\n throw new Error(\n `Invalid connection.ipAddressType: ${ipTypeRaw}; valid values: ${Object.values(\n IpAddressTypes,\n ).join(', ')}`,\n );\n }\n ipType = ipTypeRaw as unknown as IpType;\n }\n\n const clientOpts = await connector.getOptions({\n instanceConnectionName: instance,\n ipType: ipType ?? IpAddressTypes.PUBLIC,\n authType: AuthTypes.IAM,\n });\n\n const rawConfig = config.get() as Record<string, unknown>;\n const normalized = normalizeConnection(rawConfig.connection as any);\n const sanitizedConnection = omit(normalized, [\n 'type',\n 'instance',\n ]) as Partial<Knex.StaticConnectionConfig>;\n\n return {\n ...(rawConfig as Record<string, unknown>),\n client: 'pg',\n connection: {\n ...sanitizedConnection,\n ...clientOpts,\n },\n };\n}\n\nexport async function buildRdsPgConfig(config: Config): Promise<Knex.Config> {\n const { Signer } =\n require('@aws-sdk/rds-signer') as typeof import('@aws-sdk/rds-signer');\n\n let hostname: string;\n let port: number;\n let username: string;\n try {\n hostname = config.getString('connection.host');\n port = config.getNumber('connection.port');\n username = config.getString('connection.user');\n } catch (err) {\n throw new ForwardedError(\n 'AWS RDS IAM auth: missing required database connection config — make sure connection.host, connection.port, and connection.user are set and any environment variables they reference are set',\n err,\n );\n }\n const region =\n config.getOptionalString('connection.region') ??\n process.env.AWS_REGION ??\n process.env.AWS_DEFAULT_REGION;\n if (!region) {\n throw new Error(\n 'Missing region for AWS RDS IAM auth: set connection.region or the AWS_REGION environment variable',\n );\n }\n\n const rawConfig = config.get() as Record<string, unknown>;\n const sanitizedConnection = omit(\n config.get('connection') as Record<string, unknown>,\n ['type', 'region'],\n ) as Partial<Knex.StaticConnectionConfig>;\n\n const signer = new Signer({ hostname, port, username, region });\n\n // RDS IAM auth tokens are valid for 15 minutes. Renew 1 minute early so\n // that pooled connections are refreshed before the token actually expires.\n const tokenTtlMs = 15 * 60 * 1000;\n const renewalOffsetMs = 60 * 1000;\n\n async function getConnectionConfig() {\n try {\n const password = await signer.getAuthToken();\n const tokenExpiration = Date.now() + tokenTtlMs - renewalOffsetMs;\n return {\n ...sanitizedConnection,\n password,\n expirationChecker: () => tokenExpiration <= Date.now(),\n };\n } catch (err) {\n throw new ForwardedError(\n `AWS RDS IAM auth token acquisition failed for ${username}@${hostname}:${port}`,\n err,\n );\n }\n }\n\n return {\n ...(rawConfig as Record<string, unknown>),\n connection: getConnectionConfig,\n };\n}\n\n/**\n * Gets the postgres connection config\n *\n * @param dbConfig - The database config\n * @param parseConnectionString - Flag to explicitly control connection string parsing\n */\nexport function getPgConnectionConfig(\n dbConfig: Config,\n parseConnectionString?: boolean,\n): Knex.PgConnectionConfig | string {\n const connection = dbConfig.get('connection') as any;\n const isConnectionString =\n typeof connection === 'string' || connection instanceof String;\n const autoParse = typeof parseConnectionString !== 'boolean';\n\n const shouldParseConnectionString = autoParse\n ? isConnectionString\n : parseConnectionString && isConnectionString;\n\n return shouldParseConnectionString\n ? parsePgConnectionString(connection as string)\n : connection;\n}\n\n/**\n * Parses a connection string using pg-connection-string\n *\n * @param connectionString - The postgres connection string\n */\nexport function parsePgConnectionString(connectionString: string) {\n const parse = requirePgConnectionString();\n return parse(connectionString);\n}\n\nfunction requirePgConnectionString() {\n try {\n return require('pg-connection-string').parse;\n } catch (e) {\n throw new ForwardedError(\"Postgres: Install 'pg-connection-string'\", e);\n }\n}\n\nconst PG_DATABASE_ADMIN_OVERRIDES: Knex.Config = {\n connection: { database: 'postgres' },\n pool: { min: 0, max: 1, acquireTimeoutMillis: 10000 },\n};\n\nconst PG_SCHEMA_ADMIN_OVERRIDES: Knex.Config = {\n pool: { min: 0, max: 1, acquireTimeoutMillis: 10000 },\n};\n\n/**\n * Creates the missing Postgres database if it does not exist\n *\n * @param dbConfig - The database config\n * @param databases - The name of the databases to create\n */\nexport async function ensurePgDatabaseExists(\n dbConfig: Config,\n ...databases: Array<string>\n) {\n await Promise.all(\n databases.map(async database => {\n return retryPgAdminOperation(() =>\n ddlLimiter(async () => {\n const admin = await createPgDatabaseClient(\n dbConfig,\n PG_DATABASE_ADMIN_OVERRIDES,\n );\n try {\n await ensurePgDatabase(admin, database);\n } finally {\n await admin.destroy();\n }\n }),\n );\n }),\n );\n}\n\nasync function ensurePgDatabase(admin: Knex, database: string): Promise<void> {\n const result = await admin\n .from('pg_database')\n .where('datname', database)\n .count<Record<string, { count: string }>>();\n\n if (parseInt(result[0].count, 10) === 0) {\n await admin.raw(`CREATE DATABASE ??`, [database]);\n }\n}\n\nasync function retryPgAdminOperation(\n operation: () => Promise<void>,\n): Promise<void> {\n // For initial setup we use a smaller timeout but several retries. Given that this\n // is a separate connection pool we should never really run into issues with connection\n // acquisition timeouts, but we do anyway. This might be a bug in knex or some other dependency.\n const maxAttempts = 3;\n for (let attempt = 1; ; attempt++) {\n try {\n return await operation();\n } catch (error) {\n if (attempt >= maxAttempts) {\n throw error;\n }\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n }\n}\n\nasync function ensurePgSchema(\n admin: Knex,\n role: string | undefined,\n schema: string,\n): Promise<void> {\n if (role) {\n await admin.raw(`CREATE SCHEMA IF NOT EXISTS ?? AUTHORIZATION ??`, [\n schema,\n role,\n ]);\n } else {\n await admin.raw(`CREATE SCHEMA IF NOT EXISTS ??`, [schema]);\n }\n}\n\n/**\n * Creates the missing Postgres schema if it does not exist\n *\n * @param dbConfig - The database config\n * @param schemas - The name of the schemas to create\n */\nexport async function ensurePgSchemaExists(\n dbConfig: Config,\n ...schemas: Array<string>\n): Promise<void> {\n const admin = await createPgDatabaseClient(dbConfig);\n const role = dbConfig.getOptionalString('role');\n\n try {\n await Promise.all(\n schemas.map(schema =>\n ddlLimiter(() => ensurePgSchema(admin, role, schema)),\n ),\n );\n } finally {\n await admin.destroy();\n }\n}\n\n/**\n * Drops the Postgres databases.\n *\n * @param dbConfig - The database config\n * @param databases - The name of the databases to drop\n */\nexport async function dropPgDatabase(\n dbConfig: Config,\n ...databases: Array<string>\n) {\n const admin = await createPgDatabaseClient(dbConfig);\n try {\n await Promise.all(\n databases.map(async database => {\n await ddlLimiter(() => admin.raw(`DROP DATABASE ??`, [database]));\n }),\n );\n } finally {\n await admin.destroy();\n }\n}\n\n/**\n * Provides a config lookup path for a plugin's config block.\n */\nfunction pluginPath(pluginId: string): string {\n return `plugin.${pluginId}`;\n}\n\nfunction normalizeConnection(\n connection: Knex.StaticConnectionConfig | JsonObject | string | undefined,\n): Partial<Knex.StaticConnectionConfig> {\n if (typeof connection === 'undefined' || connection === null) {\n return {};\n }\n\n return typeof connection === 'string' || connection instanceof String\n ? parsePgConnectionString(connection as string)\n : connection;\n}\n\n/**\n * The computed configuration for a plugin's postgres database connection.\n */\nexport interface PgPluginDatabaseConfig {\n /** The database client type (e.g. 'pg') */\n client: string;\n /** Whether the client type was overridden at the plugin level */\n clientOverridden: boolean;\n /** The optional role to set on connections */\n role: string | undefined;\n /** Additional knex configuration merged from base and plugin config */\n additionalKnexConfig: JsonObject | undefined;\n /** Whether to ensure the database exists */\n ensureExists: boolean;\n /** Whether to ensure the schema exists */\n ensureSchemaExists: boolean;\n /** The plugin division mode ('database' or 'schema') */\n pluginDivisionMode: string;\n /** The connection configuration */\n connection: Knex.PgConnectionConfig;\n /** The database name, if any */\n databaseName: string | undefined;\n /** Database client overrides including schema overrides if applicable */\n databaseClientOverrides: Knex.Config;\n /** The full knex config for the plugin */\n knexConfig: Knex.Config;\n}\n\n/**\n * Computes all postgres database configuration for a plugin from the provided config.\n *\n * @param config - The database config object\n * @param pluginId - The plugin ID to compute config for\n * @param prefix - The database name prefix (e.g. 'backstage_plugin_')\n * @returns All computed configuration values for the plugin\n */\nexport function computePgPluginConfig(\n config: Config,\n pluginId: string,\n prefix: string,\n): PgPluginDatabaseConfig {\n // Client type\n const pluginClient = config.getOptionalString(\n `${pluginPath(pluginId)}.client`,\n );\n const baseClient = config.getString('client');\n const client = pluginClient ?? baseClient;\n const clientOverridden = client !== baseClient;\n\n // Role\n const role =\n config.getOptionalString(`${pluginPath(pluginId)}.role`) ??\n config.getOptionalString('role');\n\n // Additional knex config\n const pluginKnexConfig = config\n .getOptionalConfig(`${pluginPath(pluginId)}.knexConfig`)\n ?.get<JsonObject>();\n const baseKnexConfig = config\n .getOptionalConfig('knexConfig')\n ?.get<JsonObject>();\n const additionalKnexConfig = merge(baseKnexConfig, pluginKnexConfig);\n\n // Ensure exists flags\n const baseEnsureExists = config.getOptionalBoolean('ensureExists') ?? true;\n const ensureExists =\n config.getOptionalBoolean(`${pluginPath(pluginId)}.ensureExists`) ??\n baseEnsureExists;\n\n const baseEnsureSchemaExists =\n config.getOptionalBoolean('ensureSchemaExists') ?? false;\n const ensureSchemaExists =\n config.getOptionalBoolean(\n `${pluginPath(pluginId)}.getEnsureSchemaExistsConfig`,\n ) ?? baseEnsureSchemaExists;\n\n // Plugin division mode\n const pluginDivisionMode =\n config.getOptionalString('pluginDivisionMode') ?? 'database';\n\n // Connection config\n let baseConnection = normalizeConnection(config.get('connection'));\n\n // Databases cannot be shared unless the `pluginDivisionMode` is set to `schema`.\n // The `database` property from the base connection is omitted unless\n // `pluginDivisionMode` is set to `schema`.\n if (pluginDivisionMode !== 'schema') {\n baseConnection = omit(baseConnection, 'database');\n }\n\n // Get and normalize optional plugin specific database connection\n const pluginConnection = normalizeConnection(\n config.getOptional(`${pluginPath(pluginId)}.connection`),\n );\n\n (\n baseConnection as Knex.PgConnectionConfig\n ).application_name ||= `backstage_plugin_${pluginId}`;\n\n const connection = {\n // Include base connection if client type has not been overridden\n ...(clientOverridden ? {} : baseConnection),\n ...pluginConnection,\n } as Knex.PgConnectionConfig;\n\n // Database name\n const connectionDatabaseName = (connection as Knex.ConnectionConfig)\n ?.database;\n let databaseName: string | undefined;\n\n if (pluginDivisionMode === 'schema') {\n // `pluginDivisionMode` as `schema` should use overridden databaseName if supplied\n // or fallback to default knex database\n databaseName = connectionDatabaseName;\n } else {\n // All other supported databases should fallback to an auto-prefixed name\n databaseName = connectionDatabaseName ?? `${prefix}${pluginId}`;\n }\n\n // Database client overrides\n let databaseClientOverrides: Knex.Config = {};\n if (databaseName) {\n databaseClientOverrides = { connection: { database: databaseName } };\n }\n if (pluginDivisionMode === 'schema') {\n databaseClientOverrides = mergeDatabaseConfig({}, databaseClientOverrides, {\n searchPath: [pluginId],\n });\n }\n\n // Full knex config for plugin\n const knexConfig: Knex.Config = {\n ...additionalKnexConfig,\n client,\n connection,\n ...(role && { role }),\n };\n\n return {\n client,\n clientOverridden,\n role,\n additionalKnexConfig,\n ensureExists,\n ensureSchemaExists,\n pluginDivisionMode,\n connection,\n databaseName,\n databaseClientOverrides,\n knexConfig,\n };\n}\n\nexport class PgConnector implements Connector {\n private readonly config: Config;\n private readonly prefix: string;\n private readonly databaseEnsureCache = new Map<string, Promise<void>>();\n private readonly customEnsureDatabaseExists?: typeof ensurePgDatabaseExists;\n private readonly databaseAdminPool: PgAdminPool;\n private readonly schemaAdminPool: PgAdminPool;\n\n constructor(\n config: Config,\n prefix: string,\n options: {\n ensureDatabaseExists?: typeof ensurePgDatabaseExists;\n createAdminClient?: (overrides: Knex.Config) => Promise<Knex>;\n adminPoolIdleTimeoutMillis?: number;\n } = {},\n ) {\n this.config = config;\n this.prefix = prefix;\n this.customEnsureDatabaseExists = options.ensureDatabaseExists;\n\n const createAdminClient =\n options.createAdminClient ??\n ((overrides: Knex.Config) =>\n createPgDatabaseClient(this.config, overrides));\n const idleTimeoutMillis = options.adminPoolIdleTimeoutMillis ?? 10_000;\n this.databaseAdminPool = new PgAdminPool(\n () => createAdminClient(PG_DATABASE_ADMIN_OVERRIDES),\n idleTimeoutMillis,\n );\n this.schemaAdminPool = new PgAdminPool(\n () => createAdminClient(PG_SCHEMA_ADMIN_OVERRIDES),\n idleTimeoutMillis,\n );\n }\n\n private async ensureDatabase(databaseName: string): Promise<void> {\n let promise = this.databaseEnsureCache.get(databaseName);\n if (!promise) {\n promise = this.customEnsureDatabaseExists\n ? this.customEnsureDatabaseExists(this.config, databaseName)\n : retryPgAdminOperation(() =>\n ddlLimiter(() =>\n this.runAdminOperation(this.databaseAdminPool, admin =>\n ensurePgDatabase(admin, databaseName),\n ),\n ),\n );\n this.databaseEnsureCache.set(databaseName, promise);\n }\n\n try {\n await promise;\n } catch (error) {\n if (this.databaseEnsureCache.get(databaseName) === promise) {\n this.databaseEnsureCache.delete(databaseName);\n }\n throw error;\n }\n }\n\n private async runAdminOperation<T>(\n pool: PgAdminPool,\n operation: (client: Knex) => Promise<T>,\n ): Promise<T> {\n try {\n return await pool.run(operation);\n } catch (error) {\n await pool.invalidate().catch(() => {});\n throw error;\n }\n }\n\n async shutdown(): Promise<void> {\n const results = await Promise.allSettled([\n this.databaseAdminPool.shutdown(),\n this.schemaAdminPool.shutdown(),\n ]);\n const errors = results\n .filter(\n (result): result is PromiseRejectedResult =>\n result.status === 'rejected',\n )\n .map(result => result.reason);\n if (errors.length === 1) {\n throw errors[0];\n }\n if (errors.length > 1) {\n throw new AggregateError(\n errors,\n 'Failed to shut down PostgreSQL admin pools',\n );\n }\n }\n\n async getClient(\n pluginId: string,\n _deps: {\n logger: LoggerService;\n lifecycle: LifecycleService;\n },\n ): Promise<Knex> {\n const pluginDbConfig = computePgPluginConfig(\n this.config,\n pluginId,\n this.prefix,\n );\n\n if (pluginDbConfig.databaseName && pluginDbConfig.ensureExists) {\n try {\n await this.ensureDatabase(pluginDbConfig.databaseName);\n } catch (error) {\n throw new Error(\n `Failed to connect to the database to make sure that '${pluginDbConfig.databaseName}' exists, ${error}`,\n );\n }\n }\n\n if (pluginDbConfig.pluginDivisionMode === 'schema') {\n if (pluginDbConfig.ensureSchemaExists || pluginDbConfig.ensureExists) {\n try {\n await ddlLimiter(() =>\n this.runAdminOperation(this.schemaAdminPool, admin =>\n ensurePgSchema(\n admin,\n this.config.getOptionalString('role'),\n pluginId,\n ),\n ),\n );\n } catch (error) {\n throw new Error(\n `Failed to connect to the database to make sure that schema for plugin '${pluginId}' exists, ${error}`,\n );\n }\n }\n }\n\n const client = createPgDatabaseClient(\n this.config,\n mergeDatabaseConfig(\n pluginDbConfig.knexConfig,\n pluginDbConfig.databaseClientOverrides,\n ),\n );\n\n return client;\n }\n}\n"],"names":["limiterFactory","knexFactory","format","config","mergeDatabaseConfig","ConfigReader","omit","durationToMilliseconds","readDurationFromConfig","ForwardedError","merge"],"mappings":"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"}
@@ -9,6 +9,7 @@ var node_stream = require('node:stream');
9
9
  var ReadUrlResponseFactory = require('./ReadUrlResponseFactory.cjs.js');
10
10
  var posix = require('node:path/posix');
11
11
  var abortController = require('@aws-sdk/abort-controller');
12
+ var util = require('./util.cjs.js');
12
13
 
13
14
  function parseUrl(url, requireGitPath = false) {
14
15
  const parsedUrl = new URL(url);
@@ -235,6 +236,9 @@ class AwsCodeCommitUrlReader {
235
236
  );
236
237
  const responses = [];
237
238
  for (let i = 0; i < allFiles.length; i++) {
239
+ if (util.hasDotPathSegments(String(allFiles[i]))) {
240
+ continue;
241
+ }
238
242
  const getFileCommand = new clientCodecommit.GetFileCommand({
239
243
  repositoryName,
240
244
  filePath: String(allFiles[i]),