@backstage/plugin-catalog-backend 1.29.0-next.1 → 1.29.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 CHANGED
@@ -1,5 +1,77 @@
1
1
  # @backstage/plugin-catalog-backend
2
2
 
3
+ ## 1.29.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 02bd2cb: Added a new `catalog.disableRelationsCompatibility` configuration option that avoids JSON deserialization and serialization if possible when reading entities. This significantly reduces the memory usage of the catalog, and slightly increases performance, but it removes the backwards compatibility processing that ensures that both `entity.relation[].target` and `entity.relation[].targetRef` are present in returned entities.
8
+ - c1307b4: Implement `/entities` in terms of `queryEntities` to not run into memory and performance problems on large catalogs
9
+ - 384e494: Internal updates to generated code.
10
+ - 1d0bc11: Fetch all facets in a single database query
11
+
12
+ ### Patch Changes
13
+
14
+ - dfc8b41: Updated dependency `@opentelemetry/api` to `^1.9.0`.
15
+ - 8013c9c: Perform the by-query count inlined with the main query
16
+ - feba9ee: Internal refactor of filter parsing logic.
17
+ - 1fdb48e: Use a faster count method on pg when computing some metrics
18
+ - e4aab10: Fix a bug where sometimes the `by-query` endpoint could return nulls for entities that were not yet stitched.
19
+ - f159b25: Compute deltas more efficiently, which generally leads to less wasted processing cycles
20
+ - 0c33465: Implement `/entities/by-name/:kind/:namespace/:name` using `getEntitiesByRefs`
21
+ - 56511ba: Be more aggressive in dequeueing entities for stitching
22
+ - 71152e3: Correctly report stitching queue length
23
+ - 5c9cc05: Use native fetch instead of node-fetch
24
+ - d93390d: When parsing filters, do not make redundant `anyOf` and `allOf` nodes when there's only a single entry within them
25
+ - 3ab57c6: Support changing location keys on existing entities, in delta mutations
26
+ - 24ecea8: Avoid extra ordering in by-query when the user doesn't ask for it
27
+ - 2924ffe: Compute some metrics using search table facet aggregations instead of reading the full refresh state
28
+ - Updated dependencies
29
+ - @backstage/integration@1.16.0
30
+ - @backstage/backend-plugin-api@1.1.0
31
+ - @backstage/plugin-search-backend-module-catalog@0.2.6
32
+ - @backstage/plugin-catalog-node@1.15.0
33
+ - @backstage/plugin-events-node@0.4.6
34
+ - @backstage/catalog-client@1.9.0
35
+ - @backstage/plugin-permission-node@0.8.6
36
+ - @backstage/backend-openapi-utils@0.4.0
37
+ - @backstage/errors@1.2.6
38
+ - @backstage/catalog-model@1.7.2
39
+ - @backstage/config@1.3.1
40
+ - @backstage/types@1.2.0
41
+ - @backstage/plugin-catalog-common@1.1.2
42
+ - @backstage/plugin-permission-common@0.8.3
43
+
44
+ ## 1.29.0-next.2
45
+
46
+ ### Minor Changes
47
+
48
+ - c1307b4: Implement `/entities` in terms of `queryEntities` to not run into memory and performance problems on large catalogs
49
+
50
+ ### Patch Changes
51
+
52
+ - dfc8b41: Updated dependency `@opentelemetry/api` to `^1.9.0`.
53
+ - 8013c9c: Perform the by-query count inlined with the main query
54
+ - feba9ee: Use a join based strategy for filtering, when having small page sizes
55
+ - 1fdb48e: Use a faster count method on pg when computing some metrics
56
+ - 0c33465: Implement `/entities/by-name/:kind/:namespace/:name` using `getEntitiesByRefs`
57
+ - d93390d: When parsing filters, do not make redundant `anyOf` and `allOf` nodes when there's only a single entry within them
58
+ - 24ecea8: Avoid extra ordering in by-query when the user doesn't ask for it
59
+ - Updated dependencies
60
+ - @backstage/backend-plugin-api@1.1.0-next.2
61
+ - @backstage/plugin-permission-node@0.8.6-next.2
62
+ - @backstage/backend-openapi-utils@0.4.0-next.2
63
+ - @backstage/errors@1.2.6-next.0
64
+ - @backstage/plugin-catalog-node@1.15.0-next.2
65
+ - @backstage/plugin-events-node@0.4.6-next.2
66
+ - @backstage/plugin-search-backend-module-catalog@0.2.6-next.2
67
+ - @backstage/catalog-client@1.9.0-next.2
68
+ - @backstage/catalog-model@1.7.2-next.0
69
+ - @backstage/config@1.3.1-next.0
70
+ - @backstage/integration@1.16.0-next.1
71
+ - @backstage/types@1.2.0
72
+ - @backstage/plugin-catalog-common@1.1.2-next.0
73
+ - @backstage/plugin-permission-common@0.8.3-next.0
74
+
3
75
  ## 1.29.0-next.1
4
76
 
5
77
  ### Minor Changes
package/config.d.ts CHANGED
@@ -138,6 +138,16 @@ export interface Config {
138
138
  }>;
139
139
  }>;
140
140
 
141
+ /**
142
+ * Disables the compatibility layer for relations in returned entities that
143
+ * ensures that all relations objects have both `target` and `targetRef`.
144
+ *
145
+ * Enabling this option significantly reduces the memory usage of the
146
+ * catalog, and slightly increases performance, but may break consumers that
147
+ * rely on the existence of `target` in the relations objects.
148
+ */
149
+ disableRelationsCompatibility?: boolean;
150
+
141
151
  /**
142
152
  * The strategy to use for entities that are orphaned, i.e. no longer have
143
153
  * any other entities or providers referencing them. The default value is
@@ -64,18 +64,36 @@ function initDatabaseMetrics(knex) {
64
64
  registered_locations: meter.createObservableGauge("catalog_registered_locations_count", {
65
65
  description: "Total amount of registered locations in the catalog"
66
66
  }).addCallback(async (gauge) => {
67
- const total = await knex("locations").count({
68
- count: "*"
69
- });
70
- gauge.observe(Number(total[0].count));
67
+ if (knex.client.config.client === "pg") {
68
+ const total = await knex.raw(`
69
+ SELECT reltuples::bigint AS estimate
70
+ FROM pg_class
71
+ WHERE oid = 'locations'::regclass;
72
+ `);
73
+ gauge.observe(Number(total.rows[0].estimate));
74
+ } else {
75
+ const total = await knex("locations").count({
76
+ count: "*"
77
+ });
78
+ gauge.observe(Number(total[0].count));
79
+ }
71
80
  }),
72
81
  relations: meter.createObservableGauge("catalog_relations_count", {
73
82
  description: "Total amount of relations between entities"
74
83
  }).addCallback(async (gauge) => {
75
- const total = await knex("relations").count({
76
- count: "*"
77
- });
78
- gauge.observe(Number(total[0].count));
84
+ if (knex.client.config.client === "pg") {
85
+ const total = await knex.raw(`
86
+ SELECT reltuples::bigint AS estimate
87
+ FROM pg_class
88
+ WHERE oid = 'relations'::regclass;
89
+ `);
90
+ gauge.observe(Number(total.rows[0].estimate));
91
+ } else {
92
+ const total = await knex("relations").count({
93
+ count: "*"
94
+ });
95
+ gauge.observe(Number(total[0].count));
96
+ }
79
97
  })
80
98
  };
81
99
  }
@@ -1 +1 @@
1
- {"version":3,"file":"metrics.cjs.js","sources":["../../src/database/metrics.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 { Knex } from 'knex';\nimport { createGaugeMetric } from '../util/metrics';\nimport { DbRelationsRow, DbLocationsRow, DbSearchRow } from './tables';\nimport { metrics } from '@opentelemetry/api';\n\nexport function initDatabaseMetrics(knex: Knex) {\n const seenProm = new Set<string>();\n const seen = new Set<string>();\n const meter = metrics.getMeter('default');\n return {\n entities_count_prom: createGaugeMetric({\n name: 'catalog_entities_count',\n help: 'Total amount of entities in the catalog. DEPRECATED: Please use opentelemetry metrics instead.',\n labelNames: ['kind'],\n async collect() {\n const results = await knex<DbSearchRow>('search')\n .where('key', '=', 'kind')\n .whereNotNull('value')\n .select({ kind: 'value', count: knex.raw('count(*)') })\n .groupBy('value');\n\n results.forEach(({ kind, count }) => {\n seenProm.add(kind);\n this.set({ kind }, Number(count));\n });\n\n // Set all the entities that were not seenProm to 0 and delete them from the seenProm set.\n seenProm.forEach(kind => {\n if (!results.some(r => r.kind === kind)) {\n this.set({ kind }, 0);\n seenProm.delete(kind);\n }\n });\n },\n }),\n registered_locations_prom: createGaugeMetric({\n name: 'catalog_registered_locations_count',\n help: 'Total amount of registered locations in the catalog. DEPRECATED: Please use opentelemetry metrics instead.',\n async collect() {\n const total = await knex<DbLocationsRow>('locations').count({\n count: '*',\n });\n this.set(Number(total[0].count));\n },\n }),\n relations_prom: createGaugeMetric({\n name: 'catalog_relations_count',\n help: 'Total amount of relations between entities. DEPRECATED: Please use opentelemetry metrics instead.',\n async collect() {\n const total = await knex<DbRelationsRow>('relations').count({\n count: '*',\n });\n this.set(Number(total[0].count));\n },\n }),\n entities_count: meter\n .createObservableGauge('catalog_entities_count', {\n description: 'Total amount of entities in the catalog',\n })\n .addCallback(async gauge => {\n const results = await knex<DbSearchRow>('search')\n .where('key', '=', 'kind')\n .whereNotNull('value')\n .select({ kind: 'value', count: knex.raw('count(*)') })\n .groupBy('value');\n\n results.forEach(({ kind, count }) => {\n seen.add(kind);\n gauge.observe(Number(count), { kind });\n });\n\n // Set all the entities that were not seen to 0 and delete them from the seen set.\n seen.forEach(kind => {\n if (!results.some(r => r.kind === kind)) {\n gauge.observe(0, { kind });\n seen.delete(kind);\n }\n });\n }),\n registered_locations: meter\n .createObservableGauge('catalog_registered_locations_count', {\n description: 'Total amount of registered locations in the catalog',\n })\n .addCallback(async gauge => {\n const total = await knex<DbLocationsRow>('locations').count({\n count: '*',\n });\n gauge.observe(Number(total[0].count));\n }),\n relations: meter\n .createObservableGauge('catalog_relations_count', {\n description: 'Total amount of relations between entities',\n })\n .addCallback(async gauge => {\n const total = await knex<DbRelationsRow>('relations').count({\n count: '*',\n });\n gauge.observe(Number(total[0].count));\n }),\n };\n}\n"],"names":["metrics","createGaugeMetric"],"mappings":"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"}
1
+ {"version":3,"file":"metrics.cjs.js","sources":["../../src/database/metrics.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 { Knex } from 'knex';\nimport { createGaugeMetric } from '../util/metrics';\nimport { DbRelationsRow, DbLocationsRow, DbSearchRow } from './tables';\nimport { metrics } from '@opentelemetry/api';\n\nexport function initDatabaseMetrics(knex: Knex) {\n const seenProm = new Set<string>();\n const seen = new Set<string>();\n const meter = metrics.getMeter('default');\n return {\n entities_count_prom: createGaugeMetric({\n name: 'catalog_entities_count',\n help: 'Total amount of entities in the catalog. DEPRECATED: Please use opentelemetry metrics instead.',\n labelNames: ['kind'],\n async collect() {\n const results = await knex<DbSearchRow>('search')\n .where('key', '=', 'kind')\n .whereNotNull('value')\n .select({ kind: 'value', count: knex.raw('count(*)') })\n .groupBy('value');\n\n results.forEach(({ kind, count }) => {\n seenProm.add(kind);\n this.set({ kind }, Number(count));\n });\n\n // Set all the entities that were not seenProm to 0 and delete them from the seenProm set.\n seenProm.forEach(kind => {\n if (!results.some(r => r.kind === kind)) {\n this.set({ kind }, 0);\n seenProm.delete(kind);\n }\n });\n },\n }),\n registered_locations_prom: createGaugeMetric({\n name: 'catalog_registered_locations_count',\n help: 'Total amount of registered locations in the catalog. DEPRECATED: Please use opentelemetry metrics instead.',\n async collect() {\n const total = await knex<DbLocationsRow>('locations').count({\n count: '*',\n });\n this.set(Number(total[0].count));\n },\n }),\n relations_prom: createGaugeMetric({\n name: 'catalog_relations_count',\n help: 'Total amount of relations between entities. DEPRECATED: Please use opentelemetry metrics instead.',\n async collect() {\n const total = await knex<DbRelationsRow>('relations').count({\n count: '*',\n });\n this.set(Number(total[0].count));\n },\n }),\n entities_count: meter\n .createObservableGauge('catalog_entities_count', {\n description: 'Total amount of entities in the catalog',\n })\n .addCallback(async gauge => {\n const results = await knex<DbSearchRow>('search')\n .where('key', '=', 'kind')\n .whereNotNull('value')\n .select({ kind: 'value', count: knex.raw('count(*)') })\n .groupBy('value');\n\n results.forEach(({ kind, count }) => {\n seen.add(kind);\n gauge.observe(Number(count), { kind });\n });\n\n // Set all the entities that were not seen to 0 and delete them from the seen set.\n seen.forEach(kind => {\n if (!results.some(r => r.kind === kind)) {\n gauge.observe(0, { kind });\n seen.delete(kind);\n }\n });\n }),\n registered_locations: meter\n .createObservableGauge('catalog_registered_locations_count', {\n description: 'Total amount of registered locations in the catalog',\n })\n .addCallback(async gauge => {\n if (knex.client.config.client === 'pg') {\n // https://stackoverflow.com/questions/7943233/fast-way-to-discover-the-row-count-of-a-table-in-postgresql\n const total = await knex.raw(`\n SELECT reltuples::bigint AS estimate\n FROM pg_class\n WHERE oid = 'locations'::regclass;\n `);\n gauge.observe(Number(total.rows[0].estimate));\n } else {\n const total = await knex<DbLocationsRow>('locations').count({\n count: '*',\n });\n gauge.observe(Number(total[0].count));\n }\n }),\n relations: meter\n .createObservableGauge('catalog_relations_count', {\n description: 'Total amount of relations between entities',\n })\n .addCallback(async gauge => {\n if (knex.client.config.client === 'pg') {\n // https://stackoverflow.com/questions/7943233/fast-way-to-discover-the-row-count-of-a-table-in-postgresql\n const total = await knex.raw(`\n SELECT reltuples::bigint AS estimate\n FROM pg_class\n WHERE oid = 'relations'::regclass;\n `);\n gauge.observe(Number(total.rows[0].estimate));\n } else {\n const total = await knex<DbRelationsRow>('relations').count({\n count: '*',\n });\n gauge.observe(Number(total[0].count));\n }\n }),\n };\n}\n"],"names":["metrics","createGaugeMetric"],"mappings":"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"}
@@ -22,7 +22,7 @@ class AuthorizedEntitiesCatalog {
22
22
  ))[0];
23
23
  if (authorizeDecision.result === pluginPermissionCommon.AuthorizeResult.DENY) {
24
24
  return {
25
- entities: [],
25
+ entities: { type: "object", entities: [] },
26
26
  pageInfo: { hasNextPage: false }
27
27
  };
28
28
  }
@@ -44,7 +44,10 @@ class AuthorizedEntitiesCatalog {
44
44
  ))[0];
45
45
  if (authorizeDecision.result === pluginPermissionCommon.AuthorizeResult.DENY) {
46
46
  return {
47
- items: new Array(request.entityRefs.length).fill(null)
47
+ items: {
48
+ type: "object",
49
+ entities: new Array(request.entityRefs.length).fill(null)
50
+ }
48
51
  };
49
52
  }
50
53
  if (authorizeDecision.result === pluginPermissionCommon.AuthorizeResult.CONDITIONAL) {
@@ -65,7 +68,7 @@ class AuthorizedEntitiesCatalog {
65
68
  ))[0];
66
69
  if (authorizeDecision.result === pluginPermissionCommon.AuthorizeResult.DENY) {
67
70
  return {
68
- items: [],
71
+ items: { type: "object", entities: [] },
69
72
  pageInfo: {},
70
73
  totalItems: 0
71
74
  };
@@ -131,7 +134,7 @@ class AuthorizedEntitiesCatalog {
131
134
  allOf: [permissionFilter, basicEntityFilter.basicEntityFilter({ "metadata.uid": uid })]
132
135
  }
133
136
  });
134
- if (entities.length === 0) {
137
+ if (entities.entities.length === 0) {
135
138
  throw new errors.NotAllowedError();
136
139
  }
137
140
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AuthorizedEntitiesCatalog.cjs.js","sources":["../../src/service/AuthorizedEntitiesCatalog.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { NotAllowedError } from '@backstage/errors';\nimport {\n catalogEntityDeletePermission,\n catalogEntityReadPermission,\n} from '@backstage/plugin-catalog-common/alpha';\nimport { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { AuthorizeResult } from '@backstage/plugin-permission-common';\nimport { ConditionTransformer } from '@backstage/plugin-permission-node';\nimport {\n Cursor,\n EntitiesBatchRequest,\n EntitiesBatchResponse,\n EntitiesCatalog,\n EntitiesRequest,\n EntitiesResponse,\n EntityAncestryResponse,\n EntityFacetsRequest,\n EntityFacetsResponse,\n QueryEntitiesRequest,\n QueryEntitiesResponse,\n} from '../catalog/types';\nimport { basicEntityFilter } from './request';\nimport { isQueryEntitiesCursorRequest } from './util';\nimport { EntityFilter } from '@backstage/plugin-catalog-node';\nimport {\n BackstageCredentials,\n PermissionsService,\n} from '@backstage/backend-plugin-api';\n\nexport class AuthorizedEntitiesCatalog implements EntitiesCatalog {\n constructor(\n private readonly entitiesCatalog: EntitiesCatalog,\n private readonly permissionApi: PermissionsService,\n private readonly transformConditions: ConditionTransformer<EntityFilter>,\n ) {}\n\n async entities(request: EntitiesRequest): Promise<EntitiesResponse> {\n const authorizeDecision = (\n await this.permissionApi.authorizeConditional(\n [{ permission: catalogEntityReadPermission }],\n { credentials: request.credentials },\n )\n )[0];\n\n if (authorizeDecision.result === AuthorizeResult.DENY) {\n return {\n entities: [],\n pageInfo: { hasNextPage: false },\n };\n }\n\n if (authorizeDecision.result === AuthorizeResult.CONDITIONAL) {\n const permissionFilter: EntityFilter = this.transformConditions(\n authorizeDecision.conditions,\n );\n return this.entitiesCatalog.entities({\n ...request,\n filter: request?.filter\n ? { allOf: [permissionFilter, request.filter] }\n : permissionFilter,\n });\n }\n\n return this.entitiesCatalog.entities(request);\n }\n\n async entitiesBatch(\n request: EntitiesBatchRequest,\n ): Promise<EntitiesBatchResponse> {\n const authorizeDecision = (\n await this.permissionApi.authorizeConditional(\n [{ permission: catalogEntityReadPermission }],\n { credentials: request.credentials },\n )\n )[0];\n\n if (authorizeDecision.result === AuthorizeResult.DENY) {\n return {\n items: new Array(request.entityRefs.length).fill(null),\n };\n }\n\n if (authorizeDecision.result === AuthorizeResult.CONDITIONAL) {\n const permissionFilter: EntityFilter = this.transformConditions(\n authorizeDecision.conditions,\n );\n return this.entitiesCatalog.entitiesBatch({\n ...request,\n filter: request?.filter\n ? { allOf: [permissionFilter, request.filter] }\n : permissionFilter,\n });\n }\n\n return this.entitiesCatalog.entitiesBatch(request);\n }\n\n async queryEntities(\n request: QueryEntitiesRequest,\n ): Promise<QueryEntitiesResponse> {\n const authorizeDecision = (\n await this.permissionApi.authorizeConditional(\n [{ permission: catalogEntityReadPermission }],\n { credentials: request.credentials },\n )\n )[0];\n\n if (authorizeDecision.result === AuthorizeResult.DENY) {\n return {\n items: [],\n pageInfo: {},\n totalItems: 0,\n };\n }\n\n if (authorizeDecision.result === AuthorizeResult.CONDITIONAL) {\n const permissionFilter: EntityFilter = this.transformConditions(\n authorizeDecision.conditions,\n );\n\n let permissionedRequest: QueryEntitiesRequest;\n let requestFilter: EntityFilter | undefined;\n\n if (isQueryEntitiesCursorRequest(request)) {\n requestFilter = request.cursor.filter;\n\n permissionedRequest = {\n ...request,\n cursor: {\n ...request.cursor,\n filter: request.cursor.filter\n ? { allOf: [permissionFilter, request.cursor.filter] }\n : permissionFilter,\n },\n };\n } else {\n permissionedRequest = {\n ...request,\n filter: request.filter\n ? { allOf: [permissionFilter, request.filter] }\n : permissionFilter,\n };\n requestFilter = request.filter;\n }\n\n const response = await this.entitiesCatalog.queryEntities(\n permissionedRequest,\n );\n\n const prevCursor: Cursor | undefined = response.pageInfo.prevCursor && {\n ...response.pageInfo.prevCursor,\n filter: requestFilter,\n };\n\n const nextCursor: Cursor | undefined = response.pageInfo.nextCursor && {\n ...response.pageInfo.nextCursor,\n filter: requestFilter,\n };\n\n return {\n ...response,\n pageInfo: {\n prevCursor,\n nextCursor,\n },\n };\n }\n\n return this.entitiesCatalog.queryEntities(request);\n }\n\n async removeEntityByUid(\n uid: string,\n options: { credentials: BackstageCredentials },\n ): Promise<void> {\n const authorizeResponse = (\n await this.permissionApi.authorizeConditional(\n [{ permission: catalogEntityDeletePermission }],\n { credentials: options.credentials },\n )\n )[0];\n if (authorizeResponse.result === AuthorizeResult.DENY) {\n throw new NotAllowedError();\n }\n if (authorizeResponse.result === AuthorizeResult.CONDITIONAL) {\n const permissionFilter: EntityFilter = this.transformConditions(\n authorizeResponse.conditions,\n );\n const { entities } = await this.entitiesCatalog.entities({\n credentials: options.credentials,\n filter: {\n allOf: [permissionFilter, basicEntityFilter({ 'metadata.uid': uid })],\n },\n });\n if (entities.length === 0) {\n throw new NotAllowedError();\n }\n }\n return this.entitiesCatalog.removeEntityByUid(uid, {\n credentials: options.credentials,\n });\n }\n\n async entityAncestry(\n entityRef: string,\n options: { credentials: BackstageCredentials },\n ): Promise<EntityAncestryResponse> {\n const rootEntityAuthorizeResponse = (\n await this.permissionApi.authorize(\n [{ permission: catalogEntityReadPermission, resourceRef: entityRef }],\n { credentials: options.credentials },\n )\n )[0];\n if (rootEntityAuthorizeResponse.result === AuthorizeResult.DENY) {\n throw new NotAllowedError();\n }\n\n const ancestryResult = await this.entitiesCatalog.entityAncestry(\n entityRef,\n { credentials: options.credentials },\n );\n const authorizeResponse = await this.permissionApi.authorize(\n ancestryResult.items.map(item => ({\n permission: catalogEntityReadPermission,\n resourceRef: stringifyEntityRef(item.entity),\n })),\n { credentials: options.credentials },\n );\n const unauthorizedAncestryItems = ancestryResult.items.filter(\n (_, index) => authorizeResponse[index].result === AuthorizeResult.DENY,\n );\n if (unauthorizedAncestryItems.length === 0) {\n return ancestryResult;\n }\n const rootUnauthorizedEntityRefs = unauthorizedAncestryItems.map(\n ancestryItem => stringifyEntityRef(ancestryItem.entity),\n );\n const allUnauthorizedEntityRefs = new Set(\n rootUnauthorizedEntityRefs.flatMap(rootEntityRef =>\n this.findParents(\n rootEntityRef,\n ancestryResult.items,\n new Set(rootUnauthorizedEntityRefs),\n ),\n ),\n );\n return {\n rootEntityRef: ancestryResult.rootEntityRef,\n items: ancestryResult.items.filter(\n ancestryItem =>\n !allUnauthorizedEntityRefs.has(\n stringifyEntityRef(ancestryItem.entity),\n ),\n ),\n };\n }\n\n async facets(request: EntityFacetsRequest): Promise<EntityFacetsResponse> {\n const authorizeDecision = (\n await this.permissionApi.authorizeConditional(\n [{ permission: catalogEntityReadPermission }],\n { credentials: request.credentials },\n )\n )[0];\n\n if (authorizeDecision.result === AuthorizeResult.DENY) {\n return {\n facets: Object.fromEntries(request.facets.map(f => [f, []])),\n };\n }\n\n if (authorizeDecision.result === AuthorizeResult.CONDITIONAL) {\n const permissionFilter: EntityFilter = this.transformConditions(\n authorizeDecision.conditions,\n );\n return this.entitiesCatalog.facets({\n ...request,\n filter: request?.filter\n ? { allOf: [permissionFilter, request.filter] }\n : permissionFilter,\n });\n }\n\n return this.entitiesCatalog.facets(request);\n }\n\n private findParents(\n entityRef: string,\n allAncestryItems: { entity: Entity; parentEntityRefs: string[] }[],\n seenEntityRefs: Set<string>,\n ): string[] {\n const entity = allAncestryItems.find(\n ancestryItem => stringifyEntityRef(ancestryItem.entity) === entityRef,\n );\n if (!entity) return [];\n\n const newSeenEntityRefs = new Set(seenEntityRefs);\n entity.parentEntityRefs.forEach(parentRef =>\n newSeenEntityRefs.add(parentRef),\n );\n\n return [\n entityRef,\n ...entity.parentEntityRefs.flatMap(parentRef =>\n seenEntityRefs.has(parentRef)\n ? []\n : this.findParents(parentRef, allAncestryItems, newSeenEntityRefs),\n ),\n ];\n }\n}\n"],"names":["catalogEntityReadPermission","AuthorizeResult","isQueryEntitiesCursorRequest","catalogEntityDeletePermission","NotAllowedError","basicEntityFilter","stringifyEntityRef"],"mappings":"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"}
1
+ {"version":3,"file":"AuthorizedEntitiesCatalog.cjs.js","sources":["../../src/service/AuthorizedEntitiesCatalog.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { NotAllowedError } from '@backstage/errors';\nimport {\n catalogEntityDeletePermission,\n catalogEntityReadPermission,\n} from '@backstage/plugin-catalog-common/alpha';\nimport { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { AuthorizeResult } from '@backstage/plugin-permission-common';\nimport { ConditionTransformer } from '@backstage/plugin-permission-node';\nimport {\n Cursor,\n EntitiesBatchRequest,\n EntitiesBatchResponse,\n EntitiesCatalog,\n EntitiesRequest,\n EntitiesResponse,\n EntityAncestryResponse,\n EntityFacetsRequest,\n EntityFacetsResponse,\n QueryEntitiesRequest,\n QueryEntitiesResponse,\n} from '../catalog/types';\nimport { basicEntityFilter } from './request';\nimport { isQueryEntitiesCursorRequest } from './util';\nimport { EntityFilter } from '@backstage/plugin-catalog-node';\nimport {\n BackstageCredentials,\n PermissionsService,\n} from '@backstage/backend-plugin-api';\n\nexport class AuthorizedEntitiesCatalog implements EntitiesCatalog {\n constructor(\n private readonly entitiesCatalog: EntitiesCatalog,\n private readonly permissionApi: PermissionsService,\n private readonly transformConditions: ConditionTransformer<EntityFilter>,\n ) {}\n\n async entities(request: EntitiesRequest): Promise<EntitiesResponse> {\n const authorizeDecision = (\n await this.permissionApi.authorizeConditional(\n [{ permission: catalogEntityReadPermission }],\n { credentials: request.credentials },\n )\n )[0];\n\n if (authorizeDecision.result === AuthorizeResult.DENY) {\n return {\n entities: { type: 'object', entities: [] },\n pageInfo: { hasNextPage: false },\n };\n }\n\n if (authorizeDecision.result === AuthorizeResult.CONDITIONAL) {\n const permissionFilter: EntityFilter = this.transformConditions(\n authorizeDecision.conditions,\n );\n return this.entitiesCatalog.entities({\n ...request,\n filter: request?.filter\n ? { allOf: [permissionFilter, request.filter] }\n : permissionFilter,\n });\n }\n\n return this.entitiesCatalog.entities(request);\n }\n\n async entitiesBatch(\n request: EntitiesBatchRequest,\n ): Promise<EntitiesBatchResponse> {\n const authorizeDecision = (\n await this.permissionApi.authorizeConditional(\n [{ permission: catalogEntityReadPermission }],\n { credentials: request.credentials },\n )\n )[0];\n\n if (authorizeDecision.result === AuthorizeResult.DENY) {\n return {\n items: {\n type: 'object',\n entities: new Array(request.entityRefs.length).fill(null),\n },\n };\n }\n\n if (authorizeDecision.result === AuthorizeResult.CONDITIONAL) {\n const permissionFilter: EntityFilter = this.transformConditions(\n authorizeDecision.conditions,\n );\n return this.entitiesCatalog.entitiesBatch({\n ...request,\n filter: request?.filter\n ? { allOf: [permissionFilter, request.filter] }\n : permissionFilter,\n });\n }\n\n return this.entitiesCatalog.entitiesBatch(request);\n }\n\n async queryEntities(\n request: QueryEntitiesRequest,\n ): Promise<QueryEntitiesResponse> {\n const authorizeDecision = (\n await this.permissionApi.authorizeConditional(\n [{ permission: catalogEntityReadPermission }],\n { credentials: request.credentials },\n )\n )[0];\n\n if (authorizeDecision.result === AuthorizeResult.DENY) {\n return {\n items: { type: 'object', entities: [] },\n pageInfo: {},\n totalItems: 0,\n };\n }\n\n if (authorizeDecision.result === AuthorizeResult.CONDITIONAL) {\n const permissionFilter: EntityFilter = this.transformConditions(\n authorizeDecision.conditions,\n );\n\n let permissionedRequest: QueryEntitiesRequest;\n let requestFilter: EntityFilter | undefined;\n\n if (isQueryEntitiesCursorRequest(request)) {\n requestFilter = request.cursor.filter;\n\n permissionedRequest = {\n ...request,\n cursor: {\n ...request.cursor,\n filter: request.cursor.filter\n ? { allOf: [permissionFilter, request.cursor.filter] }\n : permissionFilter,\n },\n };\n } else {\n permissionedRequest = {\n ...request,\n filter: request.filter\n ? { allOf: [permissionFilter, request.filter] }\n : permissionFilter,\n };\n requestFilter = request.filter;\n }\n\n const response = await this.entitiesCatalog.queryEntities(\n permissionedRequest,\n );\n\n const prevCursor: Cursor | undefined = response.pageInfo.prevCursor && {\n ...response.pageInfo.prevCursor,\n filter: requestFilter,\n };\n\n const nextCursor: Cursor | undefined = response.pageInfo.nextCursor && {\n ...response.pageInfo.nextCursor,\n filter: requestFilter,\n };\n\n return {\n ...response,\n pageInfo: {\n prevCursor,\n nextCursor,\n },\n };\n }\n\n return this.entitiesCatalog.queryEntities(request);\n }\n\n async removeEntityByUid(\n uid: string,\n options: { credentials: BackstageCredentials },\n ): Promise<void> {\n const authorizeResponse = (\n await this.permissionApi.authorizeConditional(\n [{ permission: catalogEntityDeletePermission }],\n { credentials: options.credentials },\n )\n )[0];\n if (authorizeResponse.result === AuthorizeResult.DENY) {\n throw new NotAllowedError();\n }\n if (authorizeResponse.result === AuthorizeResult.CONDITIONAL) {\n const permissionFilter: EntityFilter = this.transformConditions(\n authorizeResponse.conditions,\n );\n const { entities } = await this.entitiesCatalog.entities({\n credentials: options.credentials,\n filter: {\n allOf: [permissionFilter, basicEntityFilter({ 'metadata.uid': uid })],\n },\n });\n if (entities.entities.length === 0) {\n throw new NotAllowedError();\n }\n }\n return this.entitiesCatalog.removeEntityByUid(uid, {\n credentials: options.credentials,\n });\n }\n\n async entityAncestry(\n entityRef: string,\n options: { credentials: BackstageCredentials },\n ): Promise<EntityAncestryResponse> {\n const rootEntityAuthorizeResponse = (\n await this.permissionApi.authorize(\n [{ permission: catalogEntityReadPermission, resourceRef: entityRef }],\n { credentials: options.credentials },\n )\n )[0];\n if (rootEntityAuthorizeResponse.result === AuthorizeResult.DENY) {\n throw new NotAllowedError();\n }\n\n const ancestryResult = await this.entitiesCatalog.entityAncestry(\n entityRef,\n { credentials: options.credentials },\n );\n const authorizeResponse = await this.permissionApi.authorize(\n ancestryResult.items.map(item => ({\n permission: catalogEntityReadPermission,\n resourceRef: stringifyEntityRef(item.entity),\n })),\n { credentials: options.credentials },\n );\n const unauthorizedAncestryItems = ancestryResult.items.filter(\n (_, index) => authorizeResponse[index].result === AuthorizeResult.DENY,\n );\n if (unauthorizedAncestryItems.length === 0) {\n return ancestryResult;\n }\n const rootUnauthorizedEntityRefs = unauthorizedAncestryItems.map(\n ancestryItem => stringifyEntityRef(ancestryItem.entity),\n );\n const allUnauthorizedEntityRefs = new Set(\n rootUnauthorizedEntityRefs.flatMap(rootEntityRef =>\n this.findParents(\n rootEntityRef,\n ancestryResult.items,\n new Set(rootUnauthorizedEntityRefs),\n ),\n ),\n );\n return {\n rootEntityRef: ancestryResult.rootEntityRef,\n items: ancestryResult.items.filter(\n ancestryItem =>\n !allUnauthorizedEntityRefs.has(\n stringifyEntityRef(ancestryItem.entity),\n ),\n ),\n };\n }\n\n async facets(request: EntityFacetsRequest): Promise<EntityFacetsResponse> {\n const authorizeDecision = (\n await this.permissionApi.authorizeConditional(\n [{ permission: catalogEntityReadPermission }],\n { credentials: request.credentials },\n )\n )[0];\n\n if (authorizeDecision.result === AuthorizeResult.DENY) {\n return {\n facets: Object.fromEntries(request.facets.map(f => [f, []])),\n };\n }\n\n if (authorizeDecision.result === AuthorizeResult.CONDITIONAL) {\n const permissionFilter: EntityFilter = this.transformConditions(\n authorizeDecision.conditions,\n );\n return this.entitiesCatalog.facets({\n ...request,\n filter: request?.filter\n ? { allOf: [permissionFilter, request.filter] }\n : permissionFilter,\n });\n }\n\n return this.entitiesCatalog.facets(request);\n }\n\n private findParents(\n entityRef: string,\n allAncestryItems: { entity: Entity; parentEntityRefs: string[] }[],\n seenEntityRefs: Set<string>,\n ): string[] {\n const entity = allAncestryItems.find(\n ancestryItem => stringifyEntityRef(ancestryItem.entity) === entityRef,\n );\n if (!entity) return [];\n\n const newSeenEntityRefs = new Set(seenEntityRefs);\n entity.parentEntityRefs.forEach(parentRef =>\n newSeenEntityRefs.add(parentRef),\n );\n\n return [\n entityRef,\n ...entity.parentEntityRefs.flatMap(parentRef =>\n seenEntityRefs.has(parentRef)\n ? []\n : this.findParents(parentRef, allAncestryItems, newSeenEntityRefs),\n ),\n ];\n }\n}\n"],"names":["catalogEntityReadPermission","AuthorizeResult","isQueryEntitiesCursorRequest","catalogEntityDeletePermission","NotAllowedError","basicEntityFilter","stringifyEntityRef"],"mappings":"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"}
@@ -46,6 +46,7 @@ var AuthorizedLocationService = require('./AuthorizedLocationService.cjs.js');
46
46
  var DefaultProviderDatabase = require('../database/DefaultProviderDatabase.cjs.js');
47
47
  var DefaultCatalogDatabase = require('../database/DefaultCatalogDatabase.cjs.js');
48
48
  var types = require('@backstage/types');
49
+ var process$1 = require('./response/process.cjs.js');
49
50
 
50
51
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
51
52
 
@@ -321,6 +322,9 @@ class CatalogBuilder {
321
322
  ...this.env,
322
323
  discovery
323
324
  });
325
+ const disableRelationsCompatibility = config.getOptionalBoolean(
326
+ "catalog.disableRelationsCompatibility"
327
+ );
324
328
  const policy = this.buildEntityPolicy();
325
329
  const processors = this.buildProcessors();
326
330
  const parser = this.parser || parse.defaultEntityDataParser;
@@ -352,7 +356,8 @@ class CatalogBuilder {
352
356
  const unauthorizedEntitiesCatalog = new DefaultEntitiesCatalog.DefaultEntitiesCatalog({
353
357
  database: dbClient,
354
358
  logger,
355
- stitcher
359
+ stitcher,
360
+ disableRelationsCompatibility
356
361
  });
357
362
  let permissionsService;
358
363
  if ("authorizeConditional" in permissions) {
@@ -393,7 +398,10 @@ class CatalogBuilder {
393
398
  })
394
399
  }
395
400
  });
396
- const entitiesByRef = lodash.keyBy(entities, catalogModel.stringifyEntityRef);
401
+ const entitiesByRef = lodash.keyBy(
402
+ process$1.entitiesResponseToObjects(entities),
403
+ catalogModel.stringifyEntityRef
404
+ );
397
405
  return resourceRefs.map(
398
406
  (resourceRef) => entitiesByRef[catalogModel.stringifyEntityRef(catalogModel.parseEntityRef(resourceRef))]
399
407
  );
@@ -447,7 +455,8 @@ class CatalogBuilder {
447
455
  permissionIntegrationRouter,
448
456
  auth,
449
457
  httpAuth,
450
- permissionsService
458
+ permissionsService,
459
+ disableRelationsCompatibility
451
460
  });
452
461
  await connectEntityProviders.connectEntityProviders(providerDatabase, entityProviders);
453
462
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"CatalogBuilder.cjs.js","sources":["../../src/service/CatalogBuilder.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createLegacyAuthAdapters,\n HostDiscovery,\n} from '@backstage/backend-common';\nimport {\n DefaultNamespaceEntityPolicy,\n Entity,\n EntityPolicies,\n EntityPolicy,\n FieldFormatEntityPolicy,\n makeValidator,\n NoForeignRootFieldsEntityPolicy,\n parseEntityRef,\n SchemaValidEntityPolicy,\n stringifyEntityRef,\n Validators,\n} from '@backstage/catalog-model';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { createHash } from 'crypto';\nimport { Router } from 'express';\nimport lodash, { keyBy } from 'lodash';\n\nimport {\n CatalogProcessor,\n CatalogProcessorParser,\n EntitiesSearchFilter,\n EntityProvider,\n PlaceholderResolver,\n LocationAnalyzer,\n ScmLocationAnalyzer,\n} from '@backstage/plugin-catalog-node';\nimport {\n AnnotateLocationEntityProcessor,\n BuiltinKindsEntityProcessor,\n CodeOwnersProcessor,\n FileReaderProcessor,\n PlaceholderProcessor,\n UrlReaderProcessor,\n} from '../processors';\nimport { ConfigLocationEntityProvider } from '../providers/ConfigLocationEntityProvider';\nimport { DefaultLocationStore } from '../providers/DefaultLocationStore';\nimport { RepoLocationAnalyzer } from '../ingestion/LocationAnalyzer';\nimport { AuthorizedLocationAnalyzer } from './AuthorizedLocationAnalyzer';\nimport {\n jsonPlaceholderResolver,\n textPlaceholderResolver,\n yamlPlaceholderResolver,\n} from '../processors/PlaceholderProcessor';\nimport { defaultEntityDataParser } from '../util/parse';\nimport {\n CatalogProcessingEngine,\n createRandomProcessingInterval,\n ProcessingIntervalFunction,\n} from '../processing';\nimport { DefaultProcessingDatabase } from '../database/DefaultProcessingDatabase';\nimport { applyDatabaseMigrations } from '../database/migrations';\nimport { DefaultCatalogProcessingEngine } from '../processing/DefaultCatalogProcessingEngine';\nimport { DefaultLocationService } from './DefaultLocationService';\nimport { DefaultEntitiesCatalog } from './DefaultEntitiesCatalog';\nimport { DefaultCatalogProcessingOrchestrator } from '../processing/DefaultCatalogProcessingOrchestrator';\nimport { DefaultStitcher } from '../stitching/DefaultStitcher';\nimport { createRouter } from './createRouter';\nimport { DefaultRefreshService } from './DefaultRefreshService';\nimport { AuthorizedRefreshService } from './AuthorizedRefreshService';\nimport { DefaultCatalogRulesEnforcer } from '../ingestion/CatalogRules';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { connectEntityProviders } from '../processing/connectEntityProviders';\nimport {\n Permission,\n PermissionAuthorizer,\n PermissionRuleParams,\n toPermissionEvaluator,\n} from '@backstage/plugin-permission-common';\nimport { permissionRules as catalogPermissionRules } from '../permissions/rules';\nimport {\n createConditionTransformer,\n createPermissionIntegrationRouter,\n PermissionRule,\n} from '@backstage/plugin-permission-node';\nimport { AuthorizedEntitiesCatalog } from './AuthorizedEntitiesCatalog';\nimport { basicEntityFilter } from './request';\nimport {\n catalogPermissions,\n RESOURCE_TYPE_CATALOG_ENTITY,\n} from '@backstage/plugin-catalog-common/alpha';\nimport { AuthorizedLocationService } from './AuthorizedLocationService';\nimport { DefaultProviderDatabase } from '../database/DefaultProviderDatabase';\nimport { DefaultCatalogDatabase } from '../database/DefaultCatalogDatabase';\nimport { EventBroker, EventsService } from '@backstage/plugin-events-node';\nimport { durationToMilliseconds } from '@backstage/types';\nimport {\n AuthService,\n DatabaseService,\n DiscoveryService,\n HttpAuthService,\n LoggerService,\n PermissionsService,\n RootConfigService,\n UrlReaderService,\n SchedulerService,\n} from '@backstage/backend-plugin-api';\n\n/**\n * This is a duplicate of the alpha `CatalogPermissionRule` type, for use in the stable API.\n *\n * @public\n */\nexport type CatalogPermissionRuleInput<\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = PermissionRule<Entity, EntitiesSearchFilter, 'catalog-entity', TParams>;\n\n/**\n * @deprecated Please migrate to the new backend system as this will be removed in the future.\n * @public\n */\nexport type CatalogEnvironment = {\n logger: LoggerService;\n database: DatabaseService;\n config: RootConfigService;\n reader: UrlReaderService;\n permissions: PermissionsService | PermissionAuthorizer;\n scheduler?: SchedulerService;\n discovery?: DiscoveryService;\n auth?: AuthService;\n httpAuth?: HttpAuthService;\n};\n\n/**\n * A builder that helps wire up all of the component parts of the catalog.\n *\n * The touch points where you can replace or extend behavior are as follows:\n *\n * - Entity policies can be added or replaced. These are automatically run\n * after the processors' pre-processing steps. All policies are given the\n * chance to inspect the entity, and all of them have to pass in order for\n * the entity to be considered valid from an overall point of view.\n * - Location analyzers can be added. These are responsible for analyzing\n * repositories when onboarding them into the catalog, by finding\n * catalog-info.yaml files and other artifacts that can help automatically\n * register or create catalog data on the user's behalf.\n * - Placeholder resolvers can be replaced or added. These run on the raw\n * structured data between the parsing and pre-processing steps, to replace\n * dollar-prefixed entries with their actual values (like $file).\n * - Field format validators can be replaced. These check the format of\n * individual core fields such as metadata.name, to ensure that they adhere\n * to certain rules.\n * - Processors can be added or replaced. These implement the functionality of\n * reading, parsing, validating, and processing the entity data before it is\n * persisted in the catalog.\n *\n * @public\n * @deprecated Please migrate to the new backend system as this will be removed in the future.\n */\nexport class CatalogBuilder {\n private readonly env: CatalogEnvironment;\n private entityPolicies: EntityPolicy[];\n private entityPoliciesReplace: boolean;\n private placeholderResolvers: Record<string, PlaceholderResolver>;\n private fieldFormatValidators: Partial<Validators>;\n private entityProviders: EntityProvider[];\n private processors: CatalogProcessor[];\n private locationAnalyzers: ScmLocationAnalyzer[];\n private processorsReplace: boolean;\n private parser: CatalogProcessorParser | undefined;\n private onProcessingError?: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise<void> | void;\n private processingInterval: ProcessingIntervalFunction;\n private locationAnalyzer: LocationAnalyzer | undefined = undefined;\n private readonly permissions: Permission[];\n private readonly permissionRules: CatalogPermissionRuleInput[];\n private allowedLocationType: string[];\n private legacySingleProcessorValidation = false;\n private eventBroker?: EventBroker | EventsService;\n\n /**\n * Creates a catalog builder.\n */\n static create(env: CatalogEnvironment): CatalogBuilder {\n return new CatalogBuilder(env);\n }\n\n private constructor(env: CatalogEnvironment) {\n this.env = env;\n this.entityPolicies = [];\n this.entityPoliciesReplace = false;\n this.placeholderResolvers = {};\n this.fieldFormatValidators = {};\n this.entityProviders = [];\n this.processors = [];\n this.locationAnalyzers = [];\n this.processorsReplace = false;\n this.parser = undefined;\n this.permissions = [...catalogPermissions];\n this.permissionRules = Object.values(catalogPermissionRules);\n this.allowedLocationType = ['url'];\n\n this.processingInterval = CatalogBuilder.getDefaultProcessingInterval(\n env.config,\n );\n }\n\n /**\n * Adds policies that are used to validate entities between the pre-\n * processing and post-processing stages. All such policies must pass for the\n * entity to be considered valid.\n *\n * If what you want to do is to replace the rules for what format is allowed\n * in various core entity fields (such as metadata.name), you may want to use\n * {@link CatalogBuilder#setFieldFormatValidators} instead.\n *\n * @param policies - One or more policies\n */\n addEntityPolicy(\n ...policies: Array<EntityPolicy | Array<EntityPolicy>>\n ): CatalogBuilder {\n this.entityPolicies.push(...policies.flat());\n return this;\n }\n\n /**\n * Processing interval determines how often entities should be processed.\n * Seconds provided will be multiplied by 1.5\n * The default processing interval is 100-150 seconds.\n * setting this too low will potentially deplete request quotas to upstream services.\n */\n setProcessingIntervalSeconds(seconds: number): CatalogBuilder {\n this.processingInterval = createRandomProcessingInterval({\n minSeconds: seconds,\n maxSeconds: seconds * 1.5,\n });\n return this;\n }\n\n /**\n * Overwrites the default processing interval function used to spread\n * entity updates in the catalog.\n */\n setProcessingInterval(\n processingInterval: ProcessingIntervalFunction,\n ): CatalogBuilder {\n this.processingInterval = processingInterval;\n return this;\n }\n\n /**\n * Overwrites the default location analyzer.\n */\n setLocationAnalyzer(locationAnalyzer: LocationAnalyzer): CatalogBuilder {\n this.locationAnalyzer = locationAnalyzer;\n return this;\n }\n\n /**\n * Sets what policies to use for validation of entities between the pre-\n * processing and post-processing stages. All such policies must pass for the\n * entity to be considered valid.\n *\n * If what you want to do is to replace the rules for what format is allowed\n * in various core entity fields (such as metadata.name), you may want to use\n * {@link CatalogBuilder#setFieldFormatValidators} instead.\n *\n * This function replaces the default set of policies; use with care.\n *\n * @param policies - One or more policies\n */\n replaceEntityPolicies(policies: EntityPolicy[]): CatalogBuilder {\n this.entityPolicies = [...policies];\n this.entityPoliciesReplace = true;\n return this;\n }\n\n /**\n * Adds, or overwrites, a handler for placeholders (e.g. $file) in entity\n * definition files.\n *\n * @param key - The key that identifies the placeholder, e.g. \"file\"\n * @param resolver - The resolver that gets values for this placeholder\n */\n setPlaceholderResolver(\n key: string,\n resolver: PlaceholderResolver,\n ): CatalogBuilder {\n this.placeholderResolvers[key] = resolver;\n return this;\n }\n\n /**\n * Sets the validator function to use for one or more special fields of an\n * entity. This is useful if the default rules for formatting of fields are\n * not sufficient.\n *\n * This function has no effect if used together with\n * {@link CatalogBuilder#replaceEntityPolicies}.\n *\n * @param validators - The (subset of) validators to set\n */\n setFieldFormatValidators(validators: Partial<Validators>): CatalogBuilder {\n lodash.merge(this.fieldFormatValidators, validators);\n return this;\n }\n\n /**\n * Adds or replaces entity providers. These are responsible for bootstrapping\n * the list of entities out of original data sources. For example, there is\n * one entity source for the config locations, and one for the database\n * stored locations. If you ingest entities out of a third party system, you\n * may want to implement that in terms of an entity provider as well.\n *\n * @param providers - One or more entity providers\n */\n addEntityProvider(\n ...providers: Array<EntityProvider | Array<EntityProvider>>\n ): CatalogBuilder {\n this.entityProviders.push(...providers.flat());\n return this;\n }\n\n /**\n * Adds entity processors. These are responsible for reading, parsing, and\n * processing entities before they are persisted in the catalog.\n *\n * @param processors - One or more processors\n */\n addProcessor(\n ...processors: Array<CatalogProcessor | Array<CatalogProcessor>>\n ): CatalogBuilder {\n this.processors.push(...processors.flat());\n return this;\n }\n\n /**\n * Sets what entity processors to use. These are responsible for reading,\n * parsing, and processing entities before they are persisted in the catalog.\n *\n * This function replaces the default set of processors, consider using with\n * {@link CatalogBuilder#getDefaultProcessors}; use with care.\n *\n * @param processors - One or more processors\n */\n replaceProcessors(processors: CatalogProcessor[]): CatalogBuilder {\n this.processors = [...processors];\n this.processorsReplace = true;\n return this;\n }\n\n /**\n * Returns the default list of entity processors. These are responsible for reading,\n * parsing, and processing entities before they are persisted in the catalog. Changing\n * the order of processing can give more control to custom processors.\n *\n * Consider using with {@link CatalogBuilder#replaceProcessors}\n *\n */\n getDefaultProcessors(): CatalogProcessor[] {\n const { config, logger, reader } = this.env;\n const integrations = ScmIntegrations.fromConfig(config);\n\n return [\n new FileReaderProcessor(),\n new UrlReaderProcessor({ reader, logger }),\n CodeOwnersProcessor.fromConfig(config, { logger, reader }),\n new AnnotateLocationEntityProcessor({ integrations }),\n ];\n }\n\n /**\n * Adds Location Analyzers. These are responsible for analyzing\n * repositories when onboarding them into the catalog, by finding\n * catalog-info.yaml files and other artifacts that can help automatically\n * register or create catalog data on the user's behalf.\n *\n * @param locationAnalyzers - One or more location analyzers\n */\n addLocationAnalyzers(\n ...analyzers: Array<ScmLocationAnalyzer | Array<ScmLocationAnalyzer>>\n ): CatalogBuilder {\n this.locationAnalyzers.push(...analyzers.flat());\n return this;\n }\n\n /**\n * Sets up the catalog to use a custom parser for entity data.\n *\n * This is the function that gets called immediately after some raw entity\n * specification data has been read from a remote source, and needs to be\n * parsed and emitted as structured data.\n *\n * @param parser - The custom parser\n */\n setEntityDataParser(parser: CatalogProcessorParser): CatalogBuilder {\n this.parser = parser;\n return this;\n }\n\n /**\n * Adds additional permissions. See\n * {@link @backstage/plugin-permission-node#Permission}.\n *\n * @param permissions - Additional permissions\n */\n addPermissions(...permissions: Array<Permission | Array<Permission>>) {\n this.permissions.push(...permissions.flat());\n return this;\n }\n\n /**\n * Adds additional permission rules. Permission rules are used to evaluate\n * catalog resources against queries. See\n * {@link @backstage/plugin-permission-node#PermissionRule}.\n *\n * @param permissionRules - Additional permission rules\n */\n addPermissionRules(\n ...permissionRules: Array<\n CatalogPermissionRuleInput | Array<CatalogPermissionRuleInput>\n >\n ) {\n this.permissionRules.push(...permissionRules.flat());\n return this;\n }\n\n /**\n * Sets up the allowed location types from being registered via the location service.\n *\n * @param allowedLocationTypes - the allowed location types\n */\n setAllowedLocationTypes(allowedLocationTypes: string[]): CatalogBuilder {\n this.allowedLocationType = allowedLocationTypes;\n return this;\n }\n\n /**\n * Enables the legacy behaviour of canceling validation early whenever only a\n * single processor declares an entity kind to be valid.\n */\n useLegacySingleProcessorValidation(): this {\n this.legacySingleProcessorValidation = true;\n return this;\n }\n\n /**\n * Enables the publishing of events for conflicts in the DefaultProcessingDatabase\n */\n setEventBroker(broker: EventBroker | EventsService): CatalogBuilder {\n this.eventBroker = broker;\n return this;\n }\n\n /**\n * Wires up and returns all of the component parts of the catalog\n */\n async build(): Promise<{\n processingEngine: CatalogProcessingEngine;\n router: Router;\n }> {\n const {\n config,\n database,\n logger,\n permissions,\n scheduler,\n discovery = HostDiscovery.fromConfig(config),\n } = this.env;\n\n const { auth, httpAuth } = createLegacyAuthAdapters({\n ...this.env,\n discovery,\n });\n\n const policy = this.buildEntityPolicy();\n const processors = this.buildProcessors();\n const parser = this.parser || defaultEntityDataParser;\n\n const dbClient = await database.getClient();\n if (!database.migrations?.skip) {\n logger.info('Performing database migration');\n await applyDatabaseMigrations(dbClient);\n }\n\n const stitcher = DefaultStitcher.fromConfig(config, {\n knex: dbClient,\n logger,\n });\n\n const processingDatabase = new DefaultProcessingDatabase({\n database: dbClient,\n logger,\n refreshInterval: this.processingInterval,\n eventBroker: this.eventBroker,\n });\n const providerDatabase = new DefaultProviderDatabase({\n database: dbClient,\n logger,\n });\n const catalogDatabase = new DefaultCatalogDatabase({\n database: dbClient,\n logger,\n });\n const integrations = ScmIntegrations.fromConfig(config);\n const rulesEnforcer = DefaultCatalogRulesEnforcer.fromConfig(config);\n\n const unauthorizedEntitiesCatalog = new DefaultEntitiesCatalog({\n database: dbClient,\n logger,\n stitcher,\n });\n\n let permissionsService: PermissionsService;\n if ('authorizeConditional' in permissions) {\n permissionsService = permissions as PermissionsService;\n } else {\n logger.warn(\n 'PermissionAuthorizer is deprecated. Please use an instance of PermissionEvaluator instead of PermissionAuthorizer in PluginEnvironment#permissions',\n );\n permissionsService = toPermissionEvaluator(permissions);\n }\n\n const orchestrator = new DefaultCatalogProcessingOrchestrator({\n processors,\n integrations,\n rulesEnforcer,\n logger,\n parser,\n policy,\n legacySingleProcessorValidation: this.legacySingleProcessorValidation,\n });\n\n const entitiesCatalog = new AuthorizedEntitiesCatalog(\n unauthorizedEntitiesCatalog,\n permissionsService,\n createConditionTransformer(this.permissionRules),\n );\n const permissionIntegrationRouter = createPermissionIntegrationRouter({\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n getResources: async (resourceRefs: string[]) => {\n const { entities } = await unauthorizedEntitiesCatalog.entities({\n credentials: await auth.getOwnServiceCredentials(),\n filter: {\n anyOf: resourceRefs.map(resourceRef => {\n const { kind, namespace, name } = parseEntityRef(resourceRef);\n\n return basicEntityFilter({\n kind,\n 'metadata.namespace': namespace,\n 'metadata.name': name,\n });\n }),\n },\n });\n\n const entitiesByRef = keyBy(entities, stringifyEntityRef);\n\n return resourceRefs.map(\n resourceRef =>\n entitiesByRef[stringifyEntityRef(parseEntityRef(resourceRef))],\n );\n },\n permissions: this.permissions,\n rules: this.permissionRules,\n });\n\n const locationStore = new DefaultLocationStore(dbClient);\n const configLocationProvider = new ConfigLocationEntityProvider(config);\n const entityProviders = lodash.uniqBy(\n [...this.entityProviders, locationStore, configLocationProvider],\n provider => provider.getProviderName(),\n );\n\n const processingEngine = new DefaultCatalogProcessingEngine({\n config,\n scheduler,\n logger,\n knex: dbClient,\n processingDatabase,\n orchestrator,\n stitcher,\n createHash: () => createHash('sha1'),\n pollingIntervalMs: 1000,\n onProcessingError: event => {\n this.onProcessingError?.(event);\n },\n eventBroker: this.eventBroker,\n });\n\n const locationAnalyzer =\n this.locationAnalyzer ??\n new AuthorizedLocationAnalyzer(\n new RepoLocationAnalyzer(logger, integrations, this.locationAnalyzers),\n permissionsService,\n );\n const locationService = new AuthorizedLocationService(\n new DefaultLocationService(locationStore, orchestrator, {\n allowedLocationTypes: this.allowedLocationType,\n }),\n permissionsService,\n );\n const refreshService = new AuthorizedRefreshService(\n new DefaultRefreshService({ database: catalogDatabase }),\n permissionsService,\n );\n\n const router = await createRouter({\n entitiesCatalog,\n locationAnalyzer,\n locationService,\n orchestrator,\n refreshService,\n logger,\n config,\n permissionIntegrationRouter,\n auth,\n httpAuth,\n permissionsService,\n });\n\n await connectEntityProviders(providerDatabase, entityProviders);\n\n return {\n processingEngine: {\n async start() {\n await processingEngine.start();\n await stitcher.start();\n },\n async stop() {\n await processingEngine.stop();\n await stitcher.stop();\n },\n },\n router,\n };\n }\n\n subscribe(options: {\n onProcessingError: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise<void> | void;\n }) {\n this.onProcessingError = options.onProcessingError;\n }\n\n private buildEntityPolicy(): EntityPolicy {\n const entityPolicies: EntityPolicy[] = this.entityPoliciesReplace\n ? [new SchemaValidEntityPolicy(), ...this.entityPolicies]\n : [\n new SchemaValidEntityPolicy(),\n new DefaultNamespaceEntityPolicy(),\n new NoForeignRootFieldsEntityPolicy(),\n new FieldFormatEntityPolicy(\n makeValidator(this.fieldFormatValidators),\n ),\n ...this.entityPolicies,\n ];\n\n return EntityPolicies.allOf(entityPolicies);\n }\n\n private buildProcessors(): CatalogProcessor[] {\n const { config, reader } = this.env;\n const integrations = ScmIntegrations.fromConfig(config);\n\n this.checkDeprecatedReaderProcessors();\n\n const placeholderResolvers: Record<string, PlaceholderResolver> = {\n json: jsonPlaceholderResolver,\n yaml: yamlPlaceholderResolver,\n text: textPlaceholderResolver,\n ...this.placeholderResolvers,\n };\n\n // The placeholder is always there no matter what\n const processors: CatalogProcessor[] = [\n new PlaceholderProcessor({\n resolvers: placeholderResolvers,\n reader,\n integrations,\n }),\n ];\n\n const builtinKindsEntityProcessor = new BuiltinKindsEntityProcessor();\n // If the user adds a processor named 'BuiltinKindsEntityProcessor',\n // skip inclusion of the catalog-backend version.\n if (\n !this.processors.some(\n processor =>\n processor.getProcessorName() ===\n builtinKindsEntityProcessor.getProcessorName(),\n )\n ) {\n processors.push(builtinKindsEntityProcessor);\n }\n\n // These are only added unless the user replaced them all\n if (!this.processorsReplace) {\n processors.push(...this.getDefaultProcessors());\n }\n\n // Add the ones (if any) that the user added\n processors.push(...this.processors);\n\n this.checkMissingExternalProcessors(processors);\n\n return processors;\n }\n\n // TODO(Rugvip): These old processors are removed, for a while we'll be throwing\n // errors here to make sure people know where to move the config\n private checkDeprecatedReaderProcessors() {\n const pc = this.env.config.getOptionalConfig('catalog.processors');\n if (pc?.has('github')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.github, move to using integrations.github instead`,\n );\n }\n if (pc?.has('gitlabApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.gitlabApi, move to using integrations.gitlab instead`,\n );\n }\n if (pc?.has('bitbucketApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.bitbucketApi, move to using integrations.bitbucket instead`,\n );\n }\n if (pc?.has('azureApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.azureApi, move to using integrations.azure instead`,\n );\n }\n }\n\n // TODO(freben): This can be removed no sooner than June 2022, after adopters have had some time to adapt to the new package structure\n private checkMissingExternalProcessors(processors: CatalogProcessor[]) {\n const skipCheckVarName = 'BACKSTAGE_CATALOG_SKIP_MISSING_PROCESSORS_CHECK';\n if (process.env[skipCheckVarName]) {\n return;\n }\n\n const locationTypes = new Set(\n this.env.config\n .getOptionalConfigArray('catalog.locations')\n ?.map(l => l.getString('type')) ?? [],\n );\n const processorNames = new Set(processors.map(p => p.getProcessorName()));\n\n function check(\n locationType: string,\n processorName: string,\n installationUrl: string,\n ) {\n if (\n locationTypes.has(locationType) &&\n !processorNames.has(processorName)\n ) {\n throw new Error(\n [\n `Your config contains a \"catalog.locations\" entry of type ${locationType},`,\n `but does not have the corresponding catalog processor ${processorName} installed.`,\n `This processor used to be built into the catalog itself, but is now moved to an`,\n `external module that has to be installed manually. Please follow the installation`,\n `instructions at ${installationUrl} if you are using this ability, or remove the`,\n `location from your app config if you do not. You can also silence this check entirely`,\n `by setting the environment variable ${skipCheckVarName} to 'true'.`,\n ].join(' '),\n );\n }\n }\n\n check(\n 'aws-cloud-accounts',\n 'AwsOrganizationCloudAccountProcessor',\n 'https://backstage.io/docs/integrations',\n );\n check(\n 's3-discovery',\n 'AwsS3DiscoveryProcessor',\n 'https://backstage.io/docs/integrations/aws-s3/discovery',\n );\n check(\n 'azure-discovery',\n 'AzureDevOpsDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/azure/discovery',\n );\n check(\n 'bitbucket-discovery',\n 'BitbucketDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/bitbucket/discovery',\n );\n check(\n 'github-discovery',\n 'GithubDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/github/discovery',\n );\n check(\n 'github-org',\n 'GithubOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/github/org',\n );\n check(\n 'gitlab-discovery',\n 'GitLabDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/gitlab/discovery',\n );\n check(\n 'ldap-org',\n 'LdapOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/ldap/org',\n );\n check(\n 'microsoft-graph-org',\n 'MicrosoftGraphOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/azure/org',\n );\n }\n\n private static getDefaultProcessingInterval(\n config: Config,\n ): ProcessingIntervalFunction {\n const processingIntervalKey = 'catalog.processingInterval';\n\n if (!config.has(processingIntervalKey)) {\n return createRandomProcessingInterval({\n minSeconds: 100,\n maxSeconds: 150,\n });\n }\n\n if (!Boolean(config.get('catalog.processingInterval'))) {\n return () => {\n throw new Error(\n 'catalog.processingInterval is set to false, processing is disabled.',\n );\n };\n }\n\n const duration = readDurationFromConfig(config, {\n key: processingIntervalKey,\n });\n\n const seconds = Math.max(\n 1,\n Math.round(durationToMilliseconds(duration) / 1000),\n );\n\n return createRandomProcessingInterval({\n minSeconds: seconds,\n maxSeconds: seconds * 1.5,\n });\n }\n}\n"],"names":["catalogPermissions","catalogPermissionRules","createRandomProcessingInterval","lodash","ScmIntegrations","FileReaderProcessor","UrlReaderProcessor","CodeOwnersProcessor","AnnotateLocationEntityProcessor","HostDiscovery","createLegacyAuthAdapters","defaultEntityDataParser","applyDatabaseMigrations","DefaultStitcher","DefaultProcessingDatabase","DefaultProviderDatabase","DefaultCatalogDatabase","DefaultCatalogRulesEnforcer","DefaultEntitiesCatalog","toPermissionEvaluator","DefaultCatalogProcessingOrchestrator","AuthorizedEntitiesCatalog","createConditionTransformer","createPermissionIntegrationRouter","RESOURCE_TYPE_CATALOG_ENTITY","parseEntityRef","basicEntityFilter","keyBy","stringifyEntityRef","DefaultLocationStore","ConfigLocationEntityProvider","DefaultCatalogProcessingEngine","createHash","AuthorizedLocationAnalyzer","RepoLocationAnalyzer","AuthorizedLocationService","DefaultLocationService","AuthorizedRefreshService","DefaultRefreshService","createRouter","connectEntityProviders","SchemaValidEntityPolicy","DefaultNamespaceEntityPolicy","NoForeignRootFieldsEntityPolicy","FieldFormatEntityPolicy","makeValidator","EntityPolicies","jsonPlaceholderResolver","yamlPlaceholderResolver","textPlaceholderResolver","PlaceholderProcessor","BuiltinKindsEntityProcessor","config","readDurationFromConfig","durationToMilliseconds"],"mappings":"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"}
1
+ {"version":3,"file":"CatalogBuilder.cjs.js","sources":["../../src/service/CatalogBuilder.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createLegacyAuthAdapters,\n HostDiscovery,\n} from '@backstage/backend-common';\nimport {\n DefaultNamespaceEntityPolicy,\n Entity,\n EntityPolicies,\n EntityPolicy,\n FieldFormatEntityPolicy,\n makeValidator,\n NoForeignRootFieldsEntityPolicy,\n parseEntityRef,\n SchemaValidEntityPolicy,\n stringifyEntityRef,\n Validators,\n} from '@backstage/catalog-model';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { createHash } from 'crypto';\nimport { Router } from 'express';\nimport lodash, { keyBy } from 'lodash';\n\nimport {\n CatalogProcessor,\n CatalogProcessorParser,\n EntitiesSearchFilter,\n EntityProvider,\n PlaceholderResolver,\n LocationAnalyzer,\n ScmLocationAnalyzer,\n} from '@backstage/plugin-catalog-node';\nimport {\n AnnotateLocationEntityProcessor,\n BuiltinKindsEntityProcessor,\n CodeOwnersProcessor,\n FileReaderProcessor,\n PlaceholderProcessor,\n UrlReaderProcessor,\n} from '../processors';\nimport { ConfigLocationEntityProvider } from '../providers/ConfigLocationEntityProvider';\nimport { DefaultLocationStore } from '../providers/DefaultLocationStore';\nimport { RepoLocationAnalyzer } from '../ingestion/LocationAnalyzer';\nimport { AuthorizedLocationAnalyzer } from './AuthorizedLocationAnalyzer';\nimport {\n jsonPlaceholderResolver,\n textPlaceholderResolver,\n yamlPlaceholderResolver,\n} from '../processors/PlaceholderProcessor';\nimport { defaultEntityDataParser } from '../util/parse';\nimport {\n CatalogProcessingEngine,\n createRandomProcessingInterval,\n ProcessingIntervalFunction,\n} from '../processing';\nimport { DefaultProcessingDatabase } from '../database/DefaultProcessingDatabase';\nimport { applyDatabaseMigrations } from '../database/migrations';\nimport { DefaultCatalogProcessingEngine } from '../processing/DefaultCatalogProcessingEngine';\nimport { DefaultLocationService } from './DefaultLocationService';\nimport { DefaultEntitiesCatalog } from './DefaultEntitiesCatalog';\nimport { DefaultCatalogProcessingOrchestrator } from '../processing/DefaultCatalogProcessingOrchestrator';\nimport { DefaultStitcher } from '../stitching/DefaultStitcher';\nimport { createRouter } from './createRouter';\nimport { DefaultRefreshService } from './DefaultRefreshService';\nimport { AuthorizedRefreshService } from './AuthorizedRefreshService';\nimport { DefaultCatalogRulesEnforcer } from '../ingestion/CatalogRules';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { connectEntityProviders } from '../processing/connectEntityProviders';\nimport {\n Permission,\n PermissionAuthorizer,\n PermissionRuleParams,\n toPermissionEvaluator,\n} from '@backstage/plugin-permission-common';\nimport { permissionRules as catalogPermissionRules } from '../permissions/rules';\nimport {\n createConditionTransformer,\n createPermissionIntegrationRouter,\n PermissionRule,\n} from '@backstage/plugin-permission-node';\nimport { AuthorizedEntitiesCatalog } from './AuthorizedEntitiesCatalog';\nimport { basicEntityFilter } from './request';\nimport {\n catalogPermissions,\n RESOURCE_TYPE_CATALOG_ENTITY,\n} from '@backstage/plugin-catalog-common/alpha';\nimport { AuthorizedLocationService } from './AuthorizedLocationService';\nimport { DefaultProviderDatabase } from '../database/DefaultProviderDatabase';\nimport { DefaultCatalogDatabase } from '../database/DefaultCatalogDatabase';\nimport { EventBroker, EventsService } from '@backstage/plugin-events-node';\nimport { durationToMilliseconds } from '@backstage/types';\nimport {\n AuthService,\n DatabaseService,\n DiscoveryService,\n HttpAuthService,\n LoggerService,\n PermissionsService,\n RootConfigService,\n UrlReaderService,\n SchedulerService,\n} from '@backstage/backend-plugin-api';\nimport { entitiesResponseToObjects } from './response';\n\n/**\n * This is a duplicate of the alpha `CatalogPermissionRule` type, for use in the stable API.\n *\n * @public\n */\nexport type CatalogPermissionRuleInput<\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = PermissionRule<Entity, EntitiesSearchFilter, 'catalog-entity', TParams>;\n\n/**\n * @deprecated Please migrate to the new backend system as this will be removed in the future.\n * @public\n */\nexport type CatalogEnvironment = {\n logger: LoggerService;\n database: DatabaseService;\n config: RootConfigService;\n reader: UrlReaderService;\n permissions: PermissionsService | PermissionAuthorizer;\n scheduler?: SchedulerService;\n discovery?: DiscoveryService;\n auth?: AuthService;\n httpAuth?: HttpAuthService;\n};\n\n/**\n * A builder that helps wire up all of the component parts of the catalog.\n *\n * The touch points where you can replace or extend behavior are as follows:\n *\n * - Entity policies can be added or replaced. These are automatically run\n * after the processors' pre-processing steps. All policies are given the\n * chance to inspect the entity, and all of them have to pass in order for\n * the entity to be considered valid from an overall point of view.\n * - Location analyzers can be added. These are responsible for analyzing\n * repositories when onboarding them into the catalog, by finding\n * catalog-info.yaml files and other artifacts that can help automatically\n * register or create catalog data on the user's behalf.\n * - Placeholder resolvers can be replaced or added. These run on the raw\n * structured data between the parsing and pre-processing steps, to replace\n * dollar-prefixed entries with their actual values (like $file).\n * - Field format validators can be replaced. These check the format of\n * individual core fields such as metadata.name, to ensure that they adhere\n * to certain rules.\n * - Processors can be added or replaced. These implement the functionality of\n * reading, parsing, validating, and processing the entity data before it is\n * persisted in the catalog.\n *\n * @public\n * @deprecated Please migrate to the new backend system as this will be removed in the future.\n */\nexport class CatalogBuilder {\n private readonly env: CatalogEnvironment;\n private entityPolicies: EntityPolicy[];\n private entityPoliciesReplace: boolean;\n private placeholderResolvers: Record<string, PlaceholderResolver>;\n private fieldFormatValidators: Partial<Validators>;\n private entityProviders: EntityProvider[];\n private processors: CatalogProcessor[];\n private locationAnalyzers: ScmLocationAnalyzer[];\n private processorsReplace: boolean;\n private parser: CatalogProcessorParser | undefined;\n private onProcessingError?: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise<void> | void;\n private processingInterval: ProcessingIntervalFunction;\n private locationAnalyzer: LocationAnalyzer | undefined = undefined;\n private readonly permissions: Permission[];\n private readonly permissionRules: CatalogPermissionRuleInput[];\n private allowedLocationType: string[];\n private legacySingleProcessorValidation = false;\n private eventBroker?: EventBroker | EventsService;\n\n /**\n * Creates a catalog builder.\n */\n static create(env: CatalogEnvironment): CatalogBuilder {\n return new CatalogBuilder(env);\n }\n\n private constructor(env: CatalogEnvironment) {\n this.env = env;\n this.entityPolicies = [];\n this.entityPoliciesReplace = false;\n this.placeholderResolvers = {};\n this.fieldFormatValidators = {};\n this.entityProviders = [];\n this.processors = [];\n this.locationAnalyzers = [];\n this.processorsReplace = false;\n this.parser = undefined;\n this.permissions = [...catalogPermissions];\n this.permissionRules = Object.values(catalogPermissionRules);\n this.allowedLocationType = ['url'];\n\n this.processingInterval = CatalogBuilder.getDefaultProcessingInterval(\n env.config,\n );\n }\n\n /**\n * Adds policies that are used to validate entities between the pre-\n * processing and post-processing stages. All such policies must pass for the\n * entity to be considered valid.\n *\n * If what you want to do is to replace the rules for what format is allowed\n * in various core entity fields (such as metadata.name), you may want to use\n * {@link CatalogBuilder#setFieldFormatValidators} instead.\n *\n * @param policies - One or more policies\n */\n addEntityPolicy(\n ...policies: Array<EntityPolicy | Array<EntityPolicy>>\n ): CatalogBuilder {\n this.entityPolicies.push(...policies.flat());\n return this;\n }\n\n /**\n * Processing interval determines how often entities should be processed.\n * Seconds provided will be multiplied by 1.5\n * The default processing interval is 100-150 seconds.\n * setting this too low will potentially deplete request quotas to upstream services.\n */\n setProcessingIntervalSeconds(seconds: number): CatalogBuilder {\n this.processingInterval = createRandomProcessingInterval({\n minSeconds: seconds,\n maxSeconds: seconds * 1.5,\n });\n return this;\n }\n\n /**\n * Overwrites the default processing interval function used to spread\n * entity updates in the catalog.\n */\n setProcessingInterval(\n processingInterval: ProcessingIntervalFunction,\n ): CatalogBuilder {\n this.processingInterval = processingInterval;\n return this;\n }\n\n /**\n * Overwrites the default location analyzer.\n */\n setLocationAnalyzer(locationAnalyzer: LocationAnalyzer): CatalogBuilder {\n this.locationAnalyzer = locationAnalyzer;\n return this;\n }\n\n /**\n * Sets what policies to use for validation of entities between the pre-\n * processing and post-processing stages. All such policies must pass for the\n * entity to be considered valid.\n *\n * If what you want to do is to replace the rules for what format is allowed\n * in various core entity fields (such as metadata.name), you may want to use\n * {@link CatalogBuilder#setFieldFormatValidators} instead.\n *\n * This function replaces the default set of policies; use with care.\n *\n * @param policies - One or more policies\n */\n replaceEntityPolicies(policies: EntityPolicy[]): CatalogBuilder {\n this.entityPolicies = [...policies];\n this.entityPoliciesReplace = true;\n return this;\n }\n\n /**\n * Adds, or overwrites, a handler for placeholders (e.g. $file) in entity\n * definition files.\n *\n * @param key - The key that identifies the placeholder, e.g. \"file\"\n * @param resolver - The resolver that gets values for this placeholder\n */\n setPlaceholderResolver(\n key: string,\n resolver: PlaceholderResolver,\n ): CatalogBuilder {\n this.placeholderResolvers[key] = resolver;\n return this;\n }\n\n /**\n * Sets the validator function to use for one or more special fields of an\n * entity. This is useful if the default rules for formatting of fields are\n * not sufficient.\n *\n * This function has no effect if used together with\n * {@link CatalogBuilder#replaceEntityPolicies}.\n *\n * @param validators - The (subset of) validators to set\n */\n setFieldFormatValidators(validators: Partial<Validators>): CatalogBuilder {\n lodash.merge(this.fieldFormatValidators, validators);\n return this;\n }\n\n /**\n * Adds or replaces entity providers. These are responsible for bootstrapping\n * the list of entities out of original data sources. For example, there is\n * one entity source for the config locations, and one for the database\n * stored locations. If you ingest entities out of a third party system, you\n * may want to implement that in terms of an entity provider as well.\n *\n * @param providers - One or more entity providers\n */\n addEntityProvider(\n ...providers: Array<EntityProvider | Array<EntityProvider>>\n ): CatalogBuilder {\n this.entityProviders.push(...providers.flat());\n return this;\n }\n\n /**\n * Adds entity processors. These are responsible for reading, parsing, and\n * processing entities before they are persisted in the catalog.\n *\n * @param processors - One or more processors\n */\n addProcessor(\n ...processors: Array<CatalogProcessor | Array<CatalogProcessor>>\n ): CatalogBuilder {\n this.processors.push(...processors.flat());\n return this;\n }\n\n /**\n * Sets what entity processors to use. These are responsible for reading,\n * parsing, and processing entities before they are persisted in the catalog.\n *\n * This function replaces the default set of processors, consider using with\n * {@link CatalogBuilder#getDefaultProcessors}; use with care.\n *\n * @param processors - One or more processors\n */\n replaceProcessors(processors: CatalogProcessor[]): CatalogBuilder {\n this.processors = [...processors];\n this.processorsReplace = true;\n return this;\n }\n\n /**\n * Returns the default list of entity processors. These are responsible for reading,\n * parsing, and processing entities before they are persisted in the catalog. Changing\n * the order of processing can give more control to custom processors.\n *\n * Consider using with {@link CatalogBuilder#replaceProcessors}\n *\n */\n getDefaultProcessors(): CatalogProcessor[] {\n const { config, logger, reader } = this.env;\n const integrations = ScmIntegrations.fromConfig(config);\n\n return [\n new FileReaderProcessor(),\n new UrlReaderProcessor({ reader, logger }),\n CodeOwnersProcessor.fromConfig(config, { logger, reader }),\n new AnnotateLocationEntityProcessor({ integrations }),\n ];\n }\n\n /**\n * Adds Location Analyzers. These are responsible for analyzing\n * repositories when onboarding them into the catalog, by finding\n * catalog-info.yaml files and other artifacts that can help automatically\n * register or create catalog data on the user's behalf.\n *\n * @param locationAnalyzers - One or more location analyzers\n */\n addLocationAnalyzers(\n ...analyzers: Array<ScmLocationAnalyzer | Array<ScmLocationAnalyzer>>\n ): CatalogBuilder {\n this.locationAnalyzers.push(...analyzers.flat());\n return this;\n }\n\n /**\n * Sets up the catalog to use a custom parser for entity data.\n *\n * This is the function that gets called immediately after some raw entity\n * specification data has been read from a remote source, and needs to be\n * parsed and emitted as structured data.\n *\n * @param parser - The custom parser\n */\n setEntityDataParser(parser: CatalogProcessorParser): CatalogBuilder {\n this.parser = parser;\n return this;\n }\n\n /**\n * Adds additional permissions. See\n * {@link @backstage/plugin-permission-node#Permission}.\n *\n * @param permissions - Additional permissions\n */\n addPermissions(...permissions: Array<Permission | Array<Permission>>) {\n this.permissions.push(...permissions.flat());\n return this;\n }\n\n /**\n * Adds additional permission rules. Permission rules are used to evaluate\n * catalog resources against queries. See\n * {@link @backstage/plugin-permission-node#PermissionRule}.\n *\n * @param permissionRules - Additional permission rules\n */\n addPermissionRules(\n ...permissionRules: Array<\n CatalogPermissionRuleInput | Array<CatalogPermissionRuleInput>\n >\n ) {\n this.permissionRules.push(...permissionRules.flat());\n return this;\n }\n\n /**\n * Sets up the allowed location types from being registered via the location service.\n *\n * @param allowedLocationTypes - the allowed location types\n */\n setAllowedLocationTypes(allowedLocationTypes: string[]): CatalogBuilder {\n this.allowedLocationType = allowedLocationTypes;\n return this;\n }\n\n /**\n * Enables the legacy behaviour of canceling validation early whenever only a\n * single processor declares an entity kind to be valid.\n */\n useLegacySingleProcessorValidation(): this {\n this.legacySingleProcessorValidation = true;\n return this;\n }\n\n /**\n * Enables the publishing of events for conflicts in the DefaultProcessingDatabase\n */\n setEventBroker(broker: EventBroker | EventsService): CatalogBuilder {\n this.eventBroker = broker;\n return this;\n }\n\n /**\n * Wires up and returns all of the component parts of the catalog\n */\n async build(): Promise<{\n processingEngine: CatalogProcessingEngine;\n router: Router;\n }> {\n const {\n config,\n database,\n logger,\n permissions,\n scheduler,\n discovery = HostDiscovery.fromConfig(config),\n } = this.env;\n\n const { auth, httpAuth } = createLegacyAuthAdapters({\n ...this.env,\n discovery,\n });\n\n const disableRelationsCompatibility = config.getOptionalBoolean(\n 'catalog.disableRelationsCompatibility',\n );\n\n const policy = this.buildEntityPolicy();\n const processors = this.buildProcessors();\n const parser = this.parser || defaultEntityDataParser;\n\n const dbClient = await database.getClient();\n if (!database.migrations?.skip) {\n logger.info('Performing database migration');\n await applyDatabaseMigrations(dbClient);\n }\n\n const stitcher = DefaultStitcher.fromConfig(config, {\n knex: dbClient,\n logger,\n });\n\n const processingDatabase = new DefaultProcessingDatabase({\n database: dbClient,\n logger,\n refreshInterval: this.processingInterval,\n eventBroker: this.eventBroker,\n });\n const providerDatabase = new DefaultProviderDatabase({\n database: dbClient,\n logger,\n });\n const catalogDatabase = new DefaultCatalogDatabase({\n database: dbClient,\n logger,\n });\n const integrations = ScmIntegrations.fromConfig(config);\n const rulesEnforcer = DefaultCatalogRulesEnforcer.fromConfig(config);\n\n const unauthorizedEntitiesCatalog = new DefaultEntitiesCatalog({\n database: dbClient,\n logger,\n stitcher,\n disableRelationsCompatibility,\n });\n\n let permissionsService: PermissionsService;\n if ('authorizeConditional' in permissions) {\n permissionsService = permissions as PermissionsService;\n } else {\n logger.warn(\n 'PermissionAuthorizer is deprecated. Please use an instance of PermissionEvaluator instead of PermissionAuthorizer in PluginEnvironment#permissions',\n );\n permissionsService = toPermissionEvaluator(permissions);\n }\n\n const orchestrator = new DefaultCatalogProcessingOrchestrator({\n processors,\n integrations,\n rulesEnforcer,\n logger,\n parser,\n policy,\n legacySingleProcessorValidation: this.legacySingleProcessorValidation,\n });\n\n const entitiesCatalog = new AuthorizedEntitiesCatalog(\n unauthorizedEntitiesCatalog,\n permissionsService,\n createConditionTransformer(this.permissionRules),\n );\n const permissionIntegrationRouter = createPermissionIntegrationRouter({\n resourceType: RESOURCE_TYPE_CATALOG_ENTITY,\n getResources: async (resourceRefs: string[]) => {\n const { entities } = await unauthorizedEntitiesCatalog.entities({\n credentials: await auth.getOwnServiceCredentials(),\n filter: {\n anyOf: resourceRefs.map(resourceRef => {\n const { kind, namespace, name } = parseEntityRef(resourceRef);\n\n return basicEntityFilter({\n kind,\n 'metadata.namespace': namespace,\n 'metadata.name': name,\n });\n }),\n },\n });\n\n const entitiesByRef = keyBy(\n entitiesResponseToObjects(entities),\n stringifyEntityRef,\n );\n\n return resourceRefs.map(\n resourceRef =>\n entitiesByRef[stringifyEntityRef(parseEntityRef(resourceRef))],\n );\n },\n permissions: this.permissions,\n rules: this.permissionRules,\n });\n\n const locationStore = new DefaultLocationStore(dbClient);\n const configLocationProvider = new ConfigLocationEntityProvider(config);\n const entityProviders = lodash.uniqBy(\n [...this.entityProviders, locationStore, configLocationProvider],\n provider => provider.getProviderName(),\n );\n\n const processingEngine = new DefaultCatalogProcessingEngine({\n config,\n scheduler,\n logger,\n knex: dbClient,\n processingDatabase,\n orchestrator,\n stitcher,\n createHash: () => createHash('sha1'),\n pollingIntervalMs: 1000,\n onProcessingError: event => {\n this.onProcessingError?.(event);\n },\n eventBroker: this.eventBroker,\n });\n\n const locationAnalyzer =\n this.locationAnalyzer ??\n new AuthorizedLocationAnalyzer(\n new RepoLocationAnalyzer(logger, integrations, this.locationAnalyzers),\n permissionsService,\n );\n const locationService = new AuthorizedLocationService(\n new DefaultLocationService(locationStore, orchestrator, {\n allowedLocationTypes: this.allowedLocationType,\n }),\n permissionsService,\n );\n const refreshService = new AuthorizedRefreshService(\n new DefaultRefreshService({ database: catalogDatabase }),\n permissionsService,\n );\n\n const router = await createRouter({\n entitiesCatalog,\n locationAnalyzer,\n locationService,\n orchestrator,\n refreshService,\n logger,\n config,\n permissionIntegrationRouter,\n auth,\n httpAuth,\n permissionsService,\n disableRelationsCompatibility,\n });\n\n await connectEntityProviders(providerDatabase, entityProviders);\n\n return {\n processingEngine: {\n async start() {\n await processingEngine.start();\n await stitcher.start();\n },\n async stop() {\n await processingEngine.stop();\n await stitcher.stop();\n },\n },\n router,\n };\n }\n\n subscribe(options: {\n onProcessingError: (event: {\n unprocessedEntity: Entity;\n errors: Error[];\n }) => Promise<void> | void;\n }) {\n this.onProcessingError = options.onProcessingError;\n }\n\n private buildEntityPolicy(): EntityPolicy {\n const entityPolicies: EntityPolicy[] = this.entityPoliciesReplace\n ? [new SchemaValidEntityPolicy(), ...this.entityPolicies]\n : [\n new SchemaValidEntityPolicy(),\n new DefaultNamespaceEntityPolicy(),\n new NoForeignRootFieldsEntityPolicy(),\n new FieldFormatEntityPolicy(\n makeValidator(this.fieldFormatValidators),\n ),\n ...this.entityPolicies,\n ];\n\n return EntityPolicies.allOf(entityPolicies);\n }\n\n private buildProcessors(): CatalogProcessor[] {\n const { config, reader } = this.env;\n const integrations = ScmIntegrations.fromConfig(config);\n\n this.checkDeprecatedReaderProcessors();\n\n const placeholderResolvers: Record<string, PlaceholderResolver> = {\n json: jsonPlaceholderResolver,\n yaml: yamlPlaceholderResolver,\n text: textPlaceholderResolver,\n ...this.placeholderResolvers,\n };\n\n // The placeholder is always there no matter what\n const processors: CatalogProcessor[] = [\n new PlaceholderProcessor({\n resolvers: placeholderResolvers,\n reader,\n integrations,\n }),\n ];\n\n const builtinKindsEntityProcessor = new BuiltinKindsEntityProcessor();\n // If the user adds a processor named 'BuiltinKindsEntityProcessor',\n // skip inclusion of the catalog-backend version.\n if (\n !this.processors.some(\n processor =>\n processor.getProcessorName() ===\n builtinKindsEntityProcessor.getProcessorName(),\n )\n ) {\n processors.push(builtinKindsEntityProcessor);\n }\n\n // These are only added unless the user replaced them all\n if (!this.processorsReplace) {\n processors.push(...this.getDefaultProcessors());\n }\n\n // Add the ones (if any) that the user added\n processors.push(...this.processors);\n\n this.checkMissingExternalProcessors(processors);\n\n return processors;\n }\n\n // TODO(Rugvip): These old processors are removed, for a while we'll be throwing\n // errors here to make sure people know where to move the config\n private checkDeprecatedReaderProcessors() {\n const pc = this.env.config.getOptionalConfig('catalog.processors');\n if (pc?.has('github')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.github, move to using integrations.github instead`,\n );\n }\n if (pc?.has('gitlabApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.gitlabApi, move to using integrations.gitlab instead`,\n );\n }\n if (pc?.has('bitbucketApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.bitbucketApi, move to using integrations.bitbucket instead`,\n );\n }\n if (pc?.has('azureApi')) {\n throw new Error(\n `Using deprecated configuration for catalog.processors.azureApi, move to using integrations.azure instead`,\n );\n }\n }\n\n // TODO(freben): This can be removed no sooner than June 2022, after adopters have had some time to adapt to the new package structure\n private checkMissingExternalProcessors(processors: CatalogProcessor[]) {\n const skipCheckVarName = 'BACKSTAGE_CATALOG_SKIP_MISSING_PROCESSORS_CHECK';\n if (process.env[skipCheckVarName]) {\n return;\n }\n\n const locationTypes = new Set(\n this.env.config\n .getOptionalConfigArray('catalog.locations')\n ?.map(l => l.getString('type')) ?? [],\n );\n const processorNames = new Set(processors.map(p => p.getProcessorName()));\n\n function check(\n locationType: string,\n processorName: string,\n installationUrl: string,\n ) {\n if (\n locationTypes.has(locationType) &&\n !processorNames.has(processorName)\n ) {\n throw new Error(\n [\n `Your config contains a \"catalog.locations\" entry of type ${locationType},`,\n `but does not have the corresponding catalog processor ${processorName} installed.`,\n `This processor used to be built into the catalog itself, but is now moved to an`,\n `external module that has to be installed manually. Please follow the installation`,\n `instructions at ${installationUrl} if you are using this ability, or remove the`,\n `location from your app config if you do not. You can also silence this check entirely`,\n `by setting the environment variable ${skipCheckVarName} to 'true'.`,\n ].join(' '),\n );\n }\n }\n\n check(\n 'aws-cloud-accounts',\n 'AwsOrganizationCloudAccountProcessor',\n 'https://backstage.io/docs/integrations',\n );\n check(\n 's3-discovery',\n 'AwsS3DiscoveryProcessor',\n 'https://backstage.io/docs/integrations/aws-s3/discovery',\n );\n check(\n 'azure-discovery',\n 'AzureDevOpsDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/azure/discovery',\n );\n check(\n 'bitbucket-discovery',\n 'BitbucketDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/bitbucket/discovery',\n );\n check(\n 'github-discovery',\n 'GithubDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/github/discovery',\n );\n check(\n 'github-org',\n 'GithubOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/github/org',\n );\n check(\n 'gitlab-discovery',\n 'GitLabDiscoveryProcessor',\n 'https://backstage.io/docs/integrations/gitlab/discovery',\n );\n check(\n 'ldap-org',\n 'LdapOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/ldap/org',\n );\n check(\n 'microsoft-graph-org',\n 'MicrosoftGraphOrgReaderProcessor',\n 'https://backstage.io/docs/integrations/azure/org',\n );\n }\n\n private static getDefaultProcessingInterval(\n config: Config,\n ): ProcessingIntervalFunction {\n const processingIntervalKey = 'catalog.processingInterval';\n\n if (!config.has(processingIntervalKey)) {\n return createRandomProcessingInterval({\n minSeconds: 100,\n maxSeconds: 150,\n });\n }\n\n if (!Boolean(config.get('catalog.processingInterval'))) {\n return () => {\n throw new Error(\n 'catalog.processingInterval is set to false, processing is disabled.',\n );\n };\n }\n\n const duration = readDurationFromConfig(config, {\n key: processingIntervalKey,\n });\n\n const seconds = Math.max(\n 1,\n Math.round(durationToMilliseconds(duration) / 1000),\n );\n\n return createRandomProcessingInterval({\n minSeconds: seconds,\n maxSeconds: seconds * 1.5,\n });\n }\n}\n"],"names":["catalogPermissions","catalogPermissionRules","createRandomProcessingInterval","lodash","ScmIntegrations","FileReaderProcessor","UrlReaderProcessor","CodeOwnersProcessor","AnnotateLocationEntityProcessor","HostDiscovery","createLegacyAuthAdapters","defaultEntityDataParser","applyDatabaseMigrations","DefaultStitcher","DefaultProcessingDatabase","DefaultProviderDatabase","DefaultCatalogDatabase","DefaultCatalogRulesEnforcer","DefaultEntitiesCatalog","toPermissionEvaluator","DefaultCatalogProcessingOrchestrator","AuthorizedEntitiesCatalog","createConditionTransformer","createPermissionIntegrationRouter","RESOURCE_TYPE_CATALOG_ENTITY","parseEntityRef","basicEntityFilter","keyBy","entitiesResponseToObjects","stringifyEntityRef","DefaultLocationStore","ConfigLocationEntityProvider","DefaultCatalogProcessingEngine","createHash","AuthorizedLocationAnalyzer","RepoLocationAnalyzer","AuthorizedLocationService","DefaultLocationService","AuthorizedRefreshService","DefaultRefreshService","createRouter","connectEntityProviders","SchemaValidEntityPolicy","DefaultNamespaceEntityPolicy","NoForeignRootFieldsEntityPolicy","FieldFormatEntityPolicy","makeValidator","EntityPolicies","jsonPlaceholderResolver","yamlPlaceholderResolver","textPlaceholderResolver","PlaceholderProcessor","BuiltinKindsEntityProcessor","config","readDurationFromConfig","durationToMilliseconds"],"mappings":"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"}