@backstage/plugin-catalog-backend 3.8.0-next.1 → 3.8.1-next.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 +48 -0
- package/config.schema.json +331 -0
- package/dist/permissions/rules/hasAnnotation.cjs.js +15 -1
- package/dist/permissions/rules/hasAnnotation.cjs.js.map +1 -1
- package/dist/permissions/rules/hasLabel.cjs.js +15 -1
- package/dist/permissions/rules/hasLabel.cjs.js.map +1 -1
- package/package.json +18 -18
- package/config.d.ts +0 -308
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,53 @@
|
|
|
1
1
|
# @backstage/plugin-catalog-backend
|
|
2
2
|
|
|
3
|
+
## 3.8.1-next.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 28c1c1c: Synced zod-validation-error versions between packages
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @backstage/filter-predicates@0.1.4-next.0
|
|
10
|
+
- @backstage/plugin-permission-node@0.11.2-next.0
|
|
11
|
+
- @backstage/backend-plugin-api@1.9.3-next.0
|
|
12
|
+
- @backstage/plugin-catalog-node@2.2.3-next.0
|
|
13
|
+
- @backstage/plugin-events-node@0.4.24-next.0
|
|
14
|
+
- @backstage/catalog-client@1.16.1-next.0
|
|
15
|
+
- @backstage/backend-openapi-utils@0.6.11-next.0
|
|
16
|
+
|
|
17
|
+
## 3.8.0
|
|
18
|
+
|
|
19
|
+
### Minor Changes
|
|
20
|
+
|
|
21
|
+
- 8f20cc2: `/entities/by-query` now accepts a `totalItems` parameter (`'include'` or `'exclude'`, default `'include'`) that controls whether the response's `totalItems` count is computed. Pass `'exclude'` to skip the count entirely when the caller doesn't need it — useful for cursor-paginated user interfaces that only display the count cosmetically. The accepted values list is forward-compatible: future modes (e.g. approximate counts) can be added without breaking existing callers.
|
|
22
|
+
|
|
23
|
+
The internal `QueryEntitiesInitialRequest.skipTotalItems` option has been replaced by `totalItems: 'include' | 'exclude'`. Note that `skipTotalItems` was never exposed as a REST API parameter, so this is only a TypeScript-level change affecting direct callers of `EntitiesCatalog.queryEntities`.
|
|
24
|
+
|
|
25
|
+
Sort field keys are now lowercased before comparing against `search.key`, fixing silent mismatches for camelCase field names. The `NULLS LAST` ordering clause has been removed since NULL sort values are already excluded by the `WHERE` clause.
|
|
26
|
+
|
|
27
|
+
- dc7678c: Removed the immediate mode stitching strategy. All stitching now uses the deferred mode, which processes entities asynchronously via a worker queue. If your configuration includes `catalog.stitchingStrategy.mode: 'immediate'`, it will be ignored with a deprecation warning. The `pollingInterval` and `stitchTimeout` settings continue to work as before.
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- 9698738: Dropped the legacy `search_entity_id_idx` index which is now redundant with the covering unique index on `(entity_id, key, value)`. The old index caused the query planner to choose an inefficient scan pattern for catalog list queries with multiple sort fields, leading to severely degraded performance on large catalogs.
|
|
32
|
+
- ccfa4f1: Optimized `entitiesBatch` on PostgreSQL to use `= ANY(array)` instead of `WHERE IN ($1, $2, ...)`. This produces a single stable query plan regardless of batch size, instead of up to 200 different plans that pollute the query plan cache. On PostgreSQL, batching is no longer needed so all entity refs are fetched in a single query.
|
|
33
|
+
- 750b310: `HAS_LABEL` and `HAS_ANNOTATION` permission rules are now case insensitive.
|
|
34
|
+
- 24775dc: Added a migration that tunes PostgreSQL automatic vacuum thresholds on the `search`, `final_entities`, `relations`, and `refresh_state_references` tables, and fixes column statistics for `entity_id` in the `search` table. This prevents the query planner from falling back to sequential scans when table maintenance falls behind, keeping catalog queries fast on large installations.
|
|
35
|
+
- 39c5fbb: Added extended multi-column statistics on `(key, value)` in the `search` table (PostgreSQL only). This tells the query planner about the correlation between the `key` and `value` columns, fixing severe row count estimation errors on compound filter queries. Without this, the planner could choose to materialize and sort thousands of rows instead of using the LIMIT short-circuit index scan — causing 10-40x slower catalog list views when multiple filters are active.
|
|
36
|
+
- 4829e89: Split the `queryEntities` list and count into separate queries instead of a multi-reference CTE. When the `filtered` CTE was referenced twice (once for the count, once for the data), PostgreSQL refused to inline it, forcing full materialization of the filtered set before applying `LIMIT`. By running the count as a standalone query, the list CTE is only referenced once, allowing the planner to short-circuit on `LIMIT` and return the first page in milliseconds instead of waiting for the full filtered set to materialize.
|
|
37
|
+
|
|
38
|
+
The standalone count query also fixes a pre-existing bug where `totalItems` was inflated for entities with multi-valued sort fields (e.g. tags). The old CTE-based count counted search rows, so an entity with 3 tags would be counted 3 times. The new count uses `EXISTS` to count distinct entities, aligning `totalItems` with the number of entities actually reachable through cursor pagination.
|
|
39
|
+
|
|
40
|
+
- 774d698: Fixed a race condition in the stitch queue and entity processing claim logic where `SELECT FOR UPDATE SKIP LOCKED` row locks were released before the subsequent timestamp bump, allowing multiple workers to claim the same rows. Both the select and update now run inside a single transaction for MySQL and PostgreSQL.
|
|
41
|
+
- 0b8b677: Improved stitch queue semantics to prevent overlapping stitches for the same entity. New stitch requests that arrive while a stitch is in progress now only update the ticket (not the timestamp), so the in-progress worker is not interrupted. When the worker completes and detects a pending re-stitch, the queue entry becomes immediately eligible for pickup instead of waiting for the timeout period.
|
|
42
|
+
- Updated dependencies
|
|
43
|
+
- @backstage/catalog-client@1.16.0
|
|
44
|
+
- @backstage/integration@2.0.3
|
|
45
|
+
- @backstage/backend-plugin-api@1.9.2
|
|
46
|
+
- @backstage/backend-openapi-utils@0.6.10
|
|
47
|
+
- @backstage/plugin-catalog-node@2.2.2
|
|
48
|
+
- @backstage/plugin-events-node@0.4.23
|
|
49
|
+
- @backstage/plugin-permission-node@0.11.1
|
|
50
|
+
|
|
3
51
|
## 3.8.0-next.1
|
|
4
52
|
|
|
5
53
|
### Patch Changes
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"catalog": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"rules": {
|
|
9
|
+
"type": "array",
|
|
10
|
+
"items": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"properties": {
|
|
13
|
+
"allow": {
|
|
14
|
+
"type": "array",
|
|
15
|
+
"items": {
|
|
16
|
+
"anyOf": [
|
|
17
|
+
{
|
|
18
|
+
"type": "string"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"type": "object",
|
|
22
|
+
"properties": {
|
|
23
|
+
"kind": {
|
|
24
|
+
"type": "string"
|
|
25
|
+
},
|
|
26
|
+
"spec.type": {
|
|
27
|
+
"type": "string"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"required": [
|
|
31
|
+
"kind"
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
"description": "Allow entities of these particular kinds.\n\nE.g. [\"Component\", \"API\", \"Template\", \"Location\"]\n\nYou can also specify the type of the entity by using an object with `kind` and optional `spec.type` properties. E.g. [{ kind: \"Component\", 'spec.type': \"service\" }]"
|
|
37
|
+
},
|
|
38
|
+
"locations": {
|
|
39
|
+
"type": "array",
|
|
40
|
+
"items": {
|
|
41
|
+
"type": "object",
|
|
42
|
+
"properties": {
|
|
43
|
+
"type": {
|
|
44
|
+
"type": "string",
|
|
45
|
+
"description": "The type of location, e.g. \"url\"."
|
|
46
|
+
},
|
|
47
|
+
"exact": {
|
|
48
|
+
"type": "string",
|
|
49
|
+
"description": "The exact location, e.g. \"https://github.com/org/repo/blob/master/users.yaml\".\n\nThe exact location can also be used to match on locations that contain glob characters themselves, e.g. \"https://github.com/org/*\\/blob/master/*.yaml\"."
|
|
50
|
+
},
|
|
51
|
+
"pattern": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"description": "The pattern allowed for the location, e.g. \"https://github.com/org/*\\/blob/master/*.yaml\"."
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"required": [
|
|
57
|
+
"type"
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
"description": "Limit this rule to a specific location\n\nExample with a fixed location { \"type\": \"url\", \"exact\": \"https://github.com/a/b/blob/file.yaml\"}\n\nExample using a Regex { \"type\": \"url\", \"pattern\": \"https://github.com/org/*\\/blob/master/*.yaml\"}\n\nUsing both exact and pattern will result in an error starting the application"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"required": [
|
|
64
|
+
"allow"
|
|
65
|
+
]
|
|
66
|
+
},
|
|
67
|
+
"description": "Rules to apply to all catalog entities, from any location.\n\nAn undefined list of matchers means match all, an empty list of matchers means match none.\n\nThis is commonly used to put in what amounts to an allowlist of kinds that regular users of Backstage are permitted to register locations for. This can be used to stop them from registering yaml files describing for example a Group entity called \"admin\" that they make themselves members of, or similar."
|
|
68
|
+
},
|
|
69
|
+
"readonly": {
|
|
70
|
+
"type": "boolean",
|
|
71
|
+
"description": "Readonly defines whether the catalog allows writes after startup.\n\nSetting 'readonly=false' allows users to register their own components. This is the default value.\n\nSetting 'readonly=true' configures catalog to only allow reads. This can be used in combination with static locations to only serve operator provided locations. Effectively this removes the ability to register new components to a running backstage instance."
|
|
72
|
+
},
|
|
73
|
+
"locations": {
|
|
74
|
+
"type": "array",
|
|
75
|
+
"items": {
|
|
76
|
+
"type": "object",
|
|
77
|
+
"properties": {
|
|
78
|
+
"type": {
|
|
79
|
+
"type": "string",
|
|
80
|
+
"description": "The type of location, e.g. \"url\"."
|
|
81
|
+
},
|
|
82
|
+
"target": {
|
|
83
|
+
"type": "string",
|
|
84
|
+
"description": "The target URL of the location, e.g. \"https://github.com/org/repo/blob/master/users.yaml\"."
|
|
85
|
+
},
|
|
86
|
+
"rules": {
|
|
87
|
+
"type": "array",
|
|
88
|
+
"items": {
|
|
89
|
+
"type": "object",
|
|
90
|
+
"properties": {
|
|
91
|
+
"allow": {
|
|
92
|
+
"type": "array",
|
|
93
|
+
"items": {
|
|
94
|
+
"type": "string"
|
|
95
|
+
},
|
|
96
|
+
"description": "Allow entities of these particular kinds.\n\nE.g. [\"Group\", \"User\"]"
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"required": [
|
|
100
|
+
"allow"
|
|
101
|
+
]
|
|
102
|
+
},
|
|
103
|
+
"description": "Optional extra rules that apply to this particular location.\n\nThese override the global rules above."
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"required": [
|
|
107
|
+
"type",
|
|
108
|
+
"target"
|
|
109
|
+
]
|
|
110
|
+
},
|
|
111
|
+
"description": "A set of static locations that the catalog shall always keep itself up-to-date with. This is commonly used for large, permanent integrations that are defined by the Backstage operators at an organization, rather than individual things that users register dynamically.\n\nThese have (optional) rules of their own. These override what the global rules above specify. This way, you can prevent everybody from register e.g. User and Group entities, except for one or a few static locations that have those two kinds explicitly allowed.\n\nFor example:\n\n```yaml rules: - allow: [Component, API, Template, Location] locations: - type: url target: https://github.com/org/repo/blob/master/users.yaml rules: - allow: [User, Group] - type: url target: https://github.com/org/repo/blob/master/systems.yaml rules: - allow: [System] ```"
|
|
112
|
+
},
|
|
113
|
+
"enableRelationsCompatibility": {
|
|
114
|
+
"type": "boolean",
|
|
115
|
+
"description": "Enables the compatibility layer for relations in returned entities that ensures that all relations objects have both `target` and `targetRef`.\n\nEnabling this option significantly increases the memory usage of the catalog, and slightly reduces performance, but may avoid breaking consumers that rely on the existence of `target` in the relations objects."
|
|
116
|
+
},
|
|
117
|
+
"disableDefaultProcessors": {
|
|
118
|
+
"type": "boolean",
|
|
119
|
+
"description": "Disables the default backstage processors.\n\nEnabling this option allows more complete control of which processors are included in the backstage processing loop."
|
|
120
|
+
},
|
|
121
|
+
"orphanStrategy": {
|
|
122
|
+
"type": "string",
|
|
123
|
+
"enum": [
|
|
124
|
+
"keep",
|
|
125
|
+
"delete"
|
|
126
|
+
],
|
|
127
|
+
"description": "The strategy to use for entities that are orphaned, i.e. no longer have any other entities or providers referencing them. The default value is \"delete\"."
|
|
128
|
+
},
|
|
129
|
+
"orphanProviderStrategy": {
|
|
130
|
+
"type": "string",
|
|
131
|
+
"enum": [
|
|
132
|
+
"keep",
|
|
133
|
+
"delete"
|
|
134
|
+
],
|
|
135
|
+
"description": "The strategy to use for entities that are referenced by providers that are orphaned, i.e. entities with no providers currently configured in the catalog. The default value is \"delete\"."
|
|
136
|
+
},
|
|
137
|
+
"stitchingStrategy": {
|
|
138
|
+
"type": "object",
|
|
139
|
+
"properties": {
|
|
140
|
+
"mode": {
|
|
141
|
+
"type": "string",
|
|
142
|
+
"deprecated": "Immediate mode has been removed. This field is ignored."
|
|
143
|
+
},
|
|
144
|
+
"pollingInterval": {
|
|
145
|
+
"anyOf": [
|
|
146
|
+
{
|
|
147
|
+
"type": "object",
|
|
148
|
+
"properties": {
|
|
149
|
+
"years": {
|
|
150
|
+
"type": "number"
|
|
151
|
+
},
|
|
152
|
+
"months": {
|
|
153
|
+
"type": "number"
|
|
154
|
+
},
|
|
155
|
+
"weeks": {
|
|
156
|
+
"type": "number"
|
|
157
|
+
},
|
|
158
|
+
"days": {
|
|
159
|
+
"type": "number"
|
|
160
|
+
},
|
|
161
|
+
"hours": {
|
|
162
|
+
"type": "number"
|
|
163
|
+
},
|
|
164
|
+
"minutes": {
|
|
165
|
+
"type": "number"
|
|
166
|
+
},
|
|
167
|
+
"seconds": {
|
|
168
|
+
"type": "number"
|
|
169
|
+
},
|
|
170
|
+
"milliseconds": {
|
|
171
|
+
"type": "number"
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
"description": "Human friendly durations object."
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"type": "string"
|
|
178
|
+
}
|
|
179
|
+
],
|
|
180
|
+
"description": "Polling interval for tasks in seconds"
|
|
181
|
+
},
|
|
182
|
+
"stitchTimeout": {
|
|
183
|
+
"anyOf": [
|
|
184
|
+
{
|
|
185
|
+
"type": "object",
|
|
186
|
+
"properties": {
|
|
187
|
+
"years": {
|
|
188
|
+
"type": "number"
|
|
189
|
+
},
|
|
190
|
+
"months": {
|
|
191
|
+
"type": "number"
|
|
192
|
+
},
|
|
193
|
+
"weeks": {
|
|
194
|
+
"type": "number"
|
|
195
|
+
},
|
|
196
|
+
"days": {
|
|
197
|
+
"type": "number"
|
|
198
|
+
},
|
|
199
|
+
"hours": {
|
|
200
|
+
"type": "number"
|
|
201
|
+
},
|
|
202
|
+
"minutes": {
|
|
203
|
+
"type": "number"
|
|
204
|
+
},
|
|
205
|
+
"seconds": {
|
|
206
|
+
"type": "number"
|
|
207
|
+
},
|
|
208
|
+
"milliseconds": {
|
|
209
|
+
"type": "number"
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
"description": "Human friendly durations object."
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"type": "string"
|
|
216
|
+
}
|
|
217
|
+
],
|
|
218
|
+
"description": "How long to wait for a stitch to complete before giving up in seconds"
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
"description": "The strategy to use when stitching together the final entities."
|
|
222
|
+
},
|
|
223
|
+
"defaultLocationConflictStrategy": {
|
|
224
|
+
"type": "string",
|
|
225
|
+
"enum": [
|
|
226
|
+
"refresh",
|
|
227
|
+
"reject"
|
|
228
|
+
],
|
|
229
|
+
"description": "The strategy to use when there is a conflict with a location being registered.\n\nThe default value is \"reject\".\n\nThe \"refresh\" strategy will refresh the existing location instead of throwing a conflict error."
|
|
230
|
+
},
|
|
231
|
+
"processingInterval": {
|
|
232
|
+
"anyOf": [
|
|
233
|
+
{
|
|
234
|
+
"type": "object",
|
|
235
|
+
"properties": {
|
|
236
|
+
"years": {
|
|
237
|
+
"type": "number"
|
|
238
|
+
},
|
|
239
|
+
"months": {
|
|
240
|
+
"type": "number"
|
|
241
|
+
},
|
|
242
|
+
"weeks": {
|
|
243
|
+
"type": "number"
|
|
244
|
+
},
|
|
245
|
+
"days": {
|
|
246
|
+
"type": "number"
|
|
247
|
+
},
|
|
248
|
+
"hours": {
|
|
249
|
+
"type": "number"
|
|
250
|
+
},
|
|
251
|
+
"minutes": {
|
|
252
|
+
"type": "number"
|
|
253
|
+
},
|
|
254
|
+
"seconds": {
|
|
255
|
+
"type": "number"
|
|
256
|
+
},
|
|
257
|
+
"milliseconds": {
|
|
258
|
+
"type": "number"
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
"description": "Human friendly durations object."
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
"type": "boolean",
|
|
265
|
+
"const": false
|
|
266
|
+
}
|
|
267
|
+
],
|
|
268
|
+
"description": "The interval at which the catalog should process its entities."
|
|
269
|
+
},
|
|
270
|
+
"providerOptions": {
|
|
271
|
+
"type": "object",
|
|
272
|
+
"additionalProperties": {
|
|
273
|
+
"type": "object",
|
|
274
|
+
"properties": {
|
|
275
|
+
"disabled": {
|
|
276
|
+
"type": "boolean",
|
|
277
|
+
"description": "Determines whether this provider is disabled or not. If not specified, defaults to false."
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
"description": "Key is the provider name, value is an object with additional configuration"
|
|
281
|
+
},
|
|
282
|
+
"description": "Provider-specific additional configuration options."
|
|
283
|
+
},
|
|
284
|
+
"processorOptions": {
|
|
285
|
+
"type": "object",
|
|
286
|
+
"additionalProperties": {
|
|
287
|
+
"type": "object",
|
|
288
|
+
"properties": {
|
|
289
|
+
"disabled": {
|
|
290
|
+
"type": "boolean",
|
|
291
|
+
"description": "Determines whether this processor is disabled or not. If not specified, defaults to false."
|
|
292
|
+
},
|
|
293
|
+
"priority": {
|
|
294
|
+
"type": "number",
|
|
295
|
+
"description": "The default priority is 20, and lower value means that the processor runs earlier."
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
"description": "Key is the processor name, value is an object with additional configuration"
|
|
299
|
+
},
|
|
300
|
+
"description": "Processor-specific additional configuration options."
|
|
301
|
+
},
|
|
302
|
+
"scmEvents": {
|
|
303
|
+
"anyOf": [
|
|
304
|
+
{
|
|
305
|
+
"type": "boolean"
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
"type": "object",
|
|
309
|
+
"properties": {
|
|
310
|
+
"refresh": {
|
|
311
|
+
"type": "boolean",
|
|
312
|
+
"description": "Trigger refreshes (reprocessing) of entities that are affected by an SCM event. This may include source control file content changes, repository status changes, etc."
|
|
313
|
+
},
|
|
314
|
+
"unregister": {
|
|
315
|
+
"type": "boolean",
|
|
316
|
+
"description": "Unregister entities that are deleted as a result of an SCM event."
|
|
317
|
+
},
|
|
318
|
+
"move": {
|
|
319
|
+
"type": "boolean",
|
|
320
|
+
"description": "Move entities that are moved as a result of an SCM event."
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
],
|
|
325
|
+
"description": "Settings that control what to do when receiving messages from the SCM events service."
|
|
326
|
+
}
|
|
327
|
+
},
|
|
328
|
+
"description": "Configuration options for the catalog plugin."
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
@@ -12,7 +12,21 @@ const hasAnnotation = pluginPermissionNode.createPermissionRule({
|
|
|
12
12
|
annotation: v3.z.string().describe("Name of the annotation to match on"),
|
|
13
13
|
value: v3.z.string().optional().describe("Value of the annotation to match on")
|
|
14
14
|
}),
|
|
15
|
-
apply: (resource, { annotation, value }) =>
|
|
15
|
+
apply: (resource, { annotation, value }) => {
|
|
16
|
+
if (!resource.metadata.annotations) return false;
|
|
17
|
+
const isExactKeyMatch = !!resource.metadata.annotations?.hasOwnProperty(annotation) && (value === void 0 ? true : resource.metadata.annotations?.[annotation] === value);
|
|
18
|
+
if (isExactKeyMatch) return true;
|
|
19
|
+
const normalizedAnnotation = annotation.toLocaleLowerCase("en-US");
|
|
20
|
+
const normalizedValue = value?.toLocaleLowerCase("en-US");
|
|
21
|
+
for (const [key, val] of Object.entries(resource.metadata.annotations)) {
|
|
22
|
+
if (key.toLocaleLowerCase("en-US") === normalizedAnnotation) {
|
|
23
|
+
if (normalizedValue === void 0 || val.toLocaleLowerCase("en-US") === normalizedValue) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
},
|
|
16
30
|
toQuery: ({ annotation, value }) => value === void 0 ? {
|
|
17
31
|
key: `metadata.annotations.${annotation}`
|
|
18
32
|
} : {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hasAnnotation.cjs.js","sources":["../../../src/permissions/rules/hasAnnotation.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 { catalogEntityPermissionResourceRef } from '@backstage/plugin-catalog-node/alpha';\nimport { createPermissionRule } from '@backstage/plugin-permission-node';\nimport { z } from 'zod/v3';\n\n/**\n * A catalog {@link @backstage/plugin-permission-node#PermissionRule} which\n * filters for the presence of an annotation on a given entity.\n *\n * If a value is given, it filters for the annotation value, too.\n *\n * @alpha\n */\nexport const hasAnnotation = createPermissionRule({\n name: 'HAS_ANNOTATION',\n description: 'Allow entities with the specified annotation',\n resourceRef: catalogEntityPermissionResourceRef,\n paramsSchema: z.object({\n annotation: z.string().describe('Name of the annotation to match on'),\n value: z\n .string()\n .optional()\n .describe('Value of the annotation to match on'),\n }),\n apply: (resource, { annotation, value })
|
|
1
|
+
{"version":3,"file":"hasAnnotation.cjs.js","sources":["../../../src/permissions/rules/hasAnnotation.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 { catalogEntityPermissionResourceRef } from '@backstage/plugin-catalog-node/alpha';\nimport { createPermissionRule } from '@backstage/plugin-permission-node';\nimport { z } from 'zod/v3';\n\n/**\n * A catalog {@link @backstage/plugin-permission-node#PermissionRule} which\n * filters for the presence of an annotation on a given entity.\n *\n * If a value is given, it filters for the annotation value, too.\n *\n * @alpha\n */\nexport const hasAnnotation = createPermissionRule({\n name: 'HAS_ANNOTATION',\n description: 'Allow entities with the specified annotation',\n resourceRef: catalogEntityPermissionResourceRef,\n paramsSchema: z.object({\n annotation: z.string().describe('Name of the annotation to match on'),\n value: z\n .string()\n .optional()\n .describe('Value of the annotation to match on'),\n }),\n apply: (resource, { annotation, value }) => {\n if (!resource.metadata.annotations) return false;\n\n // exact key match\n const isExactKeyMatch =\n !!resource.metadata.annotations?.hasOwnProperty(annotation) &&\n (value === undefined\n ? true\n : resource.metadata.annotations?.[annotation] === value);\n\n if (isExactKeyMatch) return true;\n\n // case-insensitive matching if exact match is not found\n const normalizedAnnotation = annotation.toLocaleLowerCase('en-US');\n const normalizedValue = value?.toLocaleLowerCase('en-US');\n\n for (const [key, val] of Object.entries(resource.metadata.annotations)) {\n if (key.toLocaleLowerCase('en-US') === normalizedAnnotation) {\n if (\n normalizedValue === undefined ||\n val.toLocaleLowerCase('en-US') === normalizedValue\n ) {\n return true;\n }\n }\n }\n return false;\n },\n toQuery: ({ annotation, value }) =>\n value === undefined\n ? {\n key: `metadata.annotations.${annotation}`,\n }\n : {\n key: `metadata.annotations.${annotation}`,\n values: [value],\n },\n});\n"],"names":["createPermissionRule","catalogEntityPermissionResourceRef","z"],"mappings":";;;;;;AA4BO,MAAM,gBAAgBA,yCAAA,CAAqB;AAAA,EAChD,IAAA,EAAM,gBAAA;AAAA,EACN,WAAA,EAAa,8CAAA;AAAA,EACb,WAAA,EAAaC,wCAAA;AAAA,EACb,YAAA,EAAcC,KAAE,MAAA,CAAO;AAAA,IACrB,UAAA,EAAYA,IAAA,CAAE,MAAA,EAAO,CAAE,SAAS,oCAAoC,CAAA;AAAA,IACpE,OAAOA,IAAA,CACJ,MAAA,GACA,QAAA,EAAS,CACT,SAAS,qCAAqC;AAAA,GAClD,CAAA;AAAA,EACD,OAAO,CAAC,QAAA,EAAU,EAAE,UAAA,EAAY,OAAM,KAAM;AAC1C,IAAA,IAAI,CAAC,QAAA,CAAS,QAAA,CAAS,WAAA,EAAa,OAAO,KAAA;AAG3C,IAAA,MAAM,kBACJ,CAAC,CAAC,QAAA,CAAS,QAAA,CAAS,aAAa,cAAA,CAAe,UAAU,CAAA,KACzD,KAAA,KAAU,SACP,IAAA,GACA,QAAA,CAAS,QAAA,CAAS,WAAA,GAAc,UAAU,CAAA,KAAM,KAAA,CAAA;AAEtD,IAAA,IAAI,iBAAiB,OAAO,IAAA;AAG5B,IAAA,MAAM,oBAAA,GAAuB,UAAA,CAAW,iBAAA,CAAkB,OAAO,CAAA;AACjE,IAAA,MAAM,eAAA,GAAkB,KAAA,EAAO,iBAAA,CAAkB,OAAO,CAAA;AAExD,IAAA,KAAA,MAAW,CAAC,KAAK,GAAG,CAAA,IAAK,OAAO,OAAA,CAAQ,QAAA,CAAS,QAAA,CAAS,WAAW,CAAA,EAAG;AACtE,MAAA,IAAI,GAAA,CAAI,iBAAA,CAAkB,OAAO,CAAA,KAAM,oBAAA,EAAsB;AAC3D,QAAA,IACE,oBAAoB,MAAA,IACpB,GAAA,CAAI,iBAAA,CAAkB,OAAO,MAAM,eAAA,EACnC;AACA,UAAA,OAAO,IAAA;AAAA,QACT;AAAA,MACF;AAAA,IACF;AACA,IAAA,OAAO,KAAA;AAAA,EACT,CAAA;AAAA,EACA,SAAS,CAAC,EAAE,YAAY,KAAA,EAAM,KAC5B,UAAU,MAAA,GACN;AAAA,IACE,GAAA,EAAK,wBAAwB,UAAU,CAAA;AAAA,GACzC,GACA;AAAA,IACE,GAAA,EAAK,wBAAwB,UAAU,CAAA,CAAA;AAAA,IACvC,MAAA,EAAQ,CAAC,KAAK;AAAA;AAExB,CAAC;;;;"}
|
|
@@ -12,7 +12,21 @@ const hasLabel = pluginPermissionNode.createPermissionRule({
|
|
|
12
12
|
label: v3.z.string().describe("Name of the label to match on"),
|
|
13
13
|
value: v3.z.string().optional().describe("Value of the label to match on")
|
|
14
14
|
}),
|
|
15
|
-
apply: (resource, { label, value }) =>
|
|
15
|
+
apply: (resource, { label, value }) => {
|
|
16
|
+
if (!resource.metadata.labels) return false;
|
|
17
|
+
const isExactKeyMatch = !!resource.metadata.labels?.hasOwnProperty(label) && (value === void 0 ? true : resource.metadata.labels?.[label] === value);
|
|
18
|
+
if (isExactKeyMatch) return true;
|
|
19
|
+
const normalizedLabel = label.toLocaleLowerCase("en-US");
|
|
20
|
+
const normalizedValue = value?.toLocaleLowerCase("en-US");
|
|
21
|
+
for (const [key, val] of Object.entries(resource.metadata.labels)) {
|
|
22
|
+
if (key.toLocaleLowerCase("en-US") === normalizedLabel) {
|
|
23
|
+
if (normalizedValue === void 0 || val.toLocaleLowerCase("en-US") === normalizedValue) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
},
|
|
16
30
|
toQuery: ({ label, value }) => value === void 0 ? {
|
|
17
31
|
key: `metadata.labels.${label}`
|
|
18
32
|
} : {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hasLabel.cjs.js","sources":["../../../src/permissions/rules/hasLabel.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 { catalogEntityPermissionResourceRef } from '@backstage/plugin-catalog-node/alpha';\nimport { createPermissionRule } from '@backstage/plugin-permission-node';\nimport { z } from 'zod/v3';\n\n/**\n * A catalog {@link @backstage/plugin-permission-node#PermissionRule} which\n * filters for entities with a specified label in its metadata.\n * @alpha\n */\nexport const hasLabel = createPermissionRule({\n name: 'HAS_LABEL',\n description: 'Allow entities with the specified label',\n resourceRef: catalogEntityPermissionResourceRef,\n paramsSchema: z.object({\n label: z.string().describe('Name of the label to match on'),\n value: z.string().optional().describe('Value of the label to match on'),\n }),\n apply: (resource, { label, value })
|
|
1
|
+
{"version":3,"file":"hasLabel.cjs.js","sources":["../../../src/permissions/rules/hasLabel.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 { catalogEntityPermissionResourceRef } from '@backstage/plugin-catalog-node/alpha';\nimport { createPermissionRule } from '@backstage/plugin-permission-node';\nimport { z } from 'zod/v3';\n\n/**\n * A catalog {@link @backstage/plugin-permission-node#PermissionRule} which\n * filters for entities with a specified label in its metadata.\n * @alpha\n */\nexport const hasLabel = createPermissionRule({\n name: 'HAS_LABEL',\n description: 'Allow entities with the specified label',\n resourceRef: catalogEntityPermissionResourceRef,\n paramsSchema: z.object({\n label: z.string().describe('Name of the label to match on'),\n value: z.string().optional().describe('Value of the label to match on'),\n }),\n apply: (resource, { label, value }) => {\n if (!resource.metadata.labels) return false;\n\n // exact key match\n const isExactKeyMatch =\n !!resource.metadata.labels?.hasOwnProperty(label) &&\n (value === undefined\n ? true\n : resource.metadata.labels?.[label] === value);\n\n if (isExactKeyMatch) return true;\n\n // case-insensitive matching if exact match is not found\n const normalizedLabel = label.toLocaleLowerCase('en-US');\n const normalizedValue = value?.toLocaleLowerCase('en-US');\n\n for (const [key, val] of Object.entries(resource.metadata.labels)) {\n if (key.toLocaleLowerCase('en-US') === normalizedLabel) {\n if (\n normalizedValue === undefined ||\n val.toLocaleLowerCase('en-US') === normalizedValue\n ) {\n return true;\n }\n }\n }\n return false;\n },\n toQuery: ({ label, value }) =>\n value === undefined\n ? {\n key: `metadata.labels.${label}`,\n }\n : {\n key: `metadata.labels.${label}`,\n values: [value],\n },\n});\n"],"names":["createPermissionRule","catalogEntityPermissionResourceRef","z"],"mappings":";;;;;;AAyBO,MAAM,WAAWA,yCAAA,CAAqB;AAAA,EAC3C,IAAA,EAAM,WAAA;AAAA,EACN,WAAA,EAAa,yCAAA;AAAA,EACb,WAAA,EAAaC,wCAAA;AAAA,EACb,YAAA,EAAcC,KAAE,MAAA,CAAO;AAAA,IACrB,KAAA,EAAOA,IAAA,CAAE,MAAA,EAAO,CAAE,SAAS,+BAA+B,CAAA;AAAA,IAC1D,OAAOA,IAAA,CAAE,MAAA,GAAS,QAAA,EAAS,CAAE,SAAS,gCAAgC;AAAA,GACvE,CAAA;AAAA,EACD,OAAO,CAAC,QAAA,EAAU,EAAE,KAAA,EAAO,OAAM,KAAM;AACrC,IAAA,IAAI,CAAC,QAAA,CAAS,QAAA,CAAS,MAAA,EAAQ,OAAO,KAAA;AAGtC,IAAA,MAAM,kBACJ,CAAC,CAAC,QAAA,CAAS,QAAA,CAAS,QAAQ,cAAA,CAAe,KAAK,CAAA,KAC/C,KAAA,KAAU,SACP,IAAA,GACA,QAAA,CAAS,QAAA,CAAS,MAAA,GAAS,KAAK,CAAA,KAAM,KAAA,CAAA;AAE5C,IAAA,IAAI,iBAAiB,OAAO,IAAA;AAG5B,IAAA,MAAM,eAAA,GAAkB,KAAA,CAAM,iBAAA,CAAkB,OAAO,CAAA;AACvD,IAAA,MAAM,eAAA,GAAkB,KAAA,EAAO,iBAAA,CAAkB,OAAO,CAAA;AAExD,IAAA,KAAA,MAAW,CAAC,KAAK,GAAG,CAAA,IAAK,OAAO,OAAA,CAAQ,QAAA,CAAS,QAAA,CAAS,MAAM,CAAA,EAAG;AACjE,MAAA,IAAI,GAAA,CAAI,iBAAA,CAAkB,OAAO,CAAA,KAAM,eAAA,EAAiB;AACtD,QAAA,IACE,oBAAoB,MAAA,IACpB,GAAA,CAAI,iBAAA,CAAkB,OAAO,MAAM,eAAA,EACnC;AACA,UAAA,OAAO,IAAA;AAAA,QACT;AAAA,MACF;AAAA,IACF;AACA,IAAA,OAAO,KAAA;AAAA,EACT,CAAA;AAAA,EACA,SAAS,CAAC,EAAE,OAAO,KAAA,EAAM,KACvB,UAAU,MAAA,GACN;AAAA,IACE,GAAA,EAAK,mBAAmB,KAAK,CAAA;AAAA,GAC/B,GACA;AAAA,IACE,GAAA,EAAK,mBAAmB,KAAK,CAAA,CAAA;AAAA,IAC7B,MAAA,EAAQ,CAAC,KAAK;AAAA;AAExB,CAAC;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-catalog-backend",
|
|
3
|
-
"version": "3.8.
|
|
3
|
+
"version": "3.8.1-next.0",
|
|
4
4
|
"description": "The Backstage backend plugin that provides the Backstage catalog",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "backend-plugin",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"files": [
|
|
62
62
|
"dist",
|
|
63
63
|
"migrations/**/*.{js,d.ts}",
|
|
64
|
-
"config.
|
|
64
|
+
"config.schema.json"
|
|
65
65
|
],
|
|
66
66
|
"scripts": {
|
|
67
67
|
"build": "backstage-cli package build",
|
|
@@ -76,19 +76,19 @@
|
|
|
76
76
|
"test": "backstage-cli package test"
|
|
77
77
|
},
|
|
78
78
|
"dependencies": {
|
|
79
|
-
"@backstage/backend-openapi-utils": "0.6.
|
|
80
|
-
"@backstage/backend-plugin-api": "1.9.
|
|
81
|
-
"@backstage/catalog-client": "1.16.
|
|
79
|
+
"@backstage/backend-openapi-utils": "0.6.11-next.0",
|
|
80
|
+
"@backstage/backend-plugin-api": "1.9.3-next.0",
|
|
81
|
+
"@backstage/catalog-client": "1.16.1-next.0",
|
|
82
82
|
"@backstage/catalog-model": "1.9.0",
|
|
83
83
|
"@backstage/config": "1.3.8",
|
|
84
84
|
"@backstage/errors": "1.3.1",
|
|
85
|
-
"@backstage/filter-predicates": "0.1.
|
|
86
|
-
"@backstage/integration": "2.0.3
|
|
85
|
+
"@backstage/filter-predicates": "0.1.4-next.0",
|
|
86
|
+
"@backstage/integration": "2.0.3",
|
|
87
87
|
"@backstage/plugin-catalog-common": "1.1.10",
|
|
88
|
-
"@backstage/plugin-catalog-node": "2.2.
|
|
89
|
-
"@backstage/plugin-events-node": "0.4.
|
|
88
|
+
"@backstage/plugin-catalog-node": "2.2.3-next.0",
|
|
89
|
+
"@backstage/plugin-events-node": "0.4.24-next.0",
|
|
90
90
|
"@backstage/plugin-permission-common": "0.9.9",
|
|
91
|
-
"@backstage/plugin-permission-node": "0.11.
|
|
91
|
+
"@backstage/plugin-permission-node": "0.11.2-next.0",
|
|
92
92
|
"@backstage/types": "1.2.2",
|
|
93
93
|
"@opentelemetry/api": "^1.9.0",
|
|
94
94
|
"ajv": "^8.10.0",
|
|
@@ -109,15 +109,15 @@
|
|
|
109
109
|
"yaml": "^2.0.0",
|
|
110
110
|
"yn": "^4.0.0",
|
|
111
111
|
"zod": "^3.25.76 || ^4.0.0",
|
|
112
|
-
"zod-validation-error": "^
|
|
112
|
+
"zod-validation-error": "^5.0.0"
|
|
113
113
|
},
|
|
114
114
|
"devDependencies": {
|
|
115
|
-
"@backstage/backend-defaults": "0.17.
|
|
116
|
-
"@backstage/backend-test-utils": "1.11.
|
|
117
|
-
"@backstage/cli": "0.36.
|
|
118
|
-
"@backstage/plugin-catalog-backend-module-logs": "0.1.
|
|
119
|
-
"@backstage/plugin-scaffolder-common": "2.2.1
|
|
120
|
-
"@backstage/repo-tools": "0.17.
|
|
115
|
+
"@backstage/backend-defaults": "0.17.4-next.0",
|
|
116
|
+
"@backstage/backend-test-utils": "1.11.5-next.0",
|
|
117
|
+
"@backstage/cli": "0.36.4-next.0",
|
|
118
|
+
"@backstage/plugin-catalog-backend-module-logs": "0.1.24-next.0",
|
|
119
|
+
"@backstage/plugin-scaffolder-common": "2.2.1",
|
|
120
|
+
"@backstage/repo-tools": "0.17.4-next.0",
|
|
121
121
|
"@types/core-js": "^2.5.4",
|
|
122
122
|
"@types/express": "^4.17.6",
|
|
123
123
|
"@types/git-url-parse": "^9.0.0",
|
|
@@ -129,5 +129,5 @@
|
|
|
129
129
|
"wait-for-expect": "^4.0.0",
|
|
130
130
|
"winston": "^3.13.0"
|
|
131
131
|
},
|
|
132
|
-
"configSchema": "config.
|
|
132
|
+
"configSchema": "config.schema.json"
|
|
133
133
|
}
|
package/config.d.ts
DELETED
|
@@ -1,308 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2020 The Backstage Authors
|
|
3
|
-
*
|
|
4
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
* you may not use this file except in compliance with the License.
|
|
6
|
-
* You may obtain a copy of the License at
|
|
7
|
-
*
|
|
8
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
*
|
|
10
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
* See the License for the specific language governing permissions and
|
|
14
|
-
* limitations under the License.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { HumanDuration } from '@backstage/types';
|
|
18
|
-
|
|
19
|
-
export interface Config {
|
|
20
|
-
/**
|
|
21
|
-
* Configuration options for the catalog plugin.
|
|
22
|
-
*/
|
|
23
|
-
catalog?: {
|
|
24
|
-
/**
|
|
25
|
-
* Rules to apply to all catalog entities, from any location.
|
|
26
|
-
*
|
|
27
|
-
* An undefined list of matchers means match all, an empty list of
|
|
28
|
-
* matchers means match none.
|
|
29
|
-
*
|
|
30
|
-
* This is commonly used to put in what amounts to an allowlist of kinds
|
|
31
|
-
* that regular users of Backstage are permitted to register locations
|
|
32
|
-
* for. This can be used to stop them from registering yaml files
|
|
33
|
-
* describing for example a Group entity called "admin" that they make
|
|
34
|
-
* themselves members of, or similar.
|
|
35
|
-
*/
|
|
36
|
-
rules?: Array<{
|
|
37
|
-
/**
|
|
38
|
-
* Allow entities of these particular kinds.
|
|
39
|
-
*
|
|
40
|
-
* E.g. ["Component", "API", "Template", "Location"]
|
|
41
|
-
*
|
|
42
|
-
* You can also specify the type of the entity by using an object with `kind` and optional `spec.type` properties.
|
|
43
|
-
* E.g. [{ kind: "Component", 'spec.type': "service" }]
|
|
44
|
-
*/
|
|
45
|
-
allow: Array<string | { kind: string; 'spec.type'?: string }>;
|
|
46
|
-
/**
|
|
47
|
-
* Limit this rule to a specific location
|
|
48
|
-
*
|
|
49
|
-
* Example with a fixed location
|
|
50
|
-
* { "type": "url", "exact": "https://github.com/a/b/blob/file.yaml"}
|
|
51
|
-
*
|
|
52
|
-
* Example using a Regex
|
|
53
|
-
* { "type": "url", "pattern": "https://github.com/org/*\/blob/master/*.yaml"}
|
|
54
|
-
*
|
|
55
|
-
* Using both exact and pattern will result in an error starting the application
|
|
56
|
-
*/
|
|
57
|
-
locations?: Array<{
|
|
58
|
-
/**
|
|
59
|
-
* The type of location, e.g. "url".
|
|
60
|
-
*/
|
|
61
|
-
type: string;
|
|
62
|
-
/**
|
|
63
|
-
* The exact location, e.g.
|
|
64
|
-
* "https://github.com/org/repo/blob/master/users.yaml".
|
|
65
|
-
*
|
|
66
|
-
* The exact location can also be used to match on locations
|
|
67
|
-
* that contain glob characters themselves, e.g.
|
|
68
|
-
* "https://github.com/org/*\/blob/master/*.yaml".
|
|
69
|
-
*/
|
|
70
|
-
exact?: string;
|
|
71
|
-
/**
|
|
72
|
-
* The pattern allowed for the location, e.g.
|
|
73
|
-
* "https://github.com/org/*\/blob/master/*.yaml".
|
|
74
|
-
*/
|
|
75
|
-
pattern?: string;
|
|
76
|
-
}>;
|
|
77
|
-
}>;
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Readonly defines whether the catalog allows writes after startup.
|
|
81
|
-
*
|
|
82
|
-
* Setting 'readonly=false' allows users to register their own components.
|
|
83
|
-
* This is the default value.
|
|
84
|
-
*
|
|
85
|
-
* Setting 'readonly=true' configures catalog to only allow reads. This can
|
|
86
|
-
* be used in combination with static locations to only serve operator
|
|
87
|
-
* provided locations. Effectively this removes the ability to register new
|
|
88
|
-
* components to a running backstage instance.
|
|
89
|
-
*/
|
|
90
|
-
readonly?: boolean;
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* A set of static locations that the catalog shall always keep itself
|
|
94
|
-
* up-to-date with. This is commonly used for large, permanent integrations
|
|
95
|
-
* that are defined by the Backstage operators at an organization, rather
|
|
96
|
-
* than individual things that users register dynamically.
|
|
97
|
-
*
|
|
98
|
-
* These have (optional) rules of their own. These override what the global
|
|
99
|
-
* rules above specify. This way, you can prevent everybody from register
|
|
100
|
-
* e.g. User and Group entities, except for one or a few static locations
|
|
101
|
-
* that have those two kinds explicitly allowed.
|
|
102
|
-
*
|
|
103
|
-
* For example:
|
|
104
|
-
*
|
|
105
|
-
* ```yaml
|
|
106
|
-
* rules:
|
|
107
|
-
* - allow: [Component, API, Template, Location]
|
|
108
|
-
* locations:
|
|
109
|
-
* - type: url
|
|
110
|
-
* target: https://github.com/org/repo/blob/master/users.yaml
|
|
111
|
-
* rules:
|
|
112
|
-
* - allow: [User, Group]
|
|
113
|
-
* - type: url
|
|
114
|
-
* target: https://github.com/org/repo/blob/master/systems.yaml
|
|
115
|
-
* rules:
|
|
116
|
-
* - allow: [System]
|
|
117
|
-
* ```
|
|
118
|
-
*/
|
|
119
|
-
locations?: Array<{
|
|
120
|
-
/**
|
|
121
|
-
* The type of location, e.g. "url".
|
|
122
|
-
*/
|
|
123
|
-
type: string;
|
|
124
|
-
/**
|
|
125
|
-
* The target URL of the location, e.g.
|
|
126
|
-
* "https://github.com/org/repo/blob/master/users.yaml".
|
|
127
|
-
*/
|
|
128
|
-
target: string;
|
|
129
|
-
/**
|
|
130
|
-
* Optional extra rules that apply to this particular location.
|
|
131
|
-
*
|
|
132
|
-
* These override the global rules above.
|
|
133
|
-
*/
|
|
134
|
-
rules?: Array<{
|
|
135
|
-
/**
|
|
136
|
-
* Allow entities of these particular kinds.
|
|
137
|
-
*
|
|
138
|
-
* E.g. ["Group", "User"]
|
|
139
|
-
*/
|
|
140
|
-
allow: Array<string>;
|
|
141
|
-
}>;
|
|
142
|
-
}>;
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Enables the compatibility layer for relations in returned entities that
|
|
146
|
-
* ensures that all relations objects have both `target` and `targetRef`.
|
|
147
|
-
*
|
|
148
|
-
* Enabling this option significantly increases the memory usage of the
|
|
149
|
-
* catalog, and slightly reduces performance, but may avoid breaking consumers that
|
|
150
|
-
* rely on the existence of `target` in the relations objects.
|
|
151
|
-
*/
|
|
152
|
-
enableRelationsCompatibility?: boolean;
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Disables the default backstage processors.
|
|
156
|
-
*
|
|
157
|
-
* Enabling this option allows more complete control of which processors are included
|
|
158
|
-
* in the backstage processing loop.
|
|
159
|
-
*
|
|
160
|
-
*/
|
|
161
|
-
disableDefaultProcessors?: boolean;
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* The strategy to use for entities that are orphaned, i.e. no longer have
|
|
165
|
-
* any other entities or providers referencing them. The default value is
|
|
166
|
-
* "delete".
|
|
167
|
-
*/
|
|
168
|
-
orphanStrategy?: 'keep' | 'delete';
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* The strategy to use for entities that are referenced by providers that are orphaned,
|
|
172
|
-
* i.e. entities with no providers currently configured in the catalog. The default value is
|
|
173
|
-
* "delete".
|
|
174
|
-
*/
|
|
175
|
-
orphanProviderStrategy?: 'keep' | 'delete';
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* The strategy to use when stitching together the final entities.
|
|
179
|
-
*/
|
|
180
|
-
stitchingStrategy?: {
|
|
181
|
-
/** @deprecated Immediate mode has been removed. This field is ignored. */
|
|
182
|
-
mode?: string;
|
|
183
|
-
/** Polling interval for tasks in seconds */
|
|
184
|
-
pollingInterval?: HumanDuration | string;
|
|
185
|
-
/** How long to wait for a stitch to complete before giving up in seconds */
|
|
186
|
-
stitchTimeout?: HumanDuration | string;
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* The strategy to use when there is a conflict with a location being registered.
|
|
191
|
-
*
|
|
192
|
-
* The default value is "reject".
|
|
193
|
-
*
|
|
194
|
-
* The "refresh" strategy will refresh the existing location instead of throwing a conflict error.
|
|
195
|
-
*/
|
|
196
|
-
defaultLocationConflictStrategy?: 'refresh' | 'reject';
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* The interval at which the catalog should process its entities.
|
|
200
|
-
* @remarks
|
|
201
|
-
*
|
|
202
|
-
* Example:
|
|
203
|
-
*
|
|
204
|
-
* ```yaml
|
|
205
|
-
* catalog:
|
|
206
|
-
* processingInterval: { minutes: 30 }
|
|
207
|
-
* ```
|
|
208
|
-
*
|
|
209
|
-
* or to disabled processing:
|
|
210
|
-
*
|
|
211
|
-
* ```yaml
|
|
212
|
-
* catalog:
|
|
213
|
-
* processingInterval: false
|
|
214
|
-
* ```
|
|
215
|
-
*
|
|
216
|
-
* Note that this is only a suggested minimum, and the actual interval may
|
|
217
|
-
* be longer. Internally, the catalog will scale up this number by a small
|
|
218
|
-
* factor and choose random numbers in that range to spread out the load. If
|
|
219
|
-
* the catalog is overloaded and cannot process all entities during the
|
|
220
|
-
* interval, the time taken between processing runs of any given entity may
|
|
221
|
-
* also be longer than specified here.
|
|
222
|
-
*
|
|
223
|
-
* Setting this value too low risks exhausting rate limits on external
|
|
224
|
-
* systems that are queried by processors, such as version control systems
|
|
225
|
-
* housing catalog-info files.
|
|
226
|
-
*/
|
|
227
|
-
processingInterval?: HumanDuration | false;
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Provider-specific additional configuration options.
|
|
231
|
-
*/
|
|
232
|
-
providerOptions?: {
|
|
233
|
-
/**
|
|
234
|
-
* Key is the provider name, value is an object with additional configuration
|
|
235
|
-
*/
|
|
236
|
-
[name: string]: {
|
|
237
|
-
/**
|
|
238
|
-
* Determines whether this provider is disabled or not. If not specified,
|
|
239
|
-
* defaults to false.
|
|
240
|
-
*/
|
|
241
|
-
disabled?: boolean;
|
|
242
|
-
};
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Processor-specific additional configuration options.
|
|
247
|
-
*/
|
|
248
|
-
processorOptions?: {
|
|
249
|
-
/**
|
|
250
|
-
* Key is the processor name, value is an object with additional configuration
|
|
251
|
-
*/
|
|
252
|
-
[name: string]: {
|
|
253
|
-
/**
|
|
254
|
-
* Determines whether this processor is disabled or not. If not specified,
|
|
255
|
-
* defaults to false.
|
|
256
|
-
*/
|
|
257
|
-
disabled?: boolean;
|
|
258
|
-
/**
|
|
259
|
-
* The default priority is 20, and lower value means that the processor runs earlier.
|
|
260
|
-
*/
|
|
261
|
-
priority?: number;
|
|
262
|
-
};
|
|
263
|
-
};
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Settings that control what to do when receiving messages from the SCM
|
|
267
|
-
* events service.
|
|
268
|
-
*
|
|
269
|
-
* @defaultValue false
|
|
270
|
-
* @remarks
|
|
271
|
-
*
|
|
272
|
-
* This is primarily meant to affect builtin providers in the catalog
|
|
273
|
-
* backend such as the location handler, but other providers and processors
|
|
274
|
-
* may also read this configuration.
|
|
275
|
-
*
|
|
276
|
-
* If set to false, disable all handling of SCM events.
|
|
277
|
-
*
|
|
278
|
-
* If set to true, enable all default handling of SCM events. Note that the
|
|
279
|
-
* set of default handling can change over time.
|
|
280
|
-
*
|
|
281
|
-
* You can also configure individual handlers one by one.
|
|
282
|
-
*/
|
|
283
|
-
scmEvents?:
|
|
284
|
-
| boolean
|
|
285
|
-
| {
|
|
286
|
-
/**
|
|
287
|
-
* Trigger refreshes (reprocessing) of entities that are affected by an
|
|
288
|
-
* SCM event. This may include source control file content changes,
|
|
289
|
-
* repository status changes, etc.
|
|
290
|
-
*
|
|
291
|
-
* @defaultValue true
|
|
292
|
-
*/
|
|
293
|
-
refresh?: boolean;
|
|
294
|
-
/**
|
|
295
|
-
* Unregister entities that are deleted as a result of an SCM event.
|
|
296
|
-
*
|
|
297
|
-
* @defaultValue true
|
|
298
|
-
*/
|
|
299
|
-
unregister?: boolean;
|
|
300
|
-
/**
|
|
301
|
-
* Move entities that are moved as a result of an SCM event.
|
|
302
|
-
*
|
|
303
|
-
* @defaultValue true
|
|
304
|
-
*/
|
|
305
|
-
move?: boolean;
|
|
306
|
-
};
|
|
307
|
-
};
|
|
308
|
-
}
|