@backstage/plugin-catalog-backend 1.7.2-next.1 → 1.7.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 +51 -0
- package/alpha/package.json +1 -1
- package/dist/index.cjs.js +72 -52
- package/dist/index.cjs.js.map +1 -1
- package/package.json +12 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,56 @@
|
|
|
1
1
|
# @backstage/plugin-catalog-backend
|
|
2
2
|
|
|
3
|
+
## 1.7.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 071354eb7d: Add additional validation as security precations for output entities.
|
|
8
|
+
- b977c2e69f: Minor improvements to the descriptions provided with permission rules schemas
|
|
9
|
+
- 2380506364: The process of adding or modifying fields in the software-catalog search index has been simplified. For more details, see [how to customize fields in the Software Catalog index](https://backstage.io/docs/features/search/how-to-guides#how-to-customize-fields-in-the-software-catalog-index).
|
|
10
|
+
- 9573651919: The previous migration that adds the `search.original_value` column may leave some of the entities not updated. Add a migration script to trigger a reprocessing of the entities.
|
|
11
|
+
- 9f71a2fd20: Location rule target patterns now also match hidden files, i.e. path components with a leading dot.
|
|
12
|
+
- e716946103: Updated usage of the lifecycle service.
|
|
13
|
+
- 1aec041c34: Fixed an issue where entities sometimes were not properly deleted during a full mutation.
|
|
14
|
+
- 0ff03319be: Updated usage of `createBackendPlugin`.
|
|
15
|
+
- fc73f6aae5: Switched the order of reprocessing statements retroactively in migrations. This only improves the experience for those who at a later time perform a large upgrade of an old Backstage installation.
|
|
16
|
+
- Updated dependencies
|
|
17
|
+
- @backstage/backend-plugin-api@0.4.0
|
|
18
|
+
- @backstage/backend-common@0.18.2
|
|
19
|
+
- @backstage/catalog-model@1.2.0
|
|
20
|
+
- @backstage/plugin-catalog-node@1.3.3
|
|
21
|
+
- @backstage/catalog-client@1.3.1
|
|
22
|
+
- @backstage/config@1.0.6
|
|
23
|
+
- @backstage/errors@1.1.4
|
|
24
|
+
- @backstage/integration@1.4.2
|
|
25
|
+
- @backstage/types@1.0.2
|
|
26
|
+
- @backstage/plugin-catalog-common@1.0.11
|
|
27
|
+
- @backstage/plugin-permission-common@0.7.3
|
|
28
|
+
- @backstage/plugin-permission-node@0.7.5
|
|
29
|
+
- @backstage/plugin-scaffolder-common@1.2.5
|
|
30
|
+
- @backstage/plugin-search-common@1.2.1
|
|
31
|
+
|
|
32
|
+
## 1.7.2-next.2
|
|
33
|
+
|
|
34
|
+
### Patch Changes
|
|
35
|
+
|
|
36
|
+
- e716946103: Updated usage of the lifecycle service.
|
|
37
|
+
- 0ff03319be: Updated usage of `createBackendPlugin`.
|
|
38
|
+
- Updated dependencies
|
|
39
|
+
- @backstage/backend-plugin-api@0.4.0-next.2
|
|
40
|
+
- @backstage/backend-common@0.18.2-next.2
|
|
41
|
+
- @backstage/catalog-model@1.2.0-next.1
|
|
42
|
+
- @backstage/plugin-catalog-node@1.3.3-next.2
|
|
43
|
+
- @backstage/plugin-permission-node@0.7.5-next.2
|
|
44
|
+
- @backstage/catalog-client@1.3.1-next.1
|
|
45
|
+
- @backstage/config@1.0.6
|
|
46
|
+
- @backstage/errors@1.1.4
|
|
47
|
+
- @backstage/integration@1.4.2
|
|
48
|
+
- @backstage/types@1.0.2
|
|
49
|
+
- @backstage/plugin-catalog-common@1.0.11-next.1
|
|
50
|
+
- @backstage/plugin-permission-common@0.7.3
|
|
51
|
+
- @backstage/plugin-scaffolder-common@1.2.5-next.1
|
|
52
|
+
- @backstage/plugin-search-common@1.2.1
|
|
53
|
+
|
|
3
54
|
## 1.7.2-next.1
|
|
4
55
|
|
|
5
56
|
### Patch Changes
|
package/alpha/package.json
CHANGED
package/dist/index.cjs.js
CHANGED
|
@@ -823,7 +823,7 @@ const createCatalogPermissionRule = pluginPermissionNode.makeCreatePermissionRul
|
|
|
823
823
|
|
|
824
824
|
const hasAnnotation = createCatalogPermissionRule({
|
|
825
825
|
name: "HAS_ANNOTATION",
|
|
826
|
-
description: "Allow entities
|
|
826
|
+
description: "Allow entities with the specified annotation",
|
|
827
827
|
resourceType: pluginCatalogCommon.RESOURCE_TYPE_CATALOG_ENTITY,
|
|
828
828
|
paramsSchema: zod.z.object({
|
|
829
829
|
annotation: zod.z.string().describe("Name of the annotation to match on"),
|
|
@@ -843,7 +843,7 @@ const hasAnnotation = createCatalogPermissionRule({
|
|
|
843
843
|
|
|
844
844
|
const isEntityKind = createCatalogPermissionRule({
|
|
845
845
|
name: "IS_ENTITY_KIND",
|
|
846
|
-
description: "Allow entities
|
|
846
|
+
description: "Allow entities matching a specified kind",
|
|
847
847
|
resourceType: pluginCatalogCommon.RESOURCE_TYPE_CATALOG_ENTITY,
|
|
848
848
|
paramsSchema: zod.z.object({
|
|
849
849
|
kinds: zod.z.array(zod.z.string()).describe("List of kinds to match at least one of")
|
|
@@ -862,7 +862,7 @@ const isEntityKind = createCatalogPermissionRule({
|
|
|
862
862
|
|
|
863
863
|
const isEntityOwner = createCatalogPermissionRule({
|
|
864
864
|
name: "IS_ENTITY_OWNER",
|
|
865
|
-
description: "Allow entities owned by
|
|
865
|
+
description: "Allow entities owned by a specified claim",
|
|
866
866
|
resourceType: pluginCatalogCommon.RESOURCE_TYPE_CATALOG_ENTITY,
|
|
867
867
|
paramsSchema: zod.z.object({
|
|
868
868
|
claims: zod.z.array(zod.z.string()).describe(
|
|
@@ -883,10 +883,10 @@ const isEntityOwner = createCatalogPermissionRule({
|
|
|
883
883
|
|
|
884
884
|
const hasLabel = createCatalogPermissionRule({
|
|
885
885
|
name: "HAS_LABEL",
|
|
886
|
-
description: "Allow entities
|
|
886
|
+
description: "Allow entities with the specified label",
|
|
887
887
|
resourceType: pluginCatalogCommon.RESOURCE_TYPE_CATALOG_ENTITY,
|
|
888
888
|
paramsSchema: zod.z.object({
|
|
889
|
-
label: zod.z.string().describe("Name of the label to match
|
|
889
|
+
label: zod.z.string().describe("Name of the label to match on")
|
|
890
890
|
}),
|
|
891
891
|
apply: (resource, { label }) => {
|
|
892
892
|
var _a;
|
|
@@ -899,7 +899,7 @@ const hasLabel = createCatalogPermissionRule({
|
|
|
899
899
|
|
|
900
900
|
const createPropertyRule = (propertyType) => createCatalogPermissionRule({
|
|
901
901
|
name: `HAS_${propertyType.toUpperCase()}`,
|
|
902
|
-
description: `Allow entities
|
|
902
|
+
description: `Allow entities with the specified ${propertyType} subfield`,
|
|
903
903
|
resourceType: pluginCatalogCommon.RESOURCE_TYPE_CATALOG_ENTITY,
|
|
904
904
|
paramsSchema: zod.z.object({
|
|
905
905
|
key: zod.z.string().describe(`Property within the entities ${propertyType} to match on`),
|
|
@@ -3056,6 +3056,10 @@ function generateStableHash(entity) {
|
|
|
3056
3056
|
return crypto.createHash("sha1").update(stableStringify__default["default"]({ ...entity })).digest("hex");
|
|
3057
3057
|
}
|
|
3058
3058
|
|
|
3059
|
+
const scriptProtocolPattern = (
|
|
3060
|
+
// eslint-disable-next-line no-control-regex
|
|
3061
|
+
/^[\u0000-\u001F ]*j[\r\n\t]*a[\r\n\t]*v[\r\n\t]*a[\r\n\t]*s[\r\n\t]*c[\r\n\t]*r[\r\n\t]*i[\r\n\t]*p[\r\n\t]*t[\r\n\t]*\:/i
|
|
3062
|
+
);
|
|
3059
3063
|
class Stitcher {
|
|
3060
3064
|
constructor(database, logger) {
|
|
3061
3065
|
this.database = database;
|
|
@@ -3073,7 +3077,7 @@ class Stitcher {
|
|
|
3073
3077
|
}
|
|
3074
3078
|
}
|
|
3075
3079
|
async stitchOne(entityRef) {
|
|
3076
|
-
var _a, _b;
|
|
3080
|
+
var _a, _b, _c;
|
|
3077
3081
|
const entityResult = await this.database("refresh_state").where({ entity_ref: entityRef }).limit(1).select("entity_id");
|
|
3078
3082
|
if (!entityResult.length) {
|
|
3079
3083
|
return;
|
|
@@ -3141,6 +3145,12 @@ class Stitcher {
|
|
|
3141
3145
|
}));
|
|
3142
3146
|
}
|
|
3143
3147
|
}
|
|
3148
|
+
for (const annotation of [catalogModel.ANNOTATION_VIEW_URL, catalogModel.ANNOTATION_EDIT_URL]) {
|
|
3149
|
+
const value = (_a = entity.metadata.annotations) == null ? void 0 : _a[annotation];
|
|
3150
|
+
if (typeof value === "string" && scriptProtocolPattern.test(value)) {
|
|
3151
|
+
entity.metadata.annotations[annotation] = "https://backstage.io/annotation-rejected-for-security-reasons";
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3144
3154
|
entity.relations = relationsResult.filter(
|
|
3145
3155
|
(row) => row.relationType
|
|
3146
3156
|
/* exclude null row, if relevant */
|
|
@@ -3151,7 +3161,7 @@ class Stitcher {
|
|
|
3151
3161
|
if (statusItems.length) {
|
|
3152
3162
|
entity.status = {
|
|
3153
3163
|
...entity.status,
|
|
3154
|
-
items: [...(
|
|
3164
|
+
items: [...(_c = (_b = entity.status) == null ? void 0 : _b.items) != null ? _c : [], ...statusItems]
|
|
3155
3165
|
};
|
|
3156
3166
|
}
|
|
3157
3167
|
const hash = generateStableHash(entity);
|
|
@@ -3766,7 +3776,10 @@ const _DefaultCatalogRulesEnforcer = class {
|
|
|
3766
3776
|
if (matcher.exact && matcher.exact !== (location == null ? void 0 : location.target)) {
|
|
3767
3777
|
continue;
|
|
3768
3778
|
}
|
|
3769
|
-
if (matcher.pattern && !minimatch__default["default"](location == null ? void 0 : location.target, matcher.pattern, {
|
|
3779
|
+
if (matcher.pattern && !minimatch__default["default"](location == null ? void 0 : location.target, matcher.pattern, {
|
|
3780
|
+
nocase: true,
|
|
3781
|
+
dot: true
|
|
3782
|
+
})) {
|
|
3770
3783
|
continue;
|
|
3771
3784
|
}
|
|
3772
3785
|
return true;
|
|
@@ -4076,44 +4089,55 @@ class AuthorizedLocationService {
|
|
|
4076
4089
|
async function deleteWithEagerPruningOfChildren(options) {
|
|
4077
4090
|
const { tx, entityRefs, sourceKey } = options;
|
|
4078
4091
|
let removedCount = 0;
|
|
4079
|
-
const rootId = () => tx.raw(
|
|
4080
|
-
tx.client.config.client.includes("mysql") ? "CAST(NULL as UNSIGNED INT)" : "CAST(NULL as INT)",
|
|
4081
|
-
[]
|
|
4082
|
-
);
|
|
4083
4092
|
for (const refs of lodash__default["default"].chunk(entityRefs, 1e3)) {
|
|
4084
|
-
removedCount += await tx("refresh_state").whereIn(
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
"
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4093
|
+
removedCount += await tx.delete().from("refresh_state").whereIn(
|
|
4094
|
+
"entity_ref",
|
|
4095
|
+
(orphans) => orphans.withRecursive(
|
|
4096
|
+
"descendants",
|
|
4097
|
+
["entity_ref"],
|
|
4098
|
+
(initial) => initial.select("target_entity_ref").from("refresh_state_references").where("source_key", "=", sourceKey).whereIn("target_entity_ref", refs).union(
|
|
4099
|
+
(recursive) => recursive.select("refresh_state_references.target_entity_ref").from("descendants").join(
|
|
4100
|
+
"refresh_state_references",
|
|
4101
|
+
"descendants.entity_ref",
|
|
4102
|
+
"refresh_state_references.source_entity_ref"
|
|
4103
|
+
)
|
|
4104
|
+
)
|
|
4105
|
+
).withRecursive(
|
|
4106
|
+
"ancestors",
|
|
4107
|
+
["source_key", "source_entity_ref", "target_entity_ref", "subject"],
|
|
4108
|
+
(initial) => initial.select(
|
|
4109
|
+
"refresh_state_references.source_key",
|
|
4110
|
+
"refresh_state_references.source_entity_ref",
|
|
4111
|
+
"refresh_state_references.target_entity_ref",
|
|
4112
|
+
"descendants.entity_ref"
|
|
4113
|
+
).from("descendants").join(
|
|
4114
|
+
"refresh_state_references",
|
|
4115
|
+
"refresh_state_references.target_entity_ref",
|
|
4116
|
+
"descendants.entity_ref"
|
|
4117
|
+
).union(
|
|
4118
|
+
(recursive) => recursive.select(
|
|
4119
|
+
"refresh_state_references.source_key",
|
|
4120
|
+
"refresh_state_references.source_entity_ref",
|
|
4121
|
+
"refresh_state_references.target_entity_ref",
|
|
4122
|
+
"ancestors.subject"
|
|
4123
|
+
).from("ancestors").join(
|
|
4124
|
+
"refresh_state_references",
|
|
4125
|
+
"refresh_state_references.target_entity_ref",
|
|
4126
|
+
"ancestors.source_entity_ref"
|
|
4127
|
+
)
|
|
4128
|
+
)
|
|
4129
|
+
).with(
|
|
4130
|
+
"retained",
|
|
4131
|
+
["entity_ref"],
|
|
4132
|
+
(notPartOfDeletion) => notPartOfDeletion.select("subject").from("ancestors").whereNotNull("ancestors.source_key").where(
|
|
4133
|
+
(foreignKeyOrRef) => foreignKeyOrRef.where("ancestors.source_key", "!=", sourceKey).orWhereNotIn("ancestors.target_entity_ref", refs)
|
|
4134
|
+
)
|
|
4135
|
+
).select("descendants.entity_ref").from("descendants").leftOuterJoin(
|
|
4136
|
+
"retained",
|
|
4137
|
+
"retained.entity_ref",
|
|
4138
|
+
"descendants.entity_ref"
|
|
4139
|
+
).whereNull("retained.entity_ref")
|
|
4140
|
+
);
|
|
4117
4141
|
await tx("refresh_state_references").where("source_key", "=", sourceKey).whereIn("target_entity_ref", refs).delete();
|
|
4118
4142
|
}
|
|
4119
4143
|
return removedCount;
|
|
@@ -4893,7 +4917,7 @@ class CatalogExtensionPointImpl {
|
|
|
4893
4917
|
_processors = new WeakMap();
|
|
4894
4918
|
_entityProviders = new WeakMap();
|
|
4895
4919
|
const catalogPlugin = backendPluginApi.createBackendPlugin({
|
|
4896
|
-
|
|
4920
|
+
pluginId: "catalog",
|
|
4897
4921
|
register(env) {
|
|
4898
4922
|
const processingExtensions = new CatalogExtensionPointImpl();
|
|
4899
4923
|
env.registerExtensionPoint(
|
|
@@ -4931,11 +4955,7 @@ const catalogPlugin = backendPluginApi.createBackendPlugin({
|
|
|
4931
4955
|
builder.addEntityProvider(...processingExtensions.entityProviders);
|
|
4932
4956
|
const { processingEngine, router } = await builder.build();
|
|
4933
4957
|
await processingEngine.start();
|
|
4934
|
-
lifecycle.addShutdownHook(
|
|
4935
|
-
fn: async () => {
|
|
4936
|
-
await processingEngine.stop();
|
|
4937
|
-
}
|
|
4938
|
-
});
|
|
4958
|
+
lifecycle.addShutdownHook(() => processingEngine.stop());
|
|
4939
4959
|
httpRouter.use(router);
|
|
4940
4960
|
}
|
|
4941
4961
|
});
|