@backstage-community/plugin-tech-insights-backend 2.2.1 → 2.4.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 +27 -0
- package/README.md +0 -4
- package/dist/index.d.ts +9 -1
- package/dist/plugin/config.cjs.js +3 -1
- package/dist/plugin/config.cjs.js.map +1 -1
- package/dist/plugin/plugin.cjs.js +13 -3
- package/dist/plugin/plugin.cjs.js.map +1 -1
- package/dist/service/fact/factRetrievers/entityMetadataFactRetriever.cjs.js +3 -1
- package/dist/service/fact/factRetrievers/entityMetadataFactRetriever.cjs.js.map +1 -1
- package/dist/service/fact/factRetrievers/entityOwnershipFactRetriever.cjs.js +3 -1
- package/dist/service/fact/factRetrievers/entityOwnershipFactRetriever.cjs.js.map +1 -1
- package/dist/service/fact/factRetrievers/techdocsFactRetriever.cjs.js +3 -1
- package/dist/service/fact/factRetrievers/techdocsFactRetriever.cjs.js.map +1 -1
- package/dist/service/router.cjs.js +50 -2
- package/dist/service/router.cjs.js.map +1 -1
- package/package.json +16 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @backstage-community/plugin-tech-insights-backend
|
|
2
2
|
|
|
3
|
+
## 2.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- a01ae4e: Backstage version bump to v1.39.0
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [d6411fe]
|
|
12
|
+
- Updated dependencies [a01ae4e]
|
|
13
|
+
- @backstage-community/plugin-tech-insights-common@0.7.0
|
|
14
|
+
- @backstage-community/plugin-tech-insights-node@2.5.0
|
|
15
|
+
|
|
16
|
+
## 2.3.0
|
|
17
|
+
|
|
18
|
+
### Minor Changes
|
|
19
|
+
|
|
20
|
+
- ac739ca: This version adds `techInsightsCheckReadPermission`, `techInsightsCheckUpdatePermission`, and `techInsightsFactRetrieverReadPermission`, which can be used to permission Tech Insights functionalities.
|
|
21
|
+
|
|
22
|
+
### Patch Changes
|
|
23
|
+
|
|
24
|
+
- 0a26736: fix null timestamp error when using tech-insights with maturity plugin
|
|
25
|
+
- Updated dependencies [375612d]
|
|
26
|
+
- Updated dependencies [ac739ca]
|
|
27
|
+
- @backstage-community/plugin-tech-insights-node@2.4.0
|
|
28
|
+
- @backstage-community/plugin-tech-insights-common@0.6.0
|
|
29
|
+
|
|
3
30
|
## 2.2.1
|
|
4
31
|
|
|
5
32
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -2,10 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
The backend plugin for Tech Insights.
|
|
4
4
|
|
|
5
|
-
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.
|
|
6
|
-
|
|
7
|
-
Looking for the old backend installation docs? Visit [here](./docs/old-backend-system.md).
|
|
8
|
-
|
|
9
5
|
## Installation
|
|
10
6
|
|
|
11
7
|
### Install the package
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
|
|
2
|
-
import { LoggerService, DatabaseService, DiscoveryService, SchedulerService, AuthService, UrlReaderService } from '@backstage/backend-plugin-api';
|
|
2
|
+
import { LoggerService, DatabaseService, PermissionsService, HttpAuthService, DiscoveryService, SchedulerService, AuthService, UrlReaderService } from '@backstage/backend-plugin-api';
|
|
3
3
|
import { FactRetrieverRegistry as FactRetrieverRegistry$1, PersistenceContext as PersistenceContext$1, FactRetriever, FactLifecycle, FactRetrieverRegistration, FactChecker, FactCheckerFactory } from '@backstage-community/plugin-tech-insights-node';
|
|
4
4
|
import { HumanDuration } from '@backstage/types';
|
|
5
5
|
import { Duration } from 'luxon';
|
|
@@ -165,6 +165,14 @@ interface RouterOptions<CheckType extends Check, CheckResultType extends CheckRe
|
|
|
165
165
|
* Implementation of Winston logger
|
|
166
166
|
*/
|
|
167
167
|
logger: LoggerService;
|
|
168
|
+
/**
|
|
169
|
+
* Implementation of PermissionsService
|
|
170
|
+
*/
|
|
171
|
+
permissions: PermissionsService;
|
|
172
|
+
/**
|
|
173
|
+
* Implementation of HttpAuthService
|
|
174
|
+
*/
|
|
175
|
+
httpAuth: HttpAuthService;
|
|
168
176
|
}
|
|
169
177
|
/**
|
|
170
178
|
* @public
|
|
@@ -4,14 +4,16 @@ var config = require('@backstage/config');
|
|
|
4
4
|
var createFactRetriever = require('../service/fact/createFactRetriever.cjs.js');
|
|
5
5
|
require('@backstage/catalog-client');
|
|
6
6
|
require('lodash/isEmpty');
|
|
7
|
+
require('luxon');
|
|
7
8
|
require('../service/fact/factRetrievers/techdocsFactRetriever.cjs.js');
|
|
8
9
|
require('../service/persistence/persistenceContext.cjs.js');
|
|
9
10
|
require('express');
|
|
10
11
|
require('express-promise-router');
|
|
11
|
-
require('
|
|
12
|
+
require('@backstage-community/plugin-tech-insights-common');
|
|
12
13
|
require('@backstage/catalog-model');
|
|
13
14
|
require('@backstage/errors');
|
|
14
15
|
require('@backstage/backend-defaults/rootHttpRouter');
|
|
16
|
+
require('@backstage/plugin-permission-common');
|
|
15
17
|
require('p-limit');
|
|
16
18
|
|
|
17
19
|
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,6 +1,7 @@
|
|
|
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');
|
|
4
5
|
var pluginTechInsightsNode = require('@backstage-community/plugin-tech-insights-node');
|
|
5
6
|
var entityMetadataFactRetriever = require('../service/fact/factRetrievers/entityMetadataFactRetriever.cjs.js');
|
|
6
7
|
var entityOwnershipFactRetriever = require('../service/fact/factRetrievers/entityOwnershipFactRetriever.cjs.js');
|
|
@@ -55,7 +56,10 @@ const techInsightsPlugin = backendPluginApi.createBackendPlugin({
|
|
|
55
56
|
logger: backendPluginApi.coreServices.logger,
|
|
56
57
|
scheduler: backendPluginApi.coreServices.scheduler,
|
|
57
58
|
auth: backendPluginApi.coreServices.auth,
|
|
58
|
-
urlReader: backendPluginApi.coreServices.urlReader
|
|
59
|
+
urlReader: backendPluginApi.coreServices.urlReader,
|
|
60
|
+
httpAuth: backendPluginApi.coreServices.httpAuth,
|
|
61
|
+
permissions: backendPluginApi.coreServices.permissions,
|
|
62
|
+
permissionsRegistry: backendPluginApi.coreServices.permissionsRegistry
|
|
59
63
|
},
|
|
60
64
|
async init({
|
|
61
65
|
config: config$1,
|
|
@@ -65,8 +69,12 @@ const techInsightsPlugin = backendPluginApi.createBackendPlugin({
|
|
|
65
69
|
logger,
|
|
66
70
|
scheduler,
|
|
67
71
|
auth,
|
|
68
|
-
urlReader
|
|
72
|
+
urlReader,
|
|
73
|
+
httpAuth,
|
|
74
|
+
permissions,
|
|
75
|
+
permissionsRegistry
|
|
69
76
|
}) {
|
|
77
|
+
permissionsRegistry.addPermissions(pluginTechInsightsCommon.techInsightsPermissions);
|
|
70
78
|
const factRetrievers = Object.entries(
|
|
71
79
|
addedFactRetrievers
|
|
72
80
|
).map(
|
|
@@ -93,7 +101,9 @@ const techInsightsPlugin = backendPluginApi.createBackendPlugin({
|
|
|
93
101
|
await router.createRouter({
|
|
94
102
|
...context,
|
|
95
103
|
config: config$1,
|
|
96
|
-
logger
|
|
104
|
+
logger,
|
|
105
|
+
permissions,
|
|
106
|
+
httpAuth
|
|
97
107
|
})
|
|
98
108
|
);
|
|
99
109
|
}
|
|
@@ -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} 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 },\n async init({\n config,\n database,\n discovery,\n httpRouter,\n logger,\n scheduler,\n auth,\n urlReader,\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 }),\n );\n },\n });\n },\n});\n"],"names":["createBackendPlugin","techInsightsFactCheckerFactoryExtensionPoint","techInsightsFactRetrieverRegistryExtensionPoint","entityMetadataFactRetriever","entityOwnershipFactRetriever","techdocsFactRetriever","techInsightsFactRetrieversExtensionPoint","techInsightsPersistenceContextExtensionPoint","coreServices","config","createFactRetrieverRegistrationFromConfig","buildTechInsightsContext","createRouter"],"mappings":"
|
|
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 techInsightsPermissions,\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 permissionsRegistry: coreServices.permissionsRegistry,\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 permissionsRegistry,\n }) {\n permissionsRegistry.addPermissions(techInsightsPermissions);\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","techInsightsPermissions","createFactRetrieverRegistrationFromConfig","buildTechInsightsContext","createRouter"],"mappings":";;;;;;;;;;;;;AAkDO,MAAM,qBAAqBA,oCAAoB,CAAA;AAAA,EACpD,QAAU,EAAA,eAAA;AAAA,EACV,SAAS,GAAK,EAAA;AACZ,IAAA,IAAI,kBACF,GAAA,KAAA,CAAA;AACF,IAAA,GAAA,CAAI,uBAAuBC,mEAA8C,EAAA;AAAA,MACvE,sBAGE,OAA+D,EAAA;AAC/D,QAAqB,kBAAA,GAAA,OAAA;AAAA;AACvB,KACD,CAAA;AAED,IAAA,IAAI,qBAA2D,GAAA,KAAA,CAAA;AAC/D,IAAI,GAAA,CAAA,sBAAA;AAAA,MACFC,sEAAA;AAAA,MACA;AAAA,QACE,yBAAyB,QAAuC,EAAA;AAC9D,UAAwB,qBAAA,GAAA,QAAA;AAAA;AAC1B;AACF,KACF;AAIA,IAAA,MAAM,mBAAqD,GAAA;AAAA,mCACzDC,uDAAA;AAAA,oCACAC,yDAAA;AAAA,6BACAC;AAAA,KACF;AACA,IAAA,GAAA,CAAI,uBAAuBC,+DAA0C,EAAA;AAAA,MACnE,kBAAkB,cAAqD,EAAA;AACrE,QAAO,MAAA,CAAA,OAAA,CAAQ,cAAc,CAAE,CAAA,OAAA,CAAQ,CAAC,CAAC,GAAA,EAAK,KAAK,CAAM,KAAA;AACvD,UAAA,mBAAA,CAAoB,GAAG,CAAI,GAAA,KAAA;AAAA,SAC5B,CAAA;AAAA;AACH,KACD,CAAA;AAED,IAAA,IAAI,kBAAqD,GAAA,KAAA,CAAA;AACzD,IAAA,GAAA,CAAI,uBAAuBC,mEAA8C,EAAA;AAAA,MACvE,sBAAsB,OAAmC,EAAA;AACvD,QAAqB,kBAAA,GAAA,OAAA;AAAA;AACvB,KACD,CAAA;AAED,IAAA,GAAA,CAAI,YAAa,CAAA;AAAA,MACf,IAAM,EAAA;AAAA,QACJ,QAAQC,6BAAa,CAAA,UAAA;AAAA,QACrB,UAAUA,6BAAa,CAAA,QAAA;AAAA,QACvB,WAAWA,6BAAa,CAAA,SAAA;AAAA,QACxB,YAAYA,6BAAa,CAAA,UAAA;AAAA,QACzB,QAAQA,6BAAa,CAAA,MAAA;AAAA,QACrB,WAAWA,6BAAa,CAAA,SAAA;AAAA,QACxB,MAAMA,6BAAa,CAAA,IAAA;AAAA,QACnB,WAAWA,6BAAa,CAAA,SAAA;AAAA,QACxB,UAAUA,6BAAa,CAAA,QAAA;AAAA,QACvB,aAAaA,6BAAa,CAAA,WAAA;AAAA,QAC1B,qBAAqBA,6BAAa,CAAA;AAAA,OACpC;AAAA,MACA,MAAM,IAAK,CAAA;AAAA,gBACTC,QAAA;AAAA,QACA,QAAA;AAAA,QACA,SAAA;AAAA,QACA,UAAA;AAAA,QACA,MAAA;AAAA,QACA,SAAA;AAAA,QACA,IAAA;AAAA,QACA,SAAA;AAAA,QACA,QAAA;AAAA,QACA,WAAA;AAAA,QACA;AAAA,OACC,EAAA;AACD,QAAA,mBAAA,CAAoB,eAAeC,gDAAuB,CAAA;AAE1D,QAAA,MAAM,iBAA8C,MAAO,CAAA,OAAA;AAAA,UACzD;AAAA,SAEC,CAAA,GAAA;AAAA,UAAI,CAAC,CAAC,IAAM,EAAA,aAAa,CACxB,KAAAC,gDAAA;AAAA,YACEF,QAAA;AAAA,YACA,IAAA;AAAA,YACA;AAAA;AACF,SACF,CACC,MAAO,CAAA,CAAA,YAAA,KAAgB,YAAY,CAAA;AAEtC,QAAM,MAAA,OAAA,GAAU,MAAMG,mDAAyB,CAAA;AAAA,kBAC7CH,QAAA;AAAA,UACA,QAAA;AAAA,UACA,SAAA;AAAA,UACA,kBAAA;AAAA,UACA,qBAAA;AAAA,UACA,cAAA;AAAA,UACA,MAAA;AAAA,UACA,kBAAA;AAAA,UACA,SAAA;AAAA,UACA,IAAA;AAAA,UACA;AAAA,SACD,CAAA;AAED,QAAW,UAAA,CAAA,GAAA;AAAA,UACT,MAAMI,mBAAa,CAAA;AAAA,YACjB,GAAG,OAAA;AAAA,oBACHJ,QAAA;AAAA,YACA,MAAA;AAAA,YACA,WAAA;AAAA,YACA;AAAA,WACD;AAAA,SACH;AAAA;AACF,KACD,CAAA;AAAA;AAEL,CAAC;;;;"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var catalogClient = require('@backstage/catalog-client');
|
|
4
4
|
var isEmpty = require('lodash/isEmpty');
|
|
5
|
+
var luxon = require('luxon');
|
|
5
6
|
|
|
6
7
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
7
8
|
|
|
@@ -49,7 +50,8 @@ const entityMetadataFactRetriever = {
|
|
|
49
50
|
hasTitle: Boolean(entity.metadata?.title),
|
|
50
51
|
hasDescription: Boolean(entity.metadata?.description),
|
|
51
52
|
hasTags: !isEmpty__default.default(entity.metadata?.tags)
|
|
52
|
-
}
|
|
53
|
+
},
|
|
54
|
+
timestamp: luxon.DateTime.now()
|
|
53
55
|
};
|
|
54
56
|
});
|
|
55
57
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entityMetadataFactRetriever.cjs.js","sources":["../../../../src/service/fact/factRetrievers/entityMetadataFactRetriever.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 FactRetriever,\n FactRetrieverContext,\n} from '@backstage-community/plugin-tech-insights-node';\nimport { CatalogClient } from '@backstage/catalog-client';\nimport { Entity } from '@backstage/catalog-model';\nimport isEmpty from 'lodash/isEmpty';\n\n/**\n * Generates facts which indicate the completeness of entity metadata.\n *\n * @public\n */\nexport const entityMetadataFactRetriever: FactRetriever = {\n id: 'entityMetadataFactRetriever',\n version: '0.0.1',\n title: 'Entity Metadata',\n description:\n 'Generates facts which indicate the completeness of entity metadata',\n schema: {\n hasTitle: {\n type: 'boolean',\n description: 'The entity has a title in metadata',\n },\n hasDescription: {\n type: 'boolean',\n description: 'The entity has a description in metadata',\n },\n hasTags: {\n type: 'boolean',\n description: 'The entity has tags in metadata',\n },\n },\n handler: async ({ discovery, entityFilter, auth }: FactRetrieverContext) => {\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const catalogClient = new CatalogClient({\n discoveryApi: discovery,\n });\n const entities = await catalogClient.getEntities(\n { filter: entityFilter },\n { token },\n );\n\n return entities.items.map((entity: Entity) => {\n return {\n entity: {\n namespace: entity.metadata.namespace!,\n kind: entity.kind,\n name: entity.metadata.name,\n },\n facts: {\n hasTitle: Boolean(entity.metadata?.title),\n hasDescription: Boolean(entity.metadata?.description),\n hasTags: !isEmpty(entity.metadata?.tags),\n },\n };\n });\n },\n};\n"],"names":["catalogClient","CatalogClient","isEmpty"],"mappings":"
|
|
1
|
+
{"version":3,"file":"entityMetadataFactRetriever.cjs.js","sources":["../../../../src/service/fact/factRetrievers/entityMetadataFactRetriever.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 FactRetriever,\n FactRetrieverContext,\n} from '@backstage-community/plugin-tech-insights-node';\nimport { CatalogClient } from '@backstage/catalog-client';\nimport { Entity } from '@backstage/catalog-model';\nimport isEmpty from 'lodash/isEmpty';\nimport { DateTime } from 'luxon';\n\n/**\n * Generates facts which indicate the completeness of entity metadata.\n *\n * @public\n */\nexport const entityMetadataFactRetriever: FactRetriever = {\n id: 'entityMetadataFactRetriever',\n version: '0.0.1',\n title: 'Entity Metadata',\n description:\n 'Generates facts which indicate the completeness of entity metadata',\n schema: {\n hasTitle: {\n type: 'boolean',\n description: 'The entity has a title in metadata',\n },\n hasDescription: {\n type: 'boolean',\n description: 'The entity has a description in metadata',\n },\n hasTags: {\n type: 'boolean',\n description: 'The entity has tags in metadata',\n },\n },\n handler: async ({ discovery, entityFilter, auth }: FactRetrieverContext) => {\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const catalogClient = new CatalogClient({\n discoveryApi: discovery,\n });\n const entities = await catalogClient.getEntities(\n { filter: entityFilter },\n { token },\n );\n\n return entities.items.map((entity: Entity) => {\n return {\n entity: {\n namespace: entity.metadata.namespace!,\n kind: entity.kind,\n name: entity.metadata.name,\n },\n facts: {\n hasTitle: Boolean(entity.metadata?.title),\n hasDescription: Boolean(entity.metadata?.description),\n hasTags: !isEmpty(entity.metadata?.tags),\n },\n timestamp: DateTime.now(),\n };\n });\n },\n};\n"],"names":["catalogClient","CatalogClient","isEmpty","DateTime"],"mappings":";;;;;;;;;;AA8BO,MAAM,2BAA6C,GAAA;AAAA,EACxD,EAAI,EAAA,6BAAA;AAAA,EACJ,OAAS,EAAA,OAAA;AAAA,EACT,KAAO,EAAA,iBAAA;AAAA,EACP,WACE,EAAA,oEAAA;AAAA,EACF,MAAQ,EAAA;AAAA,IACN,QAAU,EAAA;AAAA,MACR,IAAM,EAAA,SAAA;AAAA,MACN,WAAa,EAAA;AAAA,KACf;AAAA,IACA,cAAgB,EAAA;AAAA,MACd,IAAM,EAAA,SAAA;AAAA,MACN,WAAa,EAAA;AAAA,KACf;AAAA,IACA,OAAS,EAAA;AAAA,MACP,IAAM,EAAA,SAAA;AAAA,MACN,WAAa,EAAA;AAAA;AACf,GACF;AAAA,EACA,SAAS,OAAO,EAAE,SAAW,EAAA,YAAA,EAAc,MAAiC,KAAA;AAC1E,IAAA,MAAM,EAAE,KAAA,EAAU,GAAA,MAAM,KAAK,qBAAsB,CAAA;AAAA,MACjD,UAAA,EAAY,MAAM,IAAA,CAAK,wBAAyB,EAAA;AAAA,MAChD,cAAgB,EAAA;AAAA,KACjB,CAAA;AACD,IAAM,MAAAA,eAAA,GAAgB,IAAIC,2BAAc,CAAA;AAAA,MACtC,YAAc,EAAA;AAAA,KACf,CAAA;AACD,IAAM,MAAA,QAAA,GAAW,MAAMD,eAAc,CAAA,WAAA;AAAA,MACnC,EAAE,QAAQ,YAAa,EAAA;AAAA,MACvB,EAAE,KAAM;AAAA,KACV;AAEA,IAAA,OAAO,QAAS,CAAA,KAAA,CAAM,GAAI,CAAA,CAAC,MAAmB,KAAA;AAC5C,MAAO,OAAA;AAAA,QACL,MAAQ,EAAA;AAAA,UACN,SAAA,EAAW,OAAO,QAAS,CAAA,SAAA;AAAA,UAC3B,MAAM,MAAO,CAAA,IAAA;AAAA,UACb,IAAA,EAAM,OAAO,QAAS,CAAA;AAAA,SACxB;AAAA,QACA,KAAO,EAAA;AAAA,UACL,QAAU,EAAA,OAAA,CAAQ,MAAO,CAAA,QAAA,EAAU,KAAK,CAAA;AAAA,UACxC,cAAgB,EAAA,OAAA,CAAQ,MAAO,CAAA,QAAA,EAAU,WAAW,CAAA;AAAA,UACpD,OAAS,EAAA,CAACE,wBAAQ,CAAA,MAAA,CAAO,UAAU,IAAI;AAAA,SACzC;AAAA,QACA,SAAA,EAAWC,eAAS,GAAI;AAAA,OAC1B;AAAA,KACD,CAAA;AAAA;AAEL;;;;"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var catalogClient = require('@backstage/catalog-client');
|
|
4
|
+
var luxon = require('luxon');
|
|
4
5
|
|
|
5
6
|
const entityOwnershipFactRetriever = {
|
|
6
7
|
id: "entityOwnershipFactRetriever",
|
|
@@ -44,7 +45,8 @@ const entityOwnershipFactRetriever = {
|
|
|
44
45
|
hasGroupOwner: Boolean(
|
|
45
46
|
entity.spec?.owner && !(entity.spec?.owner).startsWith("user:")
|
|
46
47
|
)
|
|
47
|
-
}
|
|
48
|
+
},
|
|
49
|
+
timestamp: luxon.DateTime.now()
|
|
48
50
|
};
|
|
49
51
|
});
|
|
50
52
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entityOwnershipFactRetriever.cjs.js","sources":["../../../../src/service/fact/factRetrievers/entityOwnershipFactRetriever.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 FactRetriever,\n FactRetrieverContext,\n} from '@backstage-community/plugin-tech-insights-node';\nimport { CatalogClient } from '@backstage/catalog-client';\nimport { Entity } from '@backstage/catalog-model';\n\n/**\n * Generates facts which indicate the quality of data in the spec.owner field.\n *\n * @public\n */\nexport const entityOwnershipFactRetriever: FactRetriever = {\n id: 'entityOwnershipFactRetriever',\n version: '0.0.1',\n title: 'Entity Ownership',\n description:\n 'Generates facts which indicate the quality of data in the spec.owner field',\n entityFilter: [\n { kind: ['component', 'domain', 'system', 'api', 'resource', 'template'] },\n ],\n schema: {\n hasOwner: {\n type: 'boolean',\n description: 'The spec.owner field is set',\n },\n hasGroupOwner: {\n type: 'boolean',\n description: 'The spec.owner field is set and refers to a group',\n },\n },\n handler: async ({ discovery, entityFilter, auth }: FactRetrieverContext) => {\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const catalogClient = new CatalogClient({\n discoveryApi: discovery,\n });\n const entities = await catalogClient.getEntities(\n { filter: entityFilter },\n { token },\n );\n\n return entities.items.map((entity: Entity) => {\n return {\n entity: {\n namespace: entity.metadata.namespace!,\n kind: entity.kind,\n name: entity.metadata.name,\n },\n facts: {\n hasOwner: Boolean(entity.spec?.owner),\n hasGroupOwner: Boolean(\n entity.spec?.owner &&\n !(entity.spec?.owner as string).startsWith('user:'),\n ),\n },\n };\n });\n },\n};\n"],"names":["catalogClient","CatalogClient"],"mappings":"
|
|
1
|
+
{"version":3,"file":"entityOwnershipFactRetriever.cjs.js","sources":["../../../../src/service/fact/factRetrievers/entityOwnershipFactRetriever.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 FactRetriever,\n FactRetrieverContext,\n} from '@backstage-community/plugin-tech-insights-node';\nimport { CatalogClient } from '@backstage/catalog-client';\nimport { Entity } from '@backstage/catalog-model';\nimport { DateTime } from 'luxon';\n\n/**\n * Generates facts which indicate the quality of data in the spec.owner field.\n *\n * @public\n */\nexport const entityOwnershipFactRetriever: FactRetriever = {\n id: 'entityOwnershipFactRetriever',\n version: '0.0.1',\n title: 'Entity Ownership',\n description:\n 'Generates facts which indicate the quality of data in the spec.owner field',\n entityFilter: [\n { kind: ['component', 'domain', 'system', 'api', 'resource', 'template'] },\n ],\n schema: {\n hasOwner: {\n type: 'boolean',\n description: 'The spec.owner field is set',\n },\n hasGroupOwner: {\n type: 'boolean',\n description: 'The spec.owner field is set and refers to a group',\n },\n },\n handler: async ({ discovery, entityFilter, auth }: FactRetrieverContext) => {\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const catalogClient = new CatalogClient({\n discoveryApi: discovery,\n });\n const entities = await catalogClient.getEntities(\n { filter: entityFilter },\n { token },\n );\n\n return entities.items.map((entity: Entity) => {\n return {\n entity: {\n namespace: entity.metadata.namespace!,\n kind: entity.kind,\n name: entity.metadata.name,\n },\n facts: {\n hasOwner: Boolean(entity.spec?.owner),\n hasGroupOwner: Boolean(\n entity.spec?.owner &&\n !(entity.spec?.owner as string).startsWith('user:'),\n ),\n },\n timestamp: DateTime.now(),\n };\n });\n },\n};\n"],"names":["catalogClient","CatalogClient","DateTime"],"mappings":";;;;;AA6BO,MAAM,4BAA8C,GAAA;AAAA,EACzD,EAAI,EAAA,8BAAA;AAAA,EACJ,OAAS,EAAA,OAAA;AAAA,EACT,KAAO,EAAA,kBAAA;AAAA,EACP,WACE,EAAA,4EAAA;AAAA,EACF,YAAc,EAAA;AAAA,IACZ,EAAE,MAAM,CAAC,WAAA,EAAa,UAAU,QAAU,EAAA,KAAA,EAAO,UAAY,EAAA,UAAU,CAAE;AAAA,GAC3E;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,QAAU,EAAA;AAAA,MACR,IAAM,EAAA,SAAA;AAAA,MACN,WAAa,EAAA;AAAA,KACf;AAAA,IACA,aAAe,EAAA;AAAA,MACb,IAAM,EAAA,SAAA;AAAA,MACN,WAAa,EAAA;AAAA;AACf,GACF;AAAA,EACA,SAAS,OAAO,EAAE,SAAW,EAAA,YAAA,EAAc,MAAiC,KAAA;AAC1E,IAAA,MAAM,EAAE,KAAA,EAAU,GAAA,MAAM,KAAK,qBAAsB,CAAA;AAAA,MACjD,UAAA,EAAY,MAAM,IAAA,CAAK,wBAAyB,EAAA;AAAA,MAChD,cAAgB,EAAA;AAAA,KACjB,CAAA;AACD,IAAM,MAAAA,eAAA,GAAgB,IAAIC,2BAAc,CAAA;AAAA,MACtC,YAAc,EAAA;AAAA,KACf,CAAA;AACD,IAAM,MAAA,QAAA,GAAW,MAAMD,eAAc,CAAA,WAAA;AAAA,MACnC,EAAE,QAAQ,YAAa,EAAA;AAAA,MACvB,EAAE,KAAM;AAAA,KACV;AAEA,IAAA,OAAO,QAAS,CAAA,KAAA,CAAM,GAAI,CAAA,CAAC,MAAmB,KAAA;AAC5C,MAAO,OAAA;AAAA,QACL,MAAQ,EAAA;AAAA,UACN,SAAA,EAAW,OAAO,QAAS,CAAA,SAAA;AAAA,UAC3B,MAAM,MAAO,CAAA,IAAA;AAAA,UACb,IAAA,EAAM,OAAO,QAAS,CAAA;AAAA,SACxB;AAAA,QACA,KAAO,EAAA;AAAA,UACL,QAAU,EAAA,OAAA,CAAQ,MAAO,CAAA,IAAA,EAAM,KAAK,CAAA;AAAA,UACpC,aAAe,EAAA,OAAA;AAAA,YACb,MAAA,CAAO,MAAM,KACX,IAAA,CAAA,CAAE,OAAO,IAAM,EAAA,KAAA,EAAiB,WAAW,OAAO;AAAA;AACtD,SACF;AAAA,QACA,SAAA,EAAWE,eAAS,GAAI;AAAA,OAC1B;AAAA,KACD,CAAA;AAAA;AAEL;;;;"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var catalogClient = require('@backstage/catalog-client');
|
|
4
4
|
var utils = require('./utils.cjs.js');
|
|
5
|
+
var luxon = require('luxon');
|
|
5
6
|
|
|
6
7
|
const techdocsAnnotation = "backstage.io/techdocs-ref";
|
|
7
8
|
const techdocsEntityAnnotation = "backstage.io/techdocs-entity";
|
|
@@ -52,7 +53,8 @@ const techdocsFactRetriever = {
|
|
|
52
53
|
entity,
|
|
53
54
|
techdocsEntityAnnotation
|
|
54
55
|
)
|
|
55
|
-
}
|
|
56
|
+
},
|
|
57
|
+
timestamp: luxon.DateTime.now()
|
|
56
58
|
};
|
|
57
59
|
});
|
|
58
60
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"techdocsFactRetriever.cjs.js","sources":["../../../../src/service/fact/factRetrievers/techdocsFactRetriever.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 FactRetriever,\n FactRetrieverContext,\n} from '@backstage-community/plugin-tech-insights-node';\nimport { CatalogClient } from '@backstage/catalog-client';\nimport { Entity } from '@backstage/catalog-model';\nimport { entityHasAnnotation, generateAnnotationFactName } from './utils';\n\nconst techdocsAnnotation = 'backstage.io/techdocs-ref';\nconst techdocsEntityAnnotation = 'backstage.io/techdocs-entity';\nconst techdocsAnnotationFactName =\n generateAnnotationFactName(techdocsAnnotation);\nconst techdocsEntityAnnotationFactName = generateAnnotationFactName(\n techdocsEntityAnnotation,\n);\n\n/**\n * Generates facts related to the completeness of techdocs configuration for entities.\n *\n * @public\n */\nexport const techdocsFactRetriever: FactRetriever = {\n id: 'techdocsFactRetriever',\n version: '0.1.0',\n title: 'Tech Docs',\n description:\n 'Generates facts related to the completeness of techdocs configuration for entities',\n schema: {\n [techdocsAnnotationFactName]: {\n type: 'boolean',\n description: 'The entity has a TechDocs reference annotation',\n },\n [techdocsEntityAnnotationFactName]: {\n type: 'boolean',\n description: 'The entity has a TechDocs entity annotation',\n },\n },\n handler: async ({ discovery, entityFilter, auth }: FactRetrieverContext) => {\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const catalogClient = new CatalogClient({\n discoveryApi: discovery,\n });\n const entities = await catalogClient.getEntities(\n { filter: entityFilter },\n { token },\n );\n\n return entities.items.map((entity: Entity) => {\n return {\n entity: {\n namespace: entity.metadata.namespace!,\n kind: entity.kind,\n name: entity.metadata.name,\n },\n facts: {\n [techdocsAnnotationFactName]: entityHasAnnotation(\n entity,\n techdocsAnnotation,\n ),\n [techdocsEntityAnnotationFactName]: entityHasAnnotation(\n entity,\n techdocsEntityAnnotation,\n ),\n },\n };\n });\n },\n};\n"],"names":["generateAnnotationFactName","catalogClient","CatalogClient","entityHasAnnotation"],"mappings":"
|
|
1
|
+
{"version":3,"file":"techdocsFactRetriever.cjs.js","sources":["../../../../src/service/fact/factRetrievers/techdocsFactRetriever.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 FactRetriever,\n FactRetrieverContext,\n} from '@backstage-community/plugin-tech-insights-node';\nimport { CatalogClient } from '@backstage/catalog-client';\nimport { Entity } from '@backstage/catalog-model';\nimport { entityHasAnnotation, generateAnnotationFactName } from './utils';\nimport { DateTime } from 'luxon';\n\nconst techdocsAnnotation = 'backstage.io/techdocs-ref';\nconst techdocsEntityAnnotation = 'backstage.io/techdocs-entity';\nconst techdocsAnnotationFactName =\n generateAnnotationFactName(techdocsAnnotation);\nconst techdocsEntityAnnotationFactName = generateAnnotationFactName(\n techdocsEntityAnnotation,\n);\n\n/**\n * Generates facts related to the completeness of techdocs configuration for entities.\n *\n * @public\n */\nexport const techdocsFactRetriever: FactRetriever = {\n id: 'techdocsFactRetriever',\n version: '0.1.0',\n title: 'Tech Docs',\n description:\n 'Generates facts related to the completeness of techdocs configuration for entities',\n schema: {\n [techdocsAnnotationFactName]: {\n type: 'boolean',\n description: 'The entity has a TechDocs reference annotation',\n },\n [techdocsEntityAnnotationFactName]: {\n type: 'boolean',\n description: 'The entity has a TechDocs entity annotation',\n },\n },\n handler: async ({ discovery, entityFilter, auth }: FactRetrieverContext) => {\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const catalogClient = new CatalogClient({\n discoveryApi: discovery,\n });\n const entities = await catalogClient.getEntities(\n { filter: entityFilter },\n { token },\n );\n\n return entities.items.map((entity: Entity) => {\n return {\n entity: {\n namespace: entity.metadata.namespace!,\n kind: entity.kind,\n name: entity.metadata.name,\n },\n facts: {\n [techdocsAnnotationFactName]: entityHasAnnotation(\n entity,\n techdocsAnnotation,\n ),\n [techdocsEntityAnnotationFactName]: entityHasAnnotation(\n entity,\n techdocsEntityAnnotation,\n ),\n },\n timestamp: DateTime.now(),\n };\n });\n },\n};\n"],"names":["generateAnnotationFactName","catalogClient","CatalogClient","entityHasAnnotation","DateTime"],"mappings":";;;;;;AAyBA,MAAM,kBAAqB,GAAA,2BAAA;AAC3B,MAAM,wBAA2B,GAAA,8BAAA;AACjC,MAAM,0BAAA,GACJA,iCAA2B,kBAAkB,CAAA;AAC/C,MAAM,gCAAmC,GAAAA,gCAAA;AAAA,EACvC;AACF,CAAA;AAOO,MAAM,qBAAuC,GAAA;AAAA,EAClD,EAAI,EAAA,uBAAA;AAAA,EACJ,OAAS,EAAA,OAAA;AAAA,EACT,KAAO,EAAA,WAAA;AAAA,EACP,WACE,EAAA,oFAAA;AAAA,EACF,MAAQ,EAAA;AAAA,IACN,CAAC,0BAA0B,GAAG;AAAA,MAC5B,IAAM,EAAA,SAAA;AAAA,MACN,WAAa,EAAA;AAAA,KACf;AAAA,IACA,CAAC,gCAAgC,GAAG;AAAA,MAClC,IAAM,EAAA,SAAA;AAAA,MACN,WAAa,EAAA;AAAA;AACf,GACF;AAAA,EACA,SAAS,OAAO,EAAE,SAAW,EAAA,YAAA,EAAc,MAAiC,KAAA;AAC1E,IAAA,MAAM,EAAE,KAAA,EAAU,GAAA,MAAM,KAAK,qBAAsB,CAAA;AAAA,MACjD,UAAA,EAAY,MAAM,IAAA,CAAK,wBAAyB,EAAA;AAAA,MAChD,cAAgB,EAAA;AAAA,KACjB,CAAA;AACD,IAAM,MAAAC,eAAA,GAAgB,IAAIC,2BAAc,CAAA;AAAA,MACtC,YAAc,EAAA;AAAA,KACf,CAAA;AACD,IAAM,MAAA,QAAA,GAAW,MAAMD,eAAc,CAAA,WAAA;AAAA,MACnC,EAAE,QAAQ,YAAa,EAAA;AAAA,MACvB,EAAE,KAAM;AAAA,KACV;AAEA,IAAA,OAAO,QAAS,CAAA,KAAA,CAAM,GAAI,CAAA,CAAC,MAAmB,KAAA;AAC5C,MAAO,OAAA;AAAA,QACL,MAAQ,EAAA;AAAA,UACN,SAAA,EAAW,OAAO,QAAS,CAAA,SAAA;AAAA,UAC3B,MAAM,MAAO,CAAA,IAAA;AAAA,UACb,IAAA,EAAM,OAAO,QAAS,CAAA;AAAA,SACxB;AAAA,QACA,KAAO,EAAA;AAAA,UACL,CAAC,0BAA0B,GAAGE,yBAAA;AAAA,YAC5B,MAAA;AAAA,YACA;AAAA,WACF;AAAA,UACA,CAAC,gCAAgC,GAAGA,yBAAA;AAAA,YAClC,MAAA;AAAA,YACA;AAAA;AACF,SACF;AAAA,QACA,SAAA,EAAWC,eAAS,GAAI;AAAA,OAC1B;AAAA,KACD,CAAA;AAAA;AAEL;;;;"}
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
var express = require('express');
|
|
4
4
|
var Router = require('express-promise-router');
|
|
5
|
+
var pluginTechInsightsCommon = require('@backstage-community/plugin-tech-insights-common');
|
|
5
6
|
var luxon = require('luxon');
|
|
6
7
|
var catalogModel = require('@backstage/catalog-model');
|
|
7
8
|
var errors = require('@backstage/errors');
|
|
8
9
|
var rootHttpRouter = require('@backstage/backend-defaults/rootHttpRouter');
|
|
10
|
+
var pluginPermissionCommon = require('@backstage/plugin-permission-common');
|
|
9
11
|
var pLimit = require('p-limit');
|
|
10
12
|
|
|
11
13
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
@@ -17,15 +19,36 @@ var pLimit__default = /*#__PURE__*/_interopDefaultCompat(pLimit);
|
|
|
17
19
|
async function createRouter(options) {
|
|
18
20
|
const router = Router__default.default();
|
|
19
21
|
router.use(express__default.default.json());
|
|
20
|
-
const {
|
|
22
|
+
const {
|
|
23
|
+
persistenceContext,
|
|
24
|
+
factChecker,
|
|
25
|
+
logger,
|
|
26
|
+
config,
|
|
27
|
+
permissions,
|
|
28
|
+
httpAuth
|
|
29
|
+
} = options;
|
|
21
30
|
const { techInsightsStore } = persistenceContext;
|
|
22
31
|
const factory = rootHttpRouter.MiddlewareFactory.create({ logger, config });
|
|
32
|
+
const authorize = async (request, permission) => {
|
|
33
|
+
const decision = (await permissions.authorize([{ permission }], {
|
|
34
|
+
credentials: await httpAuth.credentials(request)
|
|
35
|
+
}))[0];
|
|
36
|
+
return decision;
|
|
37
|
+
};
|
|
23
38
|
if (factChecker) {
|
|
24
39
|
logger.info("Fact checker configured. Enabling fact checking endpoints.");
|
|
25
|
-
router.get("/checks", async (
|
|
40
|
+
router.get("/checks", async (req, res) => {
|
|
41
|
+
const decision = await authorize(req, pluginTechInsightsCommon.techInsightsCheckReadPermission);
|
|
42
|
+
if (decision.result === pluginPermissionCommon.AuthorizeResult.DENY) {
|
|
43
|
+
throw new errors.NotAllowedError("Unauthorized");
|
|
44
|
+
}
|
|
26
45
|
return res.json(await factChecker.getChecks());
|
|
27
46
|
});
|
|
28
47
|
router.post("/checks/run/:namespace/:kind/:name", async (req, res) => {
|
|
48
|
+
const decision = await authorize(req, pluginTechInsightsCommon.techInsightsCheckUpdatePermission);
|
|
49
|
+
if (decision.result === pluginPermissionCommon.AuthorizeResult.DENY) {
|
|
50
|
+
throw new errors.NotAllowedError("Unauthorized");
|
|
51
|
+
}
|
|
29
52
|
const { namespace, kind, name } = req.params;
|
|
30
53
|
const { checks } = req.body;
|
|
31
54
|
const entityTriplet = catalogModel.stringifyEntityRef({ namespace, kind, name });
|
|
@@ -34,6 +57,10 @@ async function createRouter(options) {
|
|
|
34
57
|
});
|
|
35
58
|
const checksRunConcurrency = config.getOptionalNumber("techInsights.checksRunConcurrency") || 100;
|
|
36
59
|
router.post("/checks/run", async (req, res) => {
|
|
60
|
+
const decision = await authorize(req, pluginTechInsightsCommon.techInsightsCheckUpdatePermission);
|
|
61
|
+
if (decision.result === pluginPermissionCommon.AuthorizeResult.DENY) {
|
|
62
|
+
throw new errors.NotAllowedError("Unauthorized");
|
|
63
|
+
}
|
|
37
64
|
const checks = req.body.checks;
|
|
38
65
|
let entities = req.body.entities;
|
|
39
66
|
if (entities.length === 0) {
|
|
@@ -69,10 +96,24 @@ async function createRouter(options) {
|
|
|
69
96
|
);
|
|
70
97
|
}
|
|
71
98
|
router.get("/fact-schemas", async (req, res) => {
|
|
99
|
+
const decision = await authorize(
|
|
100
|
+
req,
|
|
101
|
+
pluginTechInsightsCommon.techInsightsFactRetrieverReadPermission
|
|
102
|
+
);
|
|
103
|
+
if (decision.result === pluginPermissionCommon.AuthorizeResult.DENY) {
|
|
104
|
+
throw new errors.NotAllowedError("Unauthorized");
|
|
105
|
+
}
|
|
72
106
|
const ids = req.query.ids;
|
|
73
107
|
return res.json(await techInsightsStore.getLatestSchemas(ids));
|
|
74
108
|
});
|
|
75
109
|
router.get("/facts/latest", async (req, res) => {
|
|
110
|
+
const decision = await authorize(
|
|
111
|
+
req,
|
|
112
|
+
pluginTechInsightsCommon.techInsightsFactRetrieverReadPermission
|
|
113
|
+
);
|
|
114
|
+
if (decision.result === pluginPermissionCommon.AuthorizeResult.DENY) {
|
|
115
|
+
throw new errors.NotAllowedError("Unauthorized");
|
|
116
|
+
}
|
|
76
117
|
const { entity } = req.query;
|
|
77
118
|
const { namespace, kind, name } = catalogModel.parseEntityRef(entity);
|
|
78
119
|
if (!req.query.ids) {
|
|
@@ -87,6 +128,13 @@ async function createRouter(options) {
|
|
|
87
128
|
);
|
|
88
129
|
});
|
|
89
130
|
router.get("/facts/range", async (req, res) => {
|
|
131
|
+
const decision = await authorize(
|
|
132
|
+
req,
|
|
133
|
+
pluginTechInsightsCommon.techInsightsFactRetrieverReadPermission
|
|
134
|
+
);
|
|
135
|
+
if (decision.result === pluginPermissionCommon.AuthorizeResult.DENY) {
|
|
136
|
+
throw new errors.NotAllowedError("Unauthorized");
|
|
137
|
+
}
|
|
90
138
|
const { entity } = req.query;
|
|
91
139
|
const { namespace, kind, name } = catalogModel.parseEntityRef(entity);
|
|
92
140
|
if (!req.query.ids) {
|
|
@@ -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 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} 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 { LoggerService } from '@backstage/backend-plugin-api';\nimport { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';\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/**\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 router.use(express.json());\n const { persistenceContext, factChecker, logger, config } = options;\n const { techInsightsStore } = persistenceContext;\n\n const factory = MiddlewareFactory.create({ logger, config });\n\n if (factChecker) {\n logger.info('Fact checker configured. Enabling fact checking endpoints.');\n router.get('/checks', async (_req, res) => {\n return res.json(await factChecker.getChecks());\n });\n\n router.post('/checks/run/:namespace/:kind/:name', async (req, res) => {\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 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 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 { 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 { 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","stringifyEntityRef","pLimit","results","serializeError","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 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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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage-community/plugin-tech-insights-backend",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"backstage": {
|
|
5
5
|
"role": "backend-plugin",
|
|
6
6
|
"pluginId": "tech-insights",
|
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
"@backstage-community/plugin-tech-insights-maturity-common",
|
|
13
13
|
"@backstage-community/plugin-tech-insights-node",
|
|
14
14
|
"@backstage-community/plugin-tech-insights-react"
|
|
15
|
-
]
|
|
15
|
+
],
|
|
16
|
+
"features": {
|
|
17
|
+
".": "@backstage/BackendFeature"
|
|
18
|
+
}
|
|
16
19
|
},
|
|
17
20
|
"publishConfig": {
|
|
18
21
|
"access": "public",
|
|
@@ -48,15 +51,16 @@
|
|
|
48
51
|
"test": "backstage-cli package test"
|
|
49
52
|
},
|
|
50
53
|
"dependencies": {
|
|
51
|
-
"@backstage-community/plugin-tech-insights-common": "^0.
|
|
52
|
-
"@backstage-community/plugin-tech-insights-node": "^2.
|
|
53
|
-
"@backstage/backend-defaults": "^0.
|
|
54
|
-
"@backstage/backend-plugin-api": "^1.
|
|
55
|
-
"@backstage/backend-test-utils": "^1.
|
|
56
|
-
"@backstage/catalog-client": "^1.
|
|
57
|
-
"@backstage/catalog-model": "^1.7.
|
|
54
|
+
"@backstage-community/plugin-tech-insights-common": "^0.7.0",
|
|
55
|
+
"@backstage-community/plugin-tech-insights-node": "^2.5.0",
|
|
56
|
+
"@backstage/backend-defaults": "^0.10.0",
|
|
57
|
+
"@backstage/backend-plugin-api": "^1.3.1",
|
|
58
|
+
"@backstage/backend-test-utils": "^1.5.0",
|
|
59
|
+
"@backstage/catalog-client": "^1.10.0",
|
|
60
|
+
"@backstage/catalog-model": "^1.7.4",
|
|
58
61
|
"@backstage/config": "^1.3.2",
|
|
59
62
|
"@backstage/errors": "^1.2.7",
|
|
63
|
+
"@backstage/plugin-permission-common": "^0.9.0",
|
|
60
64
|
"@backstage/types": "^1.2.1",
|
|
61
65
|
"@types/express": "^4.17.6",
|
|
62
66
|
"@types/luxon": "^3.0.0",
|
|
@@ -71,7 +75,7 @@
|
|
|
71
75
|
"yn": "^4.0.0"
|
|
72
76
|
},
|
|
73
77
|
"devDependencies": {
|
|
74
|
-
"@backstage/cli": "^0.
|
|
78
|
+
"@backstage/cli": "^0.32.1",
|
|
75
79
|
"@types/lodash": "^4.14.151",
|
|
76
80
|
"@types/semver": "^7.3.8",
|
|
77
81
|
"@types/supertest": "^6.0.0",
|
|
@@ -82,8 +86,8 @@
|
|
|
82
86
|
"configSchema": "config.d.ts",
|
|
83
87
|
"typesVersions": {
|
|
84
88
|
"*": {
|
|
85
|
-
"
|
|
86
|
-
"
|
|
89
|
+
"package.json": [
|
|
90
|
+
"package.json"
|
|
87
91
|
]
|
|
88
92
|
}
|
|
89
93
|
}
|