@backstage-community/plugin-tech-insights-backend 2.3.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +0 -14
- package/README.md +17 -0
- package/dist/plugin/config.cjs.js +1 -0
- package/dist/plugin/config.cjs.js.map +1 -1
- package/dist/plugin/plugin.cjs.js +2 -6
- package/dist/plugin/plugin.cjs.js.map +1 -1
- package/dist/service/router.cjs.js +5 -0
- package/dist/service/router.cjs.js.map +1 -1
- package/package.json +4 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,19 +1,5 @@
|
|
|
1
1
|
# @backstage-community/plugin-tech-insights-backend
|
|
2
2
|
|
|
3
|
-
## 2.3.0
|
|
4
|
-
|
|
5
|
-
### Minor Changes
|
|
6
|
-
|
|
7
|
-
- ac739ca: This version adds `techInsightsCheckReadPermission`, `techInsightsCheckUpdatePermission`, and `techInsightsFactRetrieverReadPermission`, which can be used to permission Tech Insights functionalities.
|
|
8
|
-
|
|
9
|
-
### Patch Changes
|
|
10
|
-
|
|
11
|
-
- 0a26736: fix null timestamp error when using tech-insights with maturity plugin
|
|
12
|
-
- Updated dependencies [375612d]
|
|
13
|
-
- Updated dependencies [ac739ca]
|
|
14
|
-
- @backstage-community/plugin-tech-insights-node@2.4.0
|
|
15
|
-
- @backstage-community/plugin-tech-insights-common@0.6.0
|
|
16
|
-
|
|
17
3
|
## 2.2.1
|
|
18
4
|
|
|
19
5
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
The backend plugin for Tech Insights.
|
|
4
4
|
|
|
5
|
+
## Breaking Changes in v3.0.0
|
|
6
|
+
|
|
7
|
+
This version includes breaking changes related to permissions. Please review the changes carefully before upgrading:
|
|
8
|
+
|
|
9
|
+
- Added required permissions for accessing Tech Insights features
|
|
10
|
+
- Users must now have the appropriate policies added to their roles to access Tech Insights functionality
|
|
11
|
+
- This change enforces better security by ensuring explicit permission grants for Tech Insights operations
|
|
12
|
+
|
|
13
|
+
To upgrade, you'll need to:
|
|
14
|
+
|
|
15
|
+
1. Update your permission policies to include the necessary Tech Insights permissions
|
|
16
|
+
2. Ensure your users' roles have the appropriate policies assigned
|
|
17
|
+
|
|
18
|
+
It provides the API for the frontend tech insights, scorecards and fact visualization functionality, as well as a framework to run fact retrievers and store fact values in to a data store.
|
|
19
|
+
|
|
20
|
+
Looking for the old backend installation docs? Visit [here](./docs/old-backend-system.md).
|
|
21
|
+
|
|
5
22
|
## Installation
|
|
6
23
|
|
|
7
24
|
### Install the package
|
|
@@ -14,6 +14,7 @@ require('@backstage/catalog-model');
|
|
|
14
14
|
require('@backstage/errors');
|
|
15
15
|
require('@backstage/backend-defaults/rootHttpRouter');
|
|
16
16
|
require('@backstage/plugin-permission-common');
|
|
17
|
+
require('@backstage/plugin-permission-node');
|
|
17
18
|
require('p-limit');
|
|
18
19
|
|
|
19
20
|
function readLifecycleConfig(config$1) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.cjs.js","sources":["../../src/plugin/config.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, readDurationFromConfig } from '@backstage/config';\nimport {\n FactLifecycle,\n FactRetriever,\n FactRetrieverRegistration,\n} from '@backstage-community/plugin-tech-insights-node';\nimport {\n createFactRetrieverRegistration,\n FactRetrieverRegistrationOptions,\n} from '../service';\n\ntype FactRetrieverConfig = Omit<\n FactRetrieverRegistrationOptions,\n 'factRetriever'\n>;\n\nfunction readLifecycleConfig(\n config: Config | undefined,\n): FactLifecycle | undefined {\n if (!config) {\n return undefined;\n }\n\n if (config.has('maxItems')) {\n return {\n maxItems: config.getNumber('maxItems'),\n };\n }\n\n return {\n timeToLive: readDurationFromConfig(config.getConfig('timeToLive')),\n };\n}\n\nfunction readFactRetrieverConfig(\n config: Config,\n name: string,\n): FactRetrieverConfig | undefined {\n const factRetrieverConfig = config.getOptionalConfig(\n `techInsights.factRetrievers.${name}`,\n );\n if (!factRetrieverConfig) {\n return undefined;\n }\n\n const cadence = factRetrieverConfig.getString('cadence');\n const initialDelay = factRetrieverConfig.has('initialDelay')\n ? readDurationFromConfig(factRetrieverConfig.getConfig('initialDelay'))\n : undefined;\n const lifecycle = readLifecycleConfig(\n factRetrieverConfig.getOptionalConfig('lifecycle'),\n );\n const timeout = factRetrieverConfig.has('timeout')\n ? readDurationFromConfig(factRetrieverConfig.getConfig('timeout'))\n : undefined;\n\n return {\n cadence,\n initialDelay,\n lifecycle,\n timeout,\n };\n}\n\nexport function createFactRetrieverRegistrationFromConfig(\n config: Config,\n name: string,\n factRetriever: FactRetriever,\n): FactRetrieverRegistration | undefined {\n const factRetrieverConfig = readFactRetrieverConfig(config, name);\n\n return factRetrieverConfig\n ? createFactRetrieverRegistration({\n ...factRetrieverConfig,\n factRetriever,\n })\n : undefined;\n}\n"],"names":["config","readDurationFromConfig","createFactRetrieverRegistration"],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.cjs.js","sources":["../../src/plugin/config.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, readDurationFromConfig } from '@backstage/config';\nimport {\n FactLifecycle,\n FactRetriever,\n FactRetrieverRegistration,\n} from '@backstage-community/plugin-tech-insights-node';\nimport {\n createFactRetrieverRegistration,\n FactRetrieverRegistrationOptions,\n} from '../service';\n\ntype FactRetrieverConfig = Omit<\n FactRetrieverRegistrationOptions,\n 'factRetriever'\n>;\n\nfunction readLifecycleConfig(\n config: Config | undefined,\n): FactLifecycle | undefined {\n if (!config) {\n return undefined;\n }\n\n if (config.has('maxItems')) {\n return {\n maxItems: config.getNumber('maxItems'),\n };\n }\n\n return {\n timeToLive: readDurationFromConfig(config.getConfig('timeToLive')),\n };\n}\n\nfunction readFactRetrieverConfig(\n config: Config,\n name: string,\n): FactRetrieverConfig | undefined {\n const factRetrieverConfig = config.getOptionalConfig(\n `techInsights.factRetrievers.${name}`,\n );\n if (!factRetrieverConfig) {\n return undefined;\n }\n\n const cadence = factRetrieverConfig.getString('cadence');\n const initialDelay = factRetrieverConfig.has('initialDelay')\n ? readDurationFromConfig(factRetrieverConfig.getConfig('initialDelay'))\n : undefined;\n const lifecycle = readLifecycleConfig(\n factRetrieverConfig.getOptionalConfig('lifecycle'),\n );\n const timeout = factRetrieverConfig.has('timeout')\n ? readDurationFromConfig(factRetrieverConfig.getConfig('timeout'))\n : undefined;\n\n return {\n cadence,\n initialDelay,\n lifecycle,\n timeout,\n };\n}\n\nexport function createFactRetrieverRegistrationFromConfig(\n config: Config,\n name: string,\n factRetriever: FactRetriever,\n): FactRetrieverRegistration | undefined {\n const factRetrieverConfig = readFactRetrieverConfig(config, name);\n\n return factRetrieverConfig\n ? createFactRetrieverRegistration({\n ...factRetrieverConfig,\n factRetriever,\n })\n : undefined;\n}\n"],"names":["config","readDurationFromConfig","createFactRetrieverRegistration"],"mappings":";;;;;;;;;;;;;;;;;;;AAgCA,SAAS,oBACPA,QAC2B,EAAA;AAC3B,EAAA,IAAI,CAACA,QAAQ,EAAA;AACX,IAAO,OAAA,KAAA,CAAA;AAAA;AAGT,EAAI,IAAAA,QAAA,CAAO,GAAI,CAAA,UAAU,CAAG,EAAA;AAC1B,IAAO,OAAA;AAAA,MACL,QAAA,EAAUA,QAAO,CAAA,SAAA,CAAU,UAAU;AAAA,KACvC;AAAA;AAGF,EAAO,OAAA;AAAA,IACL,UAAY,EAAAC,6BAAA,CAAuBD,QAAO,CAAA,SAAA,CAAU,YAAY,CAAC;AAAA,GACnE;AACF;AAEA,SAAS,uBAAA,CACPA,UACA,IACiC,EAAA;AACjC,EAAA,MAAM,sBAAsBA,QAAO,CAAA,iBAAA;AAAA,IACjC,+BAA+B,IAAI,CAAA;AAAA,GACrC;AACA,EAAA,IAAI,CAAC,mBAAqB,EAAA;AACxB,IAAO,OAAA,KAAA,CAAA;AAAA;AAGT,EAAM,MAAA,OAAA,GAAU,mBAAoB,CAAA,SAAA,CAAU,SAAS,CAAA;AACvD,EAAM,MAAA,YAAA,GAAe,mBAAoB,CAAA,GAAA,CAAI,cAAc,CAAA,GACvDC,8BAAuB,mBAAoB,CAAA,SAAA,CAAU,cAAc,CAAC,CACpE,GAAA,KAAA,CAAA;AACJ,EAAA,MAAM,SAAY,GAAA,mBAAA;AAAA,IAChB,mBAAA,CAAoB,kBAAkB,WAAW;AAAA,GACnD;AACA,EAAM,MAAA,OAAA,GAAU,mBAAoB,CAAA,GAAA,CAAI,SAAS,CAAA,GAC7CA,8BAAuB,mBAAoB,CAAA,SAAA,CAAU,SAAS,CAAC,CAC/D,GAAA,KAAA,CAAA;AAEJ,EAAO,OAAA;AAAA,IACL,OAAA;AAAA,IACA,YAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,GACF;AACF;AAEgB,SAAA,yCAAA,CACd,MACA,EAAA,IAAA,EACA,aACuC,EAAA;AACvC,EAAM,MAAA,mBAAA,GAAsB,uBAAwB,CAAA,MAAA,EAAQ,IAAI,CAAA;AAEhE,EAAA,OAAO,sBACHC,mDAAgC,CAAA;AAAA,IAC9B,GAAG,mBAAA;AAAA,IACH;AAAA,GACD,CACD,GAAA,KAAA,CAAA;AACN;;;;"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
|
-
var pluginTechInsightsCommon = require('@backstage-community/plugin-tech-insights-common');
|
|
5
4
|
var pluginTechInsightsNode = require('@backstage-community/plugin-tech-insights-node');
|
|
6
5
|
var entityMetadataFactRetriever = require('../service/fact/factRetrievers/entityMetadataFactRetriever.cjs.js');
|
|
7
6
|
var entityOwnershipFactRetriever = require('../service/fact/factRetrievers/entityOwnershipFactRetriever.cjs.js');
|
|
@@ -58,8 +57,7 @@ const techInsightsPlugin = backendPluginApi.createBackendPlugin({
|
|
|
58
57
|
auth: backendPluginApi.coreServices.auth,
|
|
59
58
|
urlReader: backendPluginApi.coreServices.urlReader,
|
|
60
59
|
httpAuth: backendPluginApi.coreServices.httpAuth,
|
|
61
|
-
permissions: backendPluginApi.coreServices.permissions
|
|
62
|
-
permissionsRegistry: backendPluginApi.coreServices.permissionsRegistry
|
|
60
|
+
permissions: backendPluginApi.coreServices.permissions
|
|
63
61
|
},
|
|
64
62
|
async init({
|
|
65
63
|
config: config$1,
|
|
@@ -71,10 +69,8 @@ const techInsightsPlugin = backendPluginApi.createBackendPlugin({
|
|
|
71
69
|
auth,
|
|
72
70
|
urlReader,
|
|
73
71
|
httpAuth,
|
|
74
|
-
permissions
|
|
75
|
-
permissionsRegistry
|
|
72
|
+
permissions
|
|
76
73
|
}) {
|
|
77
|
-
permissionsRegistry.addPermissions(pluginTechInsightsCommon.techInsightsPermissions);
|
|
78
74
|
const factRetrievers = Object.entries(
|
|
79
75
|
addedFactRetrievers
|
|
80
76
|
).map(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.cjs.js","sources":["../../src/plugin/plugin.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 {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport {\n CheckResult,\n Check,\n
|
|
1
|
+
{"version":3,"file":"plugin.cjs.js","sources":["../../src/plugin/plugin.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 {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport {\n CheckResult,\n Check,\n} from '@backstage-community/plugin-tech-insights-common';\nimport {\n FactCheckerFactory,\n FactRetriever,\n FactRetrieverRegistration,\n FactRetrieverRegistry,\n PersistenceContext,\n techInsightsFactCheckerFactoryExtensionPoint,\n techInsightsFactRetrieverRegistryExtensionPoint,\n techInsightsFactRetrieversExtensionPoint,\n techInsightsPersistenceContextExtensionPoint,\n} from '@backstage-community/plugin-tech-insights-node';\nimport {\n buildTechInsightsContext,\n createRouter,\n entityMetadataFactRetriever,\n entityOwnershipFactRetriever,\n techdocsFactRetriever,\n} from '../service';\nimport { createFactRetrieverRegistrationFromConfig } from './config';\n\n/**\n * The tech-insights backend plugin.\n *\n * @public\n */\nexport const techInsightsPlugin = createBackendPlugin({\n pluginId: 'tech-insights',\n register(env) {\n let factCheckerFactory: FactCheckerFactory<Check, CheckResult> | undefined =\n undefined;\n env.registerExtensionPoint(techInsightsFactCheckerFactoryExtensionPoint, {\n setFactCheckerFactory<\n CheckType extends Check,\n CheckResultType extends CheckResult,\n >(factory: FactCheckerFactory<CheckType, CheckResultType>): void {\n factCheckerFactory = factory;\n },\n });\n\n let factRetrieverRegistry: FactRetrieverRegistry | undefined = undefined;\n env.registerExtensionPoint(\n techInsightsFactRetrieverRegistryExtensionPoint,\n {\n setFactRetrieverRegistry(registry: FactRetrieverRegistry): void {\n factRetrieverRegistry = registry;\n },\n },\n );\n\n // initialized with built-in fact retrievers\n // only added as registration if there is config for them\n const addedFactRetrievers: Record<string, FactRetriever> = {\n entityMetadataFactRetriever,\n entityOwnershipFactRetriever,\n techdocsFactRetriever,\n };\n env.registerExtensionPoint(techInsightsFactRetrieversExtensionPoint, {\n addFactRetrievers(factRetrievers: Record<string, FactRetriever>): void {\n Object.entries(factRetrievers).forEach(([key, value]) => {\n addedFactRetrievers[key] = value;\n });\n },\n });\n\n let persistenceContext: PersistenceContext | undefined = undefined;\n env.registerExtensionPoint(techInsightsPersistenceContextExtensionPoint, {\n setPersistenceContext(context: PersistenceContext): void {\n persistenceContext = context;\n },\n });\n\n env.registerInit({\n deps: {\n config: coreServices.rootConfig,\n database: coreServices.database,\n discovery: coreServices.discovery,\n httpRouter: coreServices.httpRouter,\n logger: coreServices.logger,\n scheduler: coreServices.scheduler,\n auth: coreServices.auth,\n urlReader: coreServices.urlReader,\n httpAuth: coreServices.httpAuth,\n permissions: coreServices.permissions,\n },\n async init({\n config,\n database,\n discovery,\n httpRouter,\n logger,\n scheduler,\n auth,\n urlReader,\n httpAuth,\n permissions,\n }) {\n const factRetrievers: FactRetrieverRegistration[] = Object.entries(\n addedFactRetrievers,\n )\n .map(([name, factRetriever]) =>\n createFactRetrieverRegistrationFromConfig(\n config,\n name,\n factRetriever,\n ),\n )\n .filter(registration => registration) as FactRetrieverRegistration[];\n\n const context = await buildTechInsightsContext({\n config,\n database,\n discovery,\n factCheckerFactory,\n factRetrieverRegistry,\n factRetrievers,\n logger,\n persistenceContext,\n scheduler,\n auth,\n urlReader,\n });\n\n httpRouter.use(\n await createRouter({\n ...context,\n config,\n logger,\n permissions,\n httpAuth,\n }),\n );\n },\n });\n },\n});\n"],"names":["createBackendPlugin","techInsightsFactCheckerFactoryExtensionPoint","techInsightsFactRetrieverRegistryExtensionPoint","entityMetadataFactRetriever","entityOwnershipFactRetriever","techdocsFactRetriever","techInsightsFactRetrieversExtensionPoint","techInsightsPersistenceContextExtensionPoint","coreServices","config","createFactRetrieverRegistrationFromConfig","buildTechInsightsContext","createRouter"],"mappings":"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"}
|
|
@@ -8,6 +8,7 @@ var catalogModel = require('@backstage/catalog-model');
|
|
|
8
8
|
var errors = require('@backstage/errors');
|
|
9
9
|
var rootHttpRouter = require('@backstage/backend-defaults/rootHttpRouter');
|
|
10
10
|
var pluginPermissionCommon = require('@backstage/plugin-permission-common');
|
|
11
|
+
var pluginPermissionNode = require('@backstage/plugin-permission-node');
|
|
11
12
|
var pLimit = require('p-limit');
|
|
12
13
|
|
|
13
14
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
@@ -18,7 +19,11 @@ var pLimit__default = /*#__PURE__*/_interopDefaultCompat(pLimit);
|
|
|
18
19
|
|
|
19
20
|
async function createRouter(options) {
|
|
20
21
|
const router = Router__default.default();
|
|
22
|
+
const permissionsIntegrationRouter = pluginPermissionNode.createPermissionIntegrationRouter({
|
|
23
|
+
permissions: pluginTechInsightsCommon.techInsightsPermissions
|
|
24
|
+
});
|
|
21
25
|
router.use(express__default.default.json());
|
|
26
|
+
router.use(permissionsIntegrationRouter);
|
|
22
27
|
const {
|
|
23
28
|
persistenceContext,
|
|
24
29
|
factChecker,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.cjs.js","sources":["../../src/service/router.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 express, { Request } from 'express';\nimport Router from 'express-promise-router';\nimport { Config } from '@backstage/config';\nimport {\n FactChecker,\n PersistenceContext,\n} from '@backstage-community/plugin-tech-insights-node';\n\nimport {\n CheckResult,\n Check,\n techInsightsCheckReadPermission,\n techInsightsCheckUpdatePermission,\n techInsightsFactRetrieverReadPermission,\n} from '@backstage-community/plugin-tech-insights-common';\nimport { DateTime } from 'luxon';\nimport {\n CompoundEntityRef,\n parseEntityRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { serializeError } from '@backstage/errors';\nimport {\n LoggerService,\n PermissionsService,\n HttpAuthService,\n} from '@backstage/backend-plugin-api';\nimport { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';\nimport {\n AuthorizeResult,\n BasicPermission,\n} from '@backstage/plugin-permission-common';\nimport { NotAllowedError } from '@backstage/errors';\nimport pLimit from 'p-limit';\n\n/**\n * @public\n *\n * RouterOptions to construct TechInsights endpoints\n * @typeParam CheckType - Type of the check for the fact checker this builder returns\n * @typeParam CheckResultType - Type of the check result for the fact checker this builder returns\n */\nexport interface RouterOptions<\n CheckType extends Check,\n CheckResultType extends CheckResult,\n> {\n /**\n * Optional FactChecker implementation. If omitted, endpoints are not constructed\n */\n factChecker?: FactChecker<CheckType, CheckResultType>;\n\n /**\n * TechInsights PersistenceContext. Should contain an implementation of TechInsightsStore\n */\n persistenceContext: PersistenceContext;\n\n /**\n * Backstage config object\n */\n config: Config;\n\n /**\n * Implementation of Winston logger\n */\n logger: LoggerService;\n\n /**\n * Implementation of PermissionsService\n */\n permissions: PermissionsService;\n\n /**\n * Implementation of HttpAuthService\n */\n httpAuth: HttpAuthService;\n}\n\n/**\n * @public\n *\n * Constructs a tech-insights router.\n *\n * Exposes endpoints to handle facts\n * Exposes optional endpoints to handle checks if a FactChecker implementation is passed in\n *\n * @param options - RouterOptions object\n */\nexport async function createRouter<\n CheckType extends Check,\n CheckResultType extends CheckResult,\n>(options: RouterOptions<CheckType, CheckResultType>): Promise<express.Router> {\n const router = Router();\n\n router.use(express.json());\n\n const {\n persistenceContext,\n factChecker,\n logger,\n config,\n permissions,\n httpAuth,\n } = options;\n const { techInsightsStore } = persistenceContext;\n\n const factory = MiddlewareFactory.create({ logger, config });\n\n const authorize = async (request: Request, permission: BasicPermission) => {\n const decision = (\n await permissions.authorize([{ permission: permission }], {\n credentials: await httpAuth.credentials(request),\n })\n )[0];\n\n return decision;\n };\n\n if (factChecker) {\n logger.info('Fact checker configured. Enabling fact checking endpoints.');\n router.get('/checks', async (req, res) => {\n const decision = await authorize(req, techInsightsCheckReadPermission);\n\n if (decision.result === AuthorizeResult.DENY) {\n throw new NotAllowedError('Unauthorized');\n }\n return res.json(await factChecker.getChecks());\n });\n\n router.post('/checks/run/:namespace/:kind/:name', async (req, res) => {\n const decision = await authorize(req, techInsightsCheckUpdatePermission);\n\n if (decision.result === AuthorizeResult.DENY) {\n throw new NotAllowedError('Unauthorized');\n }\n\n const { namespace, kind, name } = req.params;\n const { checks }: { checks: string[] } = req.body;\n const entityTriplet = stringifyEntityRef({ namespace, kind, name });\n const checkResult = await factChecker.runChecks(entityTriplet, checks);\n return res.json(checkResult);\n });\n\n const checksRunConcurrency =\n config.getOptionalNumber('techInsights.checksRunConcurrency') || 100;\n router.post('/checks/run', async (req, res) => {\n const decision = await authorize(req, techInsightsCheckUpdatePermission);\n\n if (decision.result === AuthorizeResult.DENY) {\n throw new NotAllowedError('Unauthorized');\n }\n const checks: string[] = req.body.checks;\n let entities: CompoundEntityRef[] = req.body.entities;\n if (entities.length === 0) {\n entities = await techInsightsStore.getEntities();\n }\n const limit = pLimit(checksRunConcurrency);\n const tasks = entities.map(async entity =>\n limit(async () => {\n const entityTriplet =\n typeof entity === 'string' ? entity : stringifyEntityRef(entity);\n try {\n const results = await factChecker.runChecks(entityTriplet, checks);\n return {\n entity: entityTriplet,\n results,\n };\n } catch (e: any) {\n const error = serializeError(e);\n logger.error(`${error.name}: ${error.message}`);\n return {\n entity: entityTriplet,\n error: error,\n results: [],\n };\n }\n }),\n );\n const results = await Promise.all(tasks);\n return res.json(results);\n });\n } else {\n logger.info(\n 'Starting tech insights module without fact checking endpoints.',\n );\n }\n\n router.get('/fact-schemas', async (req, res) => {\n const decision = await authorize(\n req,\n techInsightsFactRetrieverReadPermission,\n );\n\n if (decision.result === AuthorizeResult.DENY) {\n throw new NotAllowedError('Unauthorized');\n }\n\n const ids = req.query.ids as string[];\n return res.json(await techInsightsStore.getLatestSchemas(ids));\n });\n\n /**\n * /facts/latest?entity=component:default/mycomponent&ids[]=factRetrieverId1&ids[]=factRetrieverId2\n */\n router.get('/facts/latest', async (req, res) => {\n const decision = await authorize(\n req,\n techInsightsFactRetrieverReadPermission,\n );\n\n if (decision.result === AuthorizeResult.DENY) {\n throw new NotAllowedError('Unauthorized');\n }\n const { entity } = req.query;\n const { namespace, kind, name } = parseEntityRef(entity as string);\n\n if (!req.query.ids) {\n return res\n .status(422)\n .json({ error: 'Failed to parse ids from request' });\n }\n const ids = [req.query.ids].flat() as string[];\n return res.json(\n await techInsightsStore.getLatestFactsByIds(\n ids,\n stringifyEntityRef({ namespace, kind, name }),\n ),\n );\n });\n\n /**\n * /facts/range?entity=component:default/mycomponent&startDateTime=2021-12-24T01:23:45&endDateTime=2021-12-31T23:59:59&ids[]=factRetrieverId1&ids[]=factRetrieverId2\n */\n router.get('/facts/range', async (req, res) => {\n const decision = await authorize(\n req,\n techInsightsFactRetrieverReadPermission,\n );\n\n if (decision.result === AuthorizeResult.DENY) {\n throw new NotAllowedError('Unauthorized');\n }\n\n const { entity } = req.query;\n const { namespace, kind, name } = parseEntityRef(entity as string);\n\n if (!req.query.ids) {\n return res\n .status(422)\n .json({ error: 'Failed to parse ids from request' });\n }\n const ids = [req.query.ids].flat() as string[];\n const startDatetime = DateTime.fromISO(req.query.startDatetime as string);\n const endDatetime = DateTime.fromISO(req.query.endDatetime as string);\n if (!startDatetime.isValid || !endDatetime.isValid) {\n return res.status(422).json({\n message: 'Failed to parse datetime from request',\n field: !startDatetime.isValid ? 'startDateTime' : 'endDateTime',\n value: !startDatetime.isValid ? startDatetime : endDatetime,\n });\n }\n const entityTriplet = stringifyEntityRef({ namespace, kind, name });\n return res.json(\n await techInsightsStore.getFactsBetweenTimestampsByIds(\n ids,\n entityTriplet,\n startDatetime,\n endDatetime,\n ),\n );\n });\n\n router.use(factory.error());\n return router;\n}\n"],"names":["Router","express","MiddlewareFactory","techInsightsCheckReadPermission","AuthorizeResult","NotAllowedError","techInsightsCheckUpdatePermission","stringifyEntityRef","pLimit","results","serializeError","techInsightsFactRetrieverReadPermission","parseEntityRef","DateTime"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"router.cjs.js","sources":["../../src/service/router.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 express, { Request } from 'express';\nimport Router from 'express-promise-router';\nimport { Config } from '@backstage/config';\nimport {\n FactChecker,\n PersistenceContext,\n} from '@backstage-community/plugin-tech-insights-node';\n\nimport {\n CheckResult,\n Check,\n techInsightsCheckReadPermission,\n techInsightsCheckUpdatePermission,\n techInsightsPermissions,\n techInsightsFactRetrieverReadPermission,\n} from '@backstage-community/plugin-tech-insights-common';\nimport { DateTime } from 'luxon';\nimport {\n CompoundEntityRef,\n parseEntityRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { serializeError } from '@backstage/errors';\nimport {\n LoggerService,\n PermissionsService,\n HttpAuthService,\n} from '@backstage/backend-plugin-api';\nimport { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';\nimport {\n AuthorizeResult,\n BasicPermission,\n} from '@backstage/plugin-permission-common';\nimport { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node';\nimport { NotAllowedError } from '@backstage/errors';\nimport pLimit from 'p-limit';\n\n/**\n * @public\n *\n * RouterOptions to construct TechInsights endpoints\n * @typeParam CheckType - Type of the check for the fact checker this builder returns\n * @typeParam CheckResultType - Type of the check result for the fact checker this builder returns\n */\nexport interface RouterOptions<\n CheckType extends Check,\n CheckResultType extends CheckResult,\n> {\n /**\n * Optional FactChecker implementation. If omitted, endpoints are not constructed\n */\n factChecker?: FactChecker<CheckType, CheckResultType>;\n\n /**\n * TechInsights PersistenceContext. Should contain an implementation of TechInsightsStore\n */\n persistenceContext: PersistenceContext;\n\n /**\n * Backstage config object\n */\n config: Config;\n\n /**\n * Implementation of Winston logger\n */\n logger: LoggerService;\n\n /**\n * Implementation of PermissionsService\n */\n permissions: PermissionsService;\n\n /**\n * Implementation of HttpAuthService\n */\n httpAuth: HttpAuthService;\n}\n\n/**\n * @public\n *\n * Constructs a tech-insights router.\n *\n * Exposes endpoints to handle facts\n * Exposes optional endpoints to handle checks if a FactChecker implementation is passed in\n *\n * @param options - RouterOptions object\n */\nexport async function createRouter<\n CheckType extends Check,\n CheckResultType extends CheckResult,\n>(options: RouterOptions<CheckType, CheckResultType>): Promise<express.Router> {\n const router = Router();\n\n const permissionsIntegrationRouter = createPermissionIntegrationRouter({\n permissions: techInsightsPermissions,\n });\n\n router.use(express.json());\n router.use(permissionsIntegrationRouter);\n\n const {\n persistenceContext,\n factChecker,\n logger,\n config,\n permissions,\n httpAuth,\n } = options;\n const { techInsightsStore } = persistenceContext;\n\n const factory = MiddlewareFactory.create({ logger, config });\n\n const authorize = async (request: Request, permission: BasicPermission) => {\n const decision = (\n await permissions.authorize([{ permission: permission }], {\n credentials: await httpAuth.credentials(request),\n })\n )[0];\n\n return decision;\n };\n\n if (factChecker) {\n logger.info('Fact checker configured. Enabling fact checking endpoints.');\n router.get('/checks', async (req, res) => {\n const decision = await authorize(req, techInsightsCheckReadPermission);\n\n if (decision.result === AuthorizeResult.DENY) {\n throw new NotAllowedError('Unauthorized');\n }\n return res.json(await factChecker.getChecks());\n });\n\n router.post('/checks/run/:namespace/:kind/:name', async (req, res) => {\n const decision = await authorize(req, techInsightsCheckUpdatePermission);\n\n if (decision.result === AuthorizeResult.DENY) {\n throw new NotAllowedError('Unauthorized');\n }\n\n const { namespace, kind, name } = req.params;\n const { checks }: { checks: string[] } = req.body;\n const entityTriplet = stringifyEntityRef({ namespace, kind, name });\n const checkResult = await factChecker.runChecks(entityTriplet, checks);\n return res.json(checkResult);\n });\n\n const checksRunConcurrency =\n config.getOptionalNumber('techInsights.checksRunConcurrency') || 100;\n router.post('/checks/run', async (req, res) => {\n const decision = await authorize(req, techInsightsCheckUpdatePermission);\n\n if (decision.result === AuthorizeResult.DENY) {\n throw new NotAllowedError('Unauthorized');\n }\n const checks: string[] = req.body.checks;\n let entities: CompoundEntityRef[] = req.body.entities;\n if (entities.length === 0) {\n entities = await techInsightsStore.getEntities();\n }\n const limit = pLimit(checksRunConcurrency);\n const tasks = entities.map(async entity =>\n limit(async () => {\n const entityTriplet =\n typeof entity === 'string' ? entity : stringifyEntityRef(entity);\n try {\n const results = await factChecker.runChecks(entityTriplet, checks);\n return {\n entity: entityTriplet,\n results,\n };\n } catch (e: any) {\n const error = serializeError(e);\n logger.error(`${error.name}: ${error.message}`);\n return {\n entity: entityTriplet,\n error: error,\n results: [],\n };\n }\n }),\n );\n const results = await Promise.all(tasks);\n return res.json(results);\n });\n } else {\n logger.info(\n 'Starting tech insights module without fact checking endpoints.',\n );\n }\n\n router.get('/fact-schemas', async (req, res) => {\n const decision = await authorize(\n req,\n techInsightsFactRetrieverReadPermission,\n );\n\n if (decision.result === AuthorizeResult.DENY) {\n throw new NotAllowedError('Unauthorized');\n }\n\n const ids = req.query.ids as string[];\n return res.json(await techInsightsStore.getLatestSchemas(ids));\n });\n\n /**\n * /facts/latest?entity=component:default/mycomponent&ids[]=factRetrieverId1&ids[]=factRetrieverId2\n */\n router.get('/facts/latest', async (req, res) => {\n const decision = await authorize(\n req,\n techInsightsFactRetrieverReadPermission,\n );\n\n if (decision.result === AuthorizeResult.DENY) {\n throw new NotAllowedError('Unauthorized');\n }\n const { entity } = req.query;\n const { namespace, kind, name } = parseEntityRef(entity as string);\n\n if (!req.query.ids) {\n return res\n .status(422)\n .json({ error: 'Failed to parse ids from request' });\n }\n const ids = [req.query.ids].flat() as string[];\n return res.json(\n await techInsightsStore.getLatestFactsByIds(\n ids,\n stringifyEntityRef({ namespace, kind, name }),\n ),\n );\n });\n\n /**\n * /facts/range?entity=component:default/mycomponent&startDateTime=2021-12-24T01:23:45&endDateTime=2021-12-31T23:59:59&ids[]=factRetrieverId1&ids[]=factRetrieverId2\n */\n router.get('/facts/range', async (req, res) => {\n const decision = await authorize(\n req,\n techInsightsFactRetrieverReadPermission,\n );\n\n if (decision.result === AuthorizeResult.DENY) {\n throw new NotAllowedError('Unauthorized');\n }\n\n const { entity } = req.query;\n const { namespace, kind, name } = parseEntityRef(entity as string);\n\n if (!req.query.ids) {\n return res\n .status(422)\n .json({ error: 'Failed to parse ids from request' });\n }\n const ids = [req.query.ids].flat() as string[];\n const startDatetime = DateTime.fromISO(req.query.startDatetime as string);\n const endDatetime = DateTime.fromISO(req.query.endDatetime as string);\n if (!startDatetime.isValid || !endDatetime.isValid) {\n return res.status(422).json({\n message: 'Failed to parse datetime from request',\n field: !startDatetime.isValid ? 'startDateTime' : 'endDateTime',\n value: !startDatetime.isValid ? startDatetime : endDatetime,\n });\n }\n const entityTriplet = stringifyEntityRef({ namespace, kind, name });\n return res.json(\n await techInsightsStore.getFactsBetweenTimestampsByIds(\n ids,\n entityTriplet,\n startDatetime,\n endDatetime,\n ),\n );\n });\n\n router.use(factory.error());\n return router;\n}\n"],"names":["Router","createPermissionIntegrationRouter","techInsightsPermissions","express","MiddlewareFactory","techInsightsCheckReadPermission","AuthorizeResult","NotAllowedError","techInsightsCheckUpdatePermission","stringifyEntityRef","pLimit","results","serializeError","techInsightsFactRetrieverReadPermission","parseEntityRef","DateTime"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage-community/plugin-tech-insights-backend",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"backstage": {
|
|
5
5
|
"role": "backend-plugin",
|
|
6
6
|
"pluginId": "tech-insights",
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
"test": "backstage-cli package test"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@backstage-community/plugin-tech-insights-common": "^0.
|
|
52
|
-
"@backstage-community/plugin-tech-insights-node": "^2.
|
|
51
|
+
"@backstage-community/plugin-tech-insights-common": "^0.5.0",
|
|
52
|
+
"@backstage-community/plugin-tech-insights-node": "^2.3.0",
|
|
53
53
|
"@backstage/backend-defaults": "^0.7.0",
|
|
54
54
|
"@backstage/backend-plugin-api": "^1.1.1",
|
|
55
55
|
"@backstage/backend-test-utils": "^1.3.0",
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
"@backstage/config": "^1.3.2",
|
|
59
59
|
"@backstage/errors": "^1.2.7",
|
|
60
60
|
"@backstage/plugin-permission-common": "^0.8.4",
|
|
61
|
+
"@backstage/plugin-permission-node": "^0.8.7",
|
|
61
62
|
"@backstage/types": "^1.2.1",
|
|
62
63
|
"@types/express": "^4.17.6",
|
|
63
64
|
"@types/luxon": "^3.0.0",
|