Merge pull request #10073 from backstage/rugvip/csname

catalog-model: enable usage of : and / in entity names
This commit is contained in:
Patrik Oldsberg
2022-03-09 10:39:59 +01:00
committed by GitHub
3 changed files with 39 additions and 12 deletions
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/catalog-model': patch
---
Updated `parseEntityRef` to allow `:` and `/` in the entity name. For example, parsing `'component:default/foo:bar'` will result in the name `'foo:bar'`.
Note that only parsing `'foo:bar'` itself will result in the name `'bar'` and the entity kind `'foo'`, meaning this is a particularly nasty trap for user defined entity references. For this reason it is strongly discouraged to use names that contain these characters, and the catalog model does not allow it by default. However, this change now makes is possible to use these names if the default catalog validation is replaced, and in particular a high level of automation of the catalog population can limit issues that it might otherwise cause.
+18 -5
View File
@@ -34,11 +34,24 @@ describe('ref', () => {
it('rejects bad inputs', () => {
expect(() => parseEntityRef(null as any)).toThrow();
expect(() => parseEntityRef(7 as any)).toThrow();
expect(() => parseEntityRef('a:b:c')).toThrow();
expect(() => parseEntityRef('a/b/c')).toThrow();
expect(() => parseEntityRef('a/b:c')).toThrow();
expect(() => parseEntityRef('a:b/c/d')).toThrow();
expect(() => parseEntityRef('a:b/c:d')).toThrow();
});
it('allows names with : and /', () => {
expect(
parseEntityRef('a:b:c', { defaultKind: 'k', defaultNamespace: 'ns' }),
).toEqual({ kind: 'a', namespace: 'ns', name: 'b:c' });
expect(
parseEntityRef('a/b/c', { defaultKind: 'k', defaultNamespace: 'ns' }),
).toEqual({ kind: 'k', namespace: 'a', name: 'b/c' });
expect(
parseEntityRef('a/b:c', { defaultKind: 'k', defaultNamespace: 'ns' }),
).toEqual({ kind: 'k', namespace: 'a', name: 'b:c' });
expect(
parseEntityRef('a:b/c/d', { defaultKind: 'k', defaultNamespace: 'ns' }),
).toEqual({ kind: 'a', namespace: 'b', name: 'c/d' });
expect(
parseEntityRef('a:b/c:d', { defaultKind: 'k', defaultNamespace: 'ns' }),
).toEqual({ kind: 'a', namespace: 'b', name: 'c:d' });
});
it('rejects empty parts in strings', () => {
+14 -7
View File
@@ -23,18 +23,25 @@ function parseRefString(ref: string): {
namespace?: string;
name: string;
} {
const match = /^([^:/]+:)?([^:/]+\/)?([^:/]+)$/.exec(ref.trim());
if (!match) {
let colonI = ref.indexOf(':');
const slashI = ref.indexOf('/');
// If the / is ahead of the :, treat the rest as the name
if (slashI !== -1 && slashI < colonI) {
colonI = -1;
}
const kind = colonI === -1 ? undefined : ref.slice(0, colonI);
const namespace = slashI === -1 ? undefined : ref.slice(colonI + 1, slashI);
const name = ref.slice(Math.max(colonI + 1, slashI + 1));
if (kind === '' || namespace === '' || name === '') {
throw new TypeError(
`Entity reference "${ref}" was not on the form [<kind>:][<namespace>/]<name>`,
);
}
return {
kind: match[1]?.slice(0, -1),
namespace: match[2]?.slice(0, -1),
name: match[3],
};
return { kind, namespace, name };
}
/**