@backstage/backend-defaults 0.6.2 → 0.7.0-next.1
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/CHANGELOG.md +40 -5
- package/dist/database.d.ts +1 -1
- package/dist/discovery.d.ts +1 -1
- package/dist/entrypoints/auth/JwksClient.cjs.js.map +1 -1
- package/dist/entrypoints/auth/plugin/keys/StaticConfigPluginKeySource.cjs.js.map +1 -1
- package/dist/entrypoints/database/DatabaseManager.cjs.js +2 -2
- package/dist/entrypoints/database/DatabaseManager.cjs.js.map +1 -1
- package/dist/entrypoints/discovery/HostDiscovery.cjs.js.map +1 -1
- package/dist/entrypoints/httpRouter/httpRouterServiceFactory.cjs.js +28 -3
- package/dist/entrypoints/httpRouter/httpRouterServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/readHelmetOptions.cjs.js.map +1 -1
- package/dist/package.json.cjs.js +10 -10
- package/package.json +26 -26
package/CHANGELOG.md
CHANGED
|
@@ -1,18 +1,53 @@
|
|
|
1
1
|
# @backstage/backend-defaults
|
|
2
2
|
|
|
3
|
-
## 0.
|
|
3
|
+
## 0.7.0-next.1
|
|
4
4
|
|
|
5
5
|
### Patch Changes
|
|
6
6
|
|
|
7
|
-
-
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
- @backstage/types@1.2.1-next.0
|
|
9
|
+
- @backstage/backend-app-api@1.1.1-next.1
|
|
10
|
+
- @backstage/backend-plugin-api@1.1.1-next.1
|
|
11
|
+
- @backstage/cli-node@0.2.12-next.0
|
|
12
|
+
- @backstage/config@1.3.2-next.0
|
|
13
|
+
- @backstage/config-loader@1.9.5-next.1
|
|
14
|
+
- @backstage/errors@1.2.7-next.0
|
|
15
|
+
- @backstage/plugin-auth-node@0.5.6-next.1
|
|
16
|
+
- @backstage/plugin-events-node@0.4.7-next.1
|
|
17
|
+
- @backstage/integration-aws-node@0.1.15-next.0
|
|
18
|
+
- @backstage/plugin-permission-node@0.8.7-next.1
|
|
19
|
+
- @backstage/backend-dev-utils@0.1.5
|
|
20
|
+
- @backstage/cli-common@0.1.15
|
|
21
|
+
- @backstage/integration@1.16.1-next.0
|
|
22
|
+
|
|
23
|
+
## 0.7.0-next.0
|
|
8
24
|
|
|
9
|
-
|
|
25
|
+
### Minor Changes
|
|
26
|
+
|
|
27
|
+
- ec547b8: Ensure that an error handler middleware exists at the end of each plugin `httpRouter` handler chain. This makes it so that exceptions thrown by plugin routes are caught and encoded in the standard error format.
|
|
28
|
+
|
|
29
|
+
If you were using the standard `MiddlewareFactory` just to put an `error` middleware in you router, you can now remove that at your earliest convenience since it's redundant. If you have custom error handlers in your plugin router, those will continue to function as previously. If you were relying on thrown errors propagating all the way down to the root HTTP router, you will find that they no longer do that, and may want to hoist your error handling up to the plugin level instead.
|
|
10
30
|
|
|
11
31
|
### Patch Changes
|
|
12
32
|
|
|
13
|
-
-
|
|
33
|
+
- 575613f: Go back to using `node-fetch` for gitlab
|
|
34
|
+
- 8ecf8cb: Exclude `@backstage/backend-common` from schema collection if `@backstage/backend-defaults` is present
|
|
35
|
+
- 8379bf4: Remove usages of `PluginDatabaseManager` and `PluginEndpointDiscovery` and replace with their equivalent service types
|
|
14
36
|
- Updated dependencies
|
|
15
|
-
- @backstage/
|
|
37
|
+
- @backstage/backend-app-api@1.1.1-next.0
|
|
38
|
+
- @backstage/config-loader@1.9.5-next.0
|
|
39
|
+
- @backstage/plugin-permission-node@0.8.7-next.0
|
|
40
|
+
- @backstage/plugin-auth-node@0.5.6-next.0
|
|
41
|
+
- @backstage/backend-dev-utils@0.1.5
|
|
42
|
+
- @backstage/backend-plugin-api@1.1.1-next.0
|
|
43
|
+
- @backstage/cli-common@0.1.15
|
|
44
|
+
- @backstage/cli-node@0.2.11
|
|
45
|
+
- @backstage/config@1.3.1
|
|
46
|
+
- @backstage/errors@1.2.6
|
|
47
|
+
- @backstage/integration@1.16.0
|
|
48
|
+
- @backstage/integration-aws-node@0.1.14
|
|
49
|
+
- @backstage/types@1.2.0
|
|
50
|
+
- @backstage/plugin-events-node@0.4.7-next.0
|
|
16
51
|
|
|
17
52
|
## 0.6.0
|
|
18
53
|
|
package/dist/database.d.ts
CHANGED
|
@@ -46,7 +46,7 @@ declare class DatabaseManager {
|
|
|
46
46
|
static fromConfig(config: RootConfigService, options?: DatabaseManagerOptions): DatabaseManager;
|
|
47
47
|
private constructor();
|
|
48
48
|
/**
|
|
49
|
-
* Generates a
|
|
49
|
+
* Generates a DatabaseService for consumption by plugins.
|
|
50
50
|
*
|
|
51
51
|
* @param pluginId - The plugin that the database manager should be created for. Plugin names
|
|
52
52
|
* should be unique as they are used to look up database config overrides under
|
package/dist/discovery.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ import { DiscoveryService, RootConfigService } from '@backstage/backend-plugin-a
|
|
|
13
13
|
declare const discoveryServiceFactory: _backstage_backend_plugin_api.ServiceFactory<_backstage_backend_plugin_api.DiscoveryService, "plugin", "singleton">;
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
* HostDiscovery is a basic
|
|
16
|
+
* HostDiscovery is a basic DiscoveryService implementation
|
|
17
17
|
* that can handle plugins that are hosted in a single or multiple deployments.
|
|
18
18
|
*
|
|
19
19
|
* The deployment may be scaled horizontally, as long as the external URL
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JwksClient.cjs.js","sources":["../../../src/entrypoints/auth/JwksClient.ts"],"sourcesContent":["/*\n * Copyright 2024 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 { AuthenticationError } from '@backstage/errors';\nimport {\n createRemoteJWKSet,\n decodeJwt,\n decodeProtectedHeader,\n FlattenedJWSInput,\n JWSHeaderParameters,\n} from 'jose';\nimport { GetKeyFunction } from 'jose
|
|
1
|
+
{"version":3,"file":"JwksClient.cjs.js","sources":["../../../src/entrypoints/auth/JwksClient.ts"],"sourcesContent":["/*\n * Copyright 2024 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 { AuthenticationError } from '@backstage/errors';\nimport {\n createRemoteJWKSet,\n decodeJwt,\n decodeProtectedHeader,\n FlattenedJWSInput,\n JWSHeaderParameters,\n} from 'jose';\nimport { GetKeyFunction } from 'jose';\n\nconst CLOCK_MARGIN_S = 10;\n\nexport class JwksClient {\n #keyStore?: GetKeyFunction<JWSHeaderParameters, FlattenedJWSInput>;\n #keyStoreUpdated: number = 0;\n\n constructor(private readonly getEndpoint: () => Promise<URL>) {}\n\n get getKey() {\n if (!this.#keyStore) {\n throw new AuthenticationError(\n 'refreshKeyStore must be called before jwksClient.getKey',\n );\n }\n return this.#keyStore;\n }\n\n /**\n * If the last keystore refresh is stale, update the keystore URL to the latest\n */\n async refreshKeyStore(rawJwtToken: string): Promise<void> {\n const payload = await decodeJwt(rawJwtToken);\n const header = await decodeProtectedHeader(rawJwtToken);\n\n // Refresh public keys if needed\n let keyStoreHasKey;\n try {\n if (this.#keyStore) {\n // Check if the key is present in the keystore\n const [_, rawPayload, rawSignature] = rawJwtToken.split('.');\n keyStoreHasKey = await this.#keyStore(header, {\n payload: rawPayload,\n signature: rawSignature,\n });\n }\n } catch (error) {\n keyStoreHasKey = false;\n }\n // Refresh public key URL if needed\n // Add a small margin in case clocks are out of sync\n const issuedAfterLastRefresh =\n payload?.iat && payload.iat > this.#keyStoreUpdated - CLOCK_MARGIN_S;\n if (!this.#keyStore || (!keyStoreHasKey && issuedAfterLastRefresh)) {\n const endpoint = await this.getEndpoint();\n this.#keyStore = createRemoteJWKSet(endpoint);\n this.#keyStoreUpdated = Date.now() / 1000;\n }\n }\n}\n"],"names":["AuthenticationError","decodeJwt","decodeProtectedHeader","createRemoteJWKSet"],"mappings":";;;;;AA0BA,MAAM,cAAiB,GAAA,EAAA;AAEhB,MAAM,UAAW,CAAA;AAAA,EAItB,YAA6B,WAAiC,EAAA;AAAjC,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA;AAAA;AAAkC,EAH/D,SAAA;AAAA,EACA,gBAA2B,GAAA,CAAA;AAAA,EAI3B,IAAI,MAAS,GAAA;AACX,IAAI,IAAA,CAAC,KAAK,SAAW,EAAA;AACnB,MAAA,MAAM,IAAIA,0BAAA;AAAA,QACR;AAAA,OACF;AAAA;AAEF,IAAA,OAAO,IAAK,CAAA,SAAA;AAAA;AACd;AAAA;AAAA;AAAA,EAKA,MAAM,gBAAgB,WAAoC,EAAA;AACxD,IAAM,MAAA,OAAA,GAAU,MAAMC,cAAA,CAAU,WAAW,CAAA;AAC3C,IAAM,MAAA,MAAA,GAAS,MAAMC,0BAAA,CAAsB,WAAW,CAAA;AAGtD,IAAI,IAAA,cAAA;AACJ,IAAI,IAAA;AACF,MAAA,IAAI,KAAK,SAAW,EAAA;AAElB,QAAA,MAAM,CAAC,CAAG,EAAA,UAAA,EAAY,YAAY,CAAI,GAAA,WAAA,CAAY,MAAM,GAAG,CAAA;AAC3D,QAAiB,cAAA,GAAA,MAAM,IAAK,CAAA,SAAA,CAAU,MAAQ,EAAA;AAAA,UAC5C,OAAS,EAAA,UAAA;AAAA,UACT,SAAW,EAAA;AAAA,SACZ,CAAA;AAAA;AACH,aACO,KAAO,EAAA;AACd,MAAiB,cAAA,GAAA,KAAA;AAAA;AAInB,IAAA,MAAM,yBACJ,OAAS,EAAA,GAAA,IAAO,OAAQ,CAAA,GAAA,GAAM,KAAK,gBAAmB,GAAA,cAAA;AACxD,IAAA,IAAI,CAAC,IAAA,CAAK,SAAc,IAAA,CAAC,kBAAkB,sBAAyB,EAAA;AAClE,MAAM,MAAA,QAAA,GAAW,MAAM,IAAA,CAAK,WAAY,EAAA;AACxC,MAAK,IAAA,CAAA,SAAA,GAAYC,wBAAmB,QAAQ,CAAA;AAC5C,MAAK,IAAA,CAAA,gBAAA,GAAmB,IAAK,CAAA,GAAA,EAAQ,GAAA,GAAA;AAAA;AACvC;AAEJ;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StaticConfigPluginKeySource.cjs.js","sources":["../../../../../src/entrypoints/auth/plugin/keys/StaticConfigPluginKeySource.ts"],"sourcesContent":["/*\n * Copyright 2024 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 { Config } from '@backstage/config';\nimport { HumanDuration, durationToMilliseconds } from '@backstage/types';\nimport { promises as fs } from 'fs';\nimport { JWK, exportJWK, importPKCS8, importSPKI } from 'jose';\nimport { KeyLike } from 'jose
|
|
1
|
+
{"version":3,"file":"StaticConfigPluginKeySource.cjs.js","sources":["../../../../../src/entrypoints/auth/plugin/keys/StaticConfigPluginKeySource.ts"],"sourcesContent":["/*\n * Copyright 2024 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 { Config } from '@backstage/config';\nimport { HumanDuration, durationToMilliseconds } from '@backstage/types';\nimport { promises as fs } from 'fs';\nimport { JWK, exportJWK, importPKCS8, importSPKI } from 'jose';\nimport { KeyLike } from 'jose';\nimport { KeyPayload } from './types';\nimport { PluginKeySource } from './types';\n\nexport type KeyPair = {\n publicKey: JWK;\n privateKey?: JWK;\n keyId: string;\n};\n\nexport type StaticKeyConfig = {\n publicKeyFile: string;\n privateKeyFile?: string;\n keyId: string;\n algorithm: string;\n};\n\nconst DEFAULT_ALGORITHM = 'ES256';\n\nconst SECONDS_IN_MS = 1000;\n\n/**\n * Key source that loads predefined public/private key pairs from disk.\n *\n * The private key should be represented using the PKCS#8 format,\n * while the public key should be in the SPKI format.\n *\n * @remarks\n *\n * You can generate a public and private key pair, using\n * openssl:\n *\n * Generate a private key using the ES256 algorithm\n * ```sh\n * openssl ecparam -name prime256v1 -genkey -out private.ec.key\n * ```\n * Convert it to PKCS#8 format\n * ```sh\n * openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in private.ec.key -out private.key\n * ```\n * Extract the public key\n * ```sh\n * openssl ec -inform PEM -outform PEM -pubout -in private.key -out public.key\n * ```\n *\n * Provide the paths to private.key and public.key as the respective\n * private and public key paths in the `create` method.\n */\nexport class StaticConfigPluginKeySource implements PluginKeySource {\n private constructor(\n private readonly keyPairs: KeyPair[],\n private readonly keyDurationSeconds: number,\n ) {}\n\n public static async create(options: {\n sourceConfig: Config;\n keyDuration: HumanDuration;\n }): Promise<PluginKeySource> {\n const keyConfigs = options.sourceConfig\n .getConfigArray('static.keys')\n .map(c => {\n const staticKeyConfig: StaticKeyConfig = {\n publicKeyFile: c.getString('publicKeyFile'),\n privateKeyFile: c.getOptionalString('privateKeyFile'),\n keyId: c.getString('keyId'),\n algorithm: c.getOptionalString('algorithm') ?? DEFAULT_ALGORITHM,\n };\n\n return staticKeyConfig;\n });\n\n const keyPairs = await Promise.all(\n keyConfigs.map(async k => await this.loadKeyPair(k)),\n );\n\n if (keyPairs.length < 1) {\n throw new Error(\n 'At least one key pair must be provided in static.keys, when the static key store type is used',\n );\n } else if (!keyPairs[0].privateKey) {\n throw new Error(\n 'Private key for signing must be provided in the first key pair in static.keys, when the static key store type is used',\n );\n }\n\n return new StaticConfigPluginKeySource(\n keyPairs,\n durationToMilliseconds(options.keyDuration) / SECONDS_IN_MS,\n );\n }\n\n async getPrivateSigningKey(): Promise<JWK> {\n return this.keyPairs[0].privateKey!;\n }\n\n async listKeys(): Promise<{ keys: KeyPayload[] }> {\n const keys = this.keyPairs.map(k => this.keyPairToStoredKey(k));\n return { keys };\n }\n\n private static async loadKeyPair(options: StaticKeyConfig): Promise<KeyPair> {\n const algorithm = options.algorithm;\n const keyId = options.keyId;\n const publicKey = await this.loadPublicKeyFromFile(\n options.publicKeyFile,\n keyId,\n algorithm,\n );\n const privateKey = options.privateKeyFile\n ? await this.loadPrivateKeyFromFile(\n options.privateKeyFile,\n keyId,\n algorithm,\n )\n : undefined;\n\n return { publicKey, privateKey, keyId };\n }\n\n private static async loadPublicKeyFromFile(\n path: string,\n keyId: string,\n algorithm: string,\n ): Promise<JWK> {\n return this.loadKeyFromFile(path, keyId, algorithm, importSPKI);\n }\n\n private static async loadPrivateKeyFromFile(\n path: string,\n keyId: string,\n algorithm: string,\n ): Promise<JWK> {\n return this.loadKeyFromFile(path, keyId, algorithm, importPKCS8);\n }\n\n private static async loadKeyFromFile(\n path: string,\n keyId: string,\n algorithm: string,\n importer: (content: string, algorithm: string) => Promise<KeyLike>,\n ): Promise<JWK> {\n const content = await fs.readFile(path, { encoding: 'utf8', flag: 'r' });\n const key = await importer(content, algorithm);\n const jwk = await exportJWK(key);\n jwk.kid = keyId;\n jwk.alg = algorithm;\n\n return jwk;\n }\n\n private keyPairToStoredKey(keyPair: KeyPair): KeyPayload {\n const publicKey = {\n ...keyPair.publicKey,\n kid: keyPair.keyId,\n };\n\n return {\n key: publicKey,\n id: keyPair.keyId,\n expiresAt: new Date(Date.now() + this.keyDurationSeconds * SECONDS_IN_MS),\n };\n }\n}\n"],"names":["durationToMilliseconds","importSPKI","importPKCS8","fs","exportJWK"],"mappings":"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"}
|
|
@@ -22,7 +22,7 @@ class DatabaseManagerImpl {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
|
-
* Generates a
|
|
25
|
+
* Generates a DatabaseService for consumption by plugins.
|
|
26
26
|
*
|
|
27
27
|
* @param pluginId - The plugin that the database manager should be created for. Plugin names
|
|
28
28
|
* should be unique as they are used to look up database config overrides under
|
|
@@ -158,7 +158,7 @@ class DatabaseManager {
|
|
|
158
158
|
);
|
|
159
159
|
}
|
|
160
160
|
/**
|
|
161
|
-
* Generates a
|
|
161
|
+
* Generates a DatabaseService for consumption by plugins.
|
|
162
162
|
*
|
|
163
163
|
* @param pluginId - The plugin that the database manager should be created for. Plugin names
|
|
164
164
|
* should be unique as they are used to look up database config overrides under
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DatabaseManager.cjs.js","sources":["../../../src/entrypoints/database/DatabaseManager.ts"],"sourcesContent":["/*\n * Copyright 2021 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 {\n DatabaseService,\n LifecycleService,\n LoggerService,\n RootConfigService,\n RootLifecycleService,\n RootLoggerService,\n} from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { stringifyError } from '@backstage/errors';\nimport { Knex } from 'knex';\nimport { MysqlConnector } from './connectors/mysql';\nimport { PgConnector } from './connectors/postgres';\nimport { Sqlite3Connector } from './connectors/sqlite3';\nimport { Connector, PluginDatabaseManager } from './types';\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\n/**\n * Creation options for {@link DatabaseManager}.\n *\n * @public\n */\nexport type DatabaseManagerOptions = {\n migrations?: DatabaseService['migrations'];\n rootLogger?: RootLoggerService;\n rootLifecycle?: RootLifecycleService;\n};\n\n/**\n * Testable implementation class for {@link DatabaseManager} below.\n */\nexport class DatabaseManagerImpl {\n constructor(\n private readonly config: Config,\n private readonly connectors: Record<string, Connector>,\n private readonly options?: DatabaseManagerOptions,\n private readonly databaseCache: Map<string, Promise<Knex>> = new Map(),\n private readonly keepaliveIntervals: Map<\n string,\n NodeJS.Timeout\n > = new Map(),\n ) {\n // If a rootLifecycle service was provided, register a shutdown hook to\n // clean up any database connections.\n if (options?.rootLifecycle !== undefined) {\n options.rootLifecycle.addShutdownHook(async () => {\n await this.shutdown({ logger: options.rootLogger });\n });\n }\n }\n\n /**\n * Generates a PluginDatabaseManager for consumption by plugins.\n *\n * @param pluginId - The plugin that the database manager should be created for. Plugin names\n * should be unique as they are used to look up database config overrides under\n * `backend.database.plugin`.\n */\n forPlugin(\n pluginId: string,\n deps: {\n logger: LoggerService;\n lifecycle: LifecycleService;\n },\n ): PluginDatabaseManager {\n const client = this.getClientType(pluginId).client;\n const connector = this.connectors[client];\n if (!connector) {\n throw new Error(\n `Unsupported database client type '${client}' specified for plugin '${pluginId}'`,\n );\n }\n const getClient = () => this.getDatabase(pluginId, connector, deps);\n\n const skip =\n this.options?.migrations?.skip ??\n this.config.getOptionalBoolean(`plugin.${pluginId}.skipMigrations`) ??\n this.config.getOptionalBoolean('skipMigrations') ??\n false;\n\n return { getClient, migrations: { skip } };\n }\n\n /**\n * Destroys all known connections.\n */\n private async shutdown(deps?: { logger?: LoggerService }): Promise<void> {\n const pluginIds = Array.from(this.databaseCache.keys());\n await Promise.allSettled(\n pluginIds.map(async pluginId => {\n // We no longer need to keep connections alive.\n clearInterval(this.keepaliveIntervals.get(pluginId));\n\n const connection = await this.databaseCache.get(pluginId);\n if (connection) {\n if (connection.client.config.includes('sqlite3')) {\n return; // sqlite3 does not support destroy, it hangs\n }\n await connection.destroy().catch((error: unknown) => {\n deps?.logger?.error(\n `Problem closing database connection for ${pluginId}: ${stringifyError(\n error,\n )}`,\n );\n });\n }\n }),\n );\n }\n\n /**\n * Provides the client type which should be used for a given plugin.\n *\n * The client type is determined by plugin specific config if present.\n * Otherwise the base client is used as the fallback.\n *\n * @param pluginId - Plugin to get the client type for\n * @returns Object with client type returned as `client` and boolean\n * representing whether or not the client was overridden as\n * `overridden`\n */\n private getClientType(pluginId: string): {\n client: string;\n overridden: boolean;\n } {\n const pluginClient = this.config.getOptionalString(\n `${pluginPath(pluginId)}.client`,\n );\n\n const baseClient = this.config.getString('client');\n const client = pluginClient ?? baseClient;\n return {\n client,\n overridden: client !== baseClient,\n };\n }\n\n /**\n * Provides a scoped Knex client for a plugin as per application config.\n *\n * @param pluginId - Plugin to get a Knex client for\n * @returns Promise which resolves to a scoped Knex database client for a\n * plugin\n */\n private async getDatabase(\n pluginId: string,\n connector: Connector,\n deps: {\n logger: LoggerService;\n lifecycle: LifecycleService;\n },\n ): Promise<Knex> {\n if (this.databaseCache.has(pluginId)) {\n return this.databaseCache.get(pluginId)!;\n }\n\n const clientPromise = connector.getClient(pluginId, deps);\n this.databaseCache.set(pluginId, clientPromise);\n\n if (process.env.NODE_ENV !== 'test') {\n clientPromise.then(client =>\n this.startKeepaliveLoop(pluginId, client, deps.logger),\n );\n }\n\n return clientPromise;\n }\n\n private startKeepaliveLoop(\n pluginId: string,\n client: Knex,\n logger: LoggerService,\n ): void {\n let lastKeepaliveFailed = false;\n\n this.keepaliveIntervals.set(\n pluginId,\n setInterval(() => {\n // During testing it can happen that the environment is torn down and\n // this client is `undefined`, but this interval is still run.\n client?.raw('select 1').then(\n () => {\n lastKeepaliveFailed = false;\n },\n (error: unknown) => {\n if (!lastKeepaliveFailed) {\n lastKeepaliveFailed = true;\n logger.warn(\n `Database keepalive failed for plugin ${pluginId}, ${stringifyError(\n error,\n )}`,\n );\n }\n },\n );\n }, 60 * 1000),\n );\n }\n}\n\n// NOTE: This class looks odd but is kept around for API compatibility reasons\n/**\n * Manages database connections for Backstage backend plugins.\n *\n * @public\n * @remarks\n *\n * The database manager allows the user to set connection and client settings on\n * a per pluginId basis by defining a database config block under\n * `plugin.<pluginId>` in addition to top level defaults. Optionally, a user may\n * set `prefix` which is used to prefix generated database names if config is\n * not provided.\n */\nexport class DatabaseManager {\n /**\n * Creates a {@link DatabaseManager} from `backend.database` config.\n *\n * @param config - The loaded application configuration.\n * @param options - An optional configuration object.\n */\n static fromConfig(\n config: RootConfigService,\n options?: DatabaseManagerOptions,\n ): DatabaseManager {\n const databaseConfig = config.getConfig('backend.database');\n const prefix =\n databaseConfig.getOptionalString('prefix') || 'backstage_plugin_';\n return new DatabaseManager(\n new DatabaseManagerImpl(\n databaseConfig,\n {\n pg: new PgConnector(databaseConfig, prefix),\n sqlite3: new Sqlite3Connector(databaseConfig),\n 'better-sqlite3': new Sqlite3Connector(databaseConfig),\n mysql: new MysqlConnector(databaseConfig, prefix),\n mysql2: new MysqlConnector(databaseConfig, prefix),\n },\n options,\n ),\n );\n }\n\n private constructor(private readonly impl: DatabaseManagerImpl) {}\n\n /**\n * Generates a PluginDatabaseManager for consumption by plugins.\n *\n * @param pluginId - The plugin that the database manager should be created for. Plugin names\n * should be unique as they are used to look up database config overrides under\n * `backend.database.plugin`.\n */\n forPlugin(\n pluginId: string,\n deps: {\n logger: LoggerService;\n lifecycle: LifecycleService;\n },\n ): PluginDatabaseManager {\n return this.impl.forPlugin(pluginId, deps);\n }\n}\n"],"names":["stringifyError","PgConnector","Sqlite3Connector","MysqlConnector"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DatabaseManager.cjs.js","sources":["../../../src/entrypoints/database/DatabaseManager.ts"],"sourcesContent":["/*\n * Copyright 2021 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 {\n DatabaseService,\n LifecycleService,\n LoggerService,\n RootConfigService,\n RootLifecycleService,\n RootLoggerService,\n} from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { stringifyError } from '@backstage/errors';\nimport { Knex } from 'knex';\nimport { MysqlConnector } from './connectors/mysql';\nimport { PgConnector } from './connectors/postgres';\nimport { Sqlite3Connector } from './connectors/sqlite3';\nimport { Connector } from './types';\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\n/**\n * Creation options for {@link DatabaseManager}.\n *\n * @public\n */\nexport type DatabaseManagerOptions = {\n migrations?: DatabaseService['migrations'];\n rootLogger?: RootLoggerService;\n rootLifecycle?: RootLifecycleService;\n};\n\n/**\n * Testable implementation class for {@link DatabaseManager} below.\n */\nexport class DatabaseManagerImpl {\n constructor(\n private readonly config: Config,\n private readonly connectors: Record<string, Connector>,\n private readonly options?: DatabaseManagerOptions,\n private readonly databaseCache: Map<string, Promise<Knex>> = new Map(),\n private readonly keepaliveIntervals: Map<\n string,\n NodeJS.Timeout\n > = new Map(),\n ) {\n // If a rootLifecycle service was provided, register a shutdown hook to\n // clean up any database connections.\n if (options?.rootLifecycle !== undefined) {\n options.rootLifecycle.addShutdownHook(async () => {\n await this.shutdown({ logger: options.rootLogger });\n });\n }\n }\n\n /**\n * Generates a DatabaseService for consumption by plugins.\n *\n * @param pluginId - The plugin that the database manager should be created for. Plugin names\n * should be unique as they are used to look up database config overrides under\n * `backend.database.plugin`.\n */\n forPlugin(\n pluginId: string,\n deps: {\n logger: LoggerService;\n lifecycle: LifecycleService;\n },\n ): DatabaseService {\n const client = this.getClientType(pluginId).client;\n const connector = this.connectors[client];\n if (!connector) {\n throw new Error(\n `Unsupported database client type '${client}' specified for plugin '${pluginId}'`,\n );\n }\n const getClient = () => this.getDatabase(pluginId, connector, deps);\n\n const skip =\n this.options?.migrations?.skip ??\n this.config.getOptionalBoolean(`plugin.${pluginId}.skipMigrations`) ??\n this.config.getOptionalBoolean('skipMigrations') ??\n false;\n\n return { getClient, migrations: { skip } };\n }\n\n /**\n * Destroys all known connections.\n */\n private async shutdown(deps?: { logger?: LoggerService }): Promise<void> {\n const pluginIds = Array.from(this.databaseCache.keys());\n await Promise.allSettled(\n pluginIds.map(async pluginId => {\n // We no longer need to keep connections alive.\n clearInterval(this.keepaliveIntervals.get(pluginId));\n\n const connection = await this.databaseCache.get(pluginId);\n if (connection) {\n if (connection.client.config.includes('sqlite3')) {\n return; // sqlite3 does not support destroy, it hangs\n }\n await connection.destroy().catch((error: unknown) => {\n deps?.logger?.error(\n `Problem closing database connection for ${pluginId}: ${stringifyError(\n error,\n )}`,\n );\n });\n }\n }),\n );\n }\n\n /**\n * Provides the client type which should be used for a given plugin.\n *\n * The client type is determined by plugin specific config if present.\n * Otherwise the base client is used as the fallback.\n *\n * @param pluginId - Plugin to get the client type for\n * @returns Object with client type returned as `client` and boolean\n * representing whether or not the client was overridden as\n * `overridden`\n */\n private getClientType(pluginId: string): {\n client: string;\n overridden: boolean;\n } {\n const pluginClient = this.config.getOptionalString(\n `${pluginPath(pluginId)}.client`,\n );\n\n const baseClient = this.config.getString('client');\n const client = pluginClient ?? baseClient;\n return {\n client,\n overridden: client !== baseClient,\n };\n }\n\n /**\n * Provides a scoped Knex client for a plugin as per application config.\n *\n * @param pluginId - Plugin to get a Knex client for\n * @returns Promise which resolves to a scoped Knex database client for a\n * plugin\n */\n private async getDatabase(\n pluginId: string,\n connector: Connector,\n deps: {\n logger: LoggerService;\n lifecycle: LifecycleService;\n },\n ): Promise<Knex> {\n if (this.databaseCache.has(pluginId)) {\n return this.databaseCache.get(pluginId)!;\n }\n\n const clientPromise = connector.getClient(pluginId, deps);\n this.databaseCache.set(pluginId, clientPromise);\n\n if (process.env.NODE_ENV !== 'test') {\n clientPromise.then(client =>\n this.startKeepaliveLoop(pluginId, client, deps.logger),\n );\n }\n\n return clientPromise;\n }\n\n private startKeepaliveLoop(\n pluginId: string,\n client: Knex,\n logger: LoggerService,\n ): void {\n let lastKeepaliveFailed = false;\n\n this.keepaliveIntervals.set(\n pluginId,\n setInterval(() => {\n // During testing it can happen that the environment is torn down and\n // this client is `undefined`, but this interval is still run.\n client?.raw('select 1').then(\n () => {\n lastKeepaliveFailed = false;\n },\n (error: unknown) => {\n if (!lastKeepaliveFailed) {\n lastKeepaliveFailed = true;\n logger.warn(\n `Database keepalive failed for plugin ${pluginId}, ${stringifyError(\n error,\n )}`,\n );\n }\n },\n );\n }, 60 * 1000),\n );\n }\n}\n\n// NOTE: This class looks odd but is kept around for API compatibility reasons\n/**\n * Manages database connections for Backstage backend plugins.\n *\n * @public\n * @remarks\n *\n * The database manager allows the user to set connection and client settings on\n * a per pluginId basis by defining a database config block under\n * `plugin.<pluginId>` in addition to top level defaults. Optionally, a user may\n * set `prefix` which is used to prefix generated database names if config is\n * not provided.\n */\nexport class DatabaseManager {\n /**\n * Creates a {@link DatabaseManager} from `backend.database` config.\n *\n * @param config - The loaded application configuration.\n * @param options - An optional configuration object.\n */\n static fromConfig(\n config: RootConfigService,\n options?: DatabaseManagerOptions,\n ): DatabaseManager {\n const databaseConfig = config.getConfig('backend.database');\n const prefix =\n databaseConfig.getOptionalString('prefix') || 'backstage_plugin_';\n return new DatabaseManager(\n new DatabaseManagerImpl(\n databaseConfig,\n {\n pg: new PgConnector(databaseConfig, prefix),\n sqlite3: new Sqlite3Connector(databaseConfig),\n 'better-sqlite3': new Sqlite3Connector(databaseConfig),\n mysql: new MysqlConnector(databaseConfig, prefix),\n mysql2: new MysqlConnector(databaseConfig, prefix),\n },\n options,\n ),\n );\n }\n\n private constructor(private readonly impl: DatabaseManagerImpl) {}\n\n /**\n * Generates a DatabaseService for consumption by plugins.\n *\n * @param pluginId - The plugin that the database manager should be created for. Plugin names\n * should be unique as they are used to look up database config overrides under\n * `backend.database.plugin`.\n */\n forPlugin(\n pluginId: string,\n deps: {\n logger: LoggerService;\n lifecycle: LifecycleService;\n },\n ): DatabaseService {\n return this.impl.forPlugin(pluginId, deps);\n }\n}\n"],"names":["stringifyError","PgConnector","Sqlite3Connector","MysqlConnector"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HostDiscovery.cjs.js","sources":["../../../src/entrypoints/discovery/HostDiscovery.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 { Config } from '@backstage/config';\nimport {\n DiscoveryService,\n RootConfigService,\n} from '@backstage/backend-plugin-api';\nimport { readHttpServerOptions } from '../rootHttpRouter/http/config';\n\ntype Target = string | { internal: string; external: string };\n\n/**\n * HostDiscovery is a basic
|
|
1
|
+
{"version":3,"file":"HostDiscovery.cjs.js","sources":["../../../src/entrypoints/discovery/HostDiscovery.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 { Config } from '@backstage/config';\nimport {\n DiscoveryService,\n RootConfigService,\n} from '@backstage/backend-plugin-api';\nimport { readHttpServerOptions } from '../rootHttpRouter/http/config';\n\ntype Target = string | { internal: string; external: string };\n\n/**\n * HostDiscovery is a basic DiscoveryService implementation\n * that can handle plugins that are hosted in a single or multiple deployments.\n *\n * The deployment may be scaled horizontally, as long as the external URL\n * is the same for all instances. However, internal URLs will always be\n * resolved to the same host, so there won't be any balancing of internal traffic.\n *\n * @public\n */\nexport class HostDiscovery implements DiscoveryService {\n /**\n * Creates a new HostDiscovery discovery instance by reading\n * from the `backend` config section, specifically the `.baseUrl` for\n * discovering the external URL, and the `.listen` and `.https` config\n * for the internal one.\n *\n * Can be overridden in config by providing a target and corresponding plugins in `discovery.endpoints`.\n * eg.\n *\n * ```yaml\n * discovery:\n * endpoints:\n * - target: https://internal.example.com/internal-catalog\n * plugins: [catalog]\n * - target: https://internal.example.com/secure/api/{{pluginId}}\n * plugins: [auth, permission]\n * - target:\n * internal: https://internal.example.com/search\n * external: https://example.com/search\n * plugins: [search]\n * ```\n *\n * The fixed base path is `/api`, meaning the default full internal\n * path for the `catalog` plugin will be `http://localhost:7007/api/catalog`.\n */\n static fromConfig(config: RootConfigService) {\n const basePath = '/api';\n const externalBaseUrl = config\n .getString('backend.baseUrl')\n .replace(/\\/+$/, '');\n\n const {\n listen: { host: listenHost = '::', port: listenPort },\n } = readHttpServerOptions(config.getConfig('backend'));\n const protocol = config.has('backend.https') ? 'https' : 'http';\n\n // Translate bind-all to localhost, and support IPv6\n let host = listenHost;\n if (host === '::' || host === '') {\n // We use localhost instead of ::1, since IPv6-compatible systems should default\n // to using IPv6 when they see localhost, but if the system doesn't support IPv6\n // things will still work.\n host = 'localhost';\n } else if (host === '0.0.0.0') {\n host = '127.0.0.1';\n }\n if (host.includes(':')) {\n host = `[${host}]`;\n }\n\n const internalBaseUrl = `${protocol}://${host}:${listenPort}`;\n\n return new HostDiscovery(\n internalBaseUrl + basePath,\n externalBaseUrl + basePath,\n config.getOptionalConfig('discovery'),\n );\n }\n\n private constructor(\n private readonly internalBaseUrl: string,\n private readonly externalBaseUrl: string,\n private readonly discoveryConfig: Config | undefined,\n ) {}\n\n private getTargetFromConfig(pluginId: string, type: 'internal' | 'external') {\n const endpoints = this.discoveryConfig?.getOptionalConfigArray('endpoints');\n\n const target = endpoints\n ?.find(endpoint => endpoint.getStringArray('plugins').includes(pluginId))\n ?.get<Target>('target');\n\n if (!target) {\n const baseUrl =\n type === 'external' ? this.externalBaseUrl : this.internalBaseUrl;\n\n return `${baseUrl}/${encodeURIComponent(pluginId)}`;\n }\n\n if (typeof target === 'string') {\n return target.replace(\n /\\{\\{\\s*pluginId\\s*\\}\\}/g,\n encodeURIComponent(pluginId),\n );\n }\n\n return target[type].replace(\n /\\{\\{\\s*pluginId\\s*\\}\\}/g,\n encodeURIComponent(pluginId),\n );\n }\n\n async getBaseUrl(pluginId: string): Promise<string> {\n return this.getTargetFromConfig(pluginId, 'internal');\n }\n\n async getExternalBaseUrl(pluginId: string): Promise<string> {\n return this.getTargetFromConfig(pluginId, 'external');\n }\n}\n"],"names":["config","readHttpServerOptions"],"mappings":"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"}
|
|
@@ -6,6 +6,18 @@ var createAuthIntegrationRouter = require('./http/createAuthIntegrationRouter.cj
|
|
|
6
6
|
var createCredentialsBarrier = require('./http/createCredentialsBarrier.cjs.js');
|
|
7
7
|
var createLifecycleMiddleware = require('./http/createLifecycleMiddleware.cjs.js');
|
|
8
8
|
var createCookieAuthRefreshMiddleware = require('./http/createCookieAuthRefreshMiddleware.cjs.js');
|
|
9
|
+
require('express');
|
|
10
|
+
require('lodash/trimEnd');
|
|
11
|
+
require('http');
|
|
12
|
+
require('https');
|
|
13
|
+
require('fs-extra');
|
|
14
|
+
require('path');
|
|
15
|
+
require('node-forge');
|
|
16
|
+
var MiddlewareFactory = require('../rootHttpRouter/http/MiddlewareFactory.cjs.js');
|
|
17
|
+
require('minimatch');
|
|
18
|
+
require('helmet');
|
|
19
|
+
require('lodash/kebabCase');
|
|
20
|
+
require('../rootHttpRouter/rootHttpRouterServiceFactory.cjs.js');
|
|
9
21
|
|
|
10
22
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
11
23
|
|
|
@@ -20,9 +32,18 @@ const httpRouterServiceFactory = backendPluginApi.createServiceFactory({
|
|
|
20
32
|
lifecycle: backendPluginApi.coreServices.lifecycle,
|
|
21
33
|
rootHttpRouter: backendPluginApi.coreServices.rootHttpRouter,
|
|
22
34
|
auth: backendPluginApi.coreServices.auth,
|
|
23
|
-
httpAuth: backendPluginApi.coreServices.httpAuth
|
|
35
|
+
httpAuth: backendPluginApi.coreServices.httpAuth,
|
|
36
|
+
logger: backendPluginApi.coreServices.logger
|
|
24
37
|
},
|
|
25
|
-
async factory({
|
|
38
|
+
async factory({
|
|
39
|
+
auth,
|
|
40
|
+
httpAuth,
|
|
41
|
+
config,
|
|
42
|
+
plugin,
|
|
43
|
+
rootHttpRouter,
|
|
44
|
+
lifecycle,
|
|
45
|
+
logger
|
|
46
|
+
}) {
|
|
26
47
|
const router = Router__default.default();
|
|
27
48
|
rootHttpRouter.use(`/api/${plugin.getId()}`, router);
|
|
28
49
|
const credentialsBarrier = createCredentialsBarrier.createCredentialsBarrier({
|
|
@@ -33,9 +54,13 @@ const httpRouterServiceFactory = backendPluginApi.createServiceFactory({
|
|
|
33
54
|
router.use(createLifecycleMiddleware.createLifecycleMiddleware({ config, lifecycle }));
|
|
34
55
|
router.use(credentialsBarrier.middleware);
|
|
35
56
|
router.use(createCookieAuthRefreshMiddleware.createCookieAuthRefreshMiddleware({ auth, httpAuth }));
|
|
57
|
+
const pluginRoutes = Router__default.default();
|
|
58
|
+
router.use(pluginRoutes);
|
|
59
|
+
const middleware = MiddlewareFactory.MiddlewareFactory.create({ config, logger });
|
|
60
|
+
router.use(middleware.error());
|
|
36
61
|
return {
|
|
37
62
|
use(handler) {
|
|
38
|
-
|
|
63
|
+
pluginRoutes.use(handler);
|
|
39
64
|
},
|
|
40
65
|
addAuthPolicy(policy) {
|
|
41
66
|
credentialsBarrier.addAuthPolicy(policy);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"httpRouterServiceFactory.cjs.js","sources":["../../../src/entrypoints/httpRouter/httpRouterServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2022 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 { Handler } from 'express';\nimport PromiseRouter from 'express-promise-router';\nimport {\n coreServices,\n createServiceFactory,\n HttpRouterServiceAuthPolicy,\n} from '@backstage/backend-plugin-api';\nimport {\n createLifecycleMiddleware,\n createCookieAuthRefreshMiddleware,\n createCredentialsBarrier,\n createAuthIntegrationRouter,\n} from './http';\n\n/**\n * HTTP route registration for plugins.\n *\n * See {@link @backstage/code-plugin-api#HttpRouterService}\n * and {@link https://backstage.io/docs/backend-system/core-services/http-router | the service docs}\n * for more information.\n *\n * @public\n */\nexport const httpRouterServiceFactory = createServiceFactory({\n service: coreServices.httpRouter,\n initialization: 'always',\n deps: {\n plugin: coreServices.pluginMetadata,\n config: coreServices.rootConfig,\n lifecycle: coreServices.lifecycle,\n rootHttpRouter: coreServices.rootHttpRouter,\n auth: coreServices.auth,\n httpAuth: coreServices.httpAuth,\n },\n async factory({
|
|
1
|
+
{"version":3,"file":"httpRouterServiceFactory.cjs.js","sources":["../../../src/entrypoints/httpRouter/httpRouterServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2022 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 { Handler } from 'express';\nimport PromiseRouter from 'express-promise-router';\nimport {\n coreServices,\n createServiceFactory,\n HttpRouterServiceAuthPolicy,\n} from '@backstage/backend-plugin-api';\nimport {\n createLifecycleMiddleware,\n createCookieAuthRefreshMiddleware,\n createCredentialsBarrier,\n createAuthIntegrationRouter,\n} from './http';\nimport { MiddlewareFactory } from '../rootHttpRouter';\n\n/**\n * HTTP route registration for plugins.\n *\n * See {@link @backstage/code-plugin-api#HttpRouterService}\n * and {@link https://backstage.io/docs/backend-system/core-services/http-router | the service docs}\n * for more information.\n *\n * @public\n */\nexport const httpRouterServiceFactory = createServiceFactory({\n service: coreServices.httpRouter,\n initialization: 'always',\n deps: {\n plugin: coreServices.pluginMetadata,\n config: coreServices.rootConfig,\n lifecycle: coreServices.lifecycle,\n rootHttpRouter: coreServices.rootHttpRouter,\n auth: coreServices.auth,\n httpAuth: coreServices.httpAuth,\n logger: coreServices.logger,\n },\n async factory({\n auth,\n httpAuth,\n config,\n plugin,\n rootHttpRouter,\n lifecycle,\n logger,\n }) {\n const router = PromiseRouter();\n\n rootHttpRouter.use(`/api/${plugin.getId()}`, router);\n\n const credentialsBarrier = createCredentialsBarrier({\n httpAuth,\n config,\n });\n\n router.use(createAuthIntegrationRouter({ auth }));\n router.use(createLifecycleMiddleware({ config, lifecycle }));\n router.use(credentialsBarrier.middleware);\n router.use(createCookieAuthRefreshMiddleware({ auth, httpAuth }));\n\n const pluginRoutes = PromiseRouter();\n router.use(pluginRoutes);\n\n const middleware = MiddlewareFactory.create({ config, logger });\n router.use(middleware.error());\n\n return {\n use(handler: Handler): void {\n pluginRoutes.use(handler);\n },\n addAuthPolicy(policy: HttpRouterServiceAuthPolicy): void {\n credentialsBarrier.addAuthPolicy(policy);\n },\n };\n },\n});\n"],"names":["createServiceFactory","coreServices","PromiseRouter","createCredentialsBarrier","createAuthIntegrationRouter","createLifecycleMiddleware","createCookieAuthRefreshMiddleware","MiddlewareFactory"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAwCO,MAAM,2BAA2BA,qCAAqB,CAAA;AAAA,EAC3D,SAASC,6BAAa,CAAA,UAAA;AAAA,EACtB,cAAgB,EAAA,QAAA;AAAA,EAChB,IAAM,EAAA;AAAA,IACJ,QAAQA,6BAAa,CAAA,cAAA;AAAA,IACrB,QAAQA,6BAAa,CAAA,UAAA;AAAA,IACrB,WAAWA,6BAAa,CAAA,SAAA;AAAA,IACxB,gBAAgBA,6BAAa,CAAA,cAAA;AAAA,IAC7B,MAAMA,6BAAa,CAAA,IAAA;AAAA,IACnB,UAAUA,6BAAa,CAAA,QAAA;AAAA,IACvB,QAAQA,6BAAa,CAAA;AAAA,GACvB;AAAA,EACA,MAAM,OAAQ,CAAA;AAAA,IACZ,IAAA;AAAA,IACA,QAAA;AAAA,IACA,MAAA;AAAA,IACA,MAAA;AAAA,IACA,cAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,GACC,EAAA;AACD,IAAA,MAAM,SAASC,uBAAc,EAAA;AAE7B,IAAA,cAAA,CAAe,IAAI,CAAQ,KAAA,EAAA,MAAA,CAAO,KAAM,EAAC,IAAI,MAAM,CAAA;AAEnD,IAAA,MAAM,qBAAqBC,iDAAyB,CAAA;AAAA,MAClD,QAAA;AAAA,MACA;AAAA,KACD,CAAA;AAED,IAAA,MAAA,CAAO,GAAI,CAAAC,uDAAA,CAA4B,EAAE,IAAA,EAAM,CAAC,CAAA;AAChD,IAAA,MAAA,CAAO,IAAIC,mDAA0B,CAAA,EAAE,MAAQ,EAAA,SAAA,EAAW,CAAC,CAAA;AAC3D,IAAO,MAAA,CAAA,GAAA,CAAI,mBAAmB,UAAU,CAAA;AACxC,IAAA,MAAA,CAAO,IAAIC,mEAAkC,CAAA,EAAE,IAAM,EAAA,QAAA,EAAU,CAAC,CAAA;AAEhE,IAAA,MAAM,eAAeJ,uBAAc,EAAA;AACnC,IAAA,MAAA,CAAO,IAAI,YAAY,CAAA;AAEvB,IAAA,MAAM,aAAaK,mCAAkB,CAAA,MAAA,CAAO,EAAE,MAAA,EAAQ,QAAQ,CAAA;AAC9D,IAAO,MAAA,CAAA,GAAA,CAAI,UAAW,CAAA,KAAA,EAAO,CAAA;AAE7B,IAAO,OAAA;AAAA,MACL,IAAI,OAAwB,EAAA;AAC1B,QAAA,YAAA,CAAa,IAAI,OAAO,CAAA;AAAA,OAC1B;AAAA,MACA,cAAc,MAA2C,EAAA;AACvD,QAAA,kBAAA,CAAmB,cAAc,MAAM,CAAA;AAAA;AACzC,KACF;AAAA;AAEJ,CAAC;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readHelmetOptions.cjs.js","sources":["../../../../src/entrypoints/rootHttpRouter/http/readHelmetOptions.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 { Config } from '@backstage/config';\nimport helmet from 'helmet';\nimport { HelmetOptions } from 'helmet';\nimport
|
|
1
|
+
{"version":3,"file":"readHelmetOptions.cjs.js","sources":["../../../../src/entrypoints/rootHttpRouter/http/readHelmetOptions.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 { Config } from '@backstage/config';\nimport helmet from 'helmet';\nimport { HelmetOptions } from 'helmet';\nimport kebabCase from 'lodash/kebabCase';\n\n/**\n * Attempts to read Helmet options from the backend configuration object.\n *\n * @public\n * @param config - The backend configuration object.\n * @returns A Helmet options object, or undefined if no Helmet configuration is present.\n *\n * @example\n * ```ts\n * const helmetOptions = readHelmetOptions(config.getConfig('backend'));\n * ```\n */\nexport function readHelmetOptions(config?: Config): HelmetOptions {\n const cspOptions = readCspDirectives(config);\n return {\n contentSecurityPolicy: {\n useDefaults: false,\n directives: applyCspDirectives(cspOptions),\n },\n // These are all disabled in order to maintain backwards compatibility\n // when bumping helmet v5. We can't enable these by default because\n // there is no way for users to configure them.\n // TODO(Rugvip): We should give control of this setup to consumers\n crossOriginEmbedderPolicy: false,\n crossOriginOpenerPolicy: false,\n crossOriginResourcePolicy: false,\n originAgentCluster: false,\n };\n}\n\ntype CspDirectives = Record<string, string[] | false> | undefined;\n\n/**\n * Attempts to read a CSP directives from the backend configuration object.\n *\n * @example\n * ```yaml\n * backend:\n * csp:\n * connect-src: [\"'self'\", 'http:', 'https:']\n * upgrade-insecure-requests: false\n * ```\n */\nfunction readCspDirectives(config?: Config): CspDirectives {\n const cc = config?.getOptionalConfig('csp');\n if (!cc) {\n return undefined;\n }\n\n const result: Record<string, string[] | false> = {};\n for (const key of cc.keys()) {\n if (cc.get(key) === false) {\n result[key] = false;\n } else {\n result[key] = cc.getStringArray(key);\n }\n }\n\n return result;\n}\n\ntype ContentSecurityPolicyDirectives = Exclude<\n HelmetOptions['contentSecurityPolicy'],\n boolean | undefined\n>['directives'];\n\nexport function applyCspDirectives(\n directives: CspDirectives,\n): ContentSecurityPolicyDirectives {\n const result: ContentSecurityPolicyDirectives =\n helmet.contentSecurityPolicy.getDefaultDirectives();\n\n // TODO(Rugvip): We currently use non-precompiled AJV for validation in the frontend, which uses eval.\n // It should be replaced by any other solution that doesn't require unsafe-eval.\n result['script-src'] = [\"'self'\", \"'unsafe-eval'\"];\n\n // TODO(Rugvip): This is removed so that we maintained backwards compatibility\n // when bumping to helmet v5, we could remove this as well as\n // skip setting `useDefaults: false` in the future.\n delete result['form-action'];\n\n if (directives) {\n for (const [key, value] of Object.entries(directives)) {\n const kebabCaseKey = kebabCase(key);\n if (value === false) {\n delete result[kebabCaseKey];\n } else {\n result[kebabCaseKey] = value;\n }\n }\n }\n\n return result;\n}\n"],"names":["helmet","kebabCase"],"mappings":";;;;;;;;;;AAiCO,SAAS,kBAAkB,MAAgC,EAAA;AAChE,EAAM,MAAA,UAAA,GAAa,kBAAkB,MAAM,CAAA;AAC3C,EAAO,OAAA;AAAA,IACL,qBAAuB,EAAA;AAAA,MACrB,WAAa,EAAA,KAAA;AAAA,MACb,UAAA,EAAY,mBAAmB,UAAU;AAAA,KAC3C;AAAA;AAAA;AAAA;AAAA;AAAA,IAKA,yBAA2B,EAAA,KAAA;AAAA,IAC3B,uBAAyB,EAAA,KAAA;AAAA,IACzB,yBAA2B,EAAA,KAAA;AAAA,IAC3B,kBAAoB,EAAA;AAAA,GACtB;AACF;AAeA,SAAS,kBAAkB,MAAgC,EAAA;AACzD,EAAM,MAAA,EAAA,GAAK,MAAQ,EAAA,iBAAA,CAAkB,KAAK,CAAA;AAC1C,EAAA,IAAI,CAAC,EAAI,EAAA;AACP,IAAO,OAAA,KAAA,CAAA;AAAA;AAGT,EAAA,MAAM,SAA2C,EAAC;AAClD,EAAW,KAAA,MAAA,GAAA,IAAO,EAAG,CAAA,IAAA,EAAQ,EAAA;AAC3B,IAAA,IAAI,EAAG,CAAA,GAAA,CAAI,GAAG,CAAA,KAAM,KAAO,EAAA;AACzB,MAAA,MAAA,CAAO,GAAG,CAAI,GAAA,KAAA;AAAA,KACT,MAAA;AACL,MAAA,MAAA,CAAO,GAAG,CAAA,GAAI,EAAG,CAAA,cAAA,CAAe,GAAG,CAAA;AAAA;AACrC;AAGF,EAAO,OAAA,MAAA;AACT;AAOO,SAAS,mBACd,UACiC,EAAA;AACjC,EAAM,MAAA,MAAA,GACJA,uBAAO,CAAA,qBAAA,CAAsB,oBAAqB,EAAA;AAIpD,EAAA,MAAA,CAAO,YAAY,CAAA,GAAI,CAAC,QAAA,EAAU,eAAe,CAAA;AAKjD,EAAA,OAAO,OAAO,aAAa,CAAA;AAE3B,EAAA,IAAI,UAAY,EAAA;AACd,IAAA,KAAA,MAAW,CAAC,GAAK,EAAA,KAAK,KAAK,MAAO,CAAA,OAAA,CAAQ,UAAU,CAAG,EAAA;AACrD,MAAM,MAAA,YAAA,GAAeC,2BAAU,GAAG,CAAA;AAClC,MAAA,IAAI,UAAU,KAAO,EAAA;AACnB,QAAA,OAAO,OAAO,YAAY,CAAA;AAAA,OACrB,MAAA;AACL,QAAA,MAAA,CAAO,YAAY,CAAI,GAAA,KAAA;AAAA;AACzB;AACF;AAGF,EAAO,OAAA,MAAA;AACT;;;;;"}
|
package/dist/package.json.cjs.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var name = "@backstage/backend-defaults";
|
|
6
|
-
var version = "0.
|
|
6
|
+
var version = "0.7.0-next.1";
|
|
7
7
|
var description = "Backend defaults used by Backstage backend apps";
|
|
8
8
|
var backstage = {
|
|
9
9
|
role: "node-library"
|
|
@@ -188,6 +188,14 @@ var dependencies = {
|
|
|
188
188
|
yn: "^4.0.0",
|
|
189
189
|
zod: "^3.22.4"
|
|
190
190
|
};
|
|
191
|
+
var peerDependencies = {
|
|
192
|
+
"@google-cloud/cloud-sql-connector": "^1.4.0"
|
|
193
|
+
};
|
|
194
|
+
var peerDependenciesMeta = {
|
|
195
|
+
"@google-cloud/cloud-sql-connector": {
|
|
196
|
+
optional: true
|
|
197
|
+
}
|
|
198
|
+
};
|
|
191
199
|
var devDependencies = {
|
|
192
200
|
"@aws-sdk/util-stream-node": "^3.350.0",
|
|
193
201
|
"@backstage/backend-plugin-api": "workspace:^",
|
|
@@ -209,14 +217,6 @@ var devDependencies = {
|
|
|
209
217
|
supertest: "^7.0.0",
|
|
210
218
|
"wait-for-expect": "^3.0.2"
|
|
211
219
|
};
|
|
212
|
-
var peerDependencies = {
|
|
213
|
-
"@google-cloud/cloud-sql-connector": "^1.4.0"
|
|
214
|
-
};
|
|
215
|
-
var peerDependenciesMeta = {
|
|
216
|
-
"@google-cloud/cloud-sql-connector": {
|
|
217
|
-
optional: true
|
|
218
|
-
}
|
|
219
|
-
};
|
|
220
220
|
var configSchema = "config.d.ts";
|
|
221
221
|
var packageinfo = {
|
|
222
222
|
name: name,
|
|
@@ -235,9 +235,9 @@ var packageinfo = {
|
|
|
235
235
|
files: files,
|
|
236
236
|
scripts: scripts,
|
|
237
237
|
dependencies: dependencies,
|
|
238
|
-
devDependencies: devDependencies,
|
|
239
238
|
peerDependencies: peerDependencies,
|
|
240
239
|
peerDependenciesMeta: peerDependenciesMeta,
|
|
240
|
+
devDependencies: devDependencies,
|
|
241
241
|
configSchema: configSchema
|
|
242
242
|
};
|
|
243
243
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/backend-defaults",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0-next.1",
|
|
4
4
|
"description": "Backend defaults used by Backstage backend apps",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "node-library"
|
|
@@ -193,20 +193,20 @@
|
|
|
193
193
|
"@aws-sdk/types": "^3.347.0",
|
|
194
194
|
"@azure/identity": "^4.0.0",
|
|
195
195
|
"@azure/storage-blob": "^12.5.0",
|
|
196
|
-
"@backstage/backend-app-api": "
|
|
197
|
-
"@backstage/backend-dev-utils": "
|
|
198
|
-
"@backstage/backend-plugin-api": "
|
|
199
|
-
"@backstage/cli-common": "
|
|
200
|
-
"@backstage/cli-node": "
|
|
201
|
-
"@backstage/config": "
|
|
202
|
-
"@backstage/config-loader": "
|
|
203
|
-
"@backstage/errors": "
|
|
204
|
-
"@backstage/integration": "
|
|
205
|
-
"@backstage/integration-aws-node": "
|
|
206
|
-
"@backstage/plugin-auth-node": "
|
|
207
|
-
"@backstage/plugin-events-node": "
|
|
208
|
-
"@backstage/plugin-permission-node": "
|
|
209
|
-
"@backstage/types": "
|
|
196
|
+
"@backstage/backend-app-api": "1.1.1-next.1",
|
|
197
|
+
"@backstage/backend-dev-utils": "0.1.5",
|
|
198
|
+
"@backstage/backend-plugin-api": "1.1.1-next.1",
|
|
199
|
+
"@backstage/cli-common": "0.1.15",
|
|
200
|
+
"@backstage/cli-node": "0.2.12-next.0",
|
|
201
|
+
"@backstage/config": "1.3.2-next.0",
|
|
202
|
+
"@backstage/config-loader": "1.9.5-next.1",
|
|
203
|
+
"@backstage/errors": "1.2.7-next.0",
|
|
204
|
+
"@backstage/integration": "1.16.1-next.0",
|
|
205
|
+
"@backstage/integration-aws-node": "0.1.15-next.0",
|
|
206
|
+
"@backstage/plugin-auth-node": "0.5.6-next.1",
|
|
207
|
+
"@backstage/plugin-events-node": "0.4.7-next.1",
|
|
208
|
+
"@backstage/plugin-permission-node": "0.8.7-next.1",
|
|
209
|
+
"@backstage/types": "1.2.1-next.0",
|
|
210
210
|
"@google-cloud/storage": "^7.0.0",
|
|
211
211
|
"@keyv/memcache": "^2.0.1",
|
|
212
212
|
"@keyv/redis": "^4.0.1",
|
|
@@ -257,11 +257,19 @@
|
|
|
257
257
|
"yn": "^4.0.0",
|
|
258
258
|
"zod": "^3.22.4"
|
|
259
259
|
},
|
|
260
|
+
"peerDependencies": {
|
|
261
|
+
"@google-cloud/cloud-sql-connector": "^1.4.0"
|
|
262
|
+
},
|
|
263
|
+
"peerDependenciesMeta": {
|
|
264
|
+
"@google-cloud/cloud-sql-connector": {
|
|
265
|
+
"optional": true
|
|
266
|
+
}
|
|
267
|
+
},
|
|
260
268
|
"devDependencies": {
|
|
261
269
|
"@aws-sdk/util-stream-node": "^3.350.0",
|
|
262
|
-
"@backstage/backend-plugin-api": "
|
|
263
|
-
"@backstage/backend-test-utils": "
|
|
264
|
-
"@backstage/cli": "
|
|
270
|
+
"@backstage/backend-plugin-api": "1.1.1-next.1",
|
|
271
|
+
"@backstage/backend-test-utils": "1.2.1-next.1",
|
|
272
|
+
"@backstage/cli": "0.29.5-next.1",
|
|
265
273
|
"@google-cloud/cloud-sql-connector": "^1.4.0",
|
|
266
274
|
"@types/archiver": "^6.0.0",
|
|
267
275
|
"@types/base64-stream": "^1.0.2",
|
|
@@ -278,13 +286,5 @@
|
|
|
278
286
|
"supertest": "^7.0.0",
|
|
279
287
|
"wait-for-expect": "^3.0.2"
|
|
280
288
|
},
|
|
281
|
-
"peerDependencies": {
|
|
282
|
-
"@google-cloud/cloud-sql-connector": "^1.4.0"
|
|
283
|
-
},
|
|
284
|
-
"peerDependenciesMeta": {
|
|
285
|
-
"@google-cloud/cloud-sql-connector": {
|
|
286
|
-
"optional": true
|
|
287
|
-
}
|
|
288
|
-
},
|
|
289
289
|
"configSchema": "config.d.ts"
|
|
290
290
|
}
|