Merge pull request #2974 from spotify/freben/remove-reserved-fields

chore(catalog-model): remove ReservedFieldsEntityPolicy
This commit is contained in:
Fredrik Adelöw
2020-10-20 09:57:28 +02:00
committed by GitHub
4 changed files with 0 additions and 160 deletions
@@ -1,72 +0,0 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import yaml from 'yaml';
import { ReservedFieldsEntityPolicy } from './ReservedFieldsEntityPolicy';
describe('ReservedFieldsEntityPolicy', () => {
let data: any;
let policy: ReservedFieldsEntityPolicy;
beforeEach(() => {
data = yaml.parse(`
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
uid: e01199ab-08cc-44c2-8e19-5c29ded82521
etag: lsndfkjsndfkjnsdfkjnsd==
generation: 13
name: my-component-yay
namespace: the-namespace
labels:
backstage.io/custom: ValueStuff
annotations:
example.com/bindings: are-secret
tags:
- java
- data
spec:
custom: stuff
`);
policy = new ReservedFieldsEntityPolicy();
});
it('works for the happy path', async () => {
await expect(policy.enforce(data)).resolves.toBe(data);
});
it('rejects reserved keys in the spec root', async () => {
data.spec.apiVersion = 'a/b';
await expect(policy.enforce(data)).rejects.toThrow(/spec.*apiVersion/i);
});
it('rejects reserved keys in labels', async () => {
data.metadata.labels.apiVersion = 'a';
await expect(policy.enforce(data)).rejects.toThrow(/label.*apiVersion/i);
});
it('rejects reserved keys in annotations', async () => {
data.metadata.annotations.apiVersion = 'a';
await expect(policy.enforce(data)).rejects.toThrow(
/annotation.*apiVersion/i,
);
});
it('rejects core fields mistakenly placed in metadata', async () => {
data.metadata.owner = 'emma';
await expect(policy.enforce(data)).rejects.toThrow(/owner/i);
});
});
@@ -1,85 +0,0 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { EntityPolicy } from '../../types';
import { Entity } from '../Entity';
const DEFAULT_RESERVED_ENTITY_FIELDS: string[] = [
'apiVersion',
'kind',
'spec',
'metadata.uid',
'metadata.etag',
'metadata.generation',
'metadata.name',
'metadata.namespace',
'metadata.description',
'metadata.labels',
'metadata.annotations',
'metadata.tags',
// The below items are known to appear in core kinds, and therefore should
// not be appearing in metadata (which would indicate that the user made a
// mistake in where to place them).
'spec.lifecycle',
'spec.owner',
];
/**
* Ensures that fields are not given certain reserved names.
*/
export class ReservedFieldsEntityPolicy implements EntityPolicy {
private readonly reservedFields: string[];
constructor(fields?: string[]) {
this.reservedFields = [
...(fields ?? []),
...DEFAULT_RESERVED_ENTITY_FIELDS,
];
}
async enforce(entity: Entity): Promise<Entity> {
for (const path of this.reservedFields) {
const [where, name] = path.includes('.')
? path.split('.')
: [undefined, path];
if (where !== 'metadata' && entity.metadata.hasOwnProperty(name)) {
throw new Error(
`The metadata may not contain the field ${name}, because it has reserved meaning`,
);
}
if (where !== 'spec' && entity.spec?.hasOwnProperty(name)) {
throw new Error(
`The spec may not contain the field ${name}, because it has reserved meaning`,
);
}
if (where !== 'labels' && entity.metadata.labels?.hasOwnProperty(name)) {
throw new Error(
`A label may not have the field ${name}, because it has reserved meaning`,
);
}
if (
where !== 'annotations' &&
entity.metadata.annotations?.hasOwnProperty(name)
) {
throw new Error(
`An annotation may not have the field ${name}, because it has reserved meaning`,
);
}
}
return entity;
}
}
@@ -17,5 +17,4 @@
export { DefaultNamespaceEntityPolicy } from './DefaultNamespaceEntityPolicy';
export { FieldFormatEntityPolicy } from './FieldFormatEntityPolicy';
export { NoForeignRootFieldsEntityPolicy } from './NoForeignRootFieldsEntityPolicy';
export { ReservedFieldsEntityPolicy } from './ReservedFieldsEntityPolicy';
export { SchemaValidEntityPolicy } from './SchemaValidEntityPolicy';
@@ -26,7 +26,6 @@ import {
locationEntityV1alpha1Policy,
makeValidator,
NoForeignRootFieldsEntityPolicy,
ReservedFieldsEntityPolicy,
SchemaValidEntityPolicy,
templateEntityV1alpha1Policy,
userEntityV1alpha1Policy,
@@ -396,7 +395,6 @@ export class CatalogBuilder {
new FieldFormatEntityPolicy(
makeValidator(this.fieldFormatValidators),
),
new ReservedFieldsEntityPolicy(),
...this.entityPolicies,
];