diff --git a/.changeset/mira-flygande-spoons.md b/.changeset/mira-flygande-spoons.md new file mode 100644 index 0000000000..c4c50f117a --- /dev/null +++ b/.changeset/mira-flygande-spoons.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +You can now specify an optional value when applying the `HAS_LABEL` permission rule, similar to the `HAS_ANNOTATION` permission rule. diff --git a/plugins/catalog-backend/report-alpha.api.md b/plugins/catalog-backend/report-alpha.api.md index ca521a568d..caa77a0d40 100644 --- a/plugins/catalog-backend/report-alpha.api.md +++ b/plugins/catalog-backend/report-alpha.api.md @@ -30,6 +30,7 @@ export const catalogConditions: Conditions<{ 'catalog-entity', { label: string; + value?: string | undefined; } >; hasMetadata: PermissionRule< @@ -103,6 +104,7 @@ export const permissionRules: { 'catalog-entity', { label: string; + value?: string | undefined; } >; hasMetadata: PermissionRule< diff --git a/plugins/catalog-backend/src/permissions/rules/hasLabel.test.ts b/plugins/catalog-backend/src/permissions/rules/hasLabel.test.ts index 8aa43402c5..7743120eaa 100644 --- a/plugins/catalog-backend/src/permissions/rules/hasLabel.test.ts +++ b/plugins/catalog-backend/src/permissions/rules/hasLabel.test.ts @@ -73,6 +73,50 @@ describe('hasLabel permission rule', () => { ), ).toEqual(true); }); + + it('returns false when specified label has different than expected value', () => { + expect( + hasLabel.apply( + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'test-component', + labels: { + someLabel: 'foo', + 'backstage.io/testLabel': 'bar', + }, + }, + }, + { + label: 'backstage.io/testLabel', + value: 'baz', + }, + ), + ).toEqual(false); + }); + + it('returns true when specified label has expected value', () => { + expect( + hasLabel.apply( + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'test-component', + labels: { + someLabel: 'foo', + 'backstage.io/testLabel': 'bar', + }, + }, + }, + { + label: 'backstage.io/testLabel', + value: 'bar', + }, + ), + ).toEqual(true); + }); }); describe('toQuery', () => { @@ -85,5 +129,17 @@ describe('hasLabel permission rule', () => { key: 'metadata.labels.backstage.io/testlabel', }); }); + + it('returns an appropriate catalog-backend filter with values', () => { + expect( + hasLabel.toQuery({ + label: 'backstage.io/testLabel', + value: 'foo', + }), + ).toEqual({ + key: 'metadata.labels.backstage.io/testLabel', + values: ['foo'], + }); + }); }); }); diff --git a/plugins/catalog-backend/src/permissions/rules/hasLabel.ts b/plugins/catalog-backend/src/permissions/rules/hasLabel.ts index e825b05b04..40a96dbf49 100644 --- a/plugins/catalog-backend/src/permissions/rules/hasLabel.ts +++ b/plugins/catalog-backend/src/permissions/rules/hasLabel.ts @@ -29,10 +29,18 @@ export const hasLabel = createPermissionRule({ resourceRef: catalogEntityPermissionResourceRef, paramsSchema: z.object({ label: z.string().describe('Name of the label to match on'), + value: z.string().optional().describe('Value of the label to match on'), }), - apply: (resource, { label }) => - !!resource.metadata.labels?.hasOwnProperty(label), - toQuery: ({ label }) => ({ - key: `metadata.labels.${label}`, - }), + apply: (resource, { label, value }) => + !!resource.metadata.labels?.hasOwnProperty(label) && + (value === undefined ? true : resource.metadata.labels?.[label] === value), + toQuery: ({ label, value }) => + value === undefined + ? { + key: `metadata.labels.${label}`, + } + : { + key: `metadata.labels.${label}`, + values: [value], + }, });