From b31daba201b555b2fa522043602c8ac691266a8a Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 15 Oct 2021 13:58:54 +0200 Subject: [PATCH] config-loader: collect visibility paths both by data and schema path Signed-off-by: Patrik Oldsberg --- packages/config-loader/package.json | 1 + .../src/lib/schema/compile.test.ts | 16 ++++++++++++--- .../config-loader/src/lib/schema/compile.ts | 20 ++++++++++++++----- .../config-loader/src/lib/schema/filtering.ts | 4 ++-- packages/config-loader/src/lib/schema/load.ts | 4 ++-- .../config-loader/src/lib/schema/types.ts | 9 ++++++++- 6 files changed, 41 insertions(+), 13 deletions(-) diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index d423c915d0..a719c6389b 100644 --- a/packages/config-loader/package.json +++ b/packages/config-loader/package.json @@ -38,6 +38,7 @@ "fs-extra": "9.1.0", "json-schema": "^0.3.0", "json-schema-merge-allof": "^0.8.1", + "json-schema-traverse": "^1.0.0", "typescript-json-schema": "^0.50.1", "yaml": "^1.9.2", "yup": "^0.32.9" diff --git a/packages/config-loader/src/lib/schema/compile.test.ts b/packages/config-loader/src/lib/schema/compile.test.ts index c9330a0440..e4ffc4801a 100644 --- a/packages/config-loader/src/lib/schema/compile.test.ts +++ b/packages/config-loader/src/lib/schema/compile.test.ts @@ -30,11 +30,13 @@ describe('compileConfigSchemas', () => { ]); expect(validate([{ data: { a: 1 }, context: 'test' }])).toEqual({ errors: ['Config should be string { type=string } at /a'], - visibilityByPath: new Map(), + visibilityByDataPath: new Map(), + visibilityBySchemaPath: new Map(), }); expect(validate([{ data: { b: 'b' }, context: 'test' }])).toEqual({ errors: ['Config should be number { type=number } at /b'], - visibilityByPath: new Map(), + visibilityByDataPath: new Map(), + visibilityBySchemaPath: new Map(), }); }); @@ -78,7 +80,7 @@ describe('compileConfigSchemas', () => { { data: { a: 'a', b: 'b', c: 'c', d: ['d'] }, context: 'test' }, ]), ).toEqual({ - visibilityByPath: new Map( + visibilityByDataPath: new Map( Object.entries({ '/a': 'frontend', '/b': 'secret', @@ -86,6 +88,14 @@ describe('compileConfigSchemas', () => { '/d/0': 'frontend', }), ), + visibilityBySchemaPath: new Map( + Object.entries({ + '/properties/a': 'frontend', + '/properties/b': 'secret', + '/properties/d': 'secret', + '/properties/d/items': 'frontend', + }), + ), }); }); diff --git a/packages/config-loader/src/lib/schema/compile.ts b/packages/config-loader/src/lib/schema/compile.ts index a36d2eb9a2..746a3a7a25 100644 --- a/packages/config-loader/src/lib/schema/compile.ts +++ b/packages/config-loader/src/lib/schema/compile.ts @@ -17,6 +17,7 @@ import Ajv from 'ajv'; import { JSONSchema7 as JSONSchema } from 'json-schema'; import mergeAllOf, { Resolvers } from 'json-schema-merge-allof'; +import traverse from 'json-schema-traverse'; import { ConfigReader } from '@backstage/config'; import { ConfigSchemaPackageEntry, @@ -38,7 +39,7 @@ export function compileConfigSchemas( // The ajv instance below is stateful and doesn't really allow for additional // output during validation. We work around this by having this extra piece // of state that we reset before each validation. - const visibilityByPath = new Map(); + const visibilityByDataPath = new Map(); const ajv = new Ajv({ allErrors: true, @@ -62,7 +63,7 @@ export function compileConfigSchemas( /\['?(.*?)'?\]/g, (_, segment) => `/${segment}`, ); - visibilityByPath.set(normalizedPath, visibility); + visibilityByDataPath.set(normalizedPath, visibility); } return true; }; @@ -80,10 +81,17 @@ export function compileConfigSchemas( const merged = mergeConfigSchemas(schemas.map(_ => _.value)); const validate = ajv.compile(merged); + const visibilityBySchemaPath = new Map(); + traverse(merged, (schema, path) => { + if (schema.visibility && schema.visibility !== 'backend') { + visibilityBySchemaPath.set(path, schema.visibility); + } + }); + return configs => { const config = ConfigReader.fromConfigs(configs).get(); - visibilityByPath.clear(); + visibilityByDataPath.clear(); const valid = validate(config); if (!valid) { @@ -95,12 +103,14 @@ export function compileConfigSchemas( .join(' '); return `Config ${message || ''} { ${paramStr} } at ${dataPath}`; }), - visibilityByPath: new Map(), + visibilityByDataPath: new Map(), + visibilityBySchemaPath: new Map(), }; } return { - visibilityByPath: new Map(visibilityByPath), + visibilityByDataPath: new Map(visibilityByDataPath), + visibilityBySchemaPath, }; }; } diff --git a/packages/config-loader/src/lib/schema/filtering.ts b/packages/config-loader/src/lib/schema/filtering.ts index 3533be01b7..dc7fac0293 100644 --- a/packages/config-loader/src/lib/schema/filtering.ts +++ b/packages/config-loader/src/lib/schema/filtering.ts @@ -28,7 +28,7 @@ import { export function filterByVisibility( data: JsonObject, includeVisibilities: ConfigVisibility[], - visibilityByPath: Map, + visibilityByDataPath: Map, transformFunc?: TransformFunc, withFilteredKeys?: boolean, ): { data: JsonObject; filteredKeys?: string[] } { @@ -40,7 +40,7 @@ export function filterByVisibility( filterPath: string, // Matches the format of the ConfigReader ): JsonValue | undefined { const visibility = - visibilityByPath.get(visibilityPath) ?? DEFAULT_CONFIG_VISIBILITY; + visibilityByDataPath.get(visibilityPath) ?? DEFAULT_CONFIG_VISIBILITY; const isVisible = includeVisibilities.includes(visibility); if (typeof jsonVal !== 'object') { diff --git a/packages/config-loader/src/lib/schema/load.ts b/packages/config-loader/src/lib/schema/load.ts index 2d4af3454c..60402d5237 100644 --- a/packages/config-loader/src/lib/schema/load.ts +++ b/packages/config-loader/src/lib/schema/load.ts @@ -83,7 +83,7 @@ export async function loadConfigSchema( ...filterByVisibility( data, visibility, - result.visibilityByPath, + result.visibilityByDataPath, valueTransform, withFilteredKeys, ), @@ -94,7 +94,7 @@ export async function loadConfigSchema( ...filterByVisibility( data, Array.from(CONFIG_VISIBILITIES), - result.visibilityByPath, + result.visibilityByDataPath, valueTransform, withFilteredKeys, ), diff --git a/packages/config-loader/src/lib/schema/types.ts b/packages/config-loader/src/lib/schema/types.ts index ef6a197f55..6763b3e1e1 100644 --- a/packages/config-loader/src/lib/schema/types.ts +++ b/packages/config-loader/src/lib/schema/types.ts @@ -65,7 +65,14 @@ type ValidationResult = { * * The path in the key uses the form `////` */ - visibilityByPath: Map; + visibilityByDataPath: Map; + + /** + * The configuration visibilities that were discovered during validation. + * + * The path in the key uses the form `/properties//items/additionalProperties/` + */ + visibilityBySchemaPath: Map; }; /**