@backstage/plugin-catalog-backend 1.3.1 → 1.4.0-next.2

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,56 @@
1
1
  # @backstage/plugin-catalog-backend
2
2
 
3
+ ## 1.4.0-next.2
4
+
5
+ ### Patch Changes
6
+
7
+ - eadf56bbbf: Bump `git-url-parse` version to `^13.0.0`
8
+ - 667d917488: Updated dependency `msw` to `^0.47.0`.
9
+ - 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`.
10
+ - 06e2b077a1: Limit the length of error messages that get written to the database and logs - to prevent performance issues
11
+ - Updated dependencies
12
+ - @backstage/backend-plugin-api@0.1.2-next.1
13
+ - @backstage/plugin-catalog-node@1.0.2-next.1
14
+ - @backstage/backend-common@0.15.1-next.2
15
+ - @backstage/integration@1.3.1-next.1
16
+ - @backstage/catalog-client@1.0.5-next.1
17
+ - @backstage/plugin-permission-common@0.6.4-next.1
18
+ - @backstage/plugin-permission-node@0.6.5-next.2
19
+
20
+ ## 1.4.0-next.1
21
+
22
+ ### Minor Changes
23
+
24
+ - dd395335bc: Allow unknown typed location from being registered via the location service by configuration settings
25
+ - 651c9d6800: The search index now does retain fields that have a very long value, but in the form of just a null. This makes it possible to at least filter for their existence.
26
+
27
+ ### Patch Changes
28
+
29
+ - ce77e78c93: Fixes a bug to be able to utilize refresh keys after the entity is loaded from cache
30
+ - 679f7c5e95: Include entity ref into error message when catalog policies fail
31
+ - Updated dependencies
32
+ - @backstage/plugin-permission-node@0.6.5-next.1
33
+ - @backstage/backend-common@0.15.1-next.1
34
+
35
+ ## 1.3.2-next.0
36
+
37
+ ### Patch Changes
38
+
39
+ - 243533ecdc: Added support to mysql on some raw queries
40
+ - bf5e9030eb: Updated dependency `msw` to `^0.45.0`.
41
+ - 62788b2ee8: The experimental `CatalogProcessingExtensionPoint` now accepts multiple providers and processors at once.
42
+ - Updated dependencies
43
+ - @backstage/backend-common@0.15.1-next.0
44
+ - @backstage/backend-plugin-api@0.1.2-next.0
45
+ - @backstage/catalog-client@1.0.5-next.0
46
+ - @backstage/integration@1.3.1-next.0
47
+ - @backstage/plugin-permission-common@0.6.4-next.0
48
+ - @backstage/plugin-permission-node@0.6.5-next.0
49
+ - @backstage/plugin-scaffolder-common@1.2.0-next.0
50
+ - @backstage/plugin-catalog-node@1.0.2-next.0
51
+ - @backstage/plugin-catalog-common@1.0.6-next.0
52
+ - @backstage/plugin-search-common@1.0.1-next.0
53
+
3
54
  ## 1.3.1
4
55
 
5
56
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-backend",
3
- "version": "1.3.1",
3
+ "version": "1.4.0-next.2",
4
4
  "main": "../dist/index.cjs.js",
5
5
  "types": "../dist/index.alpha.d.ts"
6
6
  }
@@ -171,7 +171,8 @@ export declare class CatalogBuilder {
171
171
  private onProcessingError?;
172
172
  private processingInterval;
173
173
  private locationAnalyzer;
174
- private permissionRules;
174
+ private readonly permissionRules;
175
+ private allowedLocationType;
175
176
  /**
176
177
  * Creates a catalog builder.
177
178
  */
@@ -293,6 +294,12 @@ export declare class CatalogBuilder {
293
294
  * @alpha
294
295
  */
295
296
  addPermissionRules(...permissionRules: Array<CatalogPermissionRule | Array<CatalogPermissionRule>>): void;
297
+ /**
298
+ * Sets up the allowed location types from being registered via the location service.
299
+ *
300
+ * @param allowedLocationTypes - the allowed location types
301
+ */
302
+ setAllowedLocationTypes(allowedLocationTypes: string[]): CatalogBuilder;
296
303
  /**
297
304
  * Wires up and returns all of the component parts of the catalog
298
305
  */
@@ -349,7 +356,7 @@ export declare type CatalogPermissionRule<TParams extends unknown[] = unknown[]>
349
356
  * Catalog plugin
350
357
  * @alpha
351
358
  */
352
- export declare const catalogPlugin: (options?: unknown) => BackendFeature;
359
+ export declare const catalogPlugin: (options?: undefined) => BackendFeature;
353
360
 
354
361
  /** @public */
355
362
  export declare interface CatalogProcessingEngine {
@@ -171,7 +171,8 @@ export declare class CatalogBuilder {
171
171
  private onProcessingError?;
172
172
  private processingInterval;
173
173
  private locationAnalyzer;
174
- private permissionRules;
174
+ private readonly permissionRules;
175
+ private allowedLocationType;
175
176
  /**
176
177
  * Creates a catalog builder.
177
178
  */
@@ -285,6 +286,12 @@ export declare class CatalogBuilder {
285
286
  */
286
287
  setEntityDataParser(parser: CatalogProcessorParser): CatalogBuilder;
287
288
  /* Excluded from this release type: addPermissionRules */
289
+ /**
290
+ * Sets up the allowed location types from being registered via the location service.
291
+ *
292
+ * @param allowedLocationTypes - the allowed location types
293
+ */
294
+ setAllowedLocationTypes(allowedLocationTypes: string[]): CatalogBuilder;
288
295
  /**
289
296
  * Wires up and returns all of the component parts of the catalog
290
297
  */
package/dist/index.cjs.js CHANGED
@@ -749,11 +749,15 @@ class UrlReaderProcessor {
749
749
  emit(pluginCatalogNode.processingResult.refresh(`${location.type}:${location.target}`));
750
750
  } catch (error) {
751
751
  errors.assertError(error);
752
- const message = `Unable to read ${location.type}, ${error}`;
752
+ const message = `Unable to read ${location.type}, ${error}`.substring(
753
+ 0,
754
+ 5e3
755
+ );
753
756
  if (error.name === "NotModifiedError" && cacheItem) {
754
757
  for (const parseResult of cacheItem.value) {
755
758
  emit(parseResult);
756
759
  }
760
+ emit(pluginCatalogNode.processingResult.refresh(`${location.type}:${location.target}`));
757
761
  } else if (error.name === "NotFoundError") {
758
762
  if (!optional) {
759
763
  emit(pluginCatalogNode.processingResult.notFoundError(location, message));
@@ -1506,7 +1510,7 @@ class DefaultProcessingDatabase {
1506
1510
  sourceEntityRef
1507
1511
  });
1508
1512
  let previousRelationRows;
1509
- if (tx.client.config.client.includes("sqlite3")) {
1513
+ if (tx.client.config.client.includes("sqlite3") || tx.client.config.client.includes("mysql")) {
1510
1514
  previousRelationRows = await tx("relations").select("*").where({ originating_entity_id: id });
1511
1515
  await tx("relations").where({ originating_entity_id: id }).delete();
1512
1516
  } else {
@@ -1558,6 +1562,12 @@ class DefaultProcessingDatabase {
1558
1562
  const { toAdd, toUpsert, toRemove } = await this.createDelta(tx, options);
1559
1563
  if (toRemove.length) {
1560
1564
  let removedCount = 0;
1565
+ const rootId = () => {
1566
+ if (tx.client.config.client.includes("mysql")) {
1567
+ return tx.raw("CAST(NULL as UNSIGNED INT)", []);
1568
+ }
1569
+ return tx.raw("CAST(NULL as INT)", []);
1570
+ };
1561
1571
  for (const refs of lodash__default["default"].chunk(toRemove, 1e3)) {
1562
1572
  removedCount += await tx("refresh_state").whereIn("entity_ref", function orphanedEntityRefs(orphans) {
1563
1573
  return orphans.withRecursive("descendants", function descendants(outer) {
@@ -1571,7 +1581,7 @@ class DefaultProcessingDatabase {
1571
1581
  });
1572
1582
  }).withRecursive("ancestors", function ancestors(outer) {
1573
1583
  return outer.select({
1574
- root_id: tx.raw("CAST(NULL as INT)", []),
1584
+ root_id: rootId(),
1575
1585
  via_entity_ref: "entity_ref",
1576
1586
  to_entity_ref: "entity_ref"
1577
1587
  }).from("descendants").union(function recursive(inner) {
@@ -1695,11 +1705,20 @@ class DefaultProcessingDatabase {
1695
1705
  }
1696
1706
  const items = await itemsQuery.where("next_update_at", "<=", tx.fn.now()).limit(request.processBatchSize).orderBy("next_update_at", "asc");
1697
1707
  const interval = this.options.refreshInterval();
1708
+ const nextUpdateAt = (refreshInterval) => {
1709
+ if (tx.client.config.client.includes("sqlite3")) {
1710
+ return tx.raw(`datetime('now', ?)`, [`${refreshInterval} seconds`]);
1711
+ }
1712
+ if (tx.client.config.client.includes("mysql")) {
1713
+ return tx.raw(`now() + interval ${refreshInterval} second`);
1714
+ }
1715
+ return tx.raw(`now() + interval '${refreshInterval} seconds'`);
1716
+ };
1698
1717
  await tx("refresh_state").whereIn(
1699
1718
  "entity_ref",
1700
1719
  items.map((i) => i.entity_ref)
1701
1720
  ).update({
1702
- next_update_at: tx.client.config.client.includes("sqlite3") ? tx.raw(`datetime('now', ?)`, [`${interval} seconds`]) : tx.raw(`now() + interval '${interval} seconds'`)
1721
+ next_update_at: nextUpdateAt(interval)
1703
1722
  });
1704
1723
  return {
1705
1724
  items: items.map(
@@ -2246,13 +2265,20 @@ function progressTracker() {
2246
2265
  }
2247
2266
 
2248
2267
  class DefaultLocationService {
2249
- constructor(store, orchestrator) {
2268
+ constructor(store, orchestrator, options = {
2269
+ allowedLocationTypes: ["url"]
2270
+ }) {
2250
2271
  this.store = store;
2251
2272
  this.orchestrator = orchestrator;
2273
+ this.options = options;
2252
2274
  }
2253
2275
  async createLocation(input, dryRun) {
2254
- if (input.type !== "url") {
2255
- throw new errors.InputError(`Registered locations must be of type 'url'`);
2276
+ if (!this.options.allowedLocationTypes.includes(input.type)) {
2277
+ throw new errors.InputError(
2278
+ `Registered locations must be of an allowed type ${JSON.stringify(
2279
+ this.options.allowedLocationTypes
2280
+ )}`
2281
+ );
2256
2282
  }
2257
2283
  if (dryRun) {
2258
2284
  return this.dryRunCreateLocation(input);
@@ -2808,10 +2834,17 @@ class DefaultCatalogProcessingOrchestrator {
2808
2834
  try {
2809
2835
  policyEnforcedEntity = await this.options.policy.enforce(entity);
2810
2836
  } catch (e) {
2811
- throw new errors.InputError("Policy check failed", e);
2837
+ throw new errors.InputError(
2838
+ `Policy check failed for ${catalogModel.stringifyEntityRef(entity)}`,
2839
+ e
2840
+ );
2812
2841
  }
2813
2842
  if (!policyEnforcedEntity) {
2814
- throw new Error("Policy unexpectedly returned no data");
2843
+ throw new Error(
2844
+ `Policy unexpectedly returned no data for ${catalogModel.stringifyEntityRef(
2845
+ entity
2846
+ )}`
2847
+ );
2815
2848
  }
2816
2849
  return policyEnforcedEntity;
2817
2850
  }
@@ -2981,8 +3014,12 @@ function mapToRows(input, entityId) {
2981
3014
  result.push({ entity_id: entityId, key, value: null });
2982
3015
  } else {
2983
3016
  const value = String(rawValue).toLocaleLowerCase("en-US");
2984
- if (key.length <= MAX_KEY_LENGTH && value.length <= MAX_VALUE_LENGTH) {
2985
- result.push({ entity_id: entityId, key, value });
3017
+ if (key.length <= MAX_KEY_LENGTH) {
3018
+ result.push({
3019
+ entity_id: entityId,
3020
+ key,
3021
+ value: value.length <= MAX_VALUE_LENGTH ? value : null
3022
+ });
2986
3023
  }
2987
3024
  }
2988
3025
  }
@@ -3905,6 +3942,7 @@ class CatalogBuilder {
3905
3942
  this.processorsReplace = false;
3906
3943
  this.parser = void 0;
3907
3944
  this.permissionRules = Object.values(permissionRules);
3945
+ this.allowedLocationType = ["url"];
3908
3946
  }
3909
3947
  static create(env) {
3910
3948
  return new CatalogBuilder(env);
@@ -3971,6 +4009,10 @@ class CatalogBuilder {
3971
4009
  addPermissionRules(...permissionRules) {
3972
4010
  this.permissionRules.push(...permissionRules.flat());
3973
4011
  }
4012
+ setAllowedLocationTypes(allowedLocationTypes) {
4013
+ this.allowedLocationType = allowedLocationTypes;
4014
+ return this;
4015
+ }
3974
4016
  async build() {
3975
4017
  var _a, _b;
3976
4018
  const { config, database, logger, permissions } = this.env;
@@ -4056,7 +4098,9 @@ class CatalogBuilder {
4056
4098
  );
4057
4099
  const locationAnalyzer = (_b = this.locationAnalyzer) != null ? _b : new RepoLocationAnalyzer(logger, integrations);
4058
4100
  const locationService = new AuthorizedLocationService(
4059
- new DefaultLocationService(locationStore, orchestrator),
4101
+ new DefaultLocationService(locationStore, orchestrator, {
4102
+ allowedLocationTypes: this.allowedLocationType
4103
+ }),
4060
4104
  permissionEvaluator
4061
4105
  );
4062
4106
  const refreshService = new AuthorizedRefreshService(
@@ -4234,11 +4278,11 @@ class CatalogExtensionPointImpl {
4234
4278
  __privateAdd(this, _processors, new Array());
4235
4279
  __privateAdd(this, _entityProviders, new Array());
4236
4280
  }
4237
- addProcessor(processor) {
4238
- __privateGet(this, _processors).push(processor);
4281
+ addProcessor(...processors) {
4282
+ __privateGet(this, _processors).push(...processors.flat());
4239
4283
  }
4240
- addEntityProvider(provider) {
4241
- __privateGet(this, _entityProviders).push(provider);
4284
+ addEntityProvider(...providers) {
4285
+ __privateGet(this, _entityProviders).push(...providers.flat());
4242
4286
  }
4243
4287
  get processors() {
4244
4288
  return __privateGet(this, _processors);