@backstage/plugin-catalog-backend-module-unprocessed 0.3.11-next.2 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,53 @@
1
1
  # @backstage/plugin-catalog-backend-module-unprocessed
2
2
 
3
+ ## 0.4.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 9c7fb30: Internal update that injects custom permissions into the catalog using its extension point
8
+ - Updated dependencies
9
+ - @backstage/plugin-catalog-node@1.9.0
10
+
11
+ ## 0.4.0
12
+
13
+ ### Minor Changes
14
+
15
+ - 924c1ac: **BREAKING**- the `@backstage/plugin-catalog-backend-module-unprocessed` constructor is now private, and have been moved to using the static `.create` method instead which now requires a `PermissionService` and `DiscoveryService`.
16
+
17
+ If you're using this module in the old backend system you'll need to migrate to using the `.create` method and pass in the new required parameters in `packages/backend/src/plugins/catalog.ts`.
18
+
19
+ No changes should be required if you're using the new backend system.
20
+
21
+ ```diff
22
+ - const unprocessed = new UnprocessedEntitiesModule(
23
+ - await env.database.getClient(),
24
+ - router,
25
+ - );
26
+ + const unprocessed = UnprocessedEntitiesModule.create({
27
+ + database: await env.database.getClient(),
28
+ + router,
29
+ + permissions: env.permissions,
30
+ + discovery: env.discovery,
31
+ + });
32
+
33
+ unprocessed.registerRoutes();
34
+ ```
35
+
36
+ Adds the ability to delete an unprocessed entity from the `refresh_state` table. This change requires enabling permissions for your Backstage instance.
37
+
38
+ ### Patch Changes
39
+
40
+ - 2bd1410: Removed unused dependencies
41
+ - Updated dependencies
42
+ - @backstage/backend-common@0.21.4
43
+ - @backstage/plugin-auth-node@0.4.9
44
+ - @backstage/errors@1.2.4
45
+ - @backstage/backend-plugin-api@0.6.14
46
+ - @backstage/plugin-permission-common@0.7.13
47
+ - @backstage/plugin-permission-node@0.7.25
48
+ - @backstage/plugin-catalog-unprocessed-entities-common@0.0.1
49
+ - @backstage/catalog-model@1.4.5
50
+
3
51
  ## 0.3.11-next.2
4
52
 
5
53
  ### Patch Changes
package/dist/index.cjs.js CHANGED
@@ -4,10 +4,15 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var backendPluginApi = require('@backstage/backend-plugin-api');
6
6
  var Router = require('express-promise-router');
7
+ var pluginPermissionCommon = require('@backstage/plugin-permission-common');
8
+ var pluginCatalogUnprocessedEntitiesCommon = require('@backstage/plugin-catalog-unprocessed-entities-common');
9
+ var errors = require('@backstage/errors');
10
+ var backendCommon = require('@backstage/backend-common');
11
+ var alpha = require('@backstage/plugin-catalog-node/alpha');
7
12
 
8
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
13
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
9
14
 
10
- var Router__default = /*#__PURE__*/_interopDefaultLegacy(Router);
15
+ var Router__default = /*#__PURE__*/_interopDefaultCompat(Router);
11
16
 
12
17
  var __defProp = Object.defineProperty;
13
18
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -16,12 +21,27 @@ var __publicField = (obj, key, value) => {
16
21
  return value;
17
22
  };
18
23
  class UnprocessedEntitiesModule {
19
- constructor(database, router) {
24
+ constructor(database, router, permissions, discovery, httpAuth) {
20
25
  this.database = database;
21
26
  this.router = router;
27
+ this.permissions = permissions;
22
28
  __publicField(this, "moduleRouter");
23
- this.moduleRouter = Router__default["default"]();
29
+ __publicField(this, "httpAuth");
30
+ this.moduleRouter = Router__default.default();
24
31
  this.router.use(this.moduleRouter);
32
+ this.httpAuth = backendCommon.createLegacyAuthAdapters({
33
+ discovery,
34
+ httpAuth
35
+ }).httpAuth;
36
+ }
37
+ static create(options) {
38
+ return new UnprocessedEntitiesModule(
39
+ options.database,
40
+ options.router,
41
+ options.permissions,
42
+ options.discovery,
43
+ options.httpAuth
44
+ );
25
45
  }
26
46
  async unprocessed(request) {
27
47
  if (request.reason === "pending") {
@@ -75,21 +95,40 @@ class UnprocessedEntitiesModule {
75
95
  return res;
76
96
  }
77
97
  registerRoutes() {
98
+ const isRequestAuthorized = async (req, permission) => {
99
+ const decision = (await this.permissions.authorize([{ permission }], {
100
+ credentials: await this.httpAuth.credentials(req)
101
+ }))[0];
102
+ return decision.result !== pluginPermissionCommon.AuthorizeResult.DENY;
103
+ };
78
104
  this.moduleRouter.get("/entities/unprocessed/failed", async (req, res) => {
79
105
  return res.json(
80
106
  await this.unprocessed({
81
107
  reason: "failed",
82
- owner: req.query.owner
108
+ owner: String(req.query.owner)
83
109
  })
84
110
  );
85
111
  }).get("/entities/unprocessed/pending", async (req, res) => {
86
112
  return res.json(
87
113
  await this.unprocessed({
88
114
  reason: "pending",
89
- owner: req.query.owner
115
+ owner: String(req.query.owner)
90
116
  })
91
117
  );
92
- });
118
+ }).delete(
119
+ "/entities/unprocessed/delete/:entity_id",
120
+ async (request, response) => {
121
+ const authorized = await isRequestAuthorized(
122
+ request,
123
+ pluginCatalogUnprocessedEntitiesCommon.unprocessedEntitiesDeletePermission
124
+ );
125
+ if (!authorized) {
126
+ throw new errors.NotAllowedError("Unauthorized");
127
+ }
128
+ await this.database("refresh_state").where({ entity_id: request.params.entity_id }).delete();
129
+ response.status(204).send();
130
+ }
131
+ );
93
132
  }
94
133
  }
95
134
 
@@ -101,13 +140,29 @@ const catalogModuleUnprocessedEntities = backendPluginApi.createBackendModule({
101
140
  deps: {
102
141
  database: backendPluginApi.coreServices.database,
103
142
  router: backendPluginApi.coreServices.httpRouter,
104
- logger: backendPluginApi.coreServices.logger
143
+ logger: backendPluginApi.coreServices.logger,
144
+ httpAuth: backendPluginApi.coreServices.httpAuth,
145
+ discovery: backendPluginApi.coreServices.discovery,
146
+ permissions: backendPluginApi.coreServices.permissions,
147
+ catalogPermissions: alpha.catalogPermissionExtensionPoint
105
148
  },
106
- async init({ database, router, logger }) {
107
- const module = new UnprocessedEntitiesModule(
108
- await database.getClient(),
109
- router
110
- );
149
+ async init({
150
+ database,
151
+ router,
152
+ logger,
153
+ permissions,
154
+ httpAuth,
155
+ discovery,
156
+ catalogPermissions
157
+ }) {
158
+ const module = UnprocessedEntitiesModule.create({
159
+ database: await database.getClient(),
160
+ router,
161
+ permissions,
162
+ discovery,
163
+ httpAuth
164
+ });
165
+ catalogPermissions.addPermissions(pluginCatalogUnprocessedEntitiesCommon.unprocessedEntitiesDeletePermission);
111
166
  module.registerRoutes();
112
167
  logger.info(
113
168
  "registered additional routes for catalogModuleUnprocessedEntities"
@@ -118,5 +173,5 @@ const catalogModuleUnprocessedEntities = backendPluginApi.createBackendModule({
118
173
  });
119
174
 
120
175
  exports.UnprocessedEntitiesModule = UnprocessedEntitiesModule;
121
- exports["default"] = catalogModuleUnprocessedEntities;
176
+ exports.default = catalogModuleUnprocessedEntities;
122
177
  //# sourceMappingURL=index.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../src/UnprocessedEntitiesModule.ts","../src/module.ts"],"sourcesContent":["/*\n * Copyright 2023 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 HydratedRefreshState,\n RefreshState,\n UnprocessedEntitiesRequest,\n UnprocessedEntitiesResponse,\n} from './types';\nimport { Knex } from 'knex';\nimport { HttpRouterService } from '@backstage/backend-plugin-api';\nimport Router from 'express-promise-router';\n\n/**\n * Module providing Unprocessed Entities API endpoints\n *\n * @public\n */\nexport class UnprocessedEntitiesModule {\n private readonly moduleRouter;\n\n constructor(\n private readonly database: Knex,\n private readonly router: Pick<HttpRouterService, 'use'>,\n ) {\n this.moduleRouter = Router();\n this.router.use(this.moduleRouter);\n }\n\n private async unprocessed(\n request: UnprocessedEntitiesRequest,\n ): Promise<UnprocessedEntitiesResponse> {\n if (request.reason === 'pending') {\n return {\n type: 'pending',\n entities: await this.pending(request.owner),\n };\n }\n return {\n type: 'failed',\n entities: await this.failed(request.owner),\n };\n }\n\n private hydrateRefreshState(r: RefreshState): HydratedRefreshState {\n return {\n ...r,\n unprocessed_entity: JSON.parse(r.unprocessed_entity),\n ...(r.processed_entity && {\n processed_entity: JSON.parse(r.processed_entity),\n }),\n ...(r.errors && { errors: JSON.parse(r.errors) }),\n ...(r.cache && { cache: JSON.parse(r.cache) }),\n };\n }\n\n private async pending(owner?: string): Promise<HydratedRefreshState[]> {\n const res = (\n await this.database('refresh_state.*')\n .from('refresh_state')\n .leftJoin(\n 'final_entities',\n 'final_entities.entity_id',\n 'refresh_state.entity_id',\n )\n .whereNull('final_entities.entity_id')\n ).map(this.hydrateRefreshState);\n if (owner) {\n return res.filter(r => r.unprocessed_entity.spec?.owner === owner);\n }\n\n return res;\n }\n\n private async failed(owner?: string): Promise<HydratedRefreshState[]> {\n const res = (\n await this.database('refresh_state.*')\n .from('refresh_state')\n .rightJoin(\n 'final_entities',\n 'final_entities.entity_id',\n 'refresh_state.entity_id',\n )\n .whereNull('final_entities.final_entity')\n ).map(this.hydrateRefreshState);\n if (owner) {\n return res.filter(r => r.unprocessed_entity.spec?.owner === owner);\n }\n\n return res;\n }\n\n registerRoutes() {\n this.moduleRouter\n .get('/entities/unprocessed/failed', async (req, res) => {\n return res.json(\n await this.unprocessed({\n reason: 'failed',\n owner: req.query.owner as string,\n }),\n );\n })\n .get('/entities/unprocessed/pending', async (req, res) => {\n return res.json(\n await this.unprocessed({\n reason: 'pending',\n owner: req.query.owner as string,\n }),\n );\n });\n }\n}\n","/*\n * Copyright 2023 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 createBackendModule,\n} from '@backstage/backend-plugin-api';\nimport { UnprocessedEntitiesModule } from './UnprocessedEntitiesModule';\n\n/**\n * Catalog Module for Unprocessed Entities\n *\n * @public\n */\nexport const catalogModuleUnprocessedEntities = createBackendModule({\n pluginId: 'catalog',\n moduleId: 'catalog-module-unprocessed-entities',\n register(env) {\n env.registerInit({\n deps: {\n database: coreServices.database,\n router: coreServices.httpRouter,\n logger: coreServices.logger,\n },\n async init({ database, router, logger }) {\n const module = new UnprocessedEntitiesModule(\n await database.getClient(),\n router,\n );\n\n module.registerRoutes();\n logger.info(\n 'registered additional routes for catalogModuleUnprocessedEntities',\n );\n },\n });\n },\n});\n"],"names":["Router","createBackendModule","coreServices"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/UnprocessedEntitiesModule.ts","../src/module.ts"],"sourcesContent":["/*\n * Copyright 2023 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 HydratedRefreshState,\n RefreshState,\n UnprocessedEntitiesRequest,\n UnprocessedEntitiesResponse,\n} from './types';\nimport { Knex } from 'knex';\nimport {\n DiscoveryService,\n HttpAuthService,\n HttpRouterService,\n PermissionsService,\n} from '@backstage/backend-plugin-api';\nimport Router from 'express-promise-router';\nimport type { Request } from 'express';\n\nimport {\n AuthorizeResult,\n BasicPermission,\n} from '@backstage/plugin-permission-common';\nimport { unprocessedEntitiesDeletePermission } from '@backstage/plugin-catalog-unprocessed-entities-common';\nimport { NotAllowedError } from '@backstage/errors';\nimport { createLegacyAuthAdapters } from '@backstage/backend-common';\n\n/**\n * Module providing Unprocessed Entities API endpoints\n *\n * @public\n */\nexport class UnprocessedEntitiesModule {\n private readonly moduleRouter;\n\n private readonly httpAuth: HttpAuthService;\n\n private constructor(\n private readonly database: Knex,\n private readonly router: Pick<HttpRouterService, 'use'>,\n private readonly permissions: PermissionsService,\n discovery: DiscoveryService,\n httpAuth?: HttpAuthService,\n ) {\n this.moduleRouter = Router();\n this.router.use(this.moduleRouter);\n\n this.httpAuth = createLegacyAuthAdapters({\n discovery,\n httpAuth,\n }).httpAuth;\n }\n\n static create(options: {\n router: Pick<HttpRouterService, 'use'>;\n database: Knex;\n discovery: DiscoveryService;\n permissions: PermissionsService;\n httpAuth?: HttpAuthService;\n }) {\n return new UnprocessedEntitiesModule(\n options.database,\n options.router,\n options.permissions,\n options.discovery,\n options.httpAuth,\n );\n }\n\n private async unprocessed(\n request: UnprocessedEntitiesRequest,\n ): Promise<UnprocessedEntitiesResponse> {\n if (request.reason === 'pending') {\n return {\n type: 'pending',\n entities: await this.pending(request.owner),\n };\n }\n return {\n type: 'failed',\n entities: await this.failed(request.owner),\n };\n }\n\n private hydrateRefreshState(r: RefreshState): HydratedRefreshState {\n return {\n ...r,\n unprocessed_entity: JSON.parse(r.unprocessed_entity),\n ...(r.processed_entity && {\n processed_entity: JSON.parse(r.processed_entity),\n }),\n ...(r.errors && { errors: JSON.parse(r.errors) }),\n ...(r.cache && { cache: JSON.parse(r.cache) }),\n };\n }\n\n private async pending(owner?: string): Promise<HydratedRefreshState[]> {\n const res = (\n await this.database('refresh_state.*')\n .from('refresh_state')\n .leftJoin(\n 'final_entities',\n 'final_entities.entity_id',\n 'refresh_state.entity_id',\n )\n .whereNull('final_entities.entity_id')\n ).map(this.hydrateRefreshState);\n if (owner) {\n return res.filter(r => r.unprocessed_entity.spec?.owner === owner);\n }\n\n return res;\n }\n\n private async failed(owner?: string): Promise<HydratedRefreshState[]> {\n const res = (\n await this.database('refresh_state.*')\n .from('refresh_state')\n .rightJoin(\n 'final_entities',\n 'final_entities.entity_id',\n 'refresh_state.entity_id',\n )\n .whereNull('final_entities.final_entity')\n ).map(this.hydrateRefreshState);\n if (owner) {\n return res.filter(r => r.unprocessed_entity.spec?.owner === owner);\n }\n\n return res;\n }\n\n registerRoutes() {\n const isRequestAuthorized = async (\n req: Request,\n permission: BasicPermission,\n ): Promise<boolean> => {\n const decision = (\n await this.permissions.authorize([{ permission }], {\n credentials: await this.httpAuth.credentials(req),\n })\n )[0];\n\n return decision.result !== AuthorizeResult.DENY;\n };\n\n this.moduleRouter\n .get('/entities/unprocessed/failed', async (req, res) => {\n return res.json(\n await this.unprocessed({\n reason: 'failed',\n owner: String(req.query.owner),\n }),\n );\n })\n .get('/entities/unprocessed/pending', async (req, res) => {\n return res.json(\n await this.unprocessed({\n reason: 'pending',\n owner: String(req.query.owner),\n }),\n );\n })\n .delete(\n '/entities/unprocessed/delete/:entity_id',\n async (request, response) => {\n const authorized = await isRequestAuthorized(\n request,\n unprocessedEntitiesDeletePermission,\n );\n\n if (!authorized) {\n throw new NotAllowedError('Unauthorized');\n }\n\n await this.database('refresh_state')\n .where({ entity_id: request.params.entity_id })\n .delete();\n\n response.status(204).send();\n },\n );\n }\n}\n","/*\n * Copyright 2023 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 createBackendModule,\n} from '@backstage/backend-plugin-api';\nimport { UnprocessedEntitiesModule } from './UnprocessedEntitiesModule';\nimport { catalogPermissionExtensionPoint } from '@backstage/plugin-catalog-node/alpha';\nimport { unprocessedEntitiesDeletePermission } from '@backstage/plugin-catalog-unprocessed-entities-common';\n\n/**\n * Catalog Module for Unprocessed Entities\n *\n * @public\n */\nexport const catalogModuleUnprocessedEntities = createBackendModule({\n pluginId: 'catalog',\n moduleId: 'catalog-module-unprocessed-entities',\n register(env) {\n env.registerInit({\n deps: {\n database: coreServices.database,\n router: coreServices.httpRouter,\n logger: coreServices.logger,\n httpAuth: coreServices.httpAuth,\n discovery: coreServices.discovery,\n permissions: coreServices.permissions,\n catalogPermissions: catalogPermissionExtensionPoint,\n },\n async init({\n database,\n router,\n logger,\n permissions,\n httpAuth,\n discovery,\n catalogPermissions,\n }) {\n const module = UnprocessedEntitiesModule.create({\n database: await database.getClient(),\n router,\n permissions,\n discovery,\n httpAuth,\n });\n\n catalogPermissions.addPermissions(unprocessedEntitiesDeletePermission);\n\n module.registerRoutes();\n\n logger.info(\n 'registered additional routes for catalogModuleUnprocessedEntities',\n );\n },\n });\n },\n});\n"],"names":["Router","createLegacyAuthAdapters","AuthorizeResult","unprocessedEntitiesDeletePermission","NotAllowedError","createBackendModule","coreServices","catalogPermissionExtensionPoint"],"mappings":"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"}
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 { HttpRouterService } from '@backstage/backend-plugin-api';
2
+ import { HttpRouterService, DiscoveryService, PermissionsService, HttpAuthService } from '@backstage/backend-plugin-api';
3
3
  import { Knex } from 'knex';
4
4
 
5
5
  /**
@@ -17,8 +17,17 @@ declare const catalogModuleUnprocessedEntities: () => _backstage_backend_plugin_
17
17
  declare class UnprocessedEntitiesModule {
18
18
  private readonly database;
19
19
  private readonly router;
20
+ private readonly permissions;
20
21
  private readonly moduleRouter;
21
- constructor(database: Knex, router: Pick<HttpRouterService, 'use'>);
22
+ private readonly httpAuth;
23
+ private constructor();
24
+ static create(options: {
25
+ router: Pick<HttpRouterService, 'use'>;
26
+ database: Knex;
27
+ discovery: DiscoveryService;
28
+ permissions: PermissionsService;
29
+ httpAuth?: HttpAuthService;
30
+ }): UnprocessedEntitiesModule;
22
31
  private unprocessed;
23
32
  private hydrateRefreshState;
24
33
  private pending;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-backend-module-unprocessed",
3
3
  "description": "Backstage Catalog module to view unprocessed entities",
4
- "version": "0.3.11-next.2",
4
+ "version": "0.4.1",
5
5
  "main": "dist/index.cjs.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "license": "Apache-2.0",
@@ -28,14 +28,21 @@
28
28
  "postpack": "backstage-cli package postpack"
29
29
  },
30
30
  "devDependencies": {
31
- "@backstage/cli": "^0.25.3-next.2"
31
+ "@backstage/cli": "^0.26.0",
32
+ "@types/express": "^4.17.6"
32
33
  },
33
34
  "files": [
34
35
  "dist"
35
36
  ],
36
37
  "dependencies": {
37
- "@backstage/backend-plugin-api": "^0.6.14-next.2",
38
- "@backstage/catalog-model": "^1.4.5-next.0",
38
+ "@backstage/backend-common": "^0.21.4",
39
+ "@backstage/backend-plugin-api": "^0.6.14",
40
+ "@backstage/catalog-model": "^1.4.5",
41
+ "@backstage/errors": "^1.2.4",
42
+ "@backstage/plugin-auth-node": "^0.4.9",
43
+ "@backstage/plugin-catalog-node": "^1.9.0",
44
+ "@backstage/plugin-catalog-unprocessed-entities-common": "^0.0.1",
45
+ "@backstage/plugin-permission-common": "^0.7.13",
39
46
  "express-promise-router": "^4.1.1",
40
47
  "knex": "^3.0.0"
41
48
  }