From 3df39d8ed3710bc4212d7e1f3ea1e83fa4202206 Mon Sep 17 00:00:00 2001 From: Nigel Wright Date: Tue, 28 Dec 2021 13:25:05 +1300 Subject: [PATCH 01/56] added additional information for s3 discovery usage Signed-off-by: Nigel Wright --- docs/integrations/aws-s3/discovery.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/integrations/aws-s3/discovery.md b/docs/integrations/aws-s3/discovery.md index d50aceacb8..656cb9f7b3 100644 --- a/docs/integrations/aws-s3/discovery.md +++ b/docs/integrations/aws-s3/discovery.md @@ -26,3 +26,16 @@ catalog: ``` Note the `s3-discovery` type, as this is not a regular `url` processor. + +As this processor is not one of the default providers, you will also need to add the below: + +```javascript +/* packages/backend/src/plugins/catalog.ts */ + +import { AwsS3DiscoveryProcessor} from '@backstage/plugin-catalog-backend'; + + +const builder = await CatalogBuilder.create(env); +/** ... other processors ... */ +builder.addProcessor(new AwsS3DiscoveryProcessor(env.reader)) +``` From 1136ed83e3e3ba30a031e80bc0bdea11be4d0c36 Mon Sep 17 00:00:00 2001 From: Colton Padden Date: Sun, 2 Jan 2022 11:39:33 -0500 Subject: [PATCH 02/56] wip: warn users of deprecated keys in app configurations Signed-off-by: Colton Padden --- packages/config-loader/api-report.md | 1 + packages/config-loader/package.json | 1 + .../config-loader/src/lib/schema/collect.ts | 4 +- .../src/lib/schema/compile.test.ts | 33 +++++++++++ .../config-loader/src/lib/schema/compile.ts | 9 +++ .../src/lib/schema/filtering.test.ts | 27 ++++++++- .../config-loader/src/lib/schema/filtering.ts | 31 ++++++++++ .../config-loader/src/lib/schema/load.test.ts | 56 ++++++++++++++++--- packages/config-loader/src/lib/schema/load.ts | 18 +++++- .../config-loader/src/lib/schema/types.ts | 14 +++++ packages/config/api-report.md | 4 ++ packages/config/src/reader.ts | 20 ++++++- packages/config/src/types.ts | 6 ++ 13 files changed, 210 insertions(+), 14 deletions(-) diff --git a/packages/config-loader/api-report.md b/packages/config-loader/api-report.md index 269159aab4..6a02a5632f 100644 --- a/packages/config-loader/api-report.md +++ b/packages/config-loader/api-report.md @@ -21,6 +21,7 @@ export type ConfigSchemaProcessingOptions = { visibility?: ConfigVisibility[]; valueTransform?: TransformFunc; withFilteredKeys?: boolean; + withDeprecatedKeys?: boolean; }; // Warning: (ae-missing-release-tag) "ConfigTarget" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index d909cde58c..2ecea8e843 100644 --- a/packages/config-loader/package.json +++ b/packages/config-loader/package.json @@ -41,6 +41,7 @@ "json-schema": "^0.4.0", "json-schema-merge-allof": "^0.8.1", "json-schema-traverse": "^1.0.0", + "lodash": "^4.17.21", "node-fetch": "^2.6.1", "typescript-json-schema": "^0.52.0", "yaml": "^1.9.2", diff --git a/packages/config-loader/src/lib/schema/collect.ts b/packages/config-loader/src/lib/schema/collect.ts index 8e7f582e44..aa3202a1b5 100644 --- a/packages/config-loader/src/lib/schema/collect.ts +++ b/packages/config-loader/src/lib/schema/collect.ts @@ -182,10 +182,10 @@ function compileTsSchemas(paths: string[]) { program, // All schemas should export a `Config` symbol 'Config', - // This enables usage of @visibility is doc comments + // This enables usage of @visibility and @deprecated is doc comments { required: true, - validationKeywords: ['visibility'], + validationKeywords: ['visibility', 'deprecated'], }, [path.split(sep).join('/')], // Unix paths are expected for all OSes here ) as JsonObject | null; diff --git a/packages/config-loader/src/lib/schema/compile.test.ts b/packages/config-loader/src/lib/schema/compile.test.ts index 1e63f3cbf8..7615fa80f5 100644 --- a/packages/config-loader/src/lib/schema/compile.test.ts +++ b/packages/config-loader/src/lib/schema/compile.test.ts @@ -40,6 +40,7 @@ describe('compileConfigSchemas', () => { ], visibilityByDataPath: new Map(), visibilityBySchemaPath: new Map(), + deprecationBySchemaPath: new Map(), }); expect(validate([{ data: { b: 'b' }, context: 'test' }])).toEqual({ errors: [ @@ -53,6 +54,7 @@ describe('compileConfigSchemas', () => { ], visibilityByDataPath: new Map(), visibilityBySchemaPath: new Map(), + deprecationBySchemaPath: new Map(), }); }); @@ -112,6 +114,7 @@ describe('compileConfigSchemas', () => { '/properties/d/items': 'frontend', }), ), + deprecationBySchemaPath: new Map(), }); }); @@ -137,4 +140,34 @@ describe('compileConfigSchemas', () => { "Config schema visibility is both 'frontend' and 'secret' for properties/a/visibility", ); }); + + it('should discover deprecations', () => { + const validate = compileConfigSchemas([ + { + path: 'a1', + value: { + type: 'object', + properties: { + a: { type: 'string', deprecated: 'deprecation reason for a' }, + b: { type: 'string', deprecated: 'deprecation reason for b' }, + c: { type: 'string' }, + }, + }, + }, + ]); + expect( + validate([ + { data: { a: 'a', b: 'b', c: 'c', d: ['d'] }, context: 'test' }, + ]), + ).toEqual({ + deprecationBySchemaPath: new Map( + Object.entries({ + '/properties/a': 'deprecation reason for a', + '/properties/b': 'deprecation reason for b', + }), + ), + visibilityByDataPath: new Map(), + visibilityBySchemaPath: new Map(), + }); + }); }); diff --git a/packages/config-loader/src/lib/schema/compile.ts b/packages/config-loader/src/lib/schema/compile.ts index 1cbf5a404d..6dcd4713f5 100644 --- a/packages/config-loader/src/lib/schema/compile.ts +++ b/packages/config-loader/src/lib/schema/compile.ts @@ -81,6 +81,13 @@ export function compileConfigSchemas( const merged = mergeConfigSchemas(schemas.map(_ => _.value)); const validate = ajv.compile(merged); + const deprecationBySchemaPath = new Map(); + traverse(merged, (schema, path) => { + if ('deprecated' in schema) { + deprecationBySchemaPath.set(path, schema.deprecated); + } + }); + const visibilityBySchemaPath = new Map(); traverse(merged, (schema, path) => { if (schema.visibility && schema.visibility !== 'backend') { @@ -99,12 +106,14 @@ export function compileConfigSchemas( errors: validate.errors ?? [], visibilityByDataPath: new Map(visibilityByDataPath), visibilityBySchemaPath, + deprecationBySchemaPath, }; } return { visibilityByDataPath: new Map(visibilityByDataPath), visibilityBySchemaPath, + deprecationBySchemaPath, }; }; } diff --git a/packages/config-loader/src/lib/schema/filtering.test.ts b/packages/config-loader/src/lib/schema/filtering.test.ts index be07b915ed..2324bebc9d 100644 --- a/packages/config-loader/src/lib/schema/filtering.test.ts +++ b/packages/config-loader/src/lib/schema/filtering.test.ts @@ -16,7 +16,11 @@ import { JsonObject } from '@backstage/types'; import { ConfigVisibility } from './types'; -import { filterByVisibility, filterErrorsByVisibility } from './filtering'; +import { + filterByVisibility, + filterErrorsByVisibility, + filterByDeprecated, +} from './filtering'; const data = { arr: ['f', 'b', 's'], @@ -64,6 +68,13 @@ const visibility = new Map( }), ); +const deprecations = new Map( + Object.entries({ + '/properties/arr': 'deprecated array', + '/properties/objB/properties/never': 'deprecated nested property', + }), +); + describe('filterByVisibility', () => { test.each<[ConfigVisibility[], JsonObject]>([ [ @@ -381,3 +392,17 @@ describe('filterErrorsByVisibility', () => { ]); }); }); + +describe('filterByDeprecated', () => { + it('should allow empty list of deprecations', () => { + expect(filterByDeprecated(data, new Map())).toEqual({ deprecatedKeys: [] }); + }); + it('should return a list of deprecated properties', () => { + expect(filterByDeprecated(data, deprecations)).toEqual({ + deprecatedKeys: [ + { key: 'arr', description: 'deprecated array' }, + { key: 'objB.never', description: 'deprecated nested property' }, + ], + }); + }); +}); diff --git a/packages/config-loader/src/lib/schema/filtering.ts b/packages/config-loader/src/lib/schema/filtering.ts index b2f39d3cc4..f955343066 100644 --- a/packages/config-loader/src/lib/schema/filtering.ts +++ b/packages/config-loader/src/lib/schema/filtering.ts @@ -15,6 +15,7 @@ */ import { JsonObject, JsonValue } from '@backstage/types'; +import { has } from 'lodash'; import { ConfigVisibility, DEFAULT_CONFIG_VISIBILITY, @@ -22,6 +23,36 @@ import { ValidationError, } from './types'; +/** + * This filters data by deprecation status to only include those which have been deprecated + * + * @param data - configuration data + * @param deprecationBySchemaPath - mapping of schema path to deprecation description + * @returns deprecated configuration keys with their deprecation description + */ +export function filterByDeprecated( + data: JsonObject, + deprecationBySchemaPath: Map, + withDeprecatedKeys: boolean = true, +): { deprecatedKeys: { key: string; description: string }[] } { + const deprecatedKeys = new Array<{ key: string; description: string }>(); + if (!withDeprecatedKeys) { + return { deprecatedKeys }; + } + + deprecationBySchemaPath.forEach((desc, schemaPath) => { + // convert schema path to object path (/properties/techdocs/properties/storageUrl -> techdocs.storageUrl) + const propertyPath = schemaPath + .replace(/^\/properties\//, '') // remove leading `/properties/` entirely + .replace(/\/properties\//g, '.'); // replace all other `/properties/` with a `.` + if (has(data, propertyPath)) { + deprecatedKeys.push({ key: propertyPath, description: desc }); + } + }); + + return { deprecatedKeys }; +} + /** * This filters data by visibility by discovering the visibility of each * value, and then only keeping the ones that are specified in `includeVisibilities`. diff --git a/packages/config-loader/src/lib/schema/load.test.ts b/packages/config-loader/src/lib/schema/load.test.ts index e2ae3cc2c7..a2f1df8d5f 100644 --- a/packages/config-loader/src/lib/schema/load.test.ts +++ b/packages/config-loader/src/lib/schema/load.test.ts @@ -62,7 +62,11 @@ describe('loadConfigSchema', () => { expect(schema.process(configs)).toEqual(configs); expect(schema.process(configs, { visibility: ['frontend'] })).toEqual([ - { data: { key1: 'a' }, context: 'test' }, + { + data: { key1: 'a' }, + context: 'test', + deprecatedKeys: [], + }, ]); expect( schema.process(configs, { @@ -71,7 +75,12 @@ describe('loadConfigSchema', () => { withFilteredKeys: true, }), ).toEqual([ - { data: { key1: 'X' }, context: 'test', filteredKeys: ['key2'] }, + { + data: { key1: 'X' }, + context: 'test', + filteredKeys: ['key2'], + deprecatedKeys: [], + }, ]); expect( schema.process(configs, { @@ -79,14 +88,23 @@ describe('loadConfigSchema', () => { withFilteredKeys: true, }), ).toEqual([ - { data: { key1: 'X', key2: 'X' }, context: 'test', filteredKeys: [] }, + { + data: { key1: 'X', key2: 'X' }, + context: 'test', + filteredKeys: [], + deprecatedKeys: [], + }, ]); const serialized = schema.serialize(); const schema2 = await loadConfigSchema({ serialized }); expect(schema2.process(configs, { visibility: ['frontend'] })).toEqual([ - { data: { key1: 'a' }, context: 'test' }, + { + data: { key1: 'a' }, + context: 'test', + deprecatedKeys: [], + }, ]); expect(() => schema2.process([...configs, { data: { key1: 3 }, context: 'test2' }]), @@ -131,7 +149,11 @@ describe('loadConfigSchema', () => { 'Config validation failed, Config should be number { type=number } at /key2', ); expect(schema.process(configs, { visibility: ['frontend'] })).toEqual([ - { data: { key1: 'a' }, context: 'test' }, + { + data: { key1: 'a' }, + context: 'test', + deprecatedKeys: [], + }, ]); expect(() => schema.process(configs, { visibility: ['secret'] })).toThrow( 'Config validation failed, Config should be number { type=number } at /key2', @@ -179,7 +201,13 @@ describe('loadConfigSchema', () => { ]; expect( schema.process(mkConfig({ x: 1 }), { visibility: ['frontend'] }), - ).toEqual([{ data: { nested: [{}] }, context: 'test' }]); + ).toEqual([ + { + data: { nested: [{}] }, + context: 'test', + deprecatedKeys: [], + }, + ]); expect(() => schema.process(mkConfig({ y: 1 }))).toThrow( 'Config validation failed, Config should be string { type=string } at /nested/0/y', ); @@ -190,10 +218,22 @@ describe('loadConfigSchema', () => { ); expect( schema.process(mkConfig({ x: 'a' }), { visibility: ['frontend'] }), - ).toEqual([{ data: { nested: [{}] }, context: 'test' }]); + ).toEqual([ + { + data: { nested: [{}] }, + context: 'test', + deprecatedKeys: [], + }, + ]); expect( schema.process(mkConfig({ y: 'aaa' }), { visibility: ['frontend'] }), - ).toEqual([{ data: { nested: [{ y: 'aaa' }] }, context: 'test' }]); + ).toEqual([ + { + data: { nested: [{ y: 'aaa' }] }, + context: 'test', + deprecatedKeys: [], + }, + ]); expect(() => schema.process(mkConfig({ y: 'aaaa' }), { visibility: ['frontend'] }), ).toThrow( diff --git a/packages/config-loader/src/lib/schema/load.ts b/packages/config-loader/src/lib/schema/load.ts index 2d78785304..303fdfade9 100644 --- a/packages/config-loader/src/lib/schema/load.ts +++ b/packages/config-loader/src/lib/schema/load.ts @@ -18,7 +18,11 @@ import { AppConfig } from '@backstage/config'; import { JsonObject } from '@backstage/types'; import { compileConfigSchemas } from './compile'; import { collectConfigSchemas } from './collect'; -import { filterByVisibility, filterErrorsByVisibility } from './filtering'; +import { + filterByVisibility, + filterErrorsByVisibility, + filterByDeprecated, +} from './filtering'; import { ValidationError, ConfigSchema, @@ -82,7 +86,7 @@ export async function loadConfigSchema( return { process( configs: AppConfig[], - { visibility, valueTransform, withFilteredKeys } = {}, + { visibility, valueTransform, withFilteredKeys, withDeprecatedKeys } = {}, ): AppConfig[] { const result = validate(configs); @@ -108,6 +112,11 @@ export async function loadConfigSchema( valueTransform, withFilteredKeys, ), + ...filterByDeprecated( + data, + result.deprecationBySchemaPath, + withDeprecatedKeys, + ), })); } else if (valueTransform) { processedConfigs = processedConfigs.map(({ data, context }) => ({ @@ -119,6 +128,11 @@ export async function loadConfigSchema( valueTransform, withFilteredKeys, ), + ...filterByDeprecated( + data, + result.deprecationBySchemaPath, + withDeprecatedKeys, + ), })); } diff --git a/packages/config-loader/src/lib/schema/types.ts b/packages/config-loader/src/lib/schema/types.ts index 53f4dec88e..76cc337f83 100644 --- a/packages/config-loader/src/lib/schema/types.ts +++ b/packages/config-loader/src/lib/schema/types.ts @@ -81,6 +81,13 @@ type ValidationResult = { * The path in the key uses the form `/properties//items/additionalProperties/` */ visibilityBySchemaPath: Map; + + /** + * The deprecated options that were discovered during validation. + * + * The path in the key uses the form `/properties//items/additionalProperties/` + */ + deprecationBySchemaPath: Map; }; /** @@ -124,6 +131,13 @@ export type ConfigSchemaProcessingOptions = { * Default: `false`. */ withFilteredKeys?: boolean; + + /** + * Whether or not to include the `deprecatedKeys` property in the output `AppConfig`s. + * + * Default: `true`. + */ + withDeprecatedKeys?: boolean; }; /** diff --git a/packages/config/api-report.md b/packages/config/api-report.md index efa6b85559..df9baeb4cd 100644 --- a/packages/config/api-report.md +++ b/packages/config/api-report.md @@ -13,6 +13,10 @@ export type AppConfig = { context: string; data: JsonObject_2; filteredKeys?: string[]; + deprecatedKeys?: { + key: string; + description: string; + }[]; }; // @public diff --git a/packages/config/src/reader.ts b/packages/config/src/reader.ts index 8c0c4140a5..5c34b215ab 100644 --- a/packages/config/src/reader.ts +++ b/packages/config/src/reader.ts @@ -83,9 +83,27 @@ export class ConfigReader implements Config { // Merge together all configs into a single config with recursive fallback // readers, giving the first config object in the array the lowest priority. return configs.reduce( - (previousReader, { data, context, filteredKeys }) => { + (previousReader, { data, context, filteredKeys, deprecatedKeys }) => { const reader = new ConfigReader(data, context, previousReader); reader.filteredKeys = filteredKeys; + + // TODO(cmpadden) introduce `deprecatedKeys` and `notifiedDeprecatedKeys` & use logger + if (deprecatedKeys) { + for (const { key, description } of deprecatedKeys) { + if (description) { + // eslint-disable-next-line no-console + console.warn( + `The configuration key '${key}' is deprecated and may be removed soon. (reason: ${description})`, + ); + } else { + // eslint-disable-next-line no-console + console.warn( + `The configuration key '${key}' is deprecated and may be removed soon.`, + ); + } + } + } + return reader; }, undefined!, diff --git a/packages/config/src/types.ts b/packages/config/src/types.ts index a543233277..37c9595565 100644 --- a/packages/config/src/types.ts +++ b/packages/config/src/types.ts @@ -36,6 +36,12 @@ export type AppConfig = { * This can be used to warn the user if they try to read any of these keys. */ filteredKeys?: string[]; + /** + * A list of deprecated keys that were found in the configuration when it was loaded. + * + * This can be used to warn the user if they are using deprecated properties. + */ + deprecatedKeys?: { key: string; description: string }[]; }; /** From 6f5a1e74f55def5c25af380b7389cf0285391b20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Sun, 26 Dec 2021 21:57:07 +0100 Subject: [PATCH 03/56] use only a sign-in resolver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- packages/core-app-api/api-report.md | 37 ++++++++++ .../auth/gcp-iap/GcpIapIdentity.ts | 74 +++++++++++++++++++ .../implementations/auth/gcp-iap/index.ts | 18 +++++ .../auth/gcp-iap/types.test.ts | 50 +++++++++++++ .../implementations/auth/gcp-iap/types.ts | 63 ++++++++++++++++ .../src/apis/implementations/auth/index.ts | 1 + 6 files changed, 243 insertions(+) create mode 100644 packages/core-app-api/src/apis/implementations/auth/gcp-iap/GcpIapIdentity.ts create mode 100644 packages/core-app-api/src/apis/implementations/auth/gcp-iap/index.ts create mode 100644 packages/core-app-api/src/apis/implementations/auth/gcp-iap/types.test.ts create mode 100644 packages/core-app-api/src/apis/implementations/auth/gcp-iap/types.ts diff --git a/packages/core-app-api/api-report.md b/packages/core-app-api/api-report.md index f94979f975..ece34959de 100644 --- a/packages/core-app-api/api-report.md +++ b/packages/core-app-api/api-report.md @@ -21,7 +21,9 @@ import { AuthProviderInfo } from '@backstage/core-plugin-api'; import { AuthRequestOptions } from '@backstage/core-plugin-api'; import { BackstageIdentity } from '@backstage/core-plugin-api'; import { BackstageIdentityApi } from '@backstage/core-plugin-api'; +import { BackstageIdentityResponse } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/core-plugin-api'; +import { BackstageUserIdentity } from '@backstage/core-plugin-api'; import { bitbucketAuthApiRef } from '@backstage/core-plugin-api'; import { ComponentType } from 'react'; import { Config } from '@backstage/config'; @@ -388,6 +390,41 @@ export type FlatRoutesProps = { children: ReactNode; }; +// @public +export class GcpIapIdentity implements IdentityApi { + constructor(session: GcpIapSession); + static fromResponse(data: unknown): GcpIapIdentity; + // (undocumented) + getBackstageIdentity(): Promise; + // (undocumented) + getCredentials(): Promise<{ + token?: string | undefined; + }>; + // (undocumented) + getIdToken(): Promise; + // (undocumented) + getProfile(): ProfileInfo; + // (undocumented) + getProfileInfo(): Promise; + // (undocumented) + getUserId(): string; + // (undocumented) + signOut(): Promise; +} + +// @public +export type GcpIapSession = { + providerInfo: { + iapToken: { + sub: string; + email: string; + [key: string]: unknown; + }; + }; + profile: ProfileInfo; + backstageIdentity: BackstageIdentityResponse; +}; + // @public export class GithubAuth implements OAuthApi, SessionApi { // (undocumented) diff --git a/packages/core-app-api/src/apis/implementations/auth/gcp-iap/GcpIapIdentity.ts b/packages/core-app-api/src/apis/implementations/auth/gcp-iap/GcpIapIdentity.ts new file mode 100644 index 0000000000..0df14e1d99 --- /dev/null +++ b/packages/core-app-api/src/apis/implementations/auth/gcp-iap/GcpIapIdentity.ts @@ -0,0 +1,74 @@ +/* + * Copyright 2021 The Backstage Authors + * + * 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 { + BackstageUserIdentity, + IdentityApi, + ProfileInfo, +} from '@backstage/core-plugin-api'; +import { GcpIapSession, gcpIapSessionSchema } from './types'; + +/** + * An identity API based on a Google Identity-Aware Proxy auth response. + * + * @public + */ +export class GcpIapIdentity implements IdentityApi { + /** + * Creates an identity instance based on the auth-backend API response. + * + * @param data - The raw JSON response from the auth-backend. + */ + static fromResponse(data: unknown): GcpIapIdentity { + const parsed = gcpIapSessionSchema.parse(data); + return new GcpIapIdentity(parsed); + } + + constructor(private readonly session: GcpIapSession) {} + + /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getUserId} */ + getUserId(): string { + return this.session.backstageIdentity.id; + } + + /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getIdToken} */ + async getIdToken(): Promise { + return this.session.backstageIdentity.token; + } + + /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getProfile} */ + getProfile(): ProfileInfo { + return this.session.profile; + } + + /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getProfileInfo} */ + async getProfileInfo(): Promise { + return this.session.profile; + } + + /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getBackstageIdentity} */ + async getBackstageIdentity(): Promise { + return this.session.backstageIdentity.identity; + } + + /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getCredentials} */ + async getCredentials(): Promise<{ token?: string | undefined }> { + return { token: this.session.backstageIdentity.token }; + } + + /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.signOut} */ + async signOut(): Promise {} +} diff --git a/packages/core-app-api/src/apis/implementations/auth/gcp-iap/index.ts b/packages/core-app-api/src/apis/implementations/auth/gcp-iap/index.ts new file mode 100644 index 0000000000..8133061f20 --- /dev/null +++ b/packages/core-app-api/src/apis/implementations/auth/gcp-iap/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2021 The Backstage Authors + * + * 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. + */ + +export { GcpIapIdentity } from './GcpIapIdentity'; +export type { GcpIapSession } from './types'; diff --git a/packages/core-app-api/src/apis/implementations/auth/gcp-iap/types.test.ts b/packages/core-app-api/src/apis/implementations/auth/gcp-iap/types.test.ts new file mode 100644 index 0000000000..cb185103e2 --- /dev/null +++ b/packages/core-app-api/src/apis/implementations/auth/gcp-iap/types.test.ts @@ -0,0 +1,50 @@ +/* + * Copyright 2021 The Backstage Authors + * + * 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 { TypeOf } from 'zod'; +import { GcpIapSession, gcpIapSessionSchema } from './types'; + +describe('types', () => { + const responseData: GcpIapSession = { + providerInfo: { + iapToken: { + sub: 's', + email: 'e', + other: 7, + }, + }, + profile: { + email: 'e', + displayName: 'd', + picture: 'p', + }, + backstageIdentity: { + id: 'i', + token: 't', + identity: { + type: 'user', + userEntityRef: 'ue', + ownershipEntityRefs: ['oe'], + }, + }, + }; + + it('has a compatible schema type', () => { + function f(_b: TypeOf) {} + f(responseData); // no tsc errors + expect(gcpIapSessionSchema.parse(responseData)).toEqual(responseData); + }); +}); diff --git a/packages/core-app-api/src/apis/implementations/auth/gcp-iap/types.ts b/packages/core-app-api/src/apis/implementations/auth/gcp-iap/types.ts new file mode 100644 index 0000000000..98c728785d --- /dev/null +++ b/packages/core-app-api/src/apis/implementations/auth/gcp-iap/types.ts @@ -0,0 +1,63 @@ +/* + * Copyright 2021 The Backstage Authors + * + * 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 { + BackstageIdentityResponse, + ProfileInfo, +} from '@backstage/core-plugin-api'; +import { z } from 'zod'; + +export const gcpIapSessionSchema = z.object({ + providerInfo: z.object({ + iapToken: z + .object({ + sub: z.string(), + email: z.string(), + }) + .catchall(z.unknown()), + }), + profile: z.object({ + email: z.string().optional(), + displayName: z.string().optional(), + picture: z.string().optional(), + }), + backstageIdentity: z.object({ + id: z.string(), + token: z.string(), + identity: z.object({ + type: z.literal('user'), + userEntityRef: z.string(), + ownershipEntityRefs: z.array(z.string()), + }), + }), +}); + +/** + * Session information for Google Identity-Aware Proxy auth. + * + * @public + */ +export type GcpIapSession = { + providerInfo: { + iapToken: { + sub: string; + email: string; + [key: string]: unknown; + }; + }; + profile: ProfileInfo; + backstageIdentity: BackstageIdentityResponse; +}; diff --git a/packages/core-app-api/src/apis/implementations/auth/index.ts b/packages/core-app-api/src/apis/implementations/auth/index.ts index 50333f07a0..c53c9b7c76 100644 --- a/packages/core-app-api/src/apis/implementations/auth/index.ts +++ b/packages/core-app-api/src/apis/implementations/auth/index.ts @@ -25,4 +25,5 @@ export * from './microsoft'; export * from './onelogin'; export * from './bitbucket'; export * from './atlassian'; +export * from './gcp-iap'; export type { OAuthApiCreateOptions, AuthApiCreateOptions } from './types'; From 6415189d9946a9790cac72b1849eb03b1447af19 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 28 Dec 2021 17:30:00 +0100 Subject: [PATCH 04/56] auth: implement frontend parts of iap-like sign-in MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/cool-baboons-switch.md | 5 + docs/auth/google/gcp-iap-auth.md | 98 ++++++++++++ packages/core-app-api/api-report.md | 37 ----- .../auth/gcp-iap/GcpIapIdentity.ts | 74 --------- .../src/apis/implementations/auth/index.ts | 1 - packages/core-components/package.json | 3 +- .../DelegatedSignInIdentity.ts | 149 ++++++++++++++++++ .../DelegatedSignInPage.tsx | 90 +++++++++++ .../src/layout/DelegatedSignInPage}/index.ts | 4 +- .../layout/DelegatedSignInPage}/types.test.ts | 14 +- .../src/layout/DelegatedSignInPage}/types.ts | 24 +-- 11 files changed, 357 insertions(+), 142 deletions(-) create mode 100644 .changeset/cool-baboons-switch.md create mode 100644 docs/auth/google/gcp-iap-auth.md delete mode 100644 packages/core-app-api/src/apis/implementations/auth/gcp-iap/GcpIapIdentity.ts create mode 100644 packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.ts create mode 100644 packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInPage.tsx rename packages/{core-app-api/src/apis/implementations/auth/gcp-iap => core-components/src/layout/DelegatedSignInPage}/index.ts (82%) rename packages/{core-app-api/src/apis/implementations/auth/gcp-iap => core-components/src/layout/DelegatedSignInPage}/types.test.ts (76%) rename packages/{core-app-api/src/apis/implementations/auth/gcp-iap => core-components/src/layout/DelegatedSignInPage}/types.ts (74%) diff --git a/.changeset/cool-baboons-switch.md b/.changeset/cool-baboons-switch.md new file mode 100644 index 0000000000..88752502c8 --- /dev/null +++ b/.changeset/cool-baboons-switch.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Add a `DelegatedSignInPage` that can be used e.g. for GCP IAP and AWS ALB diff --git a/docs/auth/google/gcp-iap-auth.md b/docs/auth/google/gcp-iap-auth.md new file mode 100644 index 0000000000..2281d7654e --- /dev/null +++ b/docs/auth/google/gcp-iap-auth.md @@ -0,0 +1,98 @@ +--- +id: provider +title: Google Identity-Aware Proxy Provider +sidebar_label: Google IAP +# prettier-ignore +description: Adding Google Identity-Aware Proxy as an authentication provider in Backstage +--- + +Backstage allows offloading the responsibility of authenticating users to the +Google HTTPS Load Balancer & [IAP](https://cloud.google.com/iap), leveraging the +authentication support on the latter. + +This tutorial shows how to use authentication on an IAP sitting in front of +Backstage. + +It is assumed an IAP is already serving traffic in front of a Backstage instance +configured to serve the frontend app from the backend. + +## Frontend Changes + +Any Backstage app needs a `SignInPage` to be configured. When using IAP Proxy +authentication Backstage will only be loaded once the user has already +successfully authenticated. As such, we won't need to display a sign-in page +visually, however we will need to pick a `SignInPage` implementation which knows +how to silently fetch the IAP-injected token and other information via the +backend. + +Update your `createApp` call in `packages/app/src/App.tsx`, to pass in the +proper sign-in page implementation. + +```diff ++import { DelegatedSignInPage } from '@backstage/core-components'; + + const app = createApp({ + components: { ++ SignInPage: props => , +``` + +## Backend Changes + +- Add a `providerFactories` entry to the router in + `packages/backend/plugin/auth.ts`. + +```ts +import { createGcpIapProvider } from '@backstage/plugin-auth-backend'; + +export default async function createPlugin({ + logger, + database, + config, + discovery, +}: PluginEnvironment): Promise { + return await createRouter({ + logger, + config, + database, + discovery, + providerFactories: { + 'gcp-iap': createGcpIapProvider({ + // Replace the auth handler if you want to customize the returned user + // profile info (can be left out; the default implementation is shown + // below which only returns the email. + async authHandler({ iapToken }) { + return { profile: { email: iapToken.email } }; + }, + signIn: { + // You need to supply an identity resolver, that takes the profile + // and the IAP token and produces the Backstage token with the + // relevant user info. + async resolver({ profile, result: { iapToken } }, ctx) { + // Somehow compute the Backstage token claims, just some dummy code + // shown here, but you may want to query your LDAP server, or + // GSuite or similar, based on the IAP token sub/email claims + const id = `user:default/${iapToken.email.split('@')[0]}`; + const fullEnt = ['group:default/team-name']; + const token = await ctx.tokenIssuer.issueToken({ + claims: { sub: id, ent: fullEnt }, + }); + return { id, token }; + }, + }, + }), + }, + }); +} +``` + +## Configuration + +Use the following `auth` configuration: + +```yaml +auth: + providers: + gcp-iap: + audience: + '/projects//global/backendServices/' +``` diff --git a/packages/core-app-api/api-report.md b/packages/core-app-api/api-report.md index ece34959de..f94979f975 100644 --- a/packages/core-app-api/api-report.md +++ b/packages/core-app-api/api-report.md @@ -21,9 +21,7 @@ import { AuthProviderInfo } from '@backstage/core-plugin-api'; import { AuthRequestOptions } from '@backstage/core-plugin-api'; import { BackstageIdentity } from '@backstage/core-plugin-api'; import { BackstageIdentityApi } from '@backstage/core-plugin-api'; -import { BackstageIdentityResponse } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/core-plugin-api'; -import { BackstageUserIdentity } from '@backstage/core-plugin-api'; import { bitbucketAuthApiRef } from '@backstage/core-plugin-api'; import { ComponentType } from 'react'; import { Config } from '@backstage/config'; @@ -390,41 +388,6 @@ export type FlatRoutesProps = { children: ReactNode; }; -// @public -export class GcpIapIdentity implements IdentityApi { - constructor(session: GcpIapSession); - static fromResponse(data: unknown): GcpIapIdentity; - // (undocumented) - getBackstageIdentity(): Promise; - // (undocumented) - getCredentials(): Promise<{ - token?: string | undefined; - }>; - // (undocumented) - getIdToken(): Promise; - // (undocumented) - getProfile(): ProfileInfo; - // (undocumented) - getProfileInfo(): Promise; - // (undocumented) - getUserId(): string; - // (undocumented) - signOut(): Promise; -} - -// @public -export type GcpIapSession = { - providerInfo: { - iapToken: { - sub: string; - email: string; - [key: string]: unknown; - }; - }; - profile: ProfileInfo; - backstageIdentity: BackstageIdentityResponse; -}; - // @public export class GithubAuth implements OAuthApi, SessionApi { // (undocumented) diff --git a/packages/core-app-api/src/apis/implementations/auth/gcp-iap/GcpIapIdentity.ts b/packages/core-app-api/src/apis/implementations/auth/gcp-iap/GcpIapIdentity.ts deleted file mode 100644 index 0df14e1d99..0000000000 --- a/packages/core-app-api/src/apis/implementations/auth/gcp-iap/GcpIapIdentity.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2021 The Backstage Authors - * - * 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 { - BackstageUserIdentity, - IdentityApi, - ProfileInfo, -} from '@backstage/core-plugin-api'; -import { GcpIapSession, gcpIapSessionSchema } from './types'; - -/** - * An identity API based on a Google Identity-Aware Proxy auth response. - * - * @public - */ -export class GcpIapIdentity implements IdentityApi { - /** - * Creates an identity instance based on the auth-backend API response. - * - * @param data - The raw JSON response from the auth-backend. - */ - static fromResponse(data: unknown): GcpIapIdentity { - const parsed = gcpIapSessionSchema.parse(data); - return new GcpIapIdentity(parsed); - } - - constructor(private readonly session: GcpIapSession) {} - - /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getUserId} */ - getUserId(): string { - return this.session.backstageIdentity.id; - } - - /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getIdToken} */ - async getIdToken(): Promise { - return this.session.backstageIdentity.token; - } - - /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getProfile} */ - getProfile(): ProfileInfo { - return this.session.profile; - } - - /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getProfileInfo} */ - async getProfileInfo(): Promise { - return this.session.profile; - } - - /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getBackstageIdentity} */ - async getBackstageIdentity(): Promise { - return this.session.backstageIdentity.identity; - } - - /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getCredentials} */ - async getCredentials(): Promise<{ token?: string | undefined }> { - return { token: this.session.backstageIdentity.token }; - } - - /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.signOut} */ - async signOut(): Promise {} -} diff --git a/packages/core-app-api/src/apis/implementations/auth/index.ts b/packages/core-app-api/src/apis/implementations/auth/index.ts index c53c9b7c76..50333f07a0 100644 --- a/packages/core-app-api/src/apis/implementations/auth/index.ts +++ b/packages/core-app-api/src/apis/implementations/auth/index.ts @@ -25,5 +25,4 @@ export * from './microsoft'; export * from './onelogin'; export * from './bitbucket'; export * from './atlassian'; -export * from './gcp-iap'; export type { OAuthApiCreateOptions, AuthApiCreateOptions } from './types'; diff --git a/packages/core-components/package.json b/packages/core-components/package.json index 82c3857a81..a15bec3eac 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -64,7 +64,8 @@ "react-virtualized-auto-sizer": "^1.0.6", "react-window": "^1.8.6", "remark-gfm": "^2.0.0", - "zen-observable": "^0.8.15" + "zen-observable": "^0.8.15", + "zod": "^3.11.6" }, "peerDependencies": { "@types/react": "^16.13.1 || ^17.0.0", diff --git a/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.ts b/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.ts new file mode 100644 index 0000000000..ca39c802b6 --- /dev/null +++ b/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.ts @@ -0,0 +1,149 @@ +/* + * Copyright 2021 The Backstage Authors + * + * 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 { + BackstageUserIdentity, + discoveryApiRef, + errorApiRef, + fetchApiRef, + IdentityApi, + ProfileInfo, +} from '@backstage/core-plugin-api'; +import { ResponseError } from '@backstage/errors'; +import { DelegatedSession, delegatedSessionSchema } from './types'; + +type DelegatedSignInIdentityOptions = { + provider: string; + refreshFrequencyMillis: number; + retryRefreshFrequencyMillis: number; + discoveryApi: typeof discoveryApiRef.T; + fetchApi: typeof fetchApiRef.T; + errorApi: typeof errorApiRef.T; +}; + +/** + * An identity API that keeps itself up to date solely based on getting session + * information from a `/refresh` endpoint. + */ +export class DelegatedSignInIdentity implements IdentityApi { + private readonly options: DelegatedSignInIdentityOptions; + private readonly abortController: AbortController; + private session: DelegatedSession | undefined; + + constructor(options: DelegatedSignInIdentityOptions) { + this.options = options; + this.abortController = new AbortController(); + this.session = undefined; + } + + async start() { + await this.refresh(false); + + let signalErrors = true; + const refreshLoop = async () => { + if (!this.abortController.signal.aborted) { + try { + await this.refresh(signalErrors); + signalErrors = true; + setTimeout(refreshLoop, this.options.refreshFrequencyMillis); + } catch { + signalErrors = false; + setTimeout(refreshLoop, this.options.retryRefreshFrequencyMillis); + } + } + }; + + setTimeout(refreshLoop, this.options.refreshFrequencyMillis); + } + + /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getUserId} */ + getUserId(): string { + return this.getSession().backstageIdentity.id; + } + + /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getIdToken} */ + async getIdToken(): Promise { + return this.getSession().backstageIdentity.token; + } + + /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getProfile} */ + getProfile(): ProfileInfo { + return this.getSession().profile; + } + + /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getProfileInfo} */ + async getProfileInfo(): Promise { + return this.getSession().profile; + } + + /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getBackstageIdentity} */ + async getBackstageIdentity(): Promise { + return this.getSession().backstageIdentity.identity; + } + + /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getCredentials} */ + async getCredentials(): Promise<{ token?: string | undefined }> { + return { token: this.getSession().backstageIdentity.token }; + } + + /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.signOut} */ + async signOut(): Promise { + this.abortController.abort(); + } + + getSession(): DelegatedSession { + if (!this.session) { + throw new Error('No session available'); + } + return this.session; + } + + async refresh(notifyErrors: boolean) { + try { + const baseUrl = await this.options.discoveryApi.getBaseUrl('auth'); + + const response = await this.options.fetchApi.fetch( + `${baseUrl}/${this.options.provider}/refresh`, + { + signal: this.abortController.signal, + headers: { 'x-requested-with': 'XMLHttpRequest' }, + credentials: 'include', + }, + ); + + if (!response.ok) { + throw await ResponseError.fromResponse(response); + } + + const session = delegatedSessionSchema.parse(await response.json()); + this.session = session; + } catch (e) { + if (this.abortController.signal.aborted) { + return; + } + + if (notifyErrors) { + this.options.errorApi.post( + new Error( + `Failed to refresh browser session, ${e}. Try reloading your browser page.`, + ), + ); + } + + throw e; + } + } +} diff --git a/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInPage.tsx b/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInPage.tsx new file mode 100644 index 0000000000..f8ecc8c2a5 --- /dev/null +++ b/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInPage.tsx @@ -0,0 +1,90 @@ +/* + * Copyright 2021 The Backstage Authors + * + * 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 { + discoveryApiRef, + errorApiRef, + fetchApiRef, + SignInPageProps, + useApi, +} from '@backstage/core-plugin-api'; +import React from 'react'; +import useAsync from 'react-use/lib/useAsync'; +import { ErrorPanel } from '../../components/ErrorPanel'; +import { Progress } from '../../components/Progress'; +import { DelegatedSignInIdentity } from './DelegatedSignInIdentity'; + +/** + * Props for {@link DelegatedSignInPage}. + * + * @public + */ +export type DelegatedSignInPageProps = SignInPageProps & { + /** + * The provider to use, e.g. "gcp-iap" or "aws-alb". This must correspond to + * a properly configured auth provider ID in the auth backend. + */ + provider: string; +}; + +/** + * A sign-in page that has no user interface of its own. Instead, it delegates + * sign-in to some reverse authenticating proxy that Backstage is deployed + * behind, and leverages its session handling. + * + * @remarks + * + * This sign-in page is useful when you are using products such as Google + * Identity-Aware Proxy or AWS Application Load Balancer or similar, to front + * your Backstage installation. This sign-in page implementation will silently + * and regularly punch through the proxy to the auth backend to refresh your + * frontend session information, without requiring user interaction. + * + * @public + */ +export const DelegatedSignInPage = (props: DelegatedSignInPageProps) => { + const discoveryApi = useApi(discoveryApiRef); + const fetchApi = useApi(fetchApiRef); + const errorApi = useApi(errorApiRef); + + const { loading, error } = useAsync(async () => { + const identity = new DelegatedSignInIdentity({ + provider: props.provider, + refreshFrequencyMillis: 60_000, + retryRefreshFrequencyMillis: 10_000, + errorApi, + discoveryApi, + fetchApi, + }); + + await identity.start(); + + props.onSignInSuccess(identity); + }, []); + + if (loading) { + return ; + } else if (error) { + return ( + + ); + } + + return null; +}; diff --git a/packages/core-app-api/src/apis/implementations/auth/gcp-iap/index.ts b/packages/core-components/src/layout/DelegatedSignInPage/index.ts similarity index 82% rename from packages/core-app-api/src/apis/implementations/auth/gcp-iap/index.ts rename to packages/core-components/src/layout/DelegatedSignInPage/index.ts index 8133061f20..bf3081e630 100644 --- a/packages/core-app-api/src/apis/implementations/auth/gcp-iap/index.ts +++ b/packages/core-components/src/layout/DelegatedSignInPage/index.ts @@ -14,5 +14,5 @@ * limitations under the License. */ -export { GcpIapIdentity } from './GcpIapIdentity'; -export type { GcpIapSession } from './types'; +export { DelegatedSignInPage } from './DelegatedSignInPage'; +export type { DelegatedSignInPageProps } from './DelegatedSignInPage'; diff --git a/packages/core-app-api/src/apis/implementations/auth/gcp-iap/types.test.ts b/packages/core-components/src/layout/DelegatedSignInPage/types.test.ts similarity index 76% rename from packages/core-app-api/src/apis/implementations/auth/gcp-iap/types.test.ts rename to packages/core-components/src/layout/DelegatedSignInPage/types.test.ts index cb185103e2..c3eeff4eec 100644 --- a/packages/core-app-api/src/apis/implementations/auth/gcp-iap/types.test.ts +++ b/packages/core-components/src/layout/DelegatedSignInPage/types.test.ts @@ -15,16 +15,12 @@ */ import { TypeOf } from 'zod'; -import { GcpIapSession, gcpIapSessionSchema } from './types'; +import { DelegatedSession, delegatedSessionSchema } from './types'; describe('types', () => { - const responseData: GcpIapSession = { + const responseData: DelegatedSession = { providerInfo: { - iapToken: { - sub: 's', - email: 'e', - other: 7, - }, + stuff: 1, }, profile: { email: 'e', @@ -43,8 +39,8 @@ describe('types', () => { }; it('has a compatible schema type', () => { - function f(_b: TypeOf) {} + function f(_b: TypeOf) {} f(responseData); // no tsc errors - expect(gcpIapSessionSchema.parse(responseData)).toEqual(responseData); + expect(delegatedSessionSchema.parse(responseData)).toEqual(responseData); }); }); diff --git a/packages/core-app-api/src/apis/implementations/auth/gcp-iap/types.ts b/packages/core-components/src/layout/DelegatedSignInPage/types.ts similarity index 74% rename from packages/core-app-api/src/apis/implementations/auth/gcp-iap/types.ts rename to packages/core-components/src/layout/DelegatedSignInPage/types.ts index 98c728785d..0ef65344a3 100644 --- a/packages/core-app-api/src/apis/implementations/auth/gcp-iap/types.ts +++ b/packages/core-components/src/layout/DelegatedSignInPage/types.ts @@ -20,15 +20,8 @@ import { } from '@backstage/core-plugin-api'; import { z } from 'zod'; -export const gcpIapSessionSchema = z.object({ - providerInfo: z.object({ - iapToken: z - .object({ - sub: z.string(), - email: z.string(), - }) - .catchall(z.unknown()), - }), +export const delegatedSessionSchema = z.object({ + providerInfo: z.object({}).catchall(z.unknown()).optional(), profile: z.object({ email: z.string().optional(), displayName: z.string().optional(), @@ -46,18 +39,13 @@ export const gcpIapSessionSchema = z.object({ }); /** - * Session information for Google Identity-Aware Proxy auth. + * Generic session information for delegated sign-in providers, e.g. common + * reverse authenticating proxy implementations. * * @public */ -export type GcpIapSession = { - providerInfo: { - iapToken: { - sub: string; - email: string; - [key: string]: unknown; - }; - }; +export type DelegatedSession = { + providerInfo?: { [key: string]: unknown }; profile: ProfileInfo; backstageIdentity: BackstageIdentityResponse; }; From 0bc142f54526fe3113556e59f71c09ea1eada2fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Mon, 3 Jan 2022 12:00:58 +0100 Subject: [PATCH 05/56] moved around the docs sections to make things clearer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- docs/auth/google/gcp-iap-auth.md | 83 +++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 28 deletions(-) diff --git a/docs/auth/google/gcp-iap-auth.md b/docs/auth/google/gcp-iap-auth.md index 2281d7654e..88077080da 100644 --- a/docs/auth/google/gcp-iap-auth.md +++ b/docs/auth/google/gcp-iap-auth.md @@ -16,30 +16,32 @@ Backstage. It is assumed an IAP is already serving traffic in front of a Backstage instance configured to serve the frontend app from the backend. -## Frontend Changes +## Configuration -Any Backstage app needs a `SignInPage` to be configured. When using IAP Proxy -authentication Backstage will only be loaded once the user has already -successfully authenticated. As such, we won't need to display a sign-in page -visually, however we will need to pick a `SignInPage` implementation which knows -how to silently fetch the IAP-injected token and other information via the -backend. +Let's start by adding the following `auth` configuration in your +`app-config.yaml` or `app-config.production.yaml` or similar: -Update your `createApp` call in `packages/app/src/App.tsx`, to pass in the -proper sign-in page implementation. - -```diff -+import { DelegatedSignInPage } from '@backstage/core-components'; - - const app = createApp({ - components: { -+ SignInPage: props => , +```yaml +auth: + providers: + gcp-iap: + audience: + '/projects//global/backendServices/' ``` +You can find the project number and service ID in the Google Cloud Console. + +This config section must be in place for the provider to load at all. Now let's +add the provider itself. + ## Backend Changes -- Add a `providerFactories` entry to the router in - `packages/backend/plugin/auth.ts`. +This provider is not enabled by default in the auth backend code, because +besides the config section above, it also needs to be given one or more +callbacks in actual code as well as described below. + +Add a `providerFactories` entry to the router in +`packages/backend/plugin/auth.ts`. ```ts import { createGcpIapProvider } from '@backstage/plugin-auth-backend'; @@ -59,7 +61,9 @@ export default async function createPlugin({ 'gcp-iap': createGcpIapProvider({ // Replace the auth handler if you want to customize the returned user // profile info (can be left out; the default implementation is shown - // below which only returns the email. + // below which only returns the email). You may want to amend this code + // with something that loads additional user profile data out of e.g. + // GSuite or LDAP or similar. async authHandler({ iapToken }) { return { profile: { email: iapToken.email } }; }, @@ -68,7 +72,7 @@ export default async function createPlugin({ // and the IAP token and produces the Backstage token with the // relevant user info. async resolver({ profile, result: { iapToken } }, ctx) { - // Somehow compute the Backstage token claims, just some dummy code + // Somehow compute the Backstage token claims. Just some dummy code // shown here, but you may want to query your LDAP server, or // GSuite or similar, based on the IAP token sub/email claims const id = `user:default/${iapToken.email.split('@')[0]}`; @@ -85,14 +89,37 @@ export default async function createPlugin({ } ``` -## Configuration +Now the backend is ready to serve auth requests on the +`/api/auth/gcp-iap/refresh` endpoint. All that's left is to update the frontend +sign-in mechanism to poll that endpoint through the IAP, on the user's behalf. -Use the following `auth` configuration: +## Frontend Changes -```yaml -auth: - providers: - gcp-iap: - audience: - '/projects//global/backendServices/' +Any Backstage app needs a `SignInPage` to be configured. Its purpose is to +establish who the user is and what their identifying credentials are, blocking +rendering the rest of the UI until that's complete, and then keeping those +credentials fresh. + +When using IAP Proxy authentication, the Backstage UI will only be loaded once +the user has already successfully completely authenticated themselves with the +IAP and has an active session, so we don't want to make the user have to go +through a _second_ layer of authentication flows after that. + +As such, we want to not display a sign-in page visually at all. Instead, we will +pick a `SignInPage` implementation component which knows how to silently make +requests to the backend provider we configured above, and just trusting its +output to properly represent the current user. Luckily, Backstage comes with a +component for this purpose out of the box. + +Update your `createApp` call in `packages/app/src/App.tsx`, as follows. + +```diff ++import { DelegatedSignInPage } from '@backstage/core-components'; + + const app = createApp({ + components: { ++ SignInPage: props => , ``` + +After this, your app should be ready to leverage the Identity-Aware Proxy for +authentication! From b254d60924aa05b2d4734e00a8bddc69068ac487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Mon, 3 Jan 2022 14:34:15 +0100 Subject: [PATCH 06/56] proper token expiry handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../DelegatedSignInIdentity.ts | 58 ++++++++++++++++--- .../DelegatedSignInPage.tsx | 2 - 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.ts b/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.ts index ca39c802b6..2d24796a17 100644 --- a/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.ts +++ b/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.ts @@ -25,10 +25,50 @@ import { import { ResponseError } from '@backstage/errors'; import { DelegatedSession, delegatedSessionSchema } from './types'; +const DEFAULTS = { + // How often we retry a failed auth refresh call + retryRefreshFrequencyMillis: 5_000, + // The amount of time between token refreshes, if we fail to get an actual + // value out of the exp claim + defaultTokenExpiryMillis: 30_000, + // The amount of time before the actual expiry of the Backstage token, that we + // shall start trying to get a new one + tokenExpiryMarginMillis: 30_000, +}; + +// The amount of time to wait until trying to refresh the auth session +function tokenToExpiryMillis(token: string | undefined): number { + if (typeof token !== 'string') { + return DEFAULTS.retryRefreshFrequencyMillis; + } + + const [_header, rawPayload, _signature] = token.split('.'); + const payload = JSON.parse(atob(rawPayload)); + const expiresInMillis = payload.exp * 1000 - Date.now(); + + return Math.max( + expiresInMillis - DEFAULTS.tokenExpiryMarginMillis, + DEFAULTS.defaultTokenExpiryMillis, + ); +} + +// Sleeps for a given duration, unless interrupted by signal +async function sleep(durationMillis: number, signal: AbortSignal) { + if (!signal.aborted) { + await new Promise(resolve => { + const timeoutHandle = setTimeout(done, durationMillis); + signal.addEventListener('abort', done); + function done() { + clearTimeout(timeoutHandle); + signal.removeEventListener('abort', done); + resolve(); + } + }); + } +} + type DelegatedSignInIdentityOptions = { provider: string; - refreshFrequencyMillis: number; - retryRefreshFrequencyMillis: number; discoveryApi: typeof discoveryApiRef.T; fetchApi: typeof fetchApiRef.T; errorApi: typeof errorApiRef.T; @@ -50,23 +90,27 @@ export class DelegatedSignInIdentity implements IdentityApi { } async start() { + // Try first refresh and bubble up any errors to the caller await this.refresh(false); let signalErrors = true; + let pause: number; + const refreshLoop = async () => { - if (!this.abortController.signal.aborted) { + while (!this.abortController.signal.aborted) { try { await this.refresh(signalErrors); signalErrors = true; - setTimeout(refreshLoop, this.options.refreshFrequencyMillis); + pause = tokenToExpiryMillis(this.session?.backstageIdentity.token); } catch { - signalErrors = false; - setTimeout(refreshLoop, this.options.retryRefreshFrequencyMillis); + signalErrors = false; // Only signal first failure in a row + pause = DEFAULTS.retryRefreshFrequencyMillis; } + await sleep(pause, this.abortController.signal); } }; - setTimeout(refreshLoop, this.options.refreshFrequencyMillis); + refreshLoop(); } /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getUserId} */ diff --git a/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInPage.tsx b/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInPage.tsx index f8ecc8c2a5..54cc0495fd 100644 --- a/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInPage.tsx +++ b/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInPage.tsx @@ -63,8 +63,6 @@ export const DelegatedSignInPage = (props: DelegatedSignInPageProps) => { const { loading, error } = useAsync(async () => { const identity = new DelegatedSignInIdentity({ provider: props.provider, - refreshFrequencyMillis: 60_000, - retryRefreshFrequencyMillis: 10_000, errorApi, discoveryApi, fetchApi, From f0a743ecaec7c8acd6053adfe5e864c8ddc7c6f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Mon, 3 Jan 2022 19:06:31 +0100 Subject: [PATCH 07/56] more tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- packages/core-components/package.json | 4 +- .../DelegatedSignInIdentity.test.ts | 195 ++++++++++++++++++ .../DelegatedSignInIdentity.ts | 46 +++-- 3 files changed, 224 insertions(+), 21 deletions(-) create mode 100644 packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.test.ts diff --git a/packages/core-components/package.json b/packages/core-components/package.json index a15bec3eac..83b6b47ad6 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -93,7 +93,9 @@ "@types/react-syntax-highlighter": "^13.5.2", "@types/react-virtualized-auto-sizer": "^1.0.1", "@types/react-window": "^1.8.5", - "@types/zen-observable": "^0.8.0" + "@types/zen-observable": "^0.8.0", + "cross-fetch": "^3.0.6", + "msw": "^0.35.0" }, "files": [ "dist" diff --git a/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.test.ts b/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.test.ts new file mode 100644 index 0000000000..11fdaf257e --- /dev/null +++ b/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.test.ts @@ -0,0 +1,195 @@ +/* + * Copyright 2022 The Backstage Authors + * + * 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 { setupRequestMockHandlers } from '@backstage/test-utils'; +import fetch from 'cross-fetch'; +import { rest } from 'msw'; +import { setupServer } from 'msw/node'; +import { + DEFAULTS, + DelegatedSignInIdentity, + sleep, + tokenToExpiryMillis, +} from './DelegatedSignInIdentity'; + +const flushPromises = () => new Promise(setImmediate); + +const validBackstageTokenExpClaim = 1641216199; +const validBackstageToken = + 'eyJhbGciOiJFUzI1NiIsImtpZCI6ImMxNTMzNDRiLWZjYzktNGIwOS1iN2ZhLTU3ZmM5MDhjMjBiNiJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjcwMDcvYXBpL2F1dGgiLCJzdWIiOiJmcmViZW4iLCJhdWQiOiJiYWNrc3RhZ2UiLCJpYXQiOjE2NDEyMTI1OTksImV4cCI6MTY0MTIxNjE5OSwiZW50IjpbInVzZXI6ZGVmYXVsdC9mcmViZW4iXX0.4nOTmPHPwhzaKTzikgUsHcszfcP-JamcojMnRfyfsKhyHCCEywe6uLFlvvmK5NbaX5Z7IIji-kg7bxKU58kwoQ'; + +describe('DelegatedSignInIdentity', () => { + describe('tokenToExpiryMillis', () => { + beforeEach(() => jest.useFakeTimers('modern')); + afterEach(() => jest.useRealTimers()); + + it('handles undefined', async () => { + expect(tokenToExpiryMillis(undefined)).toEqual( + DEFAULTS.defaultTokenExpiryMillis, + ); + }); + + it('handles a valid token', async () => { + jest.setSystemTime( + validBackstageTokenExpClaim * 1000 - + (3600 + DEFAULTS.tokenExpiryMarginMillis), + ); + expect(tokenToExpiryMillis(validBackstageToken)).toEqual(3600); + }); + }); + + describe('sleep', () => { + beforeEach(() => jest.useFakeTimers()); + afterEach(() => jest.useRealTimers()); + + it('normally sleeps', async () => { + const fn = jest.fn(); + sleep(100, new AbortController().signal).then(fn); + + await flushPromises(); + expect(fn).toBeCalledTimes(0); + + jest.advanceTimersByTime(99); + await flushPromises(); + expect(fn).toBeCalledTimes(0); + + jest.advanceTimersByTime(2); + await flushPromises(); + expect(fn).toBeCalledTimes(1); + }); + + it('can be aborted', async () => { + const controller = new AbortController(); + const fn = jest.fn(); + sleep(100, controller.signal).then(fn); + + jest.advanceTimersByTime(50); + await flushPromises(); + expect(fn).toBeCalledTimes(0); + + controller.abort(); + await flushPromises(); + expect(fn).toBeCalledTimes(1); + }); + + it('reuses the same controller nicely', async () => { + const controller = new AbortController(); + + for (let i = 0; i < 50; ++i) { + const fn = jest.fn(); + sleep(100, controller.signal).then(fn); + + jest.advanceTimersByTime(99); + await flushPromises(); + expect(fn).toBeCalledTimes(0); + + jest.advanceTimersByTime(2); + await flushPromises(); + expect(fn).toBeCalledTimes(1); + } + }); + }); + + describe('DelegatedSignInIdentity', () => { + beforeEach(() => jest.useFakeTimers()); + afterEach(() => jest.useRealTimers()); + + const worker = setupServer(); + setupRequestMockHandlers(worker); + + it('runs the happy path', async () => { + const getBaseUrl = jest.fn(); + const postError = jest.fn(); + const serverCalled = jest.fn(); + + function makeToken() { + const iat = Math.floor(Date.now() / 1000); + const exp = iat + 100; + return { + providerInfo: { + stuff: 1, + }, + profile: { + email: 'e', + displayName: 'd', + picture: 'p', + }, + backstageIdentity: { + id: 'i', + token: [ + 'eyJhbGciOiJFUzI1NiIsImtpZCI6ImMxNTMzNDRiLWZjYzktNGIwOS1iN2ZhLTU3ZmM5MDhjMjBiNiJ9', + btoa( + JSON.stringify({ + iss: 'http://localhost:7007/api/auth', + sub: 'user:default/freben', + aud: 'backstage', + iat, + exp, + ent: ['group:default/my-team'], + }), + ).replace(/=/g, ''), + '4nOTmPHPwhzaKTzikgUsHcszfcP-JamcojMnRfyfsKhyHCCEywe6uLFlvvmK5NbaX5Z7IIji-kg7bxKU58kwoQ', + ].join('.'), + identity: { + type: 'user', + userEntityRef: 'ue', + ownershipEntityRefs: ['oe'], + }, + }, + }; + } + + worker.events.on('request:match', serverCalled); + worker.use( + rest.get('http://example.com/api/auth/foo/refresh', (_, res, ctx) => + res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json(makeToken()), + ), + ), + ); + + const identity = new DelegatedSignInIdentity({ + provider: 'foo', + discoveryApi: { getBaseUrl }, + errorApi: { post: postError } as any, + fetchApi: { fetch }, + }); + + getBaseUrl.mockResolvedValue('http://example.com/api/auth'); + + await identity.start(); // should not throw + + expect(getBaseUrl).toBeCalledTimes(1); + expect(getBaseUrl).lastCalledWith('auth'); + expect(postError).toBeCalledTimes(0); + expect(serverCalled).toBeCalledTimes(1); + + // Use a fairly large margin (1000) since the iat and exp are clamped to + // full seconds, but the "local current time" isn't + jest.advanceTimersByTime( + 100 * 1000 - DEFAULTS.tokenExpiryMarginMillis - 1000, + ); + await flushPromises(); + expect(serverCalled).toBeCalledTimes(1); + + jest.advanceTimersByTime(1001); + await flushPromises(); + expect(serverCalled).toBeCalledTimes(2); + }); + }); +}); diff --git a/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.ts b/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.ts index 2d24796a17..92c8b34c50 100644 --- a/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.ts +++ b/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.ts @@ -25,35 +25,32 @@ import { import { ResponseError } from '@backstage/errors'; import { DelegatedSession, delegatedSessionSchema } from './types'; -const DEFAULTS = { +export const DEFAULTS = { // How often we retry a failed auth refresh call retryRefreshFrequencyMillis: 5_000, // The amount of time between token refreshes, if we fail to get an actual // value out of the exp claim - defaultTokenExpiryMillis: 30_000, + defaultTokenExpiryMillis: 60_000, // The amount of time before the actual expiry of the Backstage token, that we // shall start trying to get a new one tokenExpiryMarginMillis: 30_000, -}; +} as const; // The amount of time to wait until trying to refresh the auth session -function tokenToExpiryMillis(token: string | undefined): number { - if (typeof token !== 'string') { - return DEFAULTS.retryRefreshFrequencyMillis; +export function tokenToExpiryMillis(jwtToken: string | undefined): number { + if (typeof jwtToken !== 'string') { + return DEFAULTS.defaultTokenExpiryMillis; } - const [_header, rawPayload, _signature] = token.split('.'); + const [_header, rawPayload, _signature] = jwtToken.split('.'); const payload = JSON.parse(atob(rawPayload)); const expiresInMillis = payload.exp * 1000 - Date.now(); - return Math.max( - expiresInMillis - DEFAULTS.tokenExpiryMarginMillis, - DEFAULTS.defaultTokenExpiryMillis, - ); + return Math.max(expiresInMillis - DEFAULTS.tokenExpiryMarginMillis, 0); } // Sleeps for a given duration, unless interrupted by signal -async function sleep(durationMillis: number, signal: AbortSignal) { +export async function sleep(durationMillis: number, signal: AbortSignal) { if (!signal.aborted) { await new Promise(resolve => { const timeoutHandle = setTimeout(done, durationMillis); @@ -90,26 +87,35 @@ export class DelegatedSignInIdentity implements IdentityApi { } async start() { - // Try first refresh and bubble up any errors to the caller - await this.refresh(false); - let signalErrors = true; - let pause: number; + let pause = 0; - const refreshLoop = async () => { - while (!this.abortController.signal.aborted) { + const refreshOnce = async () => { + if (!this.abortController.signal.aborted) { try { await this.refresh(signalErrors); signalErrors = true; pause = tokenToExpiryMillis(this.session?.backstageIdentity.token); + if (pause <= 0) { + this.session = undefined; + } } catch { signalErrors = false; // Only signal first failure in a row pause = DEFAULTS.retryRefreshFrequencyMillis; } - await sleep(pause, this.abortController.signal); } }; + const refreshLoop = async () => { + while (!this.abortController.signal.aborted) { + await sleep(pause, this.abortController.signal); + await refreshOnce(); + } + }; + + // Try first refresh and bubble up any errors to the caller, then get the + // loop going behind the scenes and return + await refreshOnce(); refreshLoop(); } @@ -150,7 +156,7 @@ export class DelegatedSignInIdentity implements IdentityApi { getSession(): DelegatedSession { if (!this.session) { - throw new Error('No session available'); + throw new Error('No session available. Try reloading your browser page.'); } return this.session; } From 742c7a9929dc038c0f9cb77c640eecd4313a8e55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Tue, 4 Jan 2022 10:49:43 +0100 Subject: [PATCH 08/56] api report MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- packages/core-components/api-report.md | 10 ++++++++++ packages/core-components/src/layout/index.ts | 1 + 2 files changed, 11 insertions(+) diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index e84982e31a..bdd6f0e030 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -202,6 +202,16 @@ export type CustomProviderClassKey = 'form' | 'button'; // @public (undocumented) export function DashboardIcon(props: IconComponentProps): JSX.Element; +// @public +export const DelegatedSignInPage: ( + props: DelegatedSignInPageProps, +) => JSX.Element | null; + +// @public +export type DelegatedSignInPageProps = SignInPageProps & { + provider: string; +}; + // @public type DependencyEdge = T & { from: string; diff --git a/packages/core-components/src/layout/index.ts b/packages/core-components/src/layout/index.ts index 19cd6dfb78..f726481535 100644 --- a/packages/core-components/src/layout/index.ts +++ b/packages/core-components/src/layout/index.ts @@ -17,6 +17,7 @@ export * from './BottomLink'; export * from './Content'; export * from './ContentHeader'; +export * from './DelegatedSignInPage'; export * from './ErrorBoundary'; export * from './ErrorPage'; export * from './Header'; From 28b61f32b4d8d5ee9324c9ae801504593c2ab561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Tue, 4 Jan 2022 13:02:55 +0100 Subject: [PATCH 09/56] slim down and fetch on demand MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../DelegatedSignInIdentity.test.ts | 84 ++----- .../DelegatedSignInIdentity.ts | 208 +++++++++--------- .../DelegatedSignInPage.tsx | 3 - 3 files changed, 120 insertions(+), 175 deletions(-) diff --git a/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.test.ts b/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.test.ts index 11fdaf257e..16ce71980a 100644 --- a/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.test.ts +++ b/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.test.ts @@ -21,90 +21,35 @@ import { setupServer } from 'msw/node'; import { DEFAULTS, DelegatedSignInIdentity, - sleep, - tokenToExpiryMillis, + tokenToExpiry, } from './DelegatedSignInIdentity'; -const flushPromises = () => new Promise(setImmediate); - const validBackstageTokenExpClaim = 1641216199; const validBackstageToken = 'eyJhbGciOiJFUzI1NiIsImtpZCI6ImMxNTMzNDRiLWZjYzktNGIwOS1iN2ZhLTU3ZmM5MDhjMjBiNiJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjcwMDcvYXBpL2F1dGgiLCJzdWIiOiJmcmViZW4iLCJhdWQiOiJiYWNrc3RhZ2UiLCJpYXQiOjE2NDEyMTI1OTksImV4cCI6MTY0MTIxNjE5OSwiZW50IjpbInVzZXI6ZGVmYXVsdC9mcmViZW4iXX0.4nOTmPHPwhzaKTzikgUsHcszfcP-JamcojMnRfyfsKhyHCCEywe6uLFlvvmK5NbaX5Z7IIji-kg7bxKU58kwoQ'; describe('DelegatedSignInIdentity', () => { - describe('tokenToExpiryMillis', () => { + describe('tokenToExpiry', () => { beforeEach(() => jest.useFakeTimers('modern')); afterEach(() => jest.useRealTimers()); it('handles undefined', async () => { - expect(tokenToExpiryMillis(undefined)).toEqual( - DEFAULTS.defaultTokenExpiryMillis, + expect(tokenToExpiry(undefined)).toEqual( + new Date(Date.now() + DEFAULTS.defaultTokenExpiryMillis), ); }); it('handles a valid token', async () => { - jest.setSystemTime( - validBackstageTokenExpClaim * 1000 - - (3600 + DEFAULTS.tokenExpiryMarginMillis), + expect(tokenToExpiry(validBackstageToken)).toEqual( + new Date( + validBackstageTokenExpClaim * 1000 - DEFAULTS.tokenExpiryMarginMillis, + ), ); - expect(tokenToExpiryMillis(validBackstageToken)).toEqual(3600); - }); - }); - - describe('sleep', () => { - beforeEach(() => jest.useFakeTimers()); - afterEach(() => jest.useRealTimers()); - - it('normally sleeps', async () => { - const fn = jest.fn(); - sleep(100, new AbortController().signal).then(fn); - - await flushPromises(); - expect(fn).toBeCalledTimes(0); - - jest.advanceTimersByTime(99); - await flushPromises(); - expect(fn).toBeCalledTimes(0); - - jest.advanceTimersByTime(2); - await flushPromises(); - expect(fn).toBeCalledTimes(1); - }); - - it('can be aborted', async () => { - const controller = new AbortController(); - const fn = jest.fn(); - sleep(100, controller.signal).then(fn); - - jest.advanceTimersByTime(50); - await flushPromises(); - expect(fn).toBeCalledTimes(0); - - controller.abort(); - await flushPromises(); - expect(fn).toBeCalledTimes(1); - }); - - it('reuses the same controller nicely', async () => { - const controller = new AbortController(); - - for (let i = 0; i < 50; ++i) { - const fn = jest.fn(); - sleep(100, controller.signal).then(fn); - - jest.advanceTimersByTime(99); - await flushPromises(); - expect(fn).toBeCalledTimes(0); - - jest.advanceTimersByTime(2); - await flushPromises(); - expect(fn).toBeCalledTimes(1); - } }); }); describe('DelegatedSignInIdentity', () => { - beforeEach(() => jest.useFakeTimers()); + beforeEach(() => jest.useFakeTimers('modern')); afterEach(() => jest.useRealTimers()); const worker = setupServer(); @@ -112,7 +57,6 @@ describe('DelegatedSignInIdentity', () => { it('runs the happy path', async () => { const getBaseUrl = jest.fn(); - const postError = jest.fn(); const serverCalled = jest.fn(); function makeToken() { @@ -166,17 +110,17 @@ describe('DelegatedSignInIdentity', () => { const identity = new DelegatedSignInIdentity({ provider: 'foo', discoveryApi: { getBaseUrl }, - errorApi: { post: postError } as any, fetchApi: { fetch }, }); getBaseUrl.mockResolvedValue('http://example.com/api/auth'); await identity.start(); // should not throw - expect(getBaseUrl).toBeCalledTimes(1); expect(getBaseUrl).lastCalledWith('auth'); - expect(postError).toBeCalledTimes(0); + expect(serverCalled).toBeCalledTimes(1); + + await identity.getSessionAsync(); // no need to fetch again just yet expect(serverCalled).toBeCalledTimes(1); // Use a fairly large margin (1000) since the iat and exp are clamped to @@ -184,11 +128,11 @@ describe('DelegatedSignInIdentity', () => { jest.advanceTimersByTime( 100 * 1000 - DEFAULTS.tokenExpiryMarginMillis - 1000, ); - await flushPromises(); + await identity.getSessionAsync(); // still no need to fetch again expect(serverCalled).toBeCalledTimes(1); jest.advanceTimersByTime(1001); - await flushPromises(); + await identity.getSessionAsync(); // now the expiry has passed expect(serverCalled).toBeCalledTimes(2); }); }); diff --git a/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.ts b/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.ts index 92c8b34c50..750f9ef027 100644 --- a/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.ts +++ b/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.ts @@ -17,7 +17,6 @@ import { BackstageUserIdentity, discoveryApiRef, - errorApiRef, fetchApiRef, IdentityApi, ProfileInfo, @@ -26,8 +25,6 @@ import { ResponseError } from '@backstage/errors'; import { DelegatedSession, delegatedSessionSchema } from './types'; export const DEFAULTS = { - // How often we retry a failed auth refresh call - retryRefreshFrequencyMillis: 5_000, // The amount of time between token refreshes, if we fail to get an actual // value out of the exp claim defaultTokenExpiryMillis: 60_000, @@ -36,117 +33,99 @@ export const DEFAULTS = { tokenExpiryMarginMillis: 30_000, } as const; -// The amount of time to wait until trying to refresh the auth session -export function tokenToExpiryMillis(jwtToken: string | undefined): number { - if (typeof jwtToken !== 'string') { - return DEFAULTS.defaultTokenExpiryMillis; +// When the token expires, with some margin +export function tokenToExpiry(jwtToken: string | undefined): Date { + if (!jwtToken) { + return new Date(Date.now() + DEFAULTS.defaultTokenExpiryMillis); } const [_header, rawPayload, _signature] = jwtToken.split('.'); const payload = JSON.parse(atob(rawPayload)); - const expiresInMillis = payload.exp * 1000 - Date.now(); - return Math.max(expiresInMillis - DEFAULTS.tokenExpiryMarginMillis, 0); -} - -// Sleeps for a given duration, unless interrupted by signal -export async function sleep(durationMillis: number, signal: AbortSignal) { - if (!signal.aborted) { - await new Promise(resolve => { - const timeoutHandle = setTimeout(done, durationMillis); - signal.addEventListener('abort', done); - function done() { - clearTimeout(timeoutHandle); - signal.removeEventListener('abort', done); - resolve(); - } - }); - } + return new Date(payload.exp * 1000 - DEFAULTS.tokenExpiryMarginMillis); } type DelegatedSignInIdentityOptions = { provider: string; discoveryApi: typeof discoveryApiRef.T; fetchApi: typeof fetchApiRef.T; - errorApi: typeof errorApiRef.T; }; +type State = + | { + type: 'empty'; + } + | { + type: 'fetching'; + promise: Promise; + previous: DelegatedSession | undefined; + } + | { + type: 'active'; + session: DelegatedSession; + expiresAt: Date; + } + | { + type: 'failed'; + error: Error; + }; + /** - * An identity API that keeps itself up to date solely based on getting session - * information from a `/refresh` endpoint. + * An identity API that gets the user auth information solely based on a + * provider's `/refresh` endpoint. */ export class DelegatedSignInIdentity implements IdentityApi { private readonly options: DelegatedSignInIdentityOptions; private readonly abortController: AbortController; - private session: DelegatedSession | undefined; + private state: State; constructor(options: DelegatedSignInIdentityOptions) { this.options = options; this.abortController = new AbortController(); - this.session = undefined; + this.state = { type: 'empty' }; } async start() { - let signalErrors = true; - let pause = 0; - - const refreshOnce = async () => { - if (!this.abortController.signal.aborted) { - try { - await this.refresh(signalErrors); - signalErrors = true; - pause = tokenToExpiryMillis(this.session?.backstageIdentity.token); - if (pause <= 0) { - this.session = undefined; - } - } catch { - signalErrors = false; // Only signal first failure in a row - pause = DEFAULTS.retryRefreshFrequencyMillis; - } - } - }; - - const refreshLoop = async () => { - while (!this.abortController.signal.aborted) { - await sleep(pause, this.abortController.signal); - await refreshOnce(); - } - }; - - // Try first refresh and bubble up any errors to the caller, then get the - // loop going behind the scenes and return - await refreshOnce(); - refreshLoop(); + // Try to make a first fetch, bubble up any errors to the caller + await this.getSessionAsync(); } /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getUserId} */ getUserId(): string { - return this.getSession().backstageIdentity.id; + const session = this.getSessionSync(); + return session.backstageIdentity.id; } /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getIdToken} */ async getIdToken(): Promise { - return this.getSession().backstageIdentity.token; + const session = await this.getSessionAsync(); + return session.backstageIdentity.token; } /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getProfile} */ getProfile(): ProfileInfo { - return this.getSession().profile; + const session = this.getSessionSync(); + return session.profile; } /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getProfileInfo} */ async getProfileInfo(): Promise { - return this.getSession().profile; + const session = await this.getSessionAsync(); + return session.profile; } /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getBackstageIdentity} */ async getBackstageIdentity(): Promise { - return this.getSession().backstageIdentity.identity; + const session = await this.getSessionAsync(); + return session.backstageIdentity.identity; } /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getCredentials} */ async getCredentials(): Promise<{ token?: string | undefined }> { - return { token: this.getSession().backstageIdentity.token }; + const session = await this.getSessionAsync(); + return { + token: session.backstageIdentity.token, + }; } /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.signOut} */ @@ -154,46 +133,71 @@ export class DelegatedSignInIdentity implements IdentityApi { this.abortController.abort(); } - getSession(): DelegatedSession { - if (!this.session) { - throw new Error('No session available. Try reloading your browser page.'); + getSessionSync(): DelegatedSession { + if (this.state.type === 'active') { + return this.state.session; + } else if (this.state.type === 'fetching' && this.state.previous) { + return this.state.previous; } - return this.session; + throw new Error('No session available. Try reloading your browser page.'); } - async refresh(notifyErrors: boolean) { - try { - const baseUrl = await this.options.discoveryApi.getBaseUrl('auth'); - - const response = await this.options.fetchApi.fetch( - `${baseUrl}/${this.options.provider}/refresh`, - { - signal: this.abortController.signal, - headers: { 'x-requested-with': 'XMLHttpRequest' }, - credentials: 'include', - }, - ); - - if (!response.ok) { - throw await ResponseError.fromResponse(response); - } - - const session = delegatedSessionSchema.parse(await response.json()); - this.session = session; - } catch (e) { - if (this.abortController.signal.aborted) { - return; - } - - if (notifyErrors) { - this.options.errorApi.post( - new Error( - `Failed to refresh browser session, ${e}. Try reloading your browser page.`, - ), - ); - } - - throw e; + async getSessionAsync(): Promise { + if (this.state.type === 'fetching') { + return this.state.promise; + } else if ( + this.state.type === 'active' && + new Date() < this.state.expiresAt + ) { + return this.state.session; } + + const previous = + this.state.type === 'active' ? this.state.session : undefined; + + const promise = this.fetchSession().then( + session => { + this.state = { + type: 'active', + session, + expiresAt: tokenToExpiry(session.backstageIdentity.token), + }; + return session; + }, + error => { + this.state = { + type: 'failed', + error, + }; + throw error; + }, + ); + + this.state = { + type: 'fetching', + promise, + previous, + }; + + return promise; + } + + async fetchSession(): Promise { + const baseUrl = await this.options.discoveryApi.getBaseUrl('auth'); + + const response = await this.options.fetchApi.fetch( + `${baseUrl}/${this.options.provider}/refresh`, + { + signal: this.abortController.signal, + headers: { 'x-requested-with': 'XMLHttpRequest' }, + credentials: 'include', + }, + ); + + if (!response.ok) { + throw await ResponseError.fromResponse(response); + } + + return delegatedSessionSchema.parse(await response.json()); } } diff --git a/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInPage.tsx b/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInPage.tsx index 54cc0495fd..0337e3122d 100644 --- a/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInPage.tsx +++ b/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInPage.tsx @@ -16,7 +16,6 @@ import { discoveryApiRef, - errorApiRef, fetchApiRef, SignInPageProps, useApi, @@ -58,12 +57,10 @@ export type DelegatedSignInPageProps = SignInPageProps & { export const DelegatedSignInPage = (props: DelegatedSignInPageProps) => { const discoveryApi = useApi(discoveryApiRef); const fetchApi = useApi(fetchApiRef); - const errorApi = useApi(errorApiRef); const { loading, error } = useAsync(async () => { const identity = new DelegatedSignInIdentity({ provider: props.provider, - errorApi, discoveryApi, fetchApi, }); From 63fa8f83715b9a998d6ee6deb8af170cc23f8089 Mon Sep 17 00:00:00 2001 From: Colton Padden Date: Tue, 4 Jan 2022 16:24:06 -0500 Subject: [PATCH 10/56] move deprecation description key mapping into filterByVisibility Signed-off-by: Colton Padden --- .../config-loader/src/lib/schema/collect.ts | 2 +- .../src/lib/schema/compile.test.ts | 12 ++-- .../config-loader/src/lib/schema/compile.ts | 70 ++++++++++++------- .../src/lib/schema/filtering.test.ts | 51 ++++++++------ .../config-loader/src/lib/schema/filtering.ts | 46 ++++-------- .../config-loader/src/lib/schema/load.test.ts | 8 --- packages/config-loader/src/lib/schema/load.ts | 10 +-- .../config-loader/src/lib/schema/types.ts | 4 +- packages/config/src/reader.ts | 19 ++--- 9 files changed, 105 insertions(+), 117 deletions(-) diff --git a/packages/config-loader/src/lib/schema/collect.ts b/packages/config-loader/src/lib/schema/collect.ts index aa3202a1b5..a05796139b 100644 --- a/packages/config-loader/src/lib/schema/collect.ts +++ b/packages/config-loader/src/lib/schema/collect.ts @@ -182,7 +182,7 @@ function compileTsSchemas(paths: string[]) { program, // All schemas should export a `Config` symbol 'Config', - // This enables usage of @visibility and @deprecated is doc comments + // This enables usage of @visibility and @deprecated in doc comments { required: true, validationKeywords: ['visibility', 'deprecated'], diff --git a/packages/config-loader/src/lib/schema/compile.test.ts b/packages/config-loader/src/lib/schema/compile.test.ts index 7615fa80f5..7b7db87c8f 100644 --- a/packages/config-loader/src/lib/schema/compile.test.ts +++ b/packages/config-loader/src/lib/schema/compile.test.ts @@ -40,7 +40,7 @@ describe('compileConfigSchemas', () => { ], visibilityByDataPath: new Map(), visibilityBySchemaPath: new Map(), - deprecationBySchemaPath: new Map(), + deprecationByDataPath: new Map(), }); expect(validate([{ data: { b: 'b' }, context: 'test' }])).toEqual({ errors: [ @@ -54,7 +54,7 @@ describe('compileConfigSchemas', () => { ], visibilityByDataPath: new Map(), visibilityBySchemaPath: new Map(), - deprecationBySchemaPath: new Map(), + deprecationByDataPath: new Map(), }); }); @@ -114,7 +114,7 @@ describe('compileConfigSchemas', () => { '/properties/d/items': 'frontend', }), ), - deprecationBySchemaPath: new Map(), + deprecationByDataPath: new Map(), }); }); @@ -160,10 +160,10 @@ describe('compileConfigSchemas', () => { { data: { a: 'a', b: 'b', c: 'c', d: ['d'] }, context: 'test' }, ]), ).toEqual({ - deprecationBySchemaPath: new Map( + deprecationByDataPath: new Map( Object.entries({ - '/properties/a': 'deprecation reason for a', - '/properties/b': 'deprecation reason for b', + '/a': 'deprecation reason for a', + '/b': 'deprecation reason for b', }), ), visibilityByDataPath: new Map(), diff --git a/packages/config-loader/src/lib/schema/compile.ts b/packages/config-loader/src/lib/schema/compile.ts index 6dcd4713f5..b7f705751e 100644 --- a/packages/config-loader/src/lib/schema/compile.ts +++ b/packages/config-loader/src/lib/schema/compile.ts @@ -40,6 +40,7 @@ export function compileConfigSchemas( // output during validation. We work around this by having this extra piece // of state that we reset before each validation. const visibilityByDataPath = new Map(); + const deprecationByDataPath = new Map(); const ajv = new Ajv({ allErrors: true, @@ -47,28 +48,48 @@ export function compileConfigSchemas( schemas: { 'https://backstage.io/schema/config-v1': true, }, - }).addKeyword({ - keyword: 'visibility', - metaSchema: { - type: 'string', - enum: CONFIG_VISIBILITIES, - }, - compile(visibility: ConfigVisibility) { - return (_data, context) => { - if (context?.dataPath === undefined) { - return false; - } - if (visibility && visibility !== 'backend') { + }) + .addKeyword({ + keyword: 'visibility', + metaSchema: { + type: 'string', + enum: CONFIG_VISIBILITIES, + }, + compile(visibility: ConfigVisibility) { + return (_data, context) => { + if (context?.dataPath === undefined) { + return false; + } + if (visibility && visibility !== 'backend') { + const normalizedPath = context.dataPath.replace( + /\['?(.*?)'?\]/g, + (_, segment) => `/${segment}`, + ); + visibilityByDataPath.set(normalizedPath, visibility); + } + return true; + }; + }, + }) + .removeKeyword('deprecated') // remove `deprecated` keyword so that we can implement our own compiler + .addKeyword({ + keyword: 'deprecated', + metaSchema: { type: 'string' }, + compile(deprecationDescription: string) { + return (_data, context) => { + if (context?.dataPath === undefined) { + return false; + } const normalizedPath = context.dataPath.replace( /\['?(.*?)'?\]/g, (_, segment) => `/${segment}`, ); - visibilityByDataPath.set(normalizedPath, visibility); - } - return true; - }; - }, - }); + // create mapping of deprecation description and data path of property + deprecationByDataPath.set(normalizedPath, deprecationDescription); + return true; + }; + }, + }); for (const schema of schemas) { try { @@ -79,14 +100,8 @@ export function compileConfigSchemas( } const merged = mergeConfigSchemas(schemas.map(_ => _.value)); - const validate = ajv.compile(merged); - const deprecationBySchemaPath = new Map(); - traverse(merged, (schema, path) => { - if ('deprecated' in schema) { - deprecationBySchemaPath.set(path, schema.deprecated); - } - }); + const validate = ajv.compile(merged); const visibilityBySchemaPath = new Map(); traverse(merged, (schema, path) => { @@ -101,19 +116,20 @@ export function compileConfigSchemas( visibilityByDataPath.clear(); const valid = validate(config); + if (!valid) { return { errors: validate.errors ?? [], visibilityByDataPath: new Map(visibilityByDataPath), visibilityBySchemaPath, - deprecationBySchemaPath, + deprecationByDataPath, }; } return { visibilityByDataPath: new Map(visibilityByDataPath), visibilityBySchemaPath, - deprecationBySchemaPath, + deprecationByDataPath, }; }; } diff --git a/packages/config-loader/src/lib/schema/filtering.test.ts b/packages/config-loader/src/lib/schema/filtering.test.ts index 2324bebc9d..df06975c9f 100644 --- a/packages/config-loader/src/lib/schema/filtering.test.ts +++ b/packages/config-loader/src/lib/schema/filtering.test.ts @@ -16,11 +16,7 @@ import { JsonObject } from '@backstage/types'; import { ConfigVisibility } from './types'; -import { - filterByVisibility, - filterErrorsByVisibility, - filterByDeprecated, -} from './filtering'; +import { filterByVisibility, filterErrorsByVisibility } from './filtering'; const data = { arr: ['f', 'b', 's'], @@ -70,8 +66,8 @@ const visibility = new Map( const deprecations = new Map( Object.entries({ - '/properties/arr': 'deprecated array', - '/properties/objB/properties/never': 'deprecated nested property', + '/arr': 'deprecated array', + '/objB/never': 'deprecated nested property', }), ); @@ -196,9 +192,34 @@ describe('filterByVisibility', () => { [['frontend', 'backend', 'secret'], { data, filteredKeys: [] }], ])('should filter correctly with %p', (filter, expected) => { expect( - filterByVisibility(data, filter, visibility, undefined, true), + filterByVisibility( + data, + filter, + visibility, + deprecations, + undefined, + true, + false, + ), ).toEqual(expected); }); + + it('should include deprecated keys regardless of visibility', () => { + expect( + filterByVisibility( + data, + [], + visibility, + deprecations, + undefined, + true, + true, + ).deprecatedKeys, + ).toEqual([ + { key: 'arr', description: 'deprecated array' }, + { key: 'objB.never', description: 'deprecated nested property' }, + ]); + }); }); describe('filterErrorsByVisibility', () => { @@ -392,17 +413,3 @@ describe('filterErrorsByVisibility', () => { ]); }); }); - -describe('filterByDeprecated', () => { - it('should allow empty list of deprecations', () => { - expect(filterByDeprecated(data, new Map())).toEqual({ deprecatedKeys: [] }); - }); - it('should return a list of deprecated properties', () => { - expect(filterByDeprecated(data, deprecations)).toEqual({ - deprecatedKeys: [ - { key: 'arr', description: 'deprecated array' }, - { key: 'objB.never', description: 'deprecated nested property' }, - ], - }); - }); -}); diff --git a/packages/config-loader/src/lib/schema/filtering.ts b/packages/config-loader/src/lib/schema/filtering.ts index f955343066..11ee4cb47f 100644 --- a/packages/config-loader/src/lib/schema/filtering.ts +++ b/packages/config-loader/src/lib/schema/filtering.ts @@ -23,36 +23,6 @@ import { ValidationError, } from './types'; -/** - * This filters data by deprecation status to only include those which have been deprecated - * - * @param data - configuration data - * @param deprecationBySchemaPath - mapping of schema path to deprecation description - * @returns deprecated configuration keys with their deprecation description - */ -export function filterByDeprecated( - data: JsonObject, - deprecationBySchemaPath: Map, - withDeprecatedKeys: boolean = true, -): { deprecatedKeys: { key: string; description: string }[] } { - const deprecatedKeys = new Array<{ key: string; description: string }>(); - if (!withDeprecatedKeys) { - return { deprecatedKeys }; - } - - deprecationBySchemaPath.forEach((desc, schemaPath) => { - // convert schema path to object path (/properties/techdocs/properties/storageUrl -> techdocs.storageUrl) - const propertyPath = schemaPath - .replace(/^\/properties\//, '') // remove leading `/properties/` entirely - .replace(/\/properties\//g, '.'); // replace all other `/properties/` with a `.` - if (has(data, propertyPath)) { - deprecatedKeys.push({ key: propertyPath, description: desc }); - } - }); - - return { deprecatedKeys }; -} - /** * This filters data by visibility by discovering the visibility of each * value, and then only keeping the ones that are specified in `includeVisibilities`. @@ -61,10 +31,17 @@ export function filterByVisibility( data: JsonObject, includeVisibilities: ConfigVisibility[], visibilityByDataPath: Map, + deprecationByDataPath: Map, transformFunc?: TransformFunc, withFilteredKeys?: boolean, -): { data: JsonObject; filteredKeys?: string[] } { + withDeprecatedKeys?: boolean, +): { + data: JsonObject; + filteredKeys?: string[]; + deprecatedKeys?: { key: string; description: string }[]; +} { const filteredKeys = new Array(); + const deprecatedKeys = new Array<{ key: string; description: string }>(); function transform( jsonVal: JsonValue, @@ -75,6 +52,12 @@ export function filterByVisibility( visibilityByDataPath.get(visibilityPath) ?? DEFAULT_CONFIG_VISIBILITY; const isVisible = includeVisibilities.includes(visibility); + // deprecated keys are added regardless of visibility indicator + const deprecation = deprecationByDataPath.get(visibilityPath); + if (deprecation) { + deprecatedKeys.push({ key: filterPath, description: deprecation }); + } + if (typeof jsonVal !== 'object') { if (isVisible) { if (transformFunc) { @@ -140,6 +123,7 @@ export function filterByVisibility( return { filteredKeys: withFilteredKeys ? filteredKeys : undefined, + deprecatedKeys: withDeprecatedKeys ? deprecatedKeys : undefined, data: (transform(data, '', '') as JsonObject) ?? {}, }; } diff --git a/packages/config-loader/src/lib/schema/load.test.ts b/packages/config-loader/src/lib/schema/load.test.ts index a2f1df8d5f..8510ccb1d8 100644 --- a/packages/config-loader/src/lib/schema/load.test.ts +++ b/packages/config-loader/src/lib/schema/load.test.ts @@ -65,7 +65,6 @@ describe('loadConfigSchema', () => { { data: { key1: 'a' }, context: 'test', - deprecatedKeys: [], }, ]); expect( @@ -79,7 +78,6 @@ describe('loadConfigSchema', () => { data: { key1: 'X' }, context: 'test', filteredKeys: ['key2'], - deprecatedKeys: [], }, ]); expect( @@ -92,7 +90,6 @@ describe('loadConfigSchema', () => { data: { key1: 'X', key2: 'X' }, context: 'test', filteredKeys: [], - deprecatedKeys: [], }, ]); @@ -103,7 +100,6 @@ describe('loadConfigSchema', () => { { data: { key1: 'a' }, context: 'test', - deprecatedKeys: [], }, ]); expect(() => @@ -152,7 +148,6 @@ describe('loadConfigSchema', () => { { data: { key1: 'a' }, context: 'test', - deprecatedKeys: [], }, ]); expect(() => schema.process(configs, { visibility: ['secret'] })).toThrow( @@ -205,7 +200,6 @@ describe('loadConfigSchema', () => { { data: { nested: [{}] }, context: 'test', - deprecatedKeys: [], }, ]); expect(() => schema.process(mkConfig({ y: 1 }))).toThrow( @@ -222,7 +216,6 @@ describe('loadConfigSchema', () => { { data: { nested: [{}] }, context: 'test', - deprecatedKeys: [], }, ]); expect( @@ -231,7 +224,6 @@ describe('loadConfigSchema', () => { { data: { nested: [{ y: 'aaa' }] }, context: 'test', - deprecatedKeys: [], }, ]); expect(() => diff --git a/packages/config-loader/src/lib/schema/load.ts b/packages/config-loader/src/lib/schema/load.ts index 303fdfade9..9eac629ee3 100644 --- a/packages/config-loader/src/lib/schema/load.ts +++ b/packages/config-loader/src/lib/schema/load.ts @@ -109,12 +109,9 @@ export async function loadConfigSchema( data, visibility, result.visibilityByDataPath, + result.deprecationByDataPath, valueTransform, withFilteredKeys, - ), - ...filterByDeprecated( - data, - result.deprecationBySchemaPath, withDeprecatedKeys, ), })); @@ -125,12 +122,9 @@ export async function loadConfigSchema( data, Array.from(CONFIG_VISIBILITIES), result.visibilityByDataPath, + result.deprecationByDataPath, valueTransform, withFilteredKeys, - ), - ...filterByDeprecated( - data, - result.deprecationBySchemaPath, withDeprecatedKeys, ), })); diff --git a/packages/config-loader/src/lib/schema/types.ts b/packages/config-loader/src/lib/schema/types.ts index 76cc337f83..75993b3c78 100644 --- a/packages/config-loader/src/lib/schema/types.ts +++ b/packages/config-loader/src/lib/schema/types.ts @@ -85,9 +85,9 @@ type ValidationResult = { /** * The deprecated options that were discovered during validation. * - * The path in the key uses the form `/properties//items/additionalProperties/` + * The path in the key uses the form `////` */ - deprecationBySchemaPath: Map; + deprecationByDataPath: Map; }; /** diff --git a/packages/config/src/reader.ts b/packages/config/src/reader.ts index 5c34b215ab..d85ea6f482 100644 --- a/packages/config/src/reader.ts +++ b/packages/config/src/reader.ts @@ -87,20 +87,15 @@ export class ConfigReader implements Config { const reader = new ConfigReader(data, context, previousReader); reader.filteredKeys = filteredKeys; - // TODO(cmpadden) introduce `deprecatedKeys` and `notifiedDeprecatedKeys` & use logger + // TODO(cmpadden) `withDeprecatedKeys` is defaulting to false on app start if (deprecatedKeys) { for (const { key, description } of deprecatedKeys) { - if (description) { - // eslint-disable-next-line no-console - console.warn( - `The configuration key '${key}' is deprecated and may be removed soon. (reason: ${description})`, - ); - } else { - // eslint-disable-next-line no-console - console.warn( - `The configuration key '${key}' is deprecated and may be removed soon.`, - ); - } + // eslint-disable-next-line no-console + console.warn( + `The configuration key '${key}' of ${context} is deprecated and may be removed soon. ${ + description || '' + }`, + ); } } From 6e34e2cfbfbd83aa61ec184a78374e1c4220ca96 Mon Sep 17 00:00:00 2001 From: Colton Padden Date: Tue, 4 Jan 2022 16:29:28 -0500 Subject: [PATCH 11/56] Add `backstage-cli config:check --deprecated` to list deprecated settings Signed-off-by: Colton Padden --- .changeset/long-clouds-rest.md | 12 ++++++++++++ docs/local-dev/cli-commands.md | 1 + packages/cli/src/commands/config/validate.ts | 1 + packages/cli/src/commands/index.ts | 1 + packages/cli/src/lib/config.ts | 2 ++ 5 files changed, 17 insertions(+) create mode 100644 .changeset/long-clouds-rest.md diff --git a/.changeset/long-clouds-rest.md b/.changeset/long-clouds-rest.md new file mode 100644 index 0000000000..701be91536 --- /dev/null +++ b/.changeset/long-clouds-rest.md @@ -0,0 +1,12 @@ +--- +'@backstage/cli': patch +--- + +Introduce `--deprecated` option to `config:check` to log all deprecated app configuration properties + +```sh +$ yarn backstage-cli config:check --lax --deprecated +config:check --lax --deprecated +Loaded config from app-config.yaml +The configuration key 'catalog.processors.githubOrg' of app-config.yaml is deprecated and may be removed soon. Configure a GitHub integration instead. +``` diff --git a/docs/local-dev/cli-commands.md b/docs/local-dev/cli-commands.md index 412e3c4598..c65fc30da6 100644 --- a/docs/local-dev/cli-commands.md +++ b/docs/local-dev/cli-commands.md @@ -556,6 +556,7 @@ Options: --package <name> Only load config schema that applies to the given package --lax Do not require environment variables to be set --frontend Only validate the frontend configuration + --deprecated List all deprecated configuration settings --config <path> Config files to load instead of app-config.yaml (default: []) -h, --help display help for command ``` diff --git a/packages/cli/src/commands/config/validate.ts b/packages/cli/src/commands/config/validate.ts index 2d3ce60366..8d528b8300 100644 --- a/packages/cli/src/commands/config/validate.ts +++ b/packages/cli/src/commands/config/validate.ts @@ -23,5 +23,6 @@ export default async (cmd: Command) => { fromPackage: cmd.package, mockEnv: cmd.lax, fullVisibility: !cmd.frontend, + withDeprecatedKeys: cmd.deprecated, }); }; diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index bef5dfc285..49e700ac1e 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -193,6 +193,7 @@ export function registerCommands(program: CommanderStatic) { ) .option('--lax', 'Do not require environment variables to be set') .option('--frontend', 'Only validate the frontend configuration') + .option('--deprecated', 'Output deprecated configuration settings') .option(...configOption) .description( 'Validate that the given configuration loads and matches schema', diff --git a/packages/cli/src/lib/config.ts b/packages/cli/src/lib/config.ts index 986e409e58..c24021fd0b 100644 --- a/packages/cli/src/lib/config.ts +++ b/packages/cli/src/lib/config.ts @@ -28,6 +28,7 @@ type Options = { fromPackage?: string; mockEnv?: boolean; withFilteredKeys?: boolean; + withDeprecatedKeys?: boolean; fullVisibility?: boolean; }; @@ -82,6 +83,7 @@ export async function loadCliConfig(options: Options) { ? ['frontend', 'backend', 'secret'] : ['frontend'], withFilteredKeys: options.withFilteredKeys, + withDeprecatedKeys: options.withDeprecatedKeys, }); const frontendConfig = ConfigReader.fromConfigs(frontendAppConfigs); From f9c5841c801a1a543c61d8acc81befbb7aa3ae1c Mon Sep 17 00:00:00 2001 From: Colton Padden Date: Tue, 4 Jan 2022 19:33:42 -0500 Subject: [PATCH 12/56] remove deleted artifacts of filterByDeprecated Signed-off-by: Colton Padden --- packages/config-loader/package.json | 1 - packages/config-loader/src/lib/schema/filtering.ts | 1 - packages/config-loader/src/lib/schema/load.ts | 6 +----- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index 2ecea8e843..d909cde58c 100644 --- a/packages/config-loader/package.json +++ b/packages/config-loader/package.json @@ -41,7 +41,6 @@ "json-schema": "^0.4.0", "json-schema-merge-allof": "^0.8.1", "json-schema-traverse": "^1.0.0", - "lodash": "^4.17.21", "node-fetch": "^2.6.1", "typescript-json-schema": "^0.52.0", "yaml": "^1.9.2", diff --git a/packages/config-loader/src/lib/schema/filtering.ts b/packages/config-loader/src/lib/schema/filtering.ts index 11ee4cb47f..2855979b1f 100644 --- a/packages/config-loader/src/lib/schema/filtering.ts +++ b/packages/config-loader/src/lib/schema/filtering.ts @@ -15,7 +15,6 @@ */ import { JsonObject, JsonValue } from '@backstage/types'; -import { has } from 'lodash'; import { ConfigVisibility, DEFAULT_CONFIG_VISIBILITY, diff --git a/packages/config-loader/src/lib/schema/load.ts b/packages/config-loader/src/lib/schema/load.ts index 9eac629ee3..aa7ed06305 100644 --- a/packages/config-loader/src/lib/schema/load.ts +++ b/packages/config-loader/src/lib/schema/load.ts @@ -18,11 +18,7 @@ import { AppConfig } from '@backstage/config'; import { JsonObject } from '@backstage/types'; import { compileConfigSchemas } from './compile'; import { collectConfigSchemas } from './collect'; -import { - filterByVisibility, - filterErrorsByVisibility, - filterByDeprecated, -} from './filtering'; +import { filterByVisibility, filterErrorsByVisibility } from './filtering'; import { ValidationError, ConfigSchema, From a505347140e3091915c2a7dfbf4dcb202c835734 Mon Sep 17 00:00:00 2001 From: Colton Padden Date: Wed, 5 Jan 2022 14:17:11 -0500 Subject: [PATCH 13/56] enable withDeprecatedKeys in schema process for backend-common and app-backend Signed-off-by: Colton Padden --- packages/backend-common/src/config.ts | 5 ++++- packages/config/src/reader.ts | 1 - plugins/app-backend/src/lib/config.ts | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/backend-common/src/config.ts b/packages/backend-common/src/config.ts index 399898cfc4..8e0c05b86e 100644 --- a/packages/backend-common/src/config.ts +++ b/packages/backend-common/src/config.ts @@ -38,7 +38,10 @@ const updateRedactionList = ( configs: AppConfig[], logger: Logger, ) => { - const secretAppConfigs = schema.process(configs, { visibility: ['secret'] }); + const secretAppConfigs = schema.process(configs, { + visibility: ['secret'], + withDeprecatedKeys: true, + }); const secretConfig = ConfigReader.fromConfigs(secretAppConfigs); const values = new Set(); const data = secretConfig.get(); diff --git a/packages/config/src/reader.ts b/packages/config/src/reader.ts index d85ea6f482..b4bbf0722e 100644 --- a/packages/config/src/reader.ts +++ b/packages/config/src/reader.ts @@ -87,7 +87,6 @@ export class ConfigReader implements Config { const reader = new ConfigReader(data, context, previousReader); reader.filteredKeys = filteredKeys; - // TODO(cmpadden) `withDeprecatedKeys` is defaulting to false on app start if (deprecatedKeys) { for (const { key, description } of deprecatedKeys) { // eslint-disable-next-line no-console diff --git a/plugins/app-backend/src/lib/config.ts b/plugins/app-backend/src/lib/config.ts index c37dc34dcc..6959253336 100644 --- a/plugins/app-backend/src/lib/config.ts +++ b/plugins/app-backend/src/lib/config.ts @@ -91,7 +91,7 @@ export async function readConfigs(options: ReadOptions): Promise { const frontendConfigs = await schema.process( [{ data: config.get() as JsonObject, context: 'app' }], - { visibility: ['frontend'] }, + { visibility: ['frontend'], withDeprecatedKeys: true }, ); appConfigs.push(...frontendConfigs); } catch (error) { From f685e1398f857b129f5ff3402883ba31e12f3be1 Mon Sep 17 00:00:00 2001 From: Colton Padden Date: Wed, 5 Jan 2022 14:46:39 -0500 Subject: [PATCH 14/56] add changeset for deprecation warning feature Signed-off-by: Colton Padden --- .changeset/light-trainers-allow.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .changeset/light-trainers-allow.md diff --git a/.changeset/light-trainers-allow.md b/.changeset/light-trainers-allow.md new file mode 100644 index 0000000000..0ea13cd19e --- /dev/null +++ b/.changeset/light-trainers-allow.md @@ -0,0 +1,22 @@ +--- +'@backstage/backend-common': patch +'@backstage/config': patch +'@backstage/config-loader': patch +'@backstage/plugin-app-backend': patch +--- + +Loading of app configurations now reference the `@deprecated` construct from +JSDoc to determine if a property in-use has been deprecated. Users are notified +of deprecated keys in the format: + +```txt +The configuration key 'catalog.processors.githubOrg' of app-config.yaml is deprecated and may be removed soon. Configure a GitHub integration instead. +``` + +When the `withDeprecatedKeys` option is set to `true` in the `process` method +of `loadConfigSchema`, the user will be notified that deprecated keys have been +identified in their app configuration. + +The `backend-common` and `plugin-app-backend` packages have been updated to set +`withDeprecatedKeys` to true so that users are notified of deprecated settings +by default. From 19f0f9350480b471160d7cb77be630e831332dca Mon Sep 17 00:00:00 2001 From: goenning Date: Fri, 7 Jan 2022 10:25:42 +0000 Subject: [PATCH 15/56] log errors when tech insights throws an error Signed-off-by: goenning --- .changeset/great-points-design.md | 5 ++++ .../src/service/fact/FactRetrieverEngine.ts | 28 +++++++++++++------ 2 files changed, 24 insertions(+), 9 deletions(-) create mode 100644 .changeset/great-points-design.md diff --git a/.changeset/great-points-design.md b/.changeset/great-points-design.md new file mode 100644 index 0000000000..cdc24c8f81 --- /dev/null +++ b/.changeset/great-points-design.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-tech-insights-backend': patch +--- + +log errors on tech insights fact retriever diff --git a/plugins/tech-insights-backend/src/service/fact/FactRetrieverEngine.ts b/plugins/tech-insights-backend/src/service/fact/FactRetrieverEngine.ts index 11fd0d29b8..17eeab2a61 100644 --- a/plugins/tech-insights-backend/src/service/fact/FactRetrieverEngine.ts +++ b/plugins/tech-insights-backend/src/service/fact/FactRetrieverEngine.ts @@ -16,6 +16,7 @@ import { FactRetriever, FactRetrieverContext, + TechInsightFact, TechInsightsStore, } from '@backstage/plugin-tech-insights-node'; import { FactRetrieverRegistry } from './FactRetrieverRegistry'; @@ -108,15 +109,24 @@ export class FactRetrieverEngine { this.logger.info( `Retrieving facts for fact retriever ${factRetriever.id}`, ); - const facts = await factRetriever.handler({ - ...this.factRetrieverContext, - entityFilter: factRetriever.entityFilter, - }); - if (this.logger.isDebugEnabled()) { - this.logger.debug( - `Retrieved ${facts.length} facts for fact retriever ${ - factRetriever.id - } in ${duration(startTimestamp)}`, + + let facts: TechInsightFact[] = []; + try { + facts = await factRetriever.handler({ + ...this.factRetrieverContext, + entityFilter: factRetriever.entityFilter, + }); + if (this.logger.isDebugEnabled()) { + this.logger.debug( + `Retrieved ${facts.length} facts for fact retriever ${ + factRetriever.id + } in ${duration(startTimestamp)}`, + ); + } + } catch (e) { + this.logger.error( + `Failed to retrieve facts for retriever ${factRetriever.id}`, + e, ); } From 97dc62c83a6b1d7a4cc4d2f6301ba9d7315a9d1a Mon Sep 17 00:00:00 2001 From: goenning Date: Fri, 7 Jan 2022 10:29:34 +0000 Subject: [PATCH 16/56] log errors when tech insights throws an error Signed-off-by: goenning --- .changeset/great-points-design.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/great-points-design.md b/.changeset/great-points-design.md index cdc24c8f81..7ce22b1bac 100644 --- a/.changeset/great-points-design.md +++ b/.changeset/great-points-design.md @@ -2,4 +2,4 @@ '@backstage/plugin-tech-insights-backend': patch --- -log errors on tech insights fact retriever +Catch errors from a fact retriever and log them. From fb33739fbe3984f0cc00f2c90528dc28649f9d33 Mon Sep 17 00:00:00 2001 From: Nigel Wright Date: Mon, 10 Jan 2022 08:16:21 +1300 Subject: [PATCH 17/56] updated integration instructions Signed-off-by: Nigel Wright --- docs/integrations/aws-s3/discovery.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/integrations/aws-s3/discovery.md b/docs/integrations/aws-s3/discovery.md index 656cb9f7b3..5895ab453e 100644 --- a/docs/integrations/aws-s3/discovery.md +++ b/docs/integrations/aws-s3/discovery.md @@ -27,9 +27,9 @@ catalog: Note the `s3-discovery` type, as this is not a regular `url` processor. -As this processor is not one of the default providers, you will also need to add the below: +As this processor is not one of the default providers, you will also need to add the below to `packages/backend/src/plugins/catalog.ts`: -```javascript +```ts /* packages/backend/src/plugins/catalog.ts */ import { AwsS3DiscoveryProcessor} from '@backstage/plugin-catalog-backend'; From 5de4482b44dc22b70b647694a44dfe63d37014e7 Mon Sep 17 00:00:00 2001 From: Nigel Wright Date: Tue, 11 Jan 2022 09:16:25 +1300 Subject: [PATCH 18/56] chore: cleaned up markdown with prettier Signed-off-by: Nigel Wright --- docs/integrations/aws-s3/discovery.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/integrations/aws-s3/discovery.md b/docs/integrations/aws-s3/discovery.md index 5895ab453e..545a578e63 100644 --- a/docs/integrations/aws-s3/discovery.md +++ b/docs/integrations/aws-s3/discovery.md @@ -27,15 +27,15 @@ catalog: Note the `s3-discovery` type, as this is not a regular `url` processor. -As this processor is not one of the default providers, you will also need to add the below to `packages/backend/src/plugins/catalog.ts`: +As this processor is not one of the default providers, you will also need to add +the below to `packages/backend/src/plugins/catalog.ts`: ```ts /* packages/backend/src/plugins/catalog.ts */ - -import { AwsS3DiscoveryProcessor} from '@backstage/plugin-catalog-backend'; +import { AwsS3DiscoveryProcessor } from '@backstage/plugin-catalog-backend'; const builder = await CatalogBuilder.create(env); /** ... other processors ... */ -builder.addProcessor(new AwsS3DiscoveryProcessor(env.reader)) +builder.addProcessor(new AwsS3DiscoveryProcessor(env.reader)); ``` From 811fb9cf9ca1c31ff8a3cad89ae965ea62314191 Mon Sep 17 00:00:00 2001 From: goenning Date: Tue, 11 Jan 2022 09:55:04 +0000 Subject: [PATCH 19/56] remove this.logger.isDebugEnabled call Signed-off-by: goenning --- .../src/service/fact/FactRetrieverEngine.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/plugins/tech-insights-backend/src/service/fact/FactRetrieverEngine.ts b/plugins/tech-insights-backend/src/service/fact/FactRetrieverEngine.ts index 17eeab2a61..4e9d4c41b2 100644 --- a/plugins/tech-insights-backend/src/service/fact/FactRetrieverEngine.ts +++ b/plugins/tech-insights-backend/src/service/fact/FactRetrieverEngine.ts @@ -116,13 +116,11 @@ export class FactRetrieverEngine { ...this.factRetrieverContext, entityFilter: factRetriever.entityFilter, }); - if (this.logger.isDebugEnabled()) { - this.logger.debug( - `Retrieved ${facts.length} facts for fact retriever ${ - factRetriever.id - } in ${duration(startTimestamp)}`, - ); - } + this.logger.debug( + `Retrieved ${facts.length} facts for fact retriever ${ + factRetriever.id + } in ${duration(startTimestamp)}`, + ); } catch (e) { this.logger.error( `Failed to retrieve facts for retriever ${factRetriever.id}`, From bc199d884312f86477ce5f7dd14d8699725d0b55 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jan 2022 07:14:48 +0000 Subject: [PATCH 20/56] build(deps): bump follow-redirects from 1.14.6 to 1.14.7 Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.6 to 1.14.7. - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.6...v1.14.7) --- updated-dependencies: - dependency-name: follow-redirects dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4ed2f487ce..e2c244b4cc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15100,9 +15100,9 @@ fn.name@1.x.x: integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== follow-redirects@^1.0.0, follow-redirects@^1.14.0: - version "1.14.6" - resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.6.tgz#8cfb281bbc035b3c067d6cd975b0f6ade6e855cd" - integrity sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A== + version "1.14.7" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685" + integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ== for-in@^0.1.3: version "0.1.8" From 014f9a8f452d93469ff1788018086ef54b4daa36 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Jan 2022 04:14:21 +0000 Subject: [PATCH 21/56] build(deps-dev): bump @types/swagger-ui-react from 3.35.2 to 4.1.1 Bumps [@types/swagger-ui-react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/swagger-ui-react) from 3.35.2 to 4.1.1. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/swagger-ui-react) --- updated-dependencies: - dependency-name: "@types/swagger-ui-react" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- plugins/api-docs/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 8d190dae92..0d82fb2d88 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -63,7 +63,7 @@ "@testing-library/user-event": "^13.1.8", "@types/jest": "^26.0.7", "@types/node": "^14.14.32", - "@types/swagger-ui-react": "^3.23.3", + "@types/swagger-ui-react": "^4.1.1", "cross-fetch": "^3.0.6", "msw": "^0.35.0" }, diff --git a/yarn.lock b/yarn.lock index 97087652ad..c17b36f9f4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8277,10 +8277,10 @@ dependencies: "@types/superagent" "*" -"@types/swagger-ui-react@^3.23.3": - version "3.35.2" - resolved "https://registry.npmjs.org/@types/swagger-ui-react/-/swagger-ui-react-3.35.2.tgz#f362a60a0d71c2da5dc1ab420ed4aa1721e6c8a0" - integrity sha512-HA/1pw5uzn3+3gDX1R50SpzP/3GiqhUZoT5LLl8rhVu1i39Et1acz9ryuzmf5i4PoZNIfLcZYBlIok0P/6qmyA== +"@types/swagger-ui-react@^4.1.1": + version "4.1.1" + resolved "https://registry.npmjs.org/@types/swagger-ui-react/-/swagger-ui-react-4.1.1.tgz#6ae70f5b966941eb6655d79d1114d9b9ef69a980" + integrity sha512-tZqX/nShvNqtJ7WAfwOK7mphK1jqmEre4mUJh+R1RyCFVODsMTG4My2nqjXpSm8NfhVGmbFH3giD17AXmgsaJw== dependencies: "@types/react" "*" From 50f4ebc247dd4bf46dceca8216d0b3bb08e68410 Mon Sep 17 00:00:00 2001 From: blam Date: Thu, 13 Jan 2022 08:29:38 +0100 Subject: [PATCH 22/56] chore: reworking some dependencies Signed-off-by: blam --- packages/core-components/package.json | 2 +- plugins/api-docs/package.json | 3 +- yarn.lock | 105 +++++++++++++++++--------- 3 files changed, 71 insertions(+), 39 deletions(-) diff --git a/packages/core-components/package.json b/packages/core-components/package.json index 337a759da8..64938f4336 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -58,7 +58,7 @@ "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", "react-sparklines": "^1.7.0", - "react-syntax-highlighter": "^15.4.3", + "react-syntax-highlighter": "^15.4.5", "react-text-truncate": "^0.16.0", "react-use": "^17.2.4", "react-virtualized-auto-sizer": "^1.0.6", diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 0d82fb2d88..71e3dcfb66 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -46,8 +46,7 @@ "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4", - "swagger-client": "3.16.1", - "swagger-ui-react": "^4.0.0-rc.3" + "swagger-ui-react": "^4.1.3" }, "peerDependencies": { "@types/react": "^16.13.1 || ^17.0.0", diff --git a/yarn.lock b/yarn.lock index c17b36f9f4..1713059d42 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2173,7 +2173,7 @@ pirates "^4.0.0" source-map-support "^0.5.16" -"@babel/runtime-corejs3@^7.10.2", "@babel/runtime-corejs3@^7.11.2", "@babel/runtime-corejs3@^7.14.7": +"@babel/runtime-corejs3@^7.10.2", "@babel/runtime-corejs3@^7.11.2": version "7.15.3" resolved "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.15.3.tgz#28754263988198f2a928c09733ade2fb4d28089d" integrity sha512-30A3lP+sRL6ml8uhoJSs+8jwpKzbw8CqBvDc1laeptxPm5FahumJxirigcbD2qTs71Sonvj1cyZB0OKGAmxQ+A== @@ -2181,7 +2181,22 @@ core-js-pure "^3.16.0" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.0", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.4", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.0", "@babel/runtime@^7.14.6", "@babel/runtime@^7.14.8", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime-corejs3@^7.16.3": + version "7.16.8" + resolved "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.16.8.tgz#ea533d96eda6fdc76b1812248e9fbd0c11d4a1a7" + integrity sha512-3fKhuICS1lMz0plI5ktOE/yEtBRMVxplzRkdn6mJQ197XiY0JnrzYV0+Mxozq3JZ8SBV9Ecurmw1XsGbwOf+Sg== + dependencies: + core-js-pure "^3.20.2" + regenerator-runtime "^0.13.4" + +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.0", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.4", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.0", "@babel/runtime@^7.14.6", "@babel/runtime@^7.14.8", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": + version "7.16.3" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.3.tgz#b86f0db02a04187a3c17caa77de69840165d42d5" + integrity sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3": version "7.16.7" resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz#03ff99f64106588c9c403c6ecb8c3bafbbdff1fa" integrity sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ== @@ -12036,6 +12051,11 @@ core-js-pure@^3.10.2, core-js-pure@^3.16.0, core-js-pure@^3.6.5, core-js-pure@^3 resolved "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.16.2.tgz#0ef4b79cabafb251ea86eb7d139b42bd98c533e8" integrity sha512-oxKe64UH049mJqrKkynWp6Vu0Rlm/BTXO/bJZuN2mmR3RtOFNepLlSWDd1eo16PzHpQAoNG97rLU1V/YxesJjw== +core-js-pure@^3.20.2: + version "3.20.2" + resolved "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.20.2.tgz#5d263565f0e34ceeeccdc4422fae3e84ca6b8c0f" + integrity sha512-CmWHvSKn2vNL6p6StNp1EmMIfVY/pqn3JLAjfZQ8WZGPOlGoO92EkX9/Mk81i6GxvoPXjUqEQnpM3rJ5QxxIOg== + core-js@^2.4.0, core-js@^2.5.0, core-js@^2.6.10: version "2.6.12" resolved "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" @@ -13393,7 +13413,7 @@ domhandler@^4.2.0: dependencies: domelementtype "^2.2.0" -dompurify@^2.2.7, dompurify@^2.2.9: +dompurify@=2.3.3, dompurify@^2.2.7, dompurify@^2.2.9: version "2.3.3" resolved "https://registry.npmjs.org/dompurify/-/dompurify-2.3.3.tgz#c1af3eb88be47324432964d8abc75cf4b98d634c" integrity sha512-dqnqRkPMAjOZE0FogZ+ceJNM2dZ3V/yNOuFB7+39qpO93hHhfRpHw3heYQC7DPK9FqbQTfBKUJhiSfz4MvXYwg== @@ -23368,11 +23388,16 @@ printj@~1.1.0: resolved "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222" integrity sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ== -prismjs@^1.21.0, prismjs@^1.22.0, prismjs@~1.25.0: +prismjs@^1.21.0, prismjs@~1.25.0: version "1.25.0" resolved "https://registry.npmjs.org/prismjs/-/prismjs-1.25.0.tgz#6f822df1bdad965734b310b315a23315cf999756" integrity sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg== +prismjs@^1.25.0: + version "1.26.0" + resolved "https://registry.npmjs.org/prismjs/-/prismjs-1.26.0.tgz#16881b594828bb6b45296083a8cbab46b0accd47" + integrity sha512-HUoH9C5Z3jKkl3UunCyiD5jwk0+Hz0fIgQ2nbwU2Oo/ceuTAQAg+pPVnfdt2TJWRVLcxKh9iuoYDUSc8clb5UQ== + private@^0.1.8: version "0.1.8" resolved "https://registry.npmjs.org/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" @@ -23705,6 +23730,13 @@ qs@^6.10.0, qs@^6.10.1, qs@^6.9.1, qs@^6.9.4, qs@^6.9.6: dependencies: side-channel "^1.0.4" +qs@^6.10.2: + version "6.10.3" + resolved "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e" + integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== + dependencies: + side-channel "^1.0.4" + qs@~6.5.2: version "6.5.2" resolved "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" @@ -23720,11 +23752,6 @@ query-string@^7.0.0: split-on-first "^1.0.0" strict-uri-encode "^2.0.0" -querystring-browser@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/querystring-browser/-/querystring-browser-1.0.4.tgz#f2e35881840a819bc7b1bf597faf0979e6622dc6" - integrity sha1-8uNYgYQKgZvHsb9Zf68JeeZiLcY= - querystring-es3@^0.2.0: version "0.2.1" resolved "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -23871,10 +23898,10 @@ react-colorful@^5.1.2: resolved "https://registry.npmjs.org/react-colorful/-/react-colorful-5.2.2.tgz#0a69d0648db47e51359d343854d83d250a742243" integrity sha512-Xdb1Rl6lZ5SMdNBH59eE0lGqR1g2LVD8IgPlw0WeMDrOC65lYI8fgMEwj/0dDpVRVMh5qp73ciISDst/t2O2iQ== -react-copy-to-clipboard@5.0.3: - version "5.0.3" - resolved "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.3.tgz#2a0623b1115a1d8c84144e9434d3342b5af41ab4" - integrity sha512-9S3j+m+UxDZOM0Qb8mhnT/rMR0NGSrj9A/073yz2DSxPMYhmYFBMYIdI2X4o8AjOjyFsSNxDRnCX6s/gRxpriw== +react-copy-to-clipboard@5.0.4: + version "5.0.4" + resolved "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.4.tgz#42ec519b03eb9413b118af92d1780c403a5f19bf" + integrity sha512-IeVAiNVKjSPeGax/Gmkqfa/+PuMTBhutEvFUaMQLwE2tS0EXrAdgOpWDX26bWTXF3HrioorR7lr08NqeYUWQCQ== dependencies: copy-to-clipboard "^3" prop-types "^15.5.8" @@ -24229,15 +24256,15 @@ react-syntax-highlighter@^13.5.3: prismjs "^1.21.0" refractor "^3.1.0" -react-syntax-highlighter@^15.4.3, react-syntax-highlighter@^15.4.4: - version "15.4.4" - resolved "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.4.4.tgz#dc9043f19e7bd063ff3ea78986d22a6eaa943b2a" - integrity sha512-PsOFHNTzkb3OroXdoR897eKN5EZ6grht1iM+f1lJSq7/L0YVnkJaNVwC3wEUYPOAmeyl5xyer1DjL6MrumO6Zw== +react-syntax-highlighter@^15.4.5: + version "15.4.5" + resolved "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.4.5.tgz#db900d411d32a65c8e90c39cd64555bf463e712e" + integrity sha512-RC90KQTxZ/b7+9iE6s9nmiFLFjWswUcfULi4GwVzdFVKVMQySkJWBuOmJFfjwjMVCo0IUUuJrWebNKyviKpwLQ== dependencies: "@babel/runtime" "^7.3.1" highlight.js "^10.4.1" lowlight "^1.17.0" - prismjs "^1.22.0" + prismjs "^1.25.0" refractor "^3.2.0" react-test-renderer@^16.13.1: @@ -24609,7 +24636,7 @@ redux-immutable@^4.0.0: resolved "https://registry.npmjs.org/redux-immutable/-/redux-immutable-4.0.0.tgz#3a1a32df66366462b63691f0e1dc35e472bbc9f3" integrity sha1-Ohoy32Y2ZGK2NpHw4dw15HK7yfM= -redux@^4.0.0, redux@^4.1.0: +redux@^4.0.0: version "4.1.1" resolved "https://registry.npmjs.org/redux/-/redux-4.1.1.tgz#76f1c439bb42043f985fbd9bf21990e60bd67f47" integrity sha512-hZQZdDEM25UY2P493kPYuKqviVwZ58lEmGQNeQ+gXa+U0gYPUBf7NKYazbe3m+bs/DzM/ahN12DbF+NG8i0CWw== @@ -24624,6 +24651,13 @@ redux@^4.0.4: loose-envify "^1.4.0" symbol-observable "^1.2.0" +redux@^4.1.2: + version "4.1.2" + resolved "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz#140f35426d99bb4729af760afcf79eaaac407104" + integrity sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw== + dependencies: + "@babel/runtime" "^7.9.2" + reflect-metadata@^0.1.13: version "0.1.13" resolved "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" @@ -26855,39 +26889,38 @@ svgo@^2.7.0: picocolors "^1.0.0" stable "^0.1.8" -swagger-client@3.16.1, swagger-client@^3.16.1: - version "3.16.1" - resolved "https://registry.npmjs.org/swagger-client/-/swagger-client-3.16.1.tgz#df86c9d407ab52c00cb356e714b0ec732bb3ad40" - integrity sha512-BcNRQzXHRGuXfhN0f80ptlr+bSaPvXwo8+gWbpmTnbKdAjcWOKAWwUx7rgGHjTKZh0qROr/GX9xOZIY8LrBuTg== +swagger-client@^3.17.0: + version "3.18.0" + resolved "https://registry.npmjs.org/swagger-client/-/swagger-client-3.18.0.tgz#2e59e666b38ded983e26fb512421ef8ff82547f0" + integrity sha512-lNfwTXHim0QiCNuZ4BKgWle7N7+9WlFLtcP02n0xSchFtdzsKJb2kWsOlwplRU3appVFjnHRy+1eVabRc3ZhbA== dependencies: "@babel/runtime-corejs3" "^7.11.2" btoa "^1.2.1" - buffer "^6.0.3" cookie "~0.4.1" cross-fetch "^3.1.4" deep-extend "~0.6.0" fast-json-patch "^3.0.0-1" form-data-encoder "^1.4.3" formdata-node "^4.0.0" + is-plain-object "^5.0.0" js-yaml "^4.1.0" lodash "^4.17.21" - qs "^6.9.4" - querystring-browser "^1.0.4" + qs "^6.10.2" traverse "~0.6.6" url "~0.11.0" -swagger-ui-react@^4.0.0-rc.3: - version "4.0.0-rc.3" - resolved "https://registry.npmjs.org/swagger-ui-react/-/swagger-ui-react-4.0.0-rc.3.tgz#393f424daf55272dd36737be654d978daf870d3d" - integrity sha512-Mo3+NvwLbbPy+ZJZoQkc3UudevSM03SHTZqwZOI7EY4KyMgqeet3xElnAUGZC94GqBZTstU0rf/znkgdaNo9qg== +swagger-ui-react@^4.1.3: + version "4.1.3" + resolved "https://registry.npmjs.org/swagger-ui-react/-/swagger-ui-react-4.1.3.tgz#a722ecbe54ef237fa9080447a7c708c4c72d846a" + integrity sha512-o1AoXUTNH40cxWus0QOeWQ8x9tSIEmrLBrOgAOHDnvWJ1qyjT8PjgHjPbUVjMbja18coyuaAAeUdyLKvLGmlDA== dependencies: - "@babel/runtime-corejs3" "^7.14.7" + "@babel/runtime-corejs3" "^7.16.3" "@braintree/sanitize-url" "^5.0.2" base64-js "^1.5.1" classnames "^2.3.1" css.escape "1.5.1" deep-extend "0.6.0" - dompurify "^2.2.9" + dompurify "=2.3.3" ieee754 "^1.2.1" immutable "^3.x.x" js-file-download "^0.4.12" @@ -26896,20 +26929,20 @@ swagger-ui-react@^4.0.0-rc.3: memoizee "^0.4.15" prop-types "^15.7.2" randombytes "^2.1.0" - react-copy-to-clipboard "5.0.3" + react-copy-to-clipboard "5.0.4" react-debounce-input "=3.2.4" react-immutable-proptypes "2.2.0" react-immutable-pure-component "^2.2.0" react-inspector "^5.1.1" react-redux "^7.2.4" - react-syntax-highlighter "^15.4.4" - redux "^4.1.0" + react-syntax-highlighter "^15.4.5" + redux "^4.1.2" redux-immutable "^4.0.0" remarkable "^2.0.1" reselect "^4.0.0" serialize-error "^8.1.0" sha.js "^2.4.11" - swagger-client "^3.16.1" + swagger-client "^3.17.0" url-parse "^1.5.3" xml "=1.0.1" xml-but-prettier "^1.0.1" From 306d879536eea8cc563f9bc50ab6cc6297720afe Mon Sep 17 00:00:00 2001 From: blam Date: Thu, 13 Jan 2022 08:43:30 +0100 Subject: [PATCH 23/56] chore: add changeset Signed-off-by: blam --- .changeset/beige-crabs-itch.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/beige-crabs-itch.md diff --git a/.changeset/beige-crabs-itch.md b/.changeset/beige-crabs-itch.md new file mode 100644 index 0000000000..9c66e42054 --- /dev/null +++ b/.changeset/beige-crabs-itch.md @@ -0,0 +1,6 @@ +--- +'@backstage/core-components': patch +'@backstage/plugin-api-docs': patch +--- + +chore(deps): bump `react-syntax-highligher` and `swagger-ui-react` From 22a9001e693e9774449920073aaa1d5983690847 Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Thu, 13 Jan 2022 09:42:11 +0100 Subject: [PATCH 24/56] Mock API, not module. Signed-off-by: Eric Peterson --- .../SearchModal/SearchModal.test.tsx | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/plugins/search/src/components/SearchModal/SearchModal.test.tsx b/plugins/search/src/components/SearchModal/SearchModal.test.tsx index d3209f9a9b..b59be710de 100644 --- a/plugins/search/src/components/SearchModal/SearchModal.test.tsx +++ b/plugins/search/src/components/SearchModal/SearchModal.test.tsx @@ -24,16 +24,10 @@ import { rootRouteRef } from '../../plugin'; import { searchApiRef } from '../../apis'; import { SearchModal } from './SearchModal'; - -jest.mock('../SearchContext', () => ({ - ...jest.requireActual('../SearchContext'), - useSearch: jest.fn().mockReturnValue({ - result: {}, - }), -})); +import { SearchContextProvider } from '../SearchContext'; describe('SearchModal', () => { - const query = jest.fn().mockResolvedValue({}); + const query = jest.fn().mockResolvedValue({ results: [] }); const apiRegistry = TestApiRegistry.from( [configApiRef, new ConfigReader({ app: { title: 'Mock app' } })], @@ -45,7 +39,9 @@ describe('SearchModal', () => { it('Should render the Modal correctly', async () => { await renderInTestApp( - + + + , { mountedRoutes: { @@ -60,7 +56,9 @@ describe('SearchModal', () => { it('Calls toggleModal handler', async () => { await renderInTestApp( - + + + , { mountedRoutes: { From be610c5744141dc6a358a46cecef7c990e9db253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 13 Jan 2022 11:16:16 +0100 Subject: [PATCH 25/56] address review comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- docs/auth/google/gcp-iap-auth.md | 6 +-- packages/core-components/api-report.md | 20 ++++----- .../ProxiedSignInIdentity.test.ts} | 24 +++++++---- .../ProxiedSignInIdentity.ts} | 41 +++++++++++-------- .../ProxiedSignInPage.tsx} | 19 ++++----- .../index.ts | 4 +- .../types.test.ts | 8 ++-- .../types.ts | 6 +-- packages/core-components/src/layout/index.ts | 2 +- packages/core-components/src/setupTests.ts | 1 + 10 files changed, 70 insertions(+), 61 deletions(-) rename packages/core-components/src/layout/{DelegatedSignInPage/DelegatedSignInIdentity.test.ts => ProxiedSignInPage/ProxiedSignInIdentity.test.ts} (87%) rename packages/core-components/src/layout/{DelegatedSignInPage/DelegatedSignInIdentity.ts => ProxiedSignInPage/ProxiedSignInIdentity.ts} (82%) rename packages/core-components/src/layout/{DelegatedSignInPage/DelegatedSignInPage.tsx => ProxiedSignInPage/ProxiedSignInPage.tsx} (80%) rename packages/core-components/src/layout/{DelegatedSignInPage => ProxiedSignInPage}/index.ts (82%) rename packages/core-components/src/layout/{DelegatedSignInPage => ProxiedSignInPage}/types.test.ts (81%) rename packages/core-components/src/layout/{DelegatedSignInPage => ProxiedSignInPage}/types.ts (89%) diff --git a/docs/auth/google/gcp-iap-auth.md b/docs/auth/google/gcp-iap-auth.md index 88077080da..29951951d1 100644 --- a/docs/auth/google/gcp-iap-auth.md +++ b/docs/auth/google/gcp-iap-auth.md @@ -95,7 +95,7 @@ sign-in mechanism to poll that endpoint through the IAP, on the user's behalf. ## Frontend Changes -Any Backstage app needs a `SignInPage` to be configured. Its purpose is to +All Backstage apps need a `SignInPage` to be configured. Its purpose is to establish who the user is and what their identifying credentials are, blocking rendering the rest of the UI until that's complete, and then keeping those credentials fresh. @@ -114,11 +114,11 @@ component for this purpose out of the box. Update your `createApp` call in `packages/app/src/App.tsx`, as follows. ```diff -+import { DelegatedSignInPage } from '@backstage/core-components'; ++import { ProxiedSignInPage } from '@backstage/core-components'; const app = createApp({ components: { -+ SignInPage: props => , ++ SignInPage: props => , ``` After this, your app should be ready to leverage the Identity-Aware Proxy for diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index bdd6f0e030..6af2746683 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -202,16 +202,6 @@ export type CustomProviderClassKey = 'form' | 'button'; // @public (undocumented) export function DashboardIcon(props: IconComponentProps): JSX.Element; -// @public -export const DelegatedSignInPage: ( - props: DelegatedSignInPageProps, -) => JSX.Element | null; - -// @public -export type DelegatedSignInPageProps = SignInPageProps & { - provider: string; -}; - // @public type DependencyEdge = T & { from: string; @@ -765,6 +755,16 @@ export function Progress( props: PropsWithChildren, ): JSX.Element; +// @public +export const ProxiedSignInPage: ( + props: ProxiedSignInPageProps, +) => JSX.Element | null; + +// @public +export type ProxiedSignInPageProps = SignInPageProps & { + provider: string; +}; + // Warning: (ae-missing-release-tag) "Ranker" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public diff --git a/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.test.ts b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.test.ts similarity index 87% rename from packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.test.ts rename to packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.test.ts index 16ce71980a..cc23678606 100644 --- a/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.test.ts +++ b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.test.ts @@ -15,20 +15,19 @@ */ import { setupRequestMockHandlers } from '@backstage/test-utils'; -import fetch from 'cross-fetch'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { DEFAULTS, - DelegatedSignInIdentity, + ProxiedSignInIdentity, tokenToExpiry, -} from './DelegatedSignInIdentity'; +} from './ProxiedSignInIdentity'; const validBackstageTokenExpClaim = 1641216199; const validBackstageToken = 'eyJhbGciOiJFUzI1NiIsImtpZCI6ImMxNTMzNDRiLWZjYzktNGIwOS1iN2ZhLTU3ZmM5MDhjMjBiNiJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjcwMDcvYXBpL2F1dGgiLCJzdWIiOiJmcmViZW4iLCJhdWQiOiJiYWNrc3RhZ2UiLCJpYXQiOjE2NDEyMTI1OTksImV4cCI6MTY0MTIxNjE5OSwiZW50IjpbInVzZXI6ZGVmYXVsdC9mcmViZW4iXX0.4nOTmPHPwhzaKTzikgUsHcszfcP-JamcojMnRfyfsKhyHCCEywe6uLFlvvmK5NbaX5Z7IIji-kg7bxKU58kwoQ'; -describe('DelegatedSignInIdentity', () => { +describe('ProxiedSignInIdentity', () => { describe('tokenToExpiry', () => { beforeEach(() => jest.useFakeTimers('modern')); afterEach(() => jest.useRealTimers()); @@ -46,9 +45,17 @@ describe('DelegatedSignInIdentity', () => { ), ); }); + + it('handles a token that has no exp', async () => { + const [a, _b, c] = validBackstageToken.split('.'); + const botched = `${a}.${btoa(JSON.stringify({}))}.${c}`; + expect(tokenToExpiry(botched)).toEqual( + new Date(new Date(Date.now() + DEFAULTS.defaultTokenExpiryMillis)), + ); + }); }); - describe('DelegatedSignInIdentity', () => { + describe('ProxiedSignInIdentity', () => { beforeEach(() => jest.useFakeTimers('modern')); afterEach(() => jest.useRealTimers()); @@ -61,7 +68,7 @@ describe('DelegatedSignInIdentity', () => { function makeToken() { const iat = Math.floor(Date.now() / 1000); - const exp = iat + 100; + const exp = iat + 3600; return { providerInfo: { stuff: 1, @@ -107,10 +114,9 @@ describe('DelegatedSignInIdentity', () => { ), ); - const identity = new DelegatedSignInIdentity({ + const identity = new ProxiedSignInIdentity({ provider: 'foo', discoveryApi: { getBaseUrl }, - fetchApi: { fetch }, }); getBaseUrl.mockResolvedValue('http://example.com/api/auth'); @@ -126,7 +132,7 @@ describe('DelegatedSignInIdentity', () => { // Use a fairly large margin (1000) since the iat and exp are clamped to // full seconds, but the "local current time" isn't jest.advanceTimersByTime( - 100 * 1000 - DEFAULTS.tokenExpiryMarginMillis - 1000, + 3600 * 1000 - DEFAULTS.tokenExpiryMarginMillis - 1000, ); await identity.getSessionAsync(); // still no need to fetch again expect(serverCalled).toBeCalledTimes(1); diff --git a/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.ts b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.ts similarity index 82% rename from packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.ts rename to packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.ts index 750f9ef027..1f8737b200 100644 --- a/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInIdentity.ts +++ b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.ts @@ -17,38 +17,40 @@ import { BackstageUserIdentity, discoveryApiRef, - fetchApiRef, IdentityApi, ProfileInfo, } from '@backstage/core-plugin-api'; import { ResponseError } from '@backstage/errors'; -import { DelegatedSession, delegatedSessionSchema } from './types'; +import { ProxiedSession, proxiedSessionSchema } from './types'; export const DEFAULTS = { // The amount of time between token refreshes, if we fail to get an actual // value out of the exp claim - defaultTokenExpiryMillis: 60_000, + defaultTokenExpiryMillis: 5 * 60 * 1000, // The amount of time before the actual expiry of the Backstage token, that we // shall start trying to get a new one - tokenExpiryMarginMillis: 30_000, + tokenExpiryMarginMillis: 5 * 60 * 1000, } as const; // When the token expires, with some margin export function tokenToExpiry(jwtToken: string | undefined): Date { + const fallback = new Date(Date.now() + DEFAULTS.defaultTokenExpiryMillis); if (!jwtToken) { - return new Date(Date.now() + DEFAULTS.defaultTokenExpiryMillis); + return fallback; } const [_header, rawPayload, _signature] = jwtToken.split('.'); const payload = JSON.parse(atob(rawPayload)); + if (typeof payload.exp !== 'number') { + return fallback; + } return new Date(payload.exp * 1000 - DEFAULTS.tokenExpiryMarginMillis); } -type DelegatedSignInIdentityOptions = { +type ProxiedSignInIdentityOptions = { provider: string; discoveryApi: typeof discoveryApiRef.T; - fetchApi: typeof fetchApiRef.T; }; type State = @@ -57,12 +59,12 @@ type State = } | { type: 'fetching'; - promise: Promise; - previous: DelegatedSession | undefined; + promise: Promise; + previous: ProxiedSession | undefined; } | { type: 'active'; - session: DelegatedSession; + session: ProxiedSession; expiresAt: Date; } | { @@ -74,12 +76,12 @@ type State = * An identity API that gets the user auth information solely based on a * provider's `/refresh` endpoint. */ -export class DelegatedSignInIdentity implements IdentityApi { - private readonly options: DelegatedSignInIdentityOptions; +export class ProxiedSignInIdentity implements IdentityApi { + private readonly options: ProxiedSignInIdentityOptions; private readonly abortController: AbortController; private state: State; - constructor(options: DelegatedSignInIdentityOptions) { + constructor(options: ProxiedSignInIdentityOptions) { this.options = options; this.abortController = new AbortController(); this.state = { type: 'empty' }; @@ -133,7 +135,7 @@ export class DelegatedSignInIdentity implements IdentityApi { this.abortController.abort(); } - getSessionSync(): DelegatedSession { + getSessionSync(): ProxiedSession { if (this.state.type === 'active') { return this.state.session; } else if (this.state.type === 'fetching' && this.state.previous) { @@ -142,7 +144,7 @@ export class DelegatedSignInIdentity implements IdentityApi { throw new Error('No session available. Try reloading your browser page.'); } - async getSessionAsync(): Promise { + async getSessionAsync(): Promise { if (this.state.type === 'fetching') { return this.state.promise; } else if ( @@ -182,10 +184,13 @@ export class DelegatedSignInIdentity implements IdentityApi { return promise; } - async fetchSession(): Promise { + async fetchSession(): Promise { const baseUrl = await this.options.discoveryApi.getBaseUrl('auth'); - const response = await this.options.fetchApi.fetch( + // Note that we do not use the fetchApi here, since this all happens before + // sign-in completes so there can be no automatic token injection and + // similar. + const response = await fetch( `${baseUrl}/${this.options.provider}/refresh`, { signal: this.abortController.signal, @@ -198,6 +203,6 @@ export class DelegatedSignInIdentity implements IdentityApi { throw await ResponseError.fromResponse(response); } - return delegatedSessionSchema.parse(await response.json()); + return proxiedSessionSchema.parse(await response.json()); } } diff --git a/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInPage.tsx b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.tsx similarity index 80% rename from packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInPage.tsx rename to packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.tsx index 0337e3122d..adcd6ced8f 100644 --- a/packages/core-components/src/layout/DelegatedSignInPage/DelegatedSignInPage.tsx +++ b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.tsx @@ -16,7 +16,6 @@ import { discoveryApiRef, - fetchApiRef, SignInPageProps, useApi, } from '@backstage/core-plugin-api'; @@ -24,14 +23,14 @@ import React from 'react'; import useAsync from 'react-use/lib/useAsync'; import { ErrorPanel } from '../../components/ErrorPanel'; import { Progress } from '../../components/Progress'; -import { DelegatedSignInIdentity } from './DelegatedSignInIdentity'; +import { ProxiedSignInIdentity } from './ProxiedSignInIdentity'; /** - * Props for {@link DelegatedSignInPage}. + * Props for {@link ProxiedSignInPage}. * * @public */ -export type DelegatedSignInPageProps = SignInPageProps & { +export type ProxiedSignInPageProps = SignInPageProps & { /** * The provider to use, e.g. "gcp-iap" or "aws-alb". This must correspond to * a properly configured auth provider ID in the auth backend. @@ -40,9 +39,9 @@ export type DelegatedSignInPageProps = SignInPageProps & { }; /** - * A sign-in page that has no user interface of its own. Instead, it delegates - * sign-in to some reverse authenticating proxy that Backstage is deployed - * behind, and leverages its session handling. + * A sign-in page that has no user interface of its own. Instead, it relies on + * sign-in being performed by a reverse authenticating proxy that Backstage is + * deployed behind, and leverages its session handling. * * @remarks * @@ -54,15 +53,13 @@ export type DelegatedSignInPageProps = SignInPageProps & { * * @public */ -export const DelegatedSignInPage = (props: DelegatedSignInPageProps) => { +export const ProxiedSignInPage = (props: ProxiedSignInPageProps) => { const discoveryApi = useApi(discoveryApiRef); - const fetchApi = useApi(fetchApiRef); const { loading, error } = useAsync(async () => { - const identity = new DelegatedSignInIdentity({ + const identity = new ProxiedSignInIdentity({ provider: props.provider, discoveryApi, - fetchApi, }); await identity.start(); diff --git a/packages/core-components/src/layout/DelegatedSignInPage/index.ts b/packages/core-components/src/layout/ProxiedSignInPage/index.ts similarity index 82% rename from packages/core-components/src/layout/DelegatedSignInPage/index.ts rename to packages/core-components/src/layout/ProxiedSignInPage/index.ts index bf3081e630..f7bab5f46c 100644 --- a/packages/core-components/src/layout/DelegatedSignInPage/index.ts +++ b/packages/core-components/src/layout/ProxiedSignInPage/index.ts @@ -14,5 +14,5 @@ * limitations under the License. */ -export { DelegatedSignInPage } from './DelegatedSignInPage'; -export type { DelegatedSignInPageProps } from './DelegatedSignInPage'; +export { ProxiedSignInPage } from './ProxiedSignInPage'; +export type { ProxiedSignInPageProps } from './ProxiedSignInPage'; diff --git a/packages/core-components/src/layout/DelegatedSignInPage/types.test.ts b/packages/core-components/src/layout/ProxiedSignInPage/types.test.ts similarity index 81% rename from packages/core-components/src/layout/DelegatedSignInPage/types.test.ts rename to packages/core-components/src/layout/ProxiedSignInPage/types.test.ts index c3eeff4eec..5da8203cbd 100644 --- a/packages/core-components/src/layout/DelegatedSignInPage/types.test.ts +++ b/packages/core-components/src/layout/ProxiedSignInPage/types.test.ts @@ -15,10 +15,10 @@ */ import { TypeOf } from 'zod'; -import { DelegatedSession, delegatedSessionSchema } from './types'; +import { ProxiedSession, proxiedSessionSchema } from './types'; describe('types', () => { - const responseData: DelegatedSession = { + const responseData: ProxiedSession = { providerInfo: { stuff: 1, }, @@ -39,8 +39,8 @@ describe('types', () => { }; it('has a compatible schema type', () => { - function f(_b: TypeOf) {} + function f(_b: TypeOf) {} f(responseData); // no tsc errors - expect(delegatedSessionSchema.parse(responseData)).toEqual(responseData); + expect(proxiedSessionSchema.parse(responseData)).toEqual(responseData); }); }); diff --git a/packages/core-components/src/layout/DelegatedSignInPage/types.ts b/packages/core-components/src/layout/ProxiedSignInPage/types.ts similarity index 89% rename from packages/core-components/src/layout/DelegatedSignInPage/types.ts rename to packages/core-components/src/layout/ProxiedSignInPage/types.ts index 0ef65344a3..f5b54f306a 100644 --- a/packages/core-components/src/layout/DelegatedSignInPage/types.ts +++ b/packages/core-components/src/layout/ProxiedSignInPage/types.ts @@ -20,7 +20,7 @@ import { } from '@backstage/core-plugin-api'; import { z } from 'zod'; -export const delegatedSessionSchema = z.object({ +export const proxiedSessionSchema = z.object({ providerInfo: z.object({}).catchall(z.unknown()).optional(), profile: z.object({ email: z.string().optional(), @@ -39,12 +39,12 @@ export const delegatedSessionSchema = z.object({ }); /** - * Generic session information for delegated sign-in providers, e.g. common + * Generic session information for proxied sign-in providers, e.g. common * reverse authenticating proxy implementations. * * @public */ -export type DelegatedSession = { +export type ProxiedSession = { providerInfo?: { [key: string]: unknown }; profile: ProfileInfo; backstageIdentity: BackstageIdentityResponse; diff --git a/packages/core-components/src/layout/index.ts b/packages/core-components/src/layout/index.ts index f726481535..9bb7fbaa26 100644 --- a/packages/core-components/src/layout/index.ts +++ b/packages/core-components/src/layout/index.ts @@ -17,7 +17,6 @@ export * from './BottomLink'; export * from './Content'; export * from './ContentHeader'; -export * from './DelegatedSignInPage'; export * from './ErrorBoundary'; export * from './ErrorPage'; export * from './Header'; @@ -27,6 +26,7 @@ export * from './HomepageTimer'; export * from './InfoCard'; export * from './ItemCard'; export * from './Page'; +export * from './ProxiedSignInPage'; export * from './Sidebar'; export * from './SignInPage'; export * from './TabbedCard'; diff --git a/packages/core-components/src/setupTests.ts b/packages/core-components/src/setupTests.ts index 963c0f188b..c1d649f2ad 100644 --- a/packages/core-components/src/setupTests.ts +++ b/packages/core-components/src/setupTests.ts @@ -15,3 +15,4 @@ */ import '@testing-library/jest-dom'; +import 'cross-fetch/polyfill'; From 7a35aa9377ef1963b3b159fcf6a77921a205f788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 13 Jan 2022 11:39:42 +0100 Subject: [PATCH 26/56] typo in changeset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/cool-baboons-switch.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/cool-baboons-switch.md b/.changeset/cool-baboons-switch.md index 88752502c8..9bf09bab74 100644 --- a/.changeset/cool-baboons-switch.md +++ b/.changeset/cool-baboons-switch.md @@ -2,4 +2,4 @@ '@backstage/core-components': patch --- -Add a `DelegatedSignInPage` that can be used e.g. for GCP IAP and AWS ALB +Add a `ProxiedSignInPage` that can be used e.g. for GCP IAP and AWS ALB From 0a6c68582a152aba13e6ecdef21e5111eefbec09 Mon Sep 17 00:00:00 2001 From: Joon Park Date: Thu, 13 Jan 2022 10:59:13 +0000 Subject: [PATCH 27/56] Add authorization to entities get endpoints in catalog-backend. (#8711) * Add authorization to entities get endpoints in catalog-backend. The delete endpoint and the ancestry endpoint, as well as the rest of the endpoints in catalog-backend will be covered in later PRs. Signed-off-by: Joon Park * Refactor permissioning into AuthorizedNextEntitiesCatalog Signed-off-by: Joon Park * Create integration router in builder Signed-off-by: Joon Park * Fix test authorization strings Signed-off-by: Joon Park --- .changeset/small-hotels-shake.md | 5 + plugins/catalog-backend/api-report.md | 3 +- plugins/catalog-backend/src/catalog/types.ts | 1 + .../service/AuthorizedEntitiesCatalog.test.ts | 96 +++++++++++++++++++ .../src/service/AuthorizedEntitiesCatalog.ts | 77 +++++++++++++++ .../src/service/NextCatalogBuilder.ts | 36 ++++++- .../src/service/NextRouter.test.ts | 74 +------------- .../catalog-backend/src/service/NextRouter.ts | 45 ++------- 8 files changed, 226 insertions(+), 111 deletions(-) create mode 100644 .changeset/small-hotels-shake.md create mode 100644 plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts create mode 100644 plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts diff --git a/.changeset/small-hotels-shake.md b/.changeset/small-hotels-shake.md new file mode 100644 index 0000000000..8cb052cf96 --- /dev/null +++ b/.changeset/small-hotels-shake.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Add authorization to catalog-backend entities GET endpoints diff --git a/plugins/catalog-backend/api-report.md b/plugins/catalog-backend/api-report.md index 702597c7c8..c503d303ba 100644 --- a/plugins/catalog-backend/api-report.md +++ b/plugins/catalog-backend/api-report.md @@ -849,6 +849,7 @@ export type EntitiesRequest = { filter?: EntityFilter; fields?: (entity: Entity) => Entity; pagination?: EntityPagination; + authorizationToken?: string; }; // Warning: (ae-missing-release-tag) "EntitiesResponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -1358,7 +1359,7 @@ export interface NextRouterOptions { // (undocumented) logger: Logger_2; // (undocumented) - permissionRules?: PermissionRule[]; + permissionIntegrationRouter?: express.Router; // (undocumented) refreshService?: RefreshService; } diff --git a/plugins/catalog-backend/src/catalog/types.ts b/plugins/catalog-backend/src/catalog/types.ts index f030d63bce..f71d7fb7d9 100644 --- a/plugins/catalog-backend/src/catalog/types.ts +++ b/plugins/catalog-backend/src/catalog/types.ts @@ -70,6 +70,7 @@ export type EntitiesRequest = { filter?: EntityFilter; fields?: (entity: Entity) => Entity; pagination?: EntityPagination; + authorizationToken?: string; }; export type EntitiesResponse = { diff --git a/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts new file mode 100644 index 0000000000..768e3a690b --- /dev/null +++ b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts @@ -0,0 +1,96 @@ +/* + * Copyright 2022 The Backstage Authors + * + * 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 { AuthorizeResult } from '@backstage/plugin-permission-common'; +import { createConditionTransformer } from '@backstage/plugin-permission-node'; +import { isEntityKind } from '../permissions/rules/isEntityKind'; +import { AuthorizedEntitiesCatalog } from './AuthorizedEntitiesCatalog'; + +describe('AuthorizedEntitiesCatalog', () => { + const fakeCatalog = { + entities: jest.fn(), + removeEntityByUid: jest.fn(), + entityAncestry: jest.fn(), + }; + const fakePermissionApi = { + authorize: jest.fn(), + }; + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('entities', () => { + it('returns empty response on DENY', async () => { + fakePermissionApi.authorize.mockResolvedValue([ + { result: AuthorizeResult.DENY }, + ]); + + const catalog = new AuthorizedEntitiesCatalog( + fakeCatalog, + fakePermissionApi, + createConditionTransformer([]), + ); + + expect( + await catalog.entities({ + authorizationToken: 'abcd', + }), + ).toEqual({ + entities: [], + pageInfo: { hasNextPage: false }, + }); + }); + + it('calls underlying catalog method with correct filter on CONDITIONAL', async () => { + fakePermissionApi.authorize.mockResolvedValue([ + { + result: AuthorizeResult.CONDITIONAL, + conditions: { rule: 'IS_ENTITY_KIND', params: [['b']] }, + }, + ]); + const catalog = new AuthorizedEntitiesCatalog( + fakeCatalog, + fakePermissionApi, + createConditionTransformer([isEntityKind]), + ); + + await catalog.entities({ authorizationToken: 'abcd' }); + + expect(fakeCatalog.entities).toHaveBeenCalledWith({ + authorizationToken: 'abcd', + filter: { key: 'kind', values: ['b'] }, + }); + }); + + it('calls underlying catalog method on ALLOW', async () => { + fakePermissionApi.authorize.mockResolvedValue([ + { result: AuthorizeResult.ALLOW }, + ]); + const catalog = new AuthorizedEntitiesCatalog( + fakeCatalog, + fakePermissionApi, + createConditionTransformer([]), + ); + + await catalog.entities({ authorizationToken: 'abcd' }); + + expect(fakeCatalog.entities).toHaveBeenCalledWith({ + authorizationToken: 'abcd', + }); + }); + }); +}); diff --git a/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts new file mode 100644 index 0000000000..5b65070c43 --- /dev/null +++ b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts @@ -0,0 +1,77 @@ +/* + * Copyright 2022 The Backstage Authors + * + * 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 { catalogEntityReadPermission } from '@backstage/plugin-catalog-common'; +import { + AuthorizeResult, + PermissionAuthorizer, +} from '@backstage/plugin-permission-common'; +import { ConditionTransformer } from '@backstage/plugin-permission-node'; +import { + EntitiesCatalog, + EntitiesRequest, + EntitiesResponse, + EntityAncestryResponse, + EntityFilter, +} from '../catalog/types'; + +export class AuthorizedEntitiesCatalog implements EntitiesCatalog { + constructor( + private readonly entitiesCatalog: EntitiesCatalog, + private readonly permissionApi: PermissionAuthorizer, + private readonly transformConditions: ConditionTransformer, + ) {} + + async entities(request?: EntitiesRequest): Promise { + const authorizeResponse = ( + await this.permissionApi.authorize( + [{ permission: catalogEntityReadPermission }], + { token: request?.authorizationToken }, + ) + )[0]; + + if (authorizeResponse.result === AuthorizeResult.DENY) { + return { + entities: [], + pageInfo: { hasNextPage: false }, + }; + } + + if (authorizeResponse.result === AuthorizeResult.CONDITIONAL) { + const permissionFilter: EntityFilter = this.transformConditions( + authorizeResponse.conditions, + ); + return this.entitiesCatalog.entities({ + ...request, + filter: request?.filter + ? { allOf: [permissionFilter, request.filter] } + : permissionFilter, + }); + } + + return this.entitiesCatalog.entities(request); + } + + removeEntityByUid(uid: string): Promise { + // TODO: Implement permissioning + return this.entitiesCatalog.removeEntityByUid(uid); + } + + entityAncestry(entityRef: string): Promise { + // TODO: Implement permissioning + return this.entitiesCatalog.entityAncestry(entityRef); + } +} diff --git a/plugins/catalog-backend/src/service/NextCatalogBuilder.ts b/plugins/catalog-backend/src/service/NextCatalogBuilder.ts index eecfb5fc11..391c89d83d 100644 --- a/plugins/catalog-backend/src/service/NextCatalogBuilder.ts +++ b/plugins/catalog-backend/src/service/NextCatalogBuilder.ts @@ -23,6 +23,7 @@ import { FieldFormatEntityPolicy, makeValidator, NoForeignRootFieldsEntityPolicy, + parseEntityRef, SchemaValidEntityPolicy, Validators, } from '@backstage/catalog-model'; @@ -90,7 +91,14 @@ import { LocationService } from './types'; import { connectEntityProviders } from '../processing/connectEntityProviders'; import { permissionRules as catalogPermissionRules } from '../permissions/rules'; import { PermissionAuthorizer } from '@backstage/plugin-permission-common'; -import { PermissionRule } from '@backstage/plugin-permission-node'; +import { + PermissionRule, + createConditionTransformer, + createPermissionIntegrationRouter, +} from '@backstage/plugin-permission-node'; +import { AuthorizedEntitiesCatalog } from './AuthorizedEntitiesCatalog'; +import { basicEntityFilter } from './request/basicEntityFilter'; +import { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common'; export type CatalogEnvironment = { logger: Logger; @@ -399,7 +407,29 @@ export class NextCatalogBuilder { parser, policy, }); - const entitiesCatalog = new NextEntitiesCatalog(dbClient); + const unauthorizedEntitiesCatalog = new NextEntitiesCatalog(dbClient); + const entitiesCatalog = new AuthorizedEntitiesCatalog( + unauthorizedEntitiesCatalog, + permissions, + createConditionTransformer(this.permissionRules), + ); + const permissionIntegrationRouter = createPermissionIntegrationRouter({ + resourceType: RESOURCE_TYPE_CATALOG_ENTITY, + getResource: async (resourceRef: string) => { + const parsed = parseEntityRef(resourceRef); + + const { entities } = await unauthorizedEntitiesCatalog.entities({ + filter: basicEntityFilter({ + kind: parsed.kind, + 'metadata.namespace': parsed.namespace, + 'metadata.name': parsed.name, + }), + }); + + return entities[0]; + }, + rules: this.permissionRules, + }); const stitcher = new Stitcher(dbClient, logger); const locationStore = new DefaultLocationStore(dbClient); @@ -435,7 +465,7 @@ export class NextCatalogBuilder { refreshService, logger, config, - permissionRules: this.permissionRules, + permissionIntegrationRouter, }); await connectEntityProviders(processingDatabase, entityProviders); diff --git a/plugins/catalog-backend/src/service/NextRouter.test.ts b/plugins/catalog-backend/src/service/NextRouter.test.ts index e835c4620a..84580d0ca4 100644 --- a/plugins/catalog-backend/src/service/NextRouter.test.ts +++ b/plugins/catalog-backend/src/service/NextRouter.test.ts @@ -24,7 +24,6 @@ import { EntitiesCatalog } from '../catalog'; import { LocationService, RefreshService } from './types'; import { basicEntityFilter } from './request'; import { createNextRouter } from './NextRouter'; -import { AuthorizeResult } from '@backstage/plugin-permission-common'; describe('createNextRouter readonly disabled', () => { let entitiesCatalog: jest.Mocked; @@ -52,7 +51,7 @@ describe('createNextRouter readonly disabled', () => { logger: getVoidLogger(), refreshService, config: new ConfigReader(undefined), - permissionRules: [], + permissionIntegrationRouter: express.Router(), }); app = express().use(router); }); @@ -340,7 +339,7 @@ describe('createNextRouter readonly enabled', () => { readonly: true, }, }), - permissionRules: [], + permissionIntegrationRouter: express.Router(), }); app = express().use(router); }); @@ -434,72 +433,3 @@ describe('createNextRouter readonly enabled', () => { }); }); }); - -describe('NextRouter permissioning', () => { - let entitiesCatalog: jest.Mocked; - let locationService: jest.Mocked; - let app: express.Express; - let refreshService: RefreshService; - - const fakeRule = { - name: 'FAKE_RULE', - description: 'fake rule', - apply: () => true, - toQuery: () => ({ key: '', values: [] }), - }; - - beforeAll(async () => { - entitiesCatalog = { - entities: jest.fn(), - removeEntityByUid: jest.fn(), - batchAddOrUpdateEntities: jest.fn(), - entityAncestry: jest.fn(), - }; - locationService = { - getLocation: jest.fn(), - createLocation: jest.fn(), - listLocations: jest.fn(), - deleteLocation: jest.fn(), - }; - refreshService = { refresh: jest.fn() }; - const router = await createNextRouter({ - entitiesCatalog, - locationService, - logger: getVoidLogger(), - refreshService, - config: new ConfigReader(undefined), - permissionRules: [fakeRule], - }); - app = express().use(router); - }); - - afterEach(() => { - jest.resetAllMocks(); - }); - - it('accepts and evaluates conditions at the apply-conditions endpoint', async () => { - const spideySense: Entity = { - apiVersion: 'a', - kind: 'b', - metadata: { - name: 'spidey-sense', - }, - }; - entitiesCatalog.entities.mockResolvedValueOnce({ - entities: [spideySense], - pageInfo: { hasNextPage: false }, - }); - - const requestBody = { - resourceType: 'catalog-entity', - resourceRef: 'component:default/spidey-sense', - conditions: { rule: 'FAKE_RULE', params: ['user:default/spiderman'] }, - }; - const response = await request(app) - .post('/.well-known/backstage/permissions/apply-conditions') - .send(requestBody); - - expect(response.status).toBe(200); - expect(response.body).toEqual({ result: AuthorizeResult.ALLOW }); - }); -}); diff --git a/plugins/catalog-backend/src/service/NextRouter.ts b/plugins/catalog-backend/src/service/NextRouter.ts index 5338f58f91..78550e1791 100644 --- a/plugins/catalog-backend/src/service/NextRouter.ts +++ b/plugins/catalog-backend/src/service/NextRouter.ts @@ -17,23 +17,16 @@ import { errorHandler } from '@backstage/backend-common'; import { analyzeLocationSchema, - Entity, locationSpecSchema, - parseEntityRef, stringifyEntityRef, } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { NotFoundError } from '@backstage/errors'; -import { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common'; -import { - createPermissionIntegrationRouter, - PermissionRule, -} from '@backstage/plugin-permission-node'; import express from 'express'; import Router from 'express-promise-router'; import { Logger } from 'winston'; import yn from 'yn'; -import { EntitiesCatalog, EntitiesSearchFilter } from '../catalog'; +import { EntitiesCatalog } from '../catalog'; import { LocationAnalyzer } from '../ingestion/types'; import { basicEntityFilter, @@ -51,7 +44,7 @@ export interface NextRouterOptions { refreshService?: RefreshService; logger: Logger; config: Config; - permissionRules?: PermissionRule[]; + permissionIntegrationRouter?: express.Router; } export async function createNextRouter( @@ -64,7 +57,7 @@ export async function createNextRouter( refreshService, config, logger, - permissionRules, + permissionIntegrationRouter, } = options; const router = Router(); @@ -88,21 +81,18 @@ export async function createNextRouter( }); } + if (permissionIntegrationRouter) { + router.use(permissionIntegrationRouter); + } + if (entitiesCatalog) { router - .use( - createPermissionIntegrationRouter({ - resourceType: RESOURCE_TYPE_CATALOG_ENTITY, - getResource: resourceRef => - getEntityResource(resourceRef, entitiesCatalog), - rules: permissionRules ?? [], - }), - ) .get('/entities', async (req, res) => { const { entities, pageInfo } = await entitiesCatalog.entities({ filter: parseEntityFilterParams(req.query), fields: parseEntityTransformParams(req.query), pagination: parseEntityPaginationParams(req.query), + authorizationToken: getBearerToken(req.header('authorization')), }); // Add a Link header to the next page @@ -120,6 +110,7 @@ export async function createNextRouter( const { uid } = req.params; const { entities } = await entitiesCatalog.entities({ filter: basicEntityFilter({ 'metadata.uid': uid }), + authorizationToken: getBearerToken(req.header('authorization')), }); if (!entities.length) { throw new NotFoundError(`No entity with uid ${uid}`); @@ -139,6 +130,7 @@ export async function createNextRouter( 'metadata.namespace': namespace, 'metadata.name': name, }), + authorizationToken: getBearerToken(req.header('authorization')), }); if (!entities.length) { throw new NotFoundError( @@ -204,23 +196,6 @@ export async function createNextRouter( return router; } -async function getEntityResource( - resourceRef: string, - entitiesCatalog: EntitiesCatalog, -): Promise { - const parsed = parseEntityRef(resourceRef); - - const { entities } = await entitiesCatalog.entities({ - filter: basicEntityFilter({ - kind: parsed.kind, - 'metadata.namespace': parsed.namespace, - 'metadata.name': parsed.name, - }), - }); - - return entities[0]; -} - function getBearerToken( authorizationHeader: string | undefined, ): string | undefined { From 6ff24fde43bf5b79c3705efa5b794ab1dedb810c Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 13 Jan 2022 12:27:34 +0100 Subject: [PATCH 28/56] workflows/dependabot-changeset-maker: only run on dependabot branches Signed-off-by: Patrik Oldsberg --- .github/workflows/dependabot-changeset-maker.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/dependabot-changeset-maker.yml b/.github/workflows/dependabot-changeset-maker.yml index e38ce12c6d..e6439f7beb 100644 --- a/.github/workflows/dependabot-changeset-maker.yml +++ b/.github/workflows/dependabot-changeset-maker.yml @@ -1,6 +1,7 @@ name: 'Dependabot changeset maker' on: - - pull_request_target + pull_request_target: + branches: 'dependabot/**' jobs: generate-changeset: From 9c0f87acc7b75f15bd82b7449062243463557bbf Mon Sep 17 00:00:00 2001 From: Erik Engervall Date: Thu, 13 Jan 2022 13:25:55 +0100 Subject: [PATCH 29/56] Improve Patch CTA copy Signed-off-by: Erik Engervall --- .../src/features/Patch/Patch.tsx | 17 +++++++++++++---- .../src/features/Patch/PatchBody.tsx | 6 ++++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/plugins/git-release-manager/src/features/Patch/Patch.tsx b/plugins/git-release-manager/src/features/Patch/Patch.tsx index c902ab0dc5..6088538161 100644 --- a/plugins/git-release-manager/src/features/Patch/Patch.tsx +++ b/plugins/git-release-manager/src/features/Patch/Patch.tsx @@ -40,24 +40,32 @@ export const Patch = ({ releaseBranch, onSuccess, }: PatchProps) => { + const ctaMessage = `Patch Release ${ + latestRelease?.prerelease ? 'Candidate' : 'Version' + }`; + return ( - - Patch Release {latestRelease?.prerelease ? 'Candidate' : 'Version'} - + {ctaMessage} ); }; -function BodyWrapper({ latestRelease, releaseBranch, onSuccess }: PatchProps) { +function BodyWrapper({ + latestRelease, + releaseBranch, + onSuccess, + ctaMessage, +}: PatchProps & { ctaMessage: string }) { const { project } = useProjectContext(); if (latestRelease === null) { @@ -93,6 +101,7 @@ function BodyWrapper({ latestRelease, releaseBranch, onSuccess }: PatchProps) { releaseBranch={releaseBranch} onSuccess={onSuccess} tagParts={bumpedTag.tagParts} + ctaMessage={ctaMessage} /> ); } diff --git a/plugins/git-release-manager/src/features/Patch/PatchBody.tsx b/plugins/git-release-manager/src/features/Patch/PatchBody.tsx index 98303890c8..c5429e389a 100644 --- a/plugins/git-release-manager/src/features/Patch/PatchBody.tsx +++ b/plugins/git-release-manager/src/features/Patch/PatchBody.tsx @@ -58,6 +58,7 @@ interface PatchBodyProps { releaseBranch: GetBranchResult['branch']; onSuccess?: ComponentConfig['onSuccess']; tagParts: NonNullable; + ctaMessage: string; } export const PatchBody = ({ @@ -66,6 +67,7 @@ export const PatchBody = ({ releaseBranch, onSuccess, tagParts, + ctaMessage, }: PatchBodyProps) => { const pluginApiClient = useApi(gitReleaseManagerApiRef); const { project } = useProjectContext(); @@ -106,7 +108,7 @@ export const PatchBody = ({ ); } @@ -320,7 +322,7 @@ export const PatchBody = ({ run(selectedPatchCommit); }} > - Patch Release Candidate + {ctaMessage} ); From c1813739c64f9c261259e95b425611736e87fa56 Mon Sep 17 00:00:00 2001 From: Erik Engervall Date: Thu, 13 Jan 2022 13:27:29 +0100 Subject: [PATCH 30/56] Add changeset Signed-off-by: Erik Engervall --- .changeset/funny-carrots-breathe.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/funny-carrots-breathe.md diff --git a/.changeset/funny-carrots-breathe.md b/.changeset/funny-carrots-breathe.md new file mode 100644 index 0000000000..5706e027e7 --- /dev/null +++ b/.changeset/funny-carrots-breathe.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-git-release-manager': patch +--- + +Improved copy for patch CTA From b00ea117cb50635f51f386e26413d83bc9fa2a9d Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 13 Jan 2022 13:00:46 +0100 Subject: [PATCH 31/56] core-components: update ProxiedSignInPage for IdentityApi deprecation removals Signed-off-by: Patrik Oldsberg --- .../ProxiedSignInIdentity.test.ts | 27 ++++++++++++++++--- .../ProxiedSignInIdentity.ts | 10 +++++-- .../layout/ProxiedSignInPage/types.test.ts | 5 ++-- .../src/layout/ProxiedSignInPage/types.ts | 3 +-- 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.test.ts b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.test.ts index cc23678606..00e0c02373 100644 --- a/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.test.ts +++ b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.test.ts @@ -79,7 +79,6 @@ describe('ProxiedSignInIdentity', () => { picture: 'p', }, backstageIdentity: { - id: 'i', token: [ 'eyJhbGciOiJFUzI1NiIsImtpZCI6ImMxNTMzNDRiLWZjYzktNGIwOS1iN2ZhLTU3ZmM5MDhjMjBiNiJ9', btoa( @@ -96,8 +95,8 @@ describe('ProxiedSignInIdentity', () => { ].join('.'), identity: { type: 'user', - userEntityRef: 'ue', - ownershipEntityRefs: ['oe'], + userEntityRef: 'k:ns/ue', + ownershipEntityRefs: ['k:ns/oe'], }, }, }; @@ -126,6 +125,28 @@ describe('ProxiedSignInIdentity', () => { expect(getBaseUrl).lastCalledWith('auth'); expect(serverCalled).toBeCalledTimes(1); + // All information should now be available + await expect(identity.getBackstageIdentity()).resolves.toEqual({ + type: 'user', + userEntityRef: 'k:ns/ue', + ownershipEntityRefs: ['k:ns/oe'], + }); + await expect(identity.getIdToken()).resolves.toEqual(expect.any(String)); + await expect(identity.getCredentials()).resolves.toEqual({ + token: expect.any(String), + }); + await expect(identity.getProfileInfo()).resolves.toEqual({ + email: 'e', + displayName: 'd', + picture: 'p', + }); + expect(identity.getUserId()).toBe('ue'); + expect(identity.getProfile()).toEqual({ + email: 'e', + displayName: 'd', + picture: 'p', + }); + await identity.getSessionAsync(); // no need to fetch again just yet expect(serverCalled).toBeCalledTimes(1); diff --git a/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.ts b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.ts index 1f8737b200..2247d17d82 100644 --- a/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.ts +++ b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.ts @@ -94,8 +94,14 @@ export class ProxiedSignInIdentity implements IdentityApi { /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getUserId} */ getUserId(): string { - const session = this.getSessionSync(); - return session.backstageIdentity.id; + const { backstageIdentity } = this.getSessionSync(); + const ref = backstageIdentity.identity.userEntityRef; + const match = /^([^:/]+:)?([^:/]+\/)?([^:/]+)$/.exec(ref); + if (!match) { + throw new TypeError(`Invalid user entity reference "${ref}"`); + } + + return match[3]; } /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getIdToken} */ diff --git a/packages/core-components/src/layout/ProxiedSignInPage/types.test.ts b/packages/core-components/src/layout/ProxiedSignInPage/types.test.ts index 5da8203cbd..178714ecf9 100644 --- a/packages/core-components/src/layout/ProxiedSignInPage/types.test.ts +++ b/packages/core-components/src/layout/ProxiedSignInPage/types.test.ts @@ -28,12 +28,11 @@ describe('types', () => { picture: 'p', }, backstageIdentity: { - id: 'i', token: 't', identity: { type: 'user', - userEntityRef: 'ue', - ownershipEntityRefs: ['oe'], + userEntityRef: 'k:ns/ue', + ownershipEntityRefs: ['k:ns/oe'], }, }, }; diff --git a/packages/core-components/src/layout/ProxiedSignInPage/types.ts b/packages/core-components/src/layout/ProxiedSignInPage/types.ts index f5b54f306a..dd4230cd8b 100644 --- a/packages/core-components/src/layout/ProxiedSignInPage/types.ts +++ b/packages/core-components/src/layout/ProxiedSignInPage/types.ts @@ -28,7 +28,6 @@ export const proxiedSessionSchema = z.object({ picture: z.string().optional(), }), backstageIdentity: z.object({ - id: z.string(), token: z.string(), identity: z.object({ type: z.literal('user'), @@ -47,5 +46,5 @@ export const proxiedSessionSchema = z.object({ export type ProxiedSession = { providerInfo?: { [key: string]: unknown }; profile: ProfileInfo; - backstageIdentity: BackstageIdentityResponse; + backstageIdentity: Omit; }; From b66704db18a51cc9d4e908981b4bcae068204ad8 Mon Sep 17 00:00:00 2001 From: MT Lewis Date: Mon, 20 Dec 2021 14:12:26 +0000 Subject: [PATCH 32/56] permission-node: accept batched requests in /apply-conditions Signed-off-by: MT Lewis --- plugins/permission-backend/package.json | 3 + .../PermissionIntegrationClient.test.ts | 359 ++++++++++++++---- .../service/PermissionIntegrationClient.ts | 85 +++-- .../src/service/router.test.ts | 85 ++++- .../permission-backend/src/service/router.ts | 100 +++-- plugins/permission-node/api-report.md | 28 +- plugins/permission-node/package.json | 2 + .../createPermissionIntegrationRouter.test.ts | 175 ++++++--- .../createPermissionIntegrationRouter.ts | 159 +++++--- plugins/permission-node/src/policy/index.ts | 1 + plugins/permission-node/src/policy/types.ts | 15 +- 11 files changed, 726 insertions(+), 286 deletions(-) diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index 890495f646..f628984013 100644 --- a/plugins/permission-backend/package.json +++ b/plugins/permission-backend/package.json @@ -21,12 +21,14 @@ "dependencies": { "@backstage/backend-common": "^0.10.1", "@backstage/config": "^0.1.11", + "@backstage/errors": "^0.1.5", "@backstage/plugin-auth-backend": "^0.6.0", "@backstage/plugin-permission-common": "^0.3.0", "@backstage/plugin-permission-node": "^0.2.3", "@types/express": "*", "express": "^4.17.1", "express-promise-router": "^4.1.0", + "lodash": "^4.17.21", "node-fetch": "^2.6.1", "winston": "^3.2.1", "yn": "^4.0.0", @@ -34,6 +36,7 @@ }, "devDependencies": { "@backstage/cli": "^0.10.4", + "@types/lodash": "^4.14.151", "@types/supertest": "^2.0.8", "supertest": "^6.1.6", "msw": "^0.35.0" diff --git a/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts b/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts index 7f46490ce2..79f604e948 100644 --- a/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts +++ b/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts @@ -16,7 +16,7 @@ import { AddressInfo } from 'net'; import { Server } from 'http'; -import express, { Router } from 'express'; +import express, { Router, RequestHandler } from 'express'; import { RestContext, rest } from 'msw'; import { setupServer, SetupServerApi } from 'msw/node'; import { PluginEndpointDiscovery } from '@backstage/backend-common'; @@ -39,14 +39,14 @@ describe('PermissionIntegrationClient', () => { const mockApplyConditionsHandler = jest.fn( (_req, res, { json }: RestContext) => { - return res(json({ result: AuthorizeResult.ALLOW })); + return res(json([{ id: '123', result: AuthorizeResult.ALLOW }])); }, ); - const mockBaseUrl = 'http://backstage:9191/i-am-a-mock-base'; + const mockBaseUrl = 'http://backstage:9191'; const discovery: PluginEndpointDiscovery = { - async getBaseUrl() { - return mockBaseUrl; + async getBaseUrl(pluginId) { + return `${mockBaseUrl}/${pluginId}`; }, async getExternalBaseUrl() { throw new Error('Not implemented.'); @@ -64,7 +64,7 @@ describe('PermissionIntegrationClient', () => { server.listen({ onUnhandledRequest: 'error' }); server.use( rest.post( - `${mockBaseUrl}/.well-known/backstage/permissions/apply-conditions`, + `${mockBaseUrl}/plugin-1/.well-known/backstage/permissions/apply-conditions`, mockApplyConditionsHandler, ), ); @@ -77,31 +77,42 @@ describe('PermissionIntegrationClient', () => { }); it('should make a POST request to the correct endpoint', async () => { - await client.applyConditions({ - pluginId: 'test-plugin', - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: mockConditions, - }); + await client.applyConditions([ + { + id: '123', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: mockConditions, + }, + ]); expect(mockApplyConditionsHandler).toHaveBeenCalled(); }); it('should include a request body', async () => { - await client.applyConditions({ - pluginId: 'test-plugin', - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: mockConditions, - }); + await client.applyConditions([ + { + id: '123', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: mockConditions, + }, + ]); expect(mockApplyConditionsHandler).toHaveBeenCalledWith( expect.objectContaining({ - body: { - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: mockConditions, - }, + body: [ + { + id: '123', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: mockConditions, + }, + ], }), expect.anything(), expect.anything(), @@ -109,25 +120,33 @@ describe('PermissionIntegrationClient', () => { }); it('should return the response from the fetch request', async () => { - const response = await client.applyConditions({ - pluginId: 'test-plugin', - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: mockConditions, - }); + const response = await client.applyConditions([ + { + id: '123', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: mockConditions, + }, + ]); expect(response).toEqual( - expect.objectContaining({ result: AuthorizeResult.ALLOW }), + expect.objectContaining([{ id: '123', result: AuthorizeResult.ALLOW }]), ); }); it('should not include authorization headers if no token is supplied', async () => { - await client.applyConditions({ - pluginId: 'test-plugin', - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: mockConditions, - }); + await client.applyConditions([ + { + id: '123', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: mockConditions, + }, + ]); const request = mockApplyConditionsHandler.mock.calls[0][0]; expect(request.headers.has('authorization')).toEqual(false); @@ -135,12 +154,16 @@ describe('PermissionIntegrationClient', () => { it('should include correctly-constructed authorization header if token is supplied', async () => { await client.applyConditions( - { - pluginId: 'test-plugin', - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: mockConditions, - }, + [ + { + id: '123', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: mockConditions, + }, + ], 'Bearer fake-token', ); @@ -156,36 +179,95 @@ describe('PermissionIntegrationClient', () => { ); await expect( - client.applyConditions({ - pluginId: 'test-plugin', - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: mockConditions, - }), + client.applyConditions([ + { + id: '123', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: mockConditions, + }, + ]), ).rejects.toThrowError(/401/i); }); it('should reject invalid responses', async () => { mockApplyConditionsHandler.mockImplementationOnce( (_req, res, { json }: RestContext) => { - return res(json({ outcome: AuthorizeResult.ALLOW })); + return res(json([{ id: '123', outcome: AuthorizeResult.ALLOW }])); }, ); await expect( - client.applyConditions({ - pluginId: 'test-plugin', - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: mockConditions, - }), + client.applyConditions([ + { + id: '123', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: mockConditions, + }, + ]), ).rejects.toThrowError(/invalid input/i); }); + + it('should batch requests to plugin backends', async () => { + mockApplyConditionsHandler.mockImplementationOnce( + (_req, res, { json }: RestContext) => { + return res( + json([ + { id: '123', result: AuthorizeResult.ALLOW }, + { id: '456', result: AuthorizeResult.DENY }, + { id: '789', result: AuthorizeResult.ALLOW }, + ]), + ); + }, + ); + + await expect( + client.applyConditions([ + { + id: '123', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: mockConditions, + }, + { + id: '456', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: mockConditions, + }, + { + id: '789', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: mockConditions, + }, + ]), + ).resolves.toEqual([ + { id: '123', result: AuthorizeResult.ALLOW }, + { id: '456', result: AuthorizeResult.DENY }, + { id: '789', result: AuthorizeResult.ALLOW }, + ]); + + expect(mockApplyConditionsHandler).toHaveBeenCalledTimes(1); + }); }); describe('integration with @backstage/plugin-permission-node', () => { let server: Server; let client: PermissionIntegrationClient; + let plugin1Router: RequestHandler; + let plugin2Router: RequestHandler; beforeAll(async () => { const router = Router(); @@ -217,7 +299,11 @@ describe('PermissionIntegrationClient', () => { const app = express(); - app.use('/test-plugin', router); + plugin1Router = jest.fn(router); + plugin2Router = jest.fn(router); + + app.use('/plugin-1', plugin1Router); + app.use('/plugin-2', plugin2Router); await new Promise(resolve => { server = app.listen(resolve); @@ -252,41 +338,148 @@ describe('PermissionIntegrationClient', () => { it('works for simple conditions', async () => { await expect( - client.applyConditions({ - pluginId: 'test-plugin', - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: { rule: 'RULE_1', params: ['no'] }, - }), - ).resolves.toEqual({ result: AuthorizeResult.DENY }); + client.applyConditions([ + { + id: '123', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: { rule: 'RULE_1', params: ['no'] }, + }, + ]), + ).resolves.toEqual([{ id: '123', result: AuthorizeResult.DENY }]); }); it('works for complex criteria', async () => { await expect( - client.applyConditions({ - pluginId: 'test-plugin', - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: { - allOf: [ - { - allOf: [ - { rule: 'RULE_1', params: ['yes'] }, - { not: { rule: 'RULE_2', params: ['no'] } }, - ], - }, - { - not: { + client.applyConditions([ + { + id: '123', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: { + allOf: [ + { allOf: [ - { rule: 'RULE_1', params: ['no'] }, - { rule: 'RULE_2', params: ['yes'] }, + { rule: 'RULE_1', params: ['yes'] }, + { not: { rule: 'RULE_2', params: ['no'] } }, ], }, - }, - ], + { + not: { + allOf: [ + { rule: 'RULE_1', params: ['no'] }, + { rule: 'RULE_2', params: ['yes'] }, + ], + }, + }, + ], + }, }, - }), - ).resolves.toEqual({ result: AuthorizeResult.ALLOW }); + ]), + ).resolves.toEqual([{ id: '123', result: AuthorizeResult.ALLOW }]); + }); + + it('makes separate batched requests to multiple plugin backends', async () => { + await expect( + client.applyConditions([ + { + id: '123', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: { rule: 'RULE_1', params: ['yes'] }, + }, + { + id: '234', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-2', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: { rule: 'RULE_1', params: ['no'] }, + }, + { + id: '345', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: { rule: 'RULE_1', params: ['no'] }, + }, + { + id: '456', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-2', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: { rule: 'RULE_1', params: ['yes'] }, + }, + ]), + ).resolves.toEqual([ + { id: '123', result: AuthorizeResult.ALLOW }, + { id: '234', result: AuthorizeResult.DENY }, + { id: '345', result: AuthorizeResult.DENY }, + { id: '456', result: AuthorizeResult.ALLOW }, + ]); + + expect(plugin1Router).toHaveBeenCalledTimes(1); + expect(plugin2Router).toHaveBeenCalledTimes(1); + }); + + it('leaves definitive results unchanged', async () => { + await expect( + client.applyConditions([ + { + id: '123', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: { rule: 'RULE_1', params: ['yes'] }, + }, + { + id: '234', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-2', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: { rule: 'RULE_1', params: ['no'] }, + }, + { + id: '345', + result: AuthorizeResult.ALLOW, + }, + { + id: '456', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: { rule: 'RULE_1', params: ['no'] }, + }, + { + id: '567', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-2', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: { rule: 'RULE_1', params: ['yes'] }, + }, + ]), + ).resolves.toEqual([ + { id: '123', result: AuthorizeResult.ALLOW }, + { id: '234', result: AuthorizeResult.DENY }, + { id: '345', result: AuthorizeResult.ALLOW }, + { id: '456', result: AuthorizeResult.DENY }, + { id: '567', result: AuthorizeResult.ALLOW }, + ]); + + expect(plugin1Router).toHaveBeenCalledTimes(1); + expect(plugin2Router).toHaveBeenCalledTimes(1); }); }); }); diff --git a/plugins/permission-backend/src/service/PermissionIntegrationClient.ts b/plugins/permission-backend/src/service/PermissionIntegrationClient.ts index de42a7f194..644cac1b38 100644 --- a/plugins/permission-backend/src/service/PermissionIntegrationClient.ts +++ b/plugins/permission-backend/src/service/PermissionIntegrationClient.ts @@ -14,22 +14,37 @@ * limitations under the License. */ +import { groupBy, keyBy } from 'lodash'; import fetch from 'node-fetch'; import { z } from 'zod'; import { PluginEndpointDiscovery } from '@backstage/backend-common'; import { + AuthorizeResponse, AuthorizeResult, - PermissionCondition, - PermissionCriteria, + Identified, } from '@backstage/plugin-permission-common'; import { - ApplyConditionsRequest, ApplyConditionsResponse, + ConditionalPolicyDecision, + PolicyDecision, } from '@backstage/plugin-permission-node'; -const responseSchema = z.object({ - result: z.literal(AuthorizeResult.ALLOW).or(z.literal(AuthorizeResult.DENY)), -}); +const responseSchema = z.array( + z.object({ + id: z.string(), + result: z + .literal(AuthorizeResult.ALLOW) + .or(z.literal(AuthorizeResult.DENY)), + }), +); + +export type ResourcePolicyDecision = Identified< + PolicyDecision & { resourceRef?: string } +>; + +type ConditionalResourcePolicyDecision = Identified< + ConditionalPolicyDecision & { resourceRef: string } +>; export class PermissionIntegrationClient { private readonly discovery: PluginEndpointDiscovery; @@ -39,32 +54,39 @@ export class PermissionIntegrationClient { } async applyConditions( - { - pluginId, - resourceRef, - resourceType, - conditions, - }: { - resourceRef: string; - pluginId: string; - resourceType: string; - conditions: PermissionCriteria; - }, + decisions: ResourcePolicyDecision[], + authHeader?: string, + ): Promise[]> { + const responses = await Promise.all( + this.groupRequestsByPluginId(decisions).map(([pluginId, requests]) => + this.makeRequest(pluginId, requests, authHeader), + ), + ); + + const responseIndex = keyBy(responses.flat(), 'id'); + + return decisions.map(decision => responseIndex[decision.id] ?? decision); + } + + private async makeRequest( + pluginId: string, + decisions: ConditionalResourcePolicyDecision[], authHeader?: string, ): Promise { const endpoint = `${await this.discovery.getBaseUrl( pluginId, )}/.well-known/backstage/permissions/apply-conditions`; - const request: ApplyConditionsRequest = { - resourceRef, - resourceType, - conditions, - }; - const response = await fetch(endpoint, { method: 'POST', - body: JSON.stringify(request), + body: JSON.stringify( + decisions.map(({ id, resourceRef, resourceType, conditions }) => ({ + id, + resourceRef, + resourceType, + conditions, + })), + ), headers: { ...(authHeader ? { authorization: authHeader } : {}), 'content-type': 'application/json', @@ -79,4 +101,19 @@ export class PermissionIntegrationClient { return responseSchema.parse(await response.json()); } + + private groupRequestsByPluginId( + decisions: ResourcePolicyDecision[], + ): [string, ConditionalResourcePolicyDecision[]][] { + return Object.entries( + groupBy( + decisions.filter( + (decision): decision is ConditionalResourcePolicyDecision => + decision.result === AuthorizeResult.CONDITIONAL && + !!decision.resourceRef, + ), + 'pluginId', + ), + ); + } } diff --git a/plugins/permission-backend/src/service/router.test.ts b/plugins/permission-backend/src/service/router.test.ts index 26fa7ef8a6..ef165b2ac5 100644 --- a/plugins/permission-backend/src/service/router.test.ts +++ b/plugins/permission-backend/src/service/router.test.ts @@ -19,14 +19,34 @@ import request from 'supertest'; import { getVoidLogger } from '@backstage/backend-common'; import { IdentityClient } from '@backstage/plugin-auth-backend'; import { AuthorizeResult } from '@backstage/plugin-permission-common'; -import { ApplyConditionsResponse } from '@backstage/plugin-permission-node'; +import { ApplyConditionsResponseEntry } from '@backstage/plugin-permission-node'; import { PermissionIntegrationClient } from './PermissionIntegrationClient'; import { createRouter } from './router'; const mockApplyConditions: jest.MockedFunction< InstanceType['applyConditions'] -> = jest.fn(); +> = jest.fn(async decisions => + decisions.map(decision => { + if ( + decision.result === AuthorizeResult.CONDITIONAL && + decision.resourceRef + ) { + return { id: decision.id, result: AuthorizeResult.DENY as const }; + } + + if (decision.result === AuthorizeResult.CONDITIONAL) { + return { + id: decision.id, + result: decision.result, + conditions: decision.conditions, + }; + } + + return decision; + }), +); + jest.mock('./PermissionIntegrationClient', () => ({ PermissionIntegrationClient: jest.fn(() => ({ applyConditions: mockApplyConditions, @@ -34,7 +54,7 @@ jest.mock('./PermissionIntegrationClient', () => ({ })); const policy = { - handle: jest.fn().mockImplementation((_req, identity) => { + handle: jest.fn().mockImplementation(async (_req, identity) => { if (identity) { return { result: AuthorizeResult.ALLOW }; } @@ -159,7 +179,7 @@ describe('createRouter', () => { describe('conditional policy result', () => { beforeEach(() => { - policy.handle.mockReturnValueOnce({ + policy.handle.mockResolvedValue({ result: AuthorizeResult.CONDITIONAL, pluginId: 'test-plugin', resourceType: 'test-resource-1', @@ -193,15 +213,22 @@ describe('createRouter', () => { ]); }); - it.each([ + it.each([ AuthorizeResult.ALLOW, AuthorizeResult.DENY, ])( 'applies conditions and returns %s if resourceRef is supplied', async result => { - mockApplyConditions.mockResolvedValueOnce({ - result, - }); + mockApplyConditions.mockResolvedValueOnce([ + { + id: '123', + result, + }, + { + id: '234', + result, + }, + ]); const response = await request(app) .post('/authorize') @@ -216,15 +243,35 @@ describe('createRouter', () => { attributes: {}, }, }, + { + id: '234', + resourceRef: 'test/resource', + permission: { + name: 'test.permission', + resourceType: 'test-resource-1', + attributes: {}, + }, + }, ]); expect(mockApplyConditions).toHaveBeenCalledWith( - { - pluginId: 'test-plugin', - resourceType: 'test-resource-1', - resourceRef: 'test/resource', - conditions: { anyOf: [{ rule: 'test-rule', params: ['abc'] }] }, - }, + [ + expect.objectContaining({ + id: '123', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'test-plugin', + resourceType: 'test-resource-1', + resourceRef: 'test/resource', + conditions: { anyOf: [{ rule: 'test-rule', params: ['abc'] }] }, + }), + expect.objectContaining({ + id: '234', + pluginId: 'test-plugin', + resourceType: 'test-resource-1', + resourceRef: 'test/resource', + conditions: { anyOf: [{ rule: 'test-rule', params: ['abc'] }] }, + }), + ], 'Bearer test-token', ); @@ -234,6 +281,10 @@ describe('createRouter', () => { id: '123', result, }, + { + id: '234', + result, + }, ]); }, ); @@ -247,10 +298,10 @@ describe('createRouter', () => { [{ id: '123' }], [{ id: '123', permission: { name: 'test.permission' } }], [{ id: '123', permission: { attributes: { invalid: 'attribute' } } }], - ])('returns a 500 error for invalid request %#', async requestBody => { + ])('returns a 400 error for invalid request %#', async requestBody => { const response = await request(app).post('/authorize').send(requestBody); - expect(response.status).toEqual(500); + expect(response.status).toEqual(400); expect(response.body).toEqual( expect.objectContaining({ error: expect.objectContaining({ @@ -261,7 +312,7 @@ describe('createRouter', () => { }); it('returns a 500 error if the policy returns a different resourceType', async () => { - policy.handle.mockReturnValueOnce({ + policy.handle.mockResolvedValueOnce({ result: AuthorizeResult.CONDITIONAL, pluginId: 'test-plugin', resourceType: 'test-resource-2', diff --git a/plugins/permission-backend/src/service/router.ts b/plugins/permission-backend/src/service/router.ts index 41791b8fc8..0e877bc816 100644 --- a/plugins/permission-backend/src/service/router.ts +++ b/plugins/permission-backend/src/service/router.ts @@ -22,6 +22,7 @@ import { errorHandler, PluginEndpointDiscovery, } from '@backstage/backend-common'; +import { InputError } from '@backstage/errors'; import { BackstageIdentityResponse, IdentityClient, @@ -32,7 +33,10 @@ import { AuthorizeRequest, Identified, } from '@backstage/plugin-permission-common'; -import { PermissionPolicy } from '@backstage/plugin-permission-node'; +import { + PermissionPolicy, + PolicyDecision, +} from '@backstage/plugin-permission-node'; import { PermissionIntegrationClient } from './PermissionIntegrationClient'; const requestSchema: z.ZodSchema[]> = z.array( @@ -69,46 +73,55 @@ export interface RouterOptions { identity: IdentityClient; } -const handleRequest = async ( - { id, resourceRef, ...request }: Identified, - user: BackstageIdentityResponse | undefined, +const applyPolicy = async ( policy: PermissionPolicy, - permissionIntegrationClient: PermissionIntegrationClient, - authHeader?: string, -): Promise> => { - const response = await policy.handle(request, user); + requests: Identified[], + user: BackstageIdentityResponse | undefined, +): Promise[]> => { + return Promise.all( + requests.map(({ id, resourceRef, ...authorizeRequest }) => + policy.handle(authorizeRequest, user).then(decision => ({ + id, + ...(decision.result === AuthorizeResult.CONDITIONAL + ? { resourceRef } + : {}), + ...decision, + })), + ), + ); +}; + +const assertMatchingResourceTypes = ( + requests: AuthorizeRequest[], + decisions: PolicyDecision[], +) => { + requests.forEach((request, index) => { + const decision = decisions[index]; - if (response.result === AuthorizeResult.CONDITIONAL) { // Sanity check that any resource provided matches the one expected by the permission - if (request.permission.resourceType !== response.resourceType) { + if ( + decision.result === AuthorizeResult.CONDITIONAL && + decision.resourceType !== request.permission.resourceType + ) { throw new Error( `Invalid resource conditions returned from permission policy for permission ${request.permission.name}`, ); } + }); +}; - if (resourceRef) { - return { - id, - ...(await permissionIntegrationClient.applyConditions( - { - resourceRef, - pluginId: response.pluginId, - resourceType: response.resourceType, - conditions: response.conditions, - }, - authHeader, - )), - }; - } +const handleRequest = async ( + requests: Identified[], + user: BackstageIdentityResponse | undefined, + policy: PermissionPolicy, + permissionIntegrationClient: PermissionIntegrationClient, + authHeader?: string, +): Promise[]> => { + const decisions = await applyPolicy(policy, requests, user); - return { - id, - result: AuthorizeResult.CONDITIONAL, - conditions: response.conditions, - }; - } + assertMatchingResourceTypes(requests, decisions); - return { id, ...response }; + return permissionIntegrationClient.applyConditions(decisions, authHeader); }; /** @@ -142,24 +155,27 @@ export async function createRouter( const token = IdentityClient.getBearerToken(req.header('authorization')); const user = token ? await identity.authenticate(token) : undefined; - const body = requestSchema.parse(req.body); + const parseResult = requestSchema.safeParse(req.body); + + if (!parseResult.success) { + throw new InputError(parseResult.error.toString()); + } + + const body = parseResult.data; res.json( - await Promise.all( - body.map(request => - handleRequest( - request, - user, - policy, - permissionIntegrationClient, - req.header('authorization'), - ), - ), + await handleRequest( + body, + user, + policy, + permissionIntegrationClient, + req.header('authorization'), ), ); }, ); router.use(errorHandler()); + return router; } diff --git a/plugins/permission-node/api-report.md b/plugins/permission-node/api-report.md index e743f18311..9e0d521cd3 100644 --- a/plugins/permission-node/api-report.md +++ b/plugins/permission-node/api-report.md @@ -9,24 +9,29 @@ import { AuthorizeResponse } from '@backstage/plugin-permission-common'; import { AuthorizeResult } from '@backstage/plugin-permission-common'; import { BackstageIdentityResponse } from '@backstage/plugin-auth-backend'; import { Config } from '@backstage/config'; +import express from 'express'; +import { Identified } from '@backstage/plugin-permission-common'; import { PermissionAuthorizer } from '@backstage/plugin-permission-common'; import { PermissionCondition } from '@backstage/plugin-permission-common'; import { PermissionCriteria } from '@backstage/plugin-permission-common'; import { PluginEndpointDiscovery } from '@backstage/backend-common'; -import { Router } from 'express'; import { TokenManager } from '@backstage/backend-common'; // @public -export type ApplyConditionsRequest = { +export type ApplyConditionsRequest = ApplyConditionsRequestEntry[]; + +// @public +export type ApplyConditionsRequestEntry = Identified<{ resourceRef: string; resourceType: string; conditions: PermissionCriteria; -}; +}>; // @public -export type ApplyConditionsResponse = { - result: AuthorizeResult.ALLOW | AuthorizeResult.DENY; -}; +export type ApplyConditionsResponse = ApplyConditionsResponseEntry[]; + +// @public +export type ApplyConditionsResponseEntry = Identified; // @public export type Condition = TRule extends PermissionRule< @@ -93,7 +98,12 @@ export const createPermissionIntegrationRouter: (options: { resourceType: string; rules: PermissionRule[]; getResource: (resourceRef: string) => Promise; -}) => Router; +}) => express.Router; + +// @public +export type DefinitivePolicyDecision = { + result: AuthorizeResult.ALLOW | AuthorizeResult.DENY; +}; // @public export const createPermissionRule: < @@ -137,9 +147,7 @@ export type PolicyAuthorizeRequest = Omit; // @public export type PolicyDecision = - | { - result: AuthorizeResult.ALLOW | AuthorizeResult.DENY; - } + | DefinitivePolicyDecision | ConditionalPolicyDecision; // @public diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index 55f955110e..a5b32e2507 100644 --- a/plugins/permission-node/package.json +++ b/plugins/permission-node/package.json @@ -31,10 +31,12 @@ "dependencies": { "@backstage/backend-common": "^0.10.1", "@backstage/config": "^0.1.11", + "@backstage/errors": "^0.1.5", "@backstage/plugin-auth-backend": "^0.6.0", "@backstage/plugin-permission-common": "^0.3.0", "@types/express": "^4.17.6", "express": "^4.17.1", + "express-promise-router": "^4.1.0", "zod": "^3.11.6" }, "devDependencies": { diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts index 15c9cf4003..c7c48ae9fc 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts @@ -16,16 +16,12 @@ import { AuthorizeResult } from '@backstage/plugin-permission-common'; import express, { Express, Router } from 'express'; -import request from 'supertest'; +import request, { Response } from 'supertest'; import { createPermissionIntegrationRouter } from './createPermissionIntegrationRouter'; const mockGetResource: jest.MockedFunction< - (resourceRef: string) => Promise -> = jest.fn((resourceRef: string) => - Promise.resolve({ - resourceRef, - }), -); + Parameters[0]['getResource'] +> = jest.fn(async resourceRef => ({ id: resourceRef })); const testRule1 = { name: 'test-rule-1', @@ -47,7 +43,7 @@ describe('createPermissionIntegrationRouter', () => { let app: Express; let router: Router; - beforeEach(() => { + beforeAll(() => { router = createPermissionIntegrationRouter({ resourceType: 'test-resource', getResource: mockGetResource, @@ -57,6 +53,10 @@ describe('createPermissionIntegrationRouter', () => { app = express().use(router); }); + afterEach(() => { + jest.clearAllMocks(); + }); + it('works', async () => { expect(router).toBeDefined(); }); @@ -70,7 +70,6 @@ describe('createPermissionIntegrationRouter', () => { { rule: 'test-rule-2', params: [{}] }, ], }, - { not: { rule: 'test-rule-2', params: [{}] }, }, @@ -95,14 +94,22 @@ describe('createPermissionIntegrationRouter', () => { ])('returns 200/ALLOW when criteria match (case %#)', async conditions => { const response = await request(app) .post('/.well-known/backstage/permissions/apply-conditions') - .send({ - resourceRef: 'default:test/resource', - resourceType: 'test-resource', - conditions, - }); + .send([ + { + id: '123', + resourceRef: 'default:test/resource', + resourceType: 'test-resource', + conditions, + }, + ]); expect(response.status).toEqual(200); - expect(response.body).toEqual({ result: AuthorizeResult.ALLOW }); + expect(response.body).toEqual([ + { + id: '123', + result: AuthorizeResult.ALLOW, + }, + ]); }); it.each([ @@ -136,27 +143,92 @@ describe('createPermissionIntegrationRouter', () => { async conditions => { const response = await request(app) .post('/.well-known/backstage/permissions/apply-conditions') - .send({ - resourceRef: 'default:test/resource', - resourceType: 'test-resource', - conditions, - }); + .send([ + { + id: '123', + resourceRef: 'default:test/resource', + resourceType: 'test-resource', + conditions, + }, + ]); expect(response.status).toEqual(200); - expect(response.body).toEqual({ result: AuthorizeResult.DENY }); + expect(response.body).toEqual([ + { id: '123', result: AuthorizeResult.DENY }, + ]); }, ); + describe('batched requests', () => { + let response: Response; + + beforeEach(async () => { + response = await request(app) + .post('/.well-known/backstage/permissions/apply-conditions') + .send([ + { + id: '123', + resourceRef: 'default:test/resource-1', + resourceType: 'test-resource', + conditions: { rule: 'test-rule-1', params: [] }, + }, + { + id: '234', + resourceRef: 'default:test/resource-1', + resourceType: 'test-resource', + conditions: { rule: 'test-rule-2', params: [] }, + }, + { + id: '345', + resourceRef: 'default:test/resource-2', + resourceType: 'test-resource', + conditions: { not: { rule: 'test-rule-1', params: [] } }, + }, + { + id: '456', + resourceRef: 'default:test/resource-3', + resourceType: 'test-resource', + conditions: { not: { rule: 'test-rule-2', params: [] } }, + }, + { + id: '567', + resourceRef: 'default:test/resource-4', + resourceType: 'test-resource', + conditions: { + anyOf: [ + { rule: 'test-rule-1', params: [] }, + { rule: 'test-rule-2', params: [] }, + ], + }, + }, + ]); + }); + + it('processes batched requests', () => { + expect(response.status).toEqual(200); + expect(response.body).toEqual([ + { id: '123', result: AuthorizeResult.ALLOW }, + { id: '234', result: AuthorizeResult.DENY }, + { id: '345', result: AuthorizeResult.DENY }, + { id: '456', result: AuthorizeResult.ALLOW }, + { id: '567', result: AuthorizeResult.ALLOW }, + ]); + }); + }); + it('returns 400 when called with incorrect resource type', async () => { const response = await request(app) .post('/.well-known/backstage/permissions/apply-conditions') - .send({ - resourceRef: 'default:test/resource', - resourceType: 'test-incorrect-resource', - conditions: { - anyOf: [], + .send([ + { + id: '123', + resourceRef: 'default:test/resource', + resourceType: 'test-incorrect-resource', + conditions: { + anyOf: [], + }, }, - }); + ]); expect(response.status).toEqual(400); expect(response.error && response.error.text).toMatch( @@ -164,47 +236,50 @@ describe('createPermissionIntegrationRouter', () => { ); }); - it('returns 400 when resource is not found', async () => { + it('returns 200/DENY when resource is not found', async () => { mockGetResource.mockReturnValueOnce(Promise.resolve(undefined)); const response = await request(app) .post('/.well-known/backstage/permissions/apply-conditions') - .send({ - resourceRef: 'default:test/resource', - resourceType: 'test-resource', - conditions: { - not: { - rule: 'testRule1', - params: ['a', 1], - }, + .send([ + { + id: '123', + resourceRef: 'default:test/resource', + resourceType: 'test-resource', + conditions: { rule: 'testRule1', params: [] }, }, - }); + ]); - expect(response.status).toEqual(400); - expect(response.error && response.error.text).toMatch( - /resource for ref default:test\/resource not found/i, - ); + expect(response.status).toEqual(200); + expect(response.body).toEqual([ + { + id: '123', + result: AuthorizeResult.DENY, + }, + ]); }); it.each([ undefined, + '', {}, { resourceType: 'test-resource-type' }, - { resourceRef: 'test/resource-ref' }, - { - resourceType: 'test-resource-type', - resourceRef: 'test/resource-ref', - }, - { conditions: { anyOf: [] } }, + [{ resourceType: 'test-resource-type' }], + [{ resourceRef: 'test/resource-ref' }], + [ + { + resourceType: 'test-resource-type', + resourceRef: 'test/resource-ref', + }, + ], + [{ conditions: { anyOf: [] } }], ])(`returns 400 for invalid input %#`, async input => { const response = await request(app) .post('/.well-known/backstage/permissions/apply-conditions') .send(input); expect(response.status).toEqual(400); - expect(response.error && response.error.text).toMatch( - /invalid request body/i, - ); + expect(response.error && response.error.text).toMatch(/invalid/i); }); }); }); diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts index b8d3e02a81..919af47c02 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts @@ -14,10 +14,14 @@ * limitations under the License. */ -import express, { Response, Router } from 'express'; +import express, { Response } from 'express'; +import Router from 'express-promise-router'; import { z } from 'zod'; +import { InputError } from '@backstage/errors'; +import { errorHandler } from '@backstage/backend-common'; import { AuthorizeResult, + Identified, PermissionCondition, PermissionCriteria, } from '@backstage/plugin-permission-common'; @@ -28,6 +32,7 @@ import { isNotCriteria, isOrCriteria, } from './util'; +import { DefinitivePolicyDecision } from '../policy/types'; const permissionCriteriaSchema: z.ZodSchema< PermissionCriteria @@ -43,11 +48,14 @@ const permissionCriteriaSchema: z.ZodSchema< ]), ); -const applyConditionsRequestSchema = z.object({ - resourceRef: z.string(), - resourceType: z.string(), - conditions: permissionCriteriaSchema, -}); +const applyConditionsRequestSchema = z.array( + z.object({ + id: z.string(), + resourceRef: z.string(), + resourceType: z.string(), + conditions: permissionCriteriaSchema, + }), +); /** * A request to load the referenced resource and apply conditions in order to @@ -55,11 +63,18 @@ const applyConditionsRequestSchema = z.object({ * * @public */ -export type ApplyConditionsRequest = { +export type ApplyConditionsRequestEntry = Identified<{ resourceRef: string; resourceType: string; conditions: PermissionCriteria; -}; +}>; + +/** + * A batch of {@link ApplyConditionsRequestEntry} objects. + * + * @public + */ +export type ApplyConditionsRequest = ApplyConditionsRequestEntry[]; /** * The result of applying the conditions, expressed as a definitive authorize @@ -67,15 +82,27 @@ export type ApplyConditionsRequest = { * * @public */ -export type ApplyConditionsResponse = { - result: AuthorizeResult.ALLOW | AuthorizeResult.DENY; -}; +export type ApplyConditionsResponseEntry = Identified; + +/** + * A batch of {@link ApplyConditionsResponseEntry} objects. + * + * @public + */ +export type ApplyConditionsResponse = ApplyConditionsResponseEntry[]; const applyConditions = ( criteria: PermissionCriteria, resource: TResource, getRule: (name: string) => PermissionRule, ): boolean => { + // If resource was not found, deny. This avoids leaking information from the + // apply-conditions API which would allow a user to differentiate between + // non-existent resources and resources to which they do not have access. + if (typeof resource === 'undefined') { + return false; + } + if (isAndCriteria(criteria)) { return criteria.allOf.every(child => applyConditions(child, resource, getRule), @@ -92,30 +119,37 @@ const applyConditions = ( }; /** - * Create an express Router which provides an authorization route to allow integration between the - * permission backend and other Backstage backend plugins. Plugin owners that wish to support - * conditional authorization for their resources should add the router created by this function - * to their express app inside their `createRouter` implementation. + * Create an express Router which provides an authorization route to allow + * integration between the permission backend and other Backstage backend + * plugins. Plugin owners that wish to support conditional authorization for + * their resources should add the router created by this function to their + * express app inside their `createRouter` implementation. * * @remarks * - * To make this concrete, we can use the Backstage software catalog as an example. The catalog has - * conditional rules around access to specific _entities_ in the catalog. The _type_ of resource is - * captured here as `resourceType`, a string identifier (`catalog-entity` in this example) that can - * be provided with permission definitions. This is merely a _type_ to verify that conditions in an - * authorization policy are constructed correctly, not a reference to a specific resource. + * To make this concrete, we can use the Backstage software catalog as an + * example. The catalog has conditional rules around access to specific + * _entities_ in the catalog. The _type_ of resource is captured here as + * `resourceType`, a string identifier (`catalog-entity` in this example) that + * can be provided with permission definitions. This is merely a _type_ to + * verify that conditions in an authorization policy are constructed correctly, + * not a reference to a specific resource. * - * The `rules` parameter is an array of {@link PermissionRule}s that introduce conditional - * filtering logic for resources; for the catalog, these are things like `isEntityOwner` or - * `hasAnnotation`. Rules describe how to filter a list of resources, and the `conditions` returned - * allow these rules to be applied with specific parameters (such as 'group:default/team-a', or + * The `rules` parameter is an array of {@link PermissionRule}s that introduce + * conditional filtering logic for resources; for the catalog, these are things + * like `isEntityOwner` or `hasAnnotation`. Rules describe how to filter a list + * of resources, and the `conditions` returned allow these rules to be applied + * with specific parameters (such as 'group:default/team-a', or * 'backstage.io/edit-url'). * - * The `getResource` argument should load a resource by reference. For the catalog, this is an - * {@link @backstage/catalog-model#EntityRef}. For other plugins, this can be any serialized format. - * This is used to construct the `createPermissionIntegrationRouter`, a function to add an - * authorization route to your backend plugin. This route will be called by the `permission-backend` - * when authorization conditions relating to this plugin need to be evaluated. + * The `getResources` argument should load resources based on a reference + * identifier. For the catalog, this is an + * {@link @backstage/catalog-model#EntityRef}. For other plugins, this can be + * any serialized format. This is used to construct the + * `createPermissionIntegrationRouter`, a function to add an authorization route + * to your backend plugin. This function will be called by the + * `permission-backend` when authorization conditions relating to this plugin + * need to be evaluated. * * @public */ @@ -123,53 +157,60 @@ export const createPermissionIntegrationRouter = (options: { resourceType: string; rules: PermissionRule[]; getResource: (resourceRef: string) => Promise; -}): Router => { +}): express.Router => { const { resourceType, rules, getResource } = options; const router = Router(); const getRule = createGetRule(rules); + const assertValidResourceTypes = (requests: ApplyConditionsRequest) => { + const invalidResourceType = requests.find( + request => request.resourceType !== resourceType, + )?.resourceType; + + if (invalidResourceType) { + throw new InputError(`Unexpected resource type: ${invalidResourceType}.`); + } + }; + + router.use(express.json()); + router.post( '/.well-known/backstage/permissions/apply-conditions', - express.json(), - async ( - req, - res: Response< - | { - result: Omit; - } - | string - >, - ) => { + async (req, res: Response) => { const parseResult = applyConditionsRequestSchema.safeParse(req.body); if (!parseResult.success) { - return res.status(400).send(`Invalid request body.`); + throw new InputError(parseResult.error.toString()); } - const { data: body } = parseResult; + const body = parseResult.data; - if (body.resourceType !== resourceType) { - return res - .status(400) - .send(`Unexpected resource type: ${body.resourceType}.`); + assertValidResourceTypes(body); + + const resources = {} as Record; + for (const { resourceRef } of body) { + if (!resources[resourceRef]) { + resources[resourceRef] = await getResource(resourceRef); + } } - const resource = await getResource(body.resourceRef); - - if (!resource) { - return res - .status(400) - .send(`Resource for ref ${body.resourceRef} not found.`); - } - - return res.status(200).json({ - result: applyConditions(body.conditions, resource, getRule) - ? AuthorizeResult.ALLOW - : AuthorizeResult.DENY, - }); + return res.status(200).json( + body.map(request => ({ + id: request.id, + result: applyConditions( + request.conditions, + resources[request.resourceRef], + getRule, + ) + ? AuthorizeResult.ALLOW + : AuthorizeResult.DENY, + })), + ); }, ); + router.use(errorHandler()); + return router; }; diff --git a/plugins/permission-node/src/policy/index.ts b/plugins/permission-node/src/policy/index.ts index c8216989a1..1b05f240d3 100644 --- a/plugins/permission-node/src/policy/index.ts +++ b/plugins/permission-node/src/policy/index.ts @@ -16,6 +16,7 @@ export type { ConditionalPolicyDecision, + DefinitivePolicyDecision, PermissionPolicy, PolicyAuthorizeRequest, PolicyDecision, diff --git a/plugins/permission-node/src/policy/types.ts b/plugins/permission-node/src/policy/types.ts index d122ad8d8d..4c6a033e11 100644 --- a/plugins/permission-node/src/policy/types.ts +++ b/plugins/permission-node/src/policy/types.ts @@ -35,6 +35,19 @@ import { BackstageIdentityResponse } from '@backstage/plugin-auth-backend'; */ export type PolicyAuthorizeRequest = Omit; +/** + * A definitive result to an authorization request, returned by the {@link PermissionPolicy}. + * + * @remarks + * + * This indicates that the policy unconditionally allows (or denies) the request. + * + * @public + */ +export type DefinitivePolicyDecision = { + result: AuthorizeResult.ALLOW | AuthorizeResult.DENY; +}; + /** * A conditional result to an authorization request, returned by the {@link PermissionPolicy}. * @@ -61,7 +74,7 @@ export type ConditionalPolicyDecision = { * @public */ export type PolicyDecision = - | { result: AuthorizeResult.ALLOW | AuthorizeResult.DENY } + | DefinitivePolicyDecision | ConditionalPolicyDecision; /** From 706b6c29e9a69afa03bef3c0be5f964236705804 Mon Sep 17 00:00:00 2001 From: MT Lewis Date: Mon, 20 Dec 2021 14:37:45 +0000 Subject: [PATCH 33/56] permission-node: allow batch retrieval of resources in /apply-conditions Signed-off-by: MT Lewis --- .../PermissionIntegrationClient.test.ts | 6 ++++- plugins/permission-node/api-report.md | 2 +- .../createPermissionIntegrationRouter.test.ts | 24 +++++++++++++++---- .../createPermissionIntegrationRouter.ts | 13 ++++------ 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts b/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts index 79f604e948..57beda9c1f 100644 --- a/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts +++ b/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts @@ -275,7 +275,11 @@ describe('PermissionIntegrationClient', () => { router.use( createPermissionIntegrationRouter({ resourceType: 'test-resource', - getResource: async resourceRef => ({ id: resourceRef }), + getResources: async resourceRefs => + resourceRefs.reduce((acc, ref) => { + acc[ref] = { id: ref }; + return acc; + }, {} as Record), rules: [ { name: 'RULE_1', diff --git a/plugins/permission-node/api-report.md b/plugins/permission-node/api-report.md index 9e0d521cd3..e90a1f2677 100644 --- a/plugins/permission-node/api-report.md +++ b/plugins/permission-node/api-report.md @@ -97,7 +97,7 @@ export const createConditionTransformer: < export const createPermissionIntegrationRouter: (options: { resourceType: string; rules: PermissionRule[]; - getResource: (resourceRef: string) => Promise; + getResources: (resourceRefs: string[]) => Promise>; }) => express.Router; // @public diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts index c7c48ae9fc..37495ae76e 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts @@ -19,9 +19,14 @@ import express, { Express, Router } from 'express'; import request, { Response } from 'supertest'; import { createPermissionIntegrationRouter } from './createPermissionIntegrationRouter'; -const mockGetResource: jest.MockedFunction< - Parameters[0]['getResource'] -> = jest.fn(async resourceRef => ({ id: resourceRef })); +const mockGetResources: jest.MockedFunction< + Parameters[0]['getResources'] +> = jest.fn(async resourceRefs => + resourceRefs.reduce( + (acc, resourceRef) => ({ ...acc, [resourceRef]: { id: resourceRef } }), + {}, + ), +); const testRule1 = { name: 'test-rule-1', @@ -46,7 +51,7 @@ describe('createPermissionIntegrationRouter', () => { beforeAll(() => { router = createPermissionIntegrationRouter({ resourceType: 'test-resource', - getResource: mockGetResource, + getResources: mockGetResources, rules: [testRule1, testRule2], }); @@ -214,6 +219,15 @@ describe('createPermissionIntegrationRouter', () => { { id: '567', result: AuthorizeResult.ALLOW }, ]); }); + + it('calls getResources for all required resources at once', () => { + expect(mockGetResources).toHaveBeenCalledWith([ + 'default:test/resource-1', + 'default:test/resource-2', + 'default:test/resource-3', + 'default:test/resource-4', + ]); + }); }); it('returns 400 when called with incorrect resource type', async () => { @@ -237,7 +251,7 @@ describe('createPermissionIntegrationRouter', () => { }); it('returns 200/DENY when resource is not found', async () => { - mockGetResource.mockReturnValueOnce(Promise.resolve(undefined)); + mockGetResources.mockReturnValueOnce(Promise.resolve({})); const response = await request(app) .post('/.well-known/backstage/permissions/apply-conditions') diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts index 919af47c02..c15f3cc80b 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts @@ -156,9 +156,9 @@ const applyConditions = ( export const createPermissionIntegrationRouter = (options: { resourceType: string; rules: PermissionRule[]; - getResource: (resourceRef: string) => Promise; + getResources: (resourceRefs: string[]) => Promise>; }): express.Router => { - const { resourceType, rules, getResource } = options; + const { resourceType, rules, getResources } = options; const router = Router(); const getRule = createGetRule(rules); @@ -188,12 +188,9 @@ export const createPermissionIntegrationRouter = (options: { assertValidResourceTypes(body); - const resources = {} as Record; - for (const { resourceRef } of body) { - if (!resources[resourceRef]) { - resources[resourceRef] = await getResource(resourceRef); - } - } + const resources = await getResources( + Array.from(new Set(body.map(({ resourceRef }) => resourceRef))), + ); return res.status(200).json( body.map(request => ({ From 419ca637c075ae4765a8e9674080642a96521c08 Mon Sep 17 00:00:00 2001 From: MT Lewis Date: Mon, 20 Dec 2021 15:14:38 +0000 Subject: [PATCH 34/56] permissions: add changeset for optimizations Signed-off-by: MT Lewis --- .changeset/shiny-bugs-beam.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .changeset/shiny-bugs-beam.md diff --git a/.changeset/shiny-bugs-beam.md b/.changeset/shiny-bugs-beam.md new file mode 100644 index 0000000000..bc50486526 --- /dev/null +++ b/.changeset/shiny-bugs-beam.md @@ -0,0 +1,11 @@ +--- +'@backstage/plugin-permission-backend': minor +'@backstage/plugin-permission-node': minor +--- + +Optimizations to the integration between the permission backend and plugin-backends using createPermissionIntegrationRouter: + +- The permission backend already supported batched requests to authorize, but would make calls to plugin backend to apply conditions serially. Now, after applying the policy for each authorization request, the permission backend makes a single batched /apply-conditions request to each plugin backend referenced in policy decisions. +- The `getResource` method accepted by `createPermissionIntegrationRouter` has been replaced with `getResources`, to allow consumers to make batch requests to upstream data stores. When /apply-conditions is called with a batch of requests, all required resources are requested in a single invocation of `getResources`. + +Plugin owners consuming `createPermissionIntegrationRouter` should replace the `getResource` method in the options with a `getResources` method, accepting an array of resourceRefs, and returning a record object mapping those resourceRefs to resources (if present). From 8e72b573aa0b7b9e6fbd43de137b48614aac4bf7 Mon Sep 17 00:00:00 2001 From: MT Lewis Date: Mon, 20 Dec 2021 17:17:20 +0000 Subject: [PATCH 35/56] permission-node: switch to array for getResources return value Signed-off-by: MT Lewis --- .changeset/shiny-bugs-beam.md | 2 +- .../service/PermissionIntegrationClient.test.ts | 7 +++---- plugins/permission-node/api-report.md | 2 +- .../createPermissionIntegrationRouter.test.ts | 9 ++++----- .../createPermissionIntegrationRouter.ts | 14 +++++++++++--- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/.changeset/shiny-bugs-beam.md b/.changeset/shiny-bugs-beam.md index bc50486526..b16c8d6729 100644 --- a/.changeset/shiny-bugs-beam.md +++ b/.changeset/shiny-bugs-beam.md @@ -8,4 +8,4 @@ Optimizations to the integration between the permission backend and plugin-backe - The permission backend already supported batched requests to authorize, but would make calls to plugin backend to apply conditions serially. Now, after applying the policy for each authorization request, the permission backend makes a single batched /apply-conditions request to each plugin backend referenced in policy decisions. - The `getResource` method accepted by `createPermissionIntegrationRouter` has been replaced with `getResources`, to allow consumers to make batch requests to upstream data stores. When /apply-conditions is called with a batch of requests, all required resources are requested in a single invocation of `getResources`. -Plugin owners consuming `createPermissionIntegrationRouter` should replace the `getResource` method in the options with a `getResources` method, accepting an array of resourceRefs, and returning a record object mapping those resourceRefs to resources (if present). +Plugin owners consuming `createPermissionIntegrationRouter` should replace the `getResource` method in the options with a `getResources` method, accepting an array of resourceRefs, and returning an array of the corresponding resources. diff --git a/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts b/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts index 57beda9c1f..4697277377 100644 --- a/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts +++ b/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts @@ -276,10 +276,9 @@ describe('PermissionIntegrationClient', () => { createPermissionIntegrationRouter({ resourceType: 'test-resource', getResources: async resourceRefs => - resourceRefs.reduce((acc, ref) => { - acc[ref] = { id: ref }; - return acc; - }, {} as Record), + resourceRefs.map(resourceRef => ({ + id: resourceRef, + })), rules: [ { name: 'RULE_1', diff --git a/plugins/permission-node/api-report.md b/plugins/permission-node/api-report.md index e90a1f2677..7023369306 100644 --- a/plugins/permission-node/api-report.md +++ b/plugins/permission-node/api-report.md @@ -97,7 +97,7 @@ export const createConditionTransformer: < export const createPermissionIntegrationRouter: (options: { resourceType: string; rules: PermissionRule[]; - getResources: (resourceRefs: string[]) => Promise>; + getResources: (resourceRefs: string[]) => Promise<(TResource | undefined)[]>; }) => express.Router; // @public diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts index 37495ae76e..2e911b7cae 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts @@ -22,10 +22,7 @@ import { createPermissionIntegrationRouter } from './createPermissionIntegration const mockGetResources: jest.MockedFunction< Parameters[0]['getResources'] > = jest.fn(async resourceRefs => - resourceRefs.reduce( - (acc, resourceRef) => ({ ...acc, [resourceRef]: { id: resourceRef } }), - {}, - ), + resourceRefs.map(resourceRef => ({ id: resourceRef })), ); const testRule1 = { @@ -251,7 +248,9 @@ describe('createPermissionIntegrationRouter', () => { }); it('returns 200/DENY when resource is not found', async () => { - mockGetResources.mockReturnValueOnce(Promise.resolve({})); + mockGetResources.mockImplementationOnce(async resourceRefs => + resourceRefs.map(() => undefined), + ); const response = await request(app) .post('/.well-known/backstage/permissions/apply-conditions') diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts index c15f3cc80b..0fdbab7a9f 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts @@ -156,7 +156,9 @@ const applyConditions = ( export const createPermissionIntegrationRouter = (options: { resourceType: string; rules: PermissionRule[]; - getResources: (resourceRefs: string[]) => Promise>; + getResources: ( + resourceRefs: string[], + ) => Promise>; }): express.Router => { const { resourceType, rules, getResources } = options; const router = Router(); @@ -188,9 +190,15 @@ export const createPermissionIntegrationRouter = (options: { assertValidResourceTypes(body); - const resources = await getResources( - Array.from(new Set(body.map(({ resourceRef }) => resourceRef))), + const resourceRefs = Array.from( + new Set(body.map(({ resourceRef }) => resourceRef)), ); + const resourceArray = await getResources(resourceRefs); + const resources = resourceRefs.reduce((acc, resourceRef, index) => { + acc[resourceRef] = resourceArray[index]; + + return acc; + }, {} as Record); return res.status(200).json( body.map(request => ({ From cbb85e07f0687121c490a7b63df1594b108293ae Mon Sep 17 00:00:00 2001 From: MT Lewis Date: Wed, 22 Dec 2021 10:17:21 +0000 Subject: [PATCH 36/56] permission-node: simplify undefined check and fix applyConditions signature Signed-off-by: MT Lewis --- .../src/integration/createPermissionIntegrationRouter.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts index 0fdbab7a9f..747e47b87d 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts @@ -93,13 +93,13 @@ export type ApplyConditionsResponse = ApplyConditionsResponseEntry[]; const applyConditions = ( criteria: PermissionCriteria, - resource: TResource, + resource: TResource | undefined, getRule: (name: string) => PermissionRule, ): boolean => { // If resource was not found, deny. This avoids leaking information from the // apply-conditions API which would allow a user to differentiate between // non-existent resources and resources to which they do not have access. - if (typeof resource === 'undefined') { + if (resource === undefined) { return false; } From e4c2ee4ba7f0b1b5b2e224488e220c3e9e0519b7 Mon Sep 17 00:00:00 2001 From: MT Lewis Date: Wed, 5 Jan 2022 12:34:46 +0000 Subject: [PATCH 37/56] build(deps): add dependency on dataloader Signed-off-by: MT Lewis --- plugins/permission-backend/package.json | 1 + yarn.lock | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index f628984013..8a9bd61445 100644 --- a/plugins/permission-backend/package.json +++ b/plugins/permission-backend/package.json @@ -26,6 +26,7 @@ "@backstage/plugin-permission-common": "^0.3.0", "@backstage/plugin-permission-node": "^0.2.3", "@types/express": "*", + "dataloader": "^2.0.0", "express": "^4.17.1", "express-promise-router": "^4.1.0", "lodash": "^4.17.21", diff --git a/yarn.lock b/yarn.lock index c96d4cd39c..88afd4080a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12834,7 +12834,7 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" -dataloader@2.0.0: +dataloader@2.0.0, dataloader@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/dataloader/-/dataloader-2.0.0.tgz#41eaf123db115987e21ca93c005cd7753c55fe6f" integrity sha512-YzhyDAwA4TaQIhM5go+vCLmU0UikghC/t9DTQYZR2M/UvZ1MdOhPezSDZcjj9uqQJOMqjLcpWtyW2iNINdlatQ== From 85b9e1ae608faaa202104bb9b59a5e7441442fe6 Mon Sep 17 00:00:00 2001 From: MT Lewis Date: Wed, 5 Jan 2022 12:35:31 +0000 Subject: [PATCH 38/56] permission-backend: use dataloader in PermissionIntegrationClient Signed-off-by: MT Lewis --- .../PermissionIntegrationClient.test.ts | 76 +++++++++++++++++++ .../service/PermissionIntegrationClient.ts | 56 +++++++------- 2 files changed, 102 insertions(+), 30 deletions(-) diff --git a/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts b/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts index 4697277377..cc1de05127 100644 --- a/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts +++ b/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts @@ -484,5 +484,81 @@ describe('PermissionIntegrationClient', () => { expect(plugin1Router).toHaveBeenCalledTimes(1); expect(plugin2Router).toHaveBeenCalledTimes(1); }); + + it('leaves conditional results without resourceRefs unchanged', async () => { + await expect( + client.applyConditions([ + { + id: '123', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: { rule: 'RULE_1', params: ['yes'] }, + }, + { + id: '234', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-2', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: { rule: 'RULE_1', params: ['no'] }, + }, + { + id: '345', + result: AuthorizeResult.ALLOW, + }, + { + id: '456', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: { rule: 'RULE_1', params: ['no'] }, + }, + { + id: '567', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-2', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: { rule: 'RULE_1', params: ['yes'] }, + }, + { + id: '789', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-2', + resourceType: 'test-resource', + conditions: { + anyOf: [ + { rule: 'RULE_1', params: ['yes'] }, + { rule: 'RULE_2', params: ['yes'] }, + ], + }, + }, + ]), + ).resolves.toEqual([ + { id: '123', result: AuthorizeResult.ALLOW }, + { id: '234', result: AuthorizeResult.DENY }, + { id: '345', result: AuthorizeResult.ALLOW }, + { id: '456', result: AuthorizeResult.DENY }, + { id: '567', result: AuthorizeResult.ALLOW }, + { + id: '789', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-2', + resourceType: 'test-resource', + conditions: { + anyOf: [ + { rule: 'RULE_1', params: ['yes'] }, + { rule: 'RULE_2', params: ['yes'] }, + ], + }, + }, + ]); + + expect(plugin1Router).toHaveBeenCalledTimes(1); + expect(plugin2Router).toHaveBeenCalledTimes(1); + }); }); }); diff --git a/plugins/permission-backend/src/service/PermissionIntegrationClient.ts b/plugins/permission-backend/src/service/PermissionIntegrationClient.ts index 644cac1b38..520e8b19ae 100644 --- a/plugins/permission-backend/src/service/PermissionIntegrationClient.ts +++ b/plugins/permission-backend/src/service/PermissionIntegrationClient.ts @@ -14,9 +14,10 @@ * limitations under the License. */ -import { groupBy, keyBy } from 'lodash'; +import { memoize } from 'lodash'; import fetch from 'node-fetch'; import { z } from 'zod'; +import DataLoader from 'dataloader'; import { PluginEndpointDiscovery } from '@backstage/backend-common'; import { AuthorizeResponse, @@ -25,6 +26,7 @@ import { } from '@backstage/plugin-permission-common'; import { ApplyConditionsResponse, + ApplyConditionsResponseEntry, ConditionalPolicyDecision, PolicyDecision, } from '@backstage/plugin-permission-node'; @@ -38,12 +40,10 @@ const responseSchema = z.array( }), ); -export type ResourcePolicyDecision = Identified< - PolicyDecision & { resourceRef?: string } ->; - -type ConditionalResourcePolicyDecision = Identified< - ConditionalPolicyDecision & { resourceRef: string } +type ResourceDecision = Identified< + T & { + resourceRef?: string; + } >; export class PermissionIntegrationClient { @@ -54,23 +54,34 @@ export class PermissionIntegrationClient { } async applyConditions( - decisions: ResourcePolicyDecision[], + decisions: ResourceDecision[], authHeader?: string, ): Promise[]> { - const responses = await Promise.all( - this.groupRequestsByPluginId(decisions).map(([pluginId, requests]) => - this.makeRequest(pluginId, requests, authHeader), - ), + const loaderFor = memoize( + (pluginId: string) => + new DataLoader< + Identified, + ApplyConditionsResponseEntry + >(requests => this.makeRequest(pluginId, requests, authHeader)), ); - const responseIndex = keyBy(responses.flat(), 'id'); + return Promise.all( + decisions.map(decision => { + if ( + decision.result !== AuthorizeResult.CONDITIONAL || + !decision.resourceRef + ) { + return decision; + } - return decisions.map(decision => responseIndex[decision.id] ?? decision); + return loaderFor(decision.pluginId).load(decision); + }), + ); } private async makeRequest( pluginId: string, - decisions: ConditionalResourcePolicyDecision[], + decisions: readonly ResourceDecision[], authHeader?: string, ): Promise { const endpoint = `${await this.discovery.getBaseUrl( @@ -101,19 +112,4 @@ export class PermissionIntegrationClient { return responseSchema.parse(await response.json()); } - - private groupRequestsByPluginId( - decisions: ResourcePolicyDecision[], - ): [string, ConditionalResourcePolicyDecision[]][] { - return Object.entries( - groupBy( - decisions.filter( - (decision): decision is ConditionalResourcePolicyDecision => - decision.result === AuthorizeResult.CONDITIONAL && - !!decision.resourceRef, - ), - 'pluginId', - ), - ); - } } From ef291ff9856e87eeb21ea09289925a983d48a587 Mon Sep 17 00:00:00 2001 From: MT Lewis Date: Wed, 5 Jan 2022 18:34:48 +0000 Subject: [PATCH 39/56] permission-backend: move dataloader to router Signed-off-by: MT Lewis --- .../PermissionIntegrationClient.test.ts | 227 +-------- .../service/PermissionIntegrationClient.ts | 47 +- .../src/service/router.test.ts | 439 ++++++++++++++++-- .../permission-backend/src/service/router.ts | 83 ++-- 4 files changed, 463 insertions(+), 333 deletions(-) diff --git a/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts b/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts index cc1de05127..814ccd3f38 100644 --- a/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts +++ b/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts @@ -77,11 +77,9 @@ describe('PermissionIntegrationClient', () => { }); it('should make a POST request to the correct endpoint', async () => { - await client.applyConditions([ + await client.applyConditions('plugin-1', [ { id: '123', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-1', resourceRef: 'testResource1', resourceType: 'test-resource', conditions: mockConditions, @@ -92,11 +90,9 @@ describe('PermissionIntegrationClient', () => { }); it('should include a request body', async () => { - await client.applyConditions([ + await client.applyConditions('plugin-1', [ { id: '123', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-1', resourceRef: 'testResource1', resourceType: 'test-resource', conditions: mockConditions, @@ -120,11 +116,9 @@ describe('PermissionIntegrationClient', () => { }); it('should return the response from the fetch request', async () => { - const response = await client.applyConditions([ + const response = await client.applyConditions('plugin-1', [ { id: '123', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-1', resourceRef: 'testResource1', resourceType: 'test-resource', conditions: mockConditions, @@ -137,11 +131,9 @@ describe('PermissionIntegrationClient', () => { }); it('should not include authorization headers if no token is supplied', async () => { - await client.applyConditions([ + await client.applyConditions('plugin-1', [ { id: '123', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-1', resourceRef: 'testResource1', resourceType: 'test-resource', conditions: mockConditions, @@ -154,11 +146,10 @@ describe('PermissionIntegrationClient', () => { it('should include correctly-constructed authorization header if token is supplied', async () => { await client.applyConditions( + 'plugin-1', [ { id: '123', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-1', resourceRef: 'testResource1', resourceType: 'test-resource', conditions: mockConditions, @@ -179,11 +170,9 @@ describe('PermissionIntegrationClient', () => { ); await expect( - client.applyConditions([ + client.applyConditions('plugin-1', [ { id: '123', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-1', resourceRef: 'testResource1', resourceType: 'test-resource', conditions: mockConditions, @@ -200,11 +189,9 @@ describe('PermissionIntegrationClient', () => { ); await expect( - client.applyConditions([ + client.applyConditions('plugin-1', [ { id: '123', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-1', resourceRef: 'testResource1', resourceType: 'test-resource', conditions: mockConditions, @@ -227,27 +214,21 @@ describe('PermissionIntegrationClient', () => { ); await expect( - client.applyConditions([ + client.applyConditions('plugin-1', [ { id: '123', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-1', resourceRef: 'testResource1', resourceType: 'test-resource', conditions: mockConditions, }, { id: '456', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-1', resourceRef: 'testResource1', resourceType: 'test-resource', conditions: mockConditions, }, { id: '789', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-1', resourceRef: 'testResource1', resourceType: 'test-resource', conditions: mockConditions, @@ -266,8 +247,7 @@ describe('PermissionIntegrationClient', () => { describe('integration with @backstage/plugin-permission-node', () => { let server: Server; let client: PermissionIntegrationClient; - let plugin1Router: RequestHandler; - let plugin2Router: RequestHandler; + let routerSpy: RequestHandler; beforeAll(async () => { const router = Router(); @@ -302,11 +282,9 @@ describe('PermissionIntegrationClient', () => { const app = express(); - plugin1Router = jest.fn(router); - plugin2Router = jest.fn(router); + routerSpy = jest.fn(router); - app.use('/plugin-1', plugin1Router); - app.use('/plugin-2', plugin2Router); + app.use('/plugin-1', routerSpy); await new Promise(resolve => { server = app.listen(resolve); @@ -341,11 +319,9 @@ describe('PermissionIntegrationClient', () => { it('works for simple conditions', async () => { await expect( - client.applyConditions([ + client.applyConditions('plugin-1', [ { id: '123', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-1', resourceRef: 'testResource1', resourceType: 'test-resource', conditions: { rule: 'RULE_1', params: ['no'] }, @@ -356,11 +332,9 @@ describe('PermissionIntegrationClient', () => { it('works for complex criteria', async () => { await expect( - client.applyConditions([ + client.applyConditions('plugin-1', [ { id: '123', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-1', resourceRef: 'testResource1', resourceType: 'test-resource', conditions: { @@ -385,180 +359,5 @@ describe('PermissionIntegrationClient', () => { ]), ).resolves.toEqual([{ id: '123', result: AuthorizeResult.ALLOW }]); }); - - it('makes separate batched requests to multiple plugin backends', async () => { - await expect( - client.applyConditions([ - { - id: '123', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-1', - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: { rule: 'RULE_1', params: ['yes'] }, - }, - { - id: '234', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-2', - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: { rule: 'RULE_1', params: ['no'] }, - }, - { - id: '345', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-1', - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: { rule: 'RULE_1', params: ['no'] }, - }, - { - id: '456', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-2', - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: { rule: 'RULE_1', params: ['yes'] }, - }, - ]), - ).resolves.toEqual([ - { id: '123', result: AuthorizeResult.ALLOW }, - { id: '234', result: AuthorizeResult.DENY }, - { id: '345', result: AuthorizeResult.DENY }, - { id: '456', result: AuthorizeResult.ALLOW }, - ]); - - expect(plugin1Router).toHaveBeenCalledTimes(1); - expect(plugin2Router).toHaveBeenCalledTimes(1); - }); - - it('leaves definitive results unchanged', async () => { - await expect( - client.applyConditions([ - { - id: '123', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-1', - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: { rule: 'RULE_1', params: ['yes'] }, - }, - { - id: '234', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-2', - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: { rule: 'RULE_1', params: ['no'] }, - }, - { - id: '345', - result: AuthorizeResult.ALLOW, - }, - { - id: '456', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-1', - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: { rule: 'RULE_1', params: ['no'] }, - }, - { - id: '567', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-2', - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: { rule: 'RULE_1', params: ['yes'] }, - }, - ]), - ).resolves.toEqual([ - { id: '123', result: AuthorizeResult.ALLOW }, - { id: '234', result: AuthorizeResult.DENY }, - { id: '345', result: AuthorizeResult.ALLOW }, - { id: '456', result: AuthorizeResult.DENY }, - { id: '567', result: AuthorizeResult.ALLOW }, - ]); - - expect(plugin1Router).toHaveBeenCalledTimes(1); - expect(plugin2Router).toHaveBeenCalledTimes(1); - }); - - it('leaves conditional results without resourceRefs unchanged', async () => { - await expect( - client.applyConditions([ - { - id: '123', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-1', - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: { rule: 'RULE_1', params: ['yes'] }, - }, - { - id: '234', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-2', - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: { rule: 'RULE_1', params: ['no'] }, - }, - { - id: '345', - result: AuthorizeResult.ALLOW, - }, - { - id: '456', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-1', - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: { rule: 'RULE_1', params: ['no'] }, - }, - { - id: '567', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-2', - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: { rule: 'RULE_1', params: ['yes'] }, - }, - { - id: '789', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-2', - resourceType: 'test-resource', - conditions: { - anyOf: [ - { rule: 'RULE_1', params: ['yes'] }, - { rule: 'RULE_2', params: ['yes'] }, - ], - }, - }, - ]), - ).resolves.toEqual([ - { id: '123', result: AuthorizeResult.ALLOW }, - { id: '234', result: AuthorizeResult.DENY }, - { id: '345', result: AuthorizeResult.ALLOW }, - { id: '456', result: AuthorizeResult.DENY }, - { id: '567', result: AuthorizeResult.ALLOW }, - { - id: '789', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'plugin-2', - resourceType: 'test-resource', - conditions: { - anyOf: [ - { rule: 'RULE_1', params: ['yes'] }, - { rule: 'RULE_2', params: ['yes'] }, - ], - }, - }, - ]); - - expect(plugin1Router).toHaveBeenCalledTimes(1); - expect(plugin2Router).toHaveBeenCalledTimes(1); - }); }); }); diff --git a/plugins/permission-backend/src/service/PermissionIntegrationClient.ts b/plugins/permission-backend/src/service/PermissionIntegrationClient.ts index 520e8b19ae..f4fdb6cbfc 100644 --- a/plugins/permission-backend/src/service/PermissionIntegrationClient.ts +++ b/plugins/permission-backend/src/service/PermissionIntegrationClient.ts @@ -14,21 +14,14 @@ * limitations under the License. */ -import { memoize } from 'lodash'; import fetch from 'node-fetch'; import { z } from 'zod'; -import DataLoader from 'dataloader'; import { PluginEndpointDiscovery } from '@backstage/backend-common'; +import { AuthorizeResult } from '@backstage/plugin-permission-common'; import { - AuthorizeResponse, - AuthorizeResult, - Identified, -} from '@backstage/plugin-permission-common'; -import { + ApplyConditionsRequestEntry, ApplyConditionsResponse, - ApplyConditionsResponseEntry, ConditionalPolicyDecision, - PolicyDecision, } from '@backstage/plugin-permission-node'; const responseSchema = z.array( @@ -40,11 +33,9 @@ const responseSchema = z.array( }), ); -type ResourceDecision = Identified< - T & { - resourceRef?: string; - } ->; +export type ResourcePolicyDecision = ConditionalPolicyDecision & { + resourceRef: string; +}; export class PermissionIntegrationClient { private readonly discovery: PluginEndpointDiscovery; @@ -54,34 +45,8 @@ export class PermissionIntegrationClient { } async applyConditions( - decisions: ResourceDecision[], - authHeader?: string, - ): Promise[]> { - const loaderFor = memoize( - (pluginId: string) => - new DataLoader< - Identified, - ApplyConditionsResponseEntry - >(requests => this.makeRequest(pluginId, requests, authHeader)), - ); - - return Promise.all( - decisions.map(decision => { - if ( - decision.result !== AuthorizeResult.CONDITIONAL || - !decision.resourceRef - ) { - return decision; - } - - return loaderFor(decision.pluginId).load(decision); - }), - ); - } - - private async makeRequest( pluginId: string, - decisions: readonly ResourceDecision[], + decisions: readonly ApplyConditionsRequestEntry[], authHeader?: string, ): Promise { const endpoint = `${await this.discovery.getBaseUrl( diff --git a/plugins/permission-backend/src/service/router.test.ts b/plugins/permission-backend/src/service/router.test.ts index ef165b2ac5..971cb6a223 100644 --- a/plugins/permission-backend/src/service/router.test.ts +++ b/plugins/permission-backend/src/service/router.test.ts @@ -19,32 +19,28 @@ import request from 'supertest'; import { getVoidLogger } from '@backstage/backend-common'; import { IdentityClient } from '@backstage/plugin-auth-backend'; import { AuthorizeResult } from '@backstage/plugin-permission-common'; -import { ApplyConditionsResponseEntry } from '@backstage/plugin-permission-node'; +import { + ApplyConditionsRequestEntry, + ApplyConditionsResponseEntry, +} from '@backstage/plugin-permission-node'; import { PermissionIntegrationClient } from './PermissionIntegrationClient'; import { createRouter } from './router'; const mockApplyConditions: jest.MockedFunction< InstanceType['applyConditions'] -> = jest.fn(async decisions => - decisions.map(decision => { - if ( - decision.result === AuthorizeResult.CONDITIONAL && - decision.resourceRef - ) { - return { id: decision.id, result: AuthorizeResult.DENY as const }; - } - - if (decision.result === AuthorizeResult.CONDITIONAL) { - return { - id: decision.id, - result: decision.result, - conditions: decision.conditions, - }; - } - - return decision; - }), +> = jest.fn( + async ( + _pluginId: string, + decisions: readonly ApplyConditionsRequestEntry[], + ) => + decisions.map(decision => ({ + id: decision.id, + result: + (decision.conditions as any).params[0] === 'yes' + ? (AuthorizeResult.ALLOW as const) + : (AuthorizeResult.DENY as const), + })), ); jest.mock('./PermissionIntegrationClient', () => ({ @@ -90,6 +86,10 @@ describe('createRouter', () => { app = express().use(router); }); + afterEach(() => { + jest.clearAllMocks(); + }); + describe('GET /health', () => { it('returns ok', async () => { const response = await request(app).get('/health'); @@ -178,18 +178,14 @@ describe('createRouter', () => { }); describe('conditional policy result', () => { - beforeEach(() => { - policy.handle.mockResolvedValue({ + it('returns conditions if no resourceRef is supplied', async () => { + policy.handle.mockResolvedValueOnce({ result: AuthorizeResult.CONDITIONAL, pluginId: 'test-plugin', resourceType: 'test-resource-1', - conditions: { - anyOf: [{ rule: 'test-rule', params: ['abc'] }], - }, + conditions: { rule: 'test-rule', params: ['abc'] }, }); - }); - it('returns conditions if no resourceRef is supplied', async () => { const response = await request(app) .post('/authorize') .send([ @@ -208,17 +204,388 @@ describe('createRouter', () => { { id: '123', result: AuthorizeResult.CONDITIONAL, - conditions: { anyOf: [{ rule: 'test-rule', params: ['abc'] }] }, + pluginId: 'test-plugin', + resourceType: 'test-resource-1', + conditions: { rule: 'test-rule', params: ['abc'] }, }, ]); }); - it.each([ - AuthorizeResult.ALLOW, - AuthorizeResult.DENY, + it('makes separate batched requests to multiple plugin backends', async () => { + policy.handle + .mockResolvedValueOnce({ + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceType: 'test-resource-1', + conditions: { rule: 'test-rule', params: ['yes'] }, + }) + .mockResolvedValueOnce({ + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-2', + resourceType: 'test-resource-2', + conditions: { rule: 'test-rule', params: ['yes'] }, + }) + .mockResolvedValueOnce({ + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceType: 'test-resource-1', + conditions: { rule: 'test-rule', params: ['no'] }, + }) + .mockResolvedValueOnce({ + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-2', + resourceType: 'test-resource-2', + conditions: { rule: 'test-rule', params: ['no'] }, + }); + + const response = await request(app) + .post('/authorize') + .auth('test-token', { type: 'bearer' }) + .send([ + { + id: '123', + permission: { + name: 'test.permission.1', + resourceType: 'test-resource-1', + attributes: {}, + }, + resourceRef: 'resource:1', + }, + { + id: '234', + permission: { + name: 'test.permission.2', + resourceType: 'test-resource-2', + attributes: {}, + }, + resourceRef: 'resource:2', + }, + { + id: '345', + permission: { + name: 'test.permission.3', + resourceType: 'test-resource-1', + attributes: {}, + }, + resourceRef: 'resource:3', + }, + { + id: '456', + permission: { + name: 'test.permission.4', + resourceType: 'test-resource-2', + attributes: {}, + }, + resourceRef: 'resource:4', + }, + ]); + + expect(mockApplyConditions).toHaveBeenCalledWith( + 'plugin-1', + [ + expect.objectContaining({ + id: '123', + resourceType: 'test-resource-1', + resourceRef: 'resource:1', + conditions: { rule: 'test-rule', params: ['yes'] }, + }), + expect.objectContaining({ + id: '345', + resourceType: 'test-resource-1', + resourceRef: 'resource:3', + conditions: { rule: 'test-rule', params: ['no'] }, + }), + ], + 'Bearer test-token', + ); + + expect(mockApplyConditions).toHaveBeenCalledWith( + 'plugin-2', + [ + expect.objectContaining({ + id: '234', + resourceType: 'test-resource-2', + resourceRef: 'resource:2', + conditions: { rule: 'test-rule', params: ['yes'] }, + }), + expect.objectContaining({ + id: '456', + resourceType: 'test-resource-2', + resourceRef: 'resource:4', + conditions: { rule: 'test-rule', params: ['no'] }, + }), + ], + 'Bearer test-token', + ); + + expect(response.status).toEqual(200); + expect(response.body).toEqual([ + { id: '123', result: AuthorizeResult.ALLOW }, + { id: '234', result: AuthorizeResult.ALLOW }, + { id: '345', result: AuthorizeResult.DENY }, + { id: '456', result: AuthorizeResult.DENY }, + ]); + }); + + it('leaves definitive results unchanged', async () => { + policy.handle + .mockResolvedValueOnce({ + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceType: 'test-resource-1', + conditions: { rule: 'test-rule', params: ['no'] }, + }) + .mockResolvedValueOnce({ + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-2', + resourceType: 'test-resource-2', + conditions: { rule: 'test-rule', params: ['no'] }, + }) + .mockResolvedValueOnce({ + result: AuthorizeResult.ALLOW, + }) + .mockResolvedValueOnce({ + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceType: 'test-resource-1', + conditions: { rule: 'test-rule', params: ['yes'] }, + }) + .mockResolvedValueOnce({ + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-2', + resourceType: 'test-resource-2', + conditions: { rule: 'test-rule', params: ['yes'] }, + }) + .mockResolvedValueOnce({ + result: AuthorizeResult.DENY, + }); + + const response = await request(app) + .post('/authorize') + .auth('test-token', { type: 'bearer' }) + .send([ + { + id: '123', + permission: { + name: 'test.permission.1', + resourceType: 'test-resource-1', + attributes: {}, + }, + resourceRef: 'resource:1', + }, + { + id: '234', + permission: { + name: 'test.permission.2', + resourceType: 'test-resource-2', + attributes: {}, + }, + resourceRef: 'resource:2', + }, + { + id: '345', + permission: { + name: 'test.permission.3', + resourceType: 'test-resource-1', + attributes: {}, + }, + resourceRef: 'resource:3', + }, + { + id: '456', + permission: { + name: 'test.permission.4', + resourceType: 'test-resource-1', + attributes: {}, + }, + resourceRef: 'resource:4', + }, + { + id: '567', + permission: { + name: 'test.permission.5', + resourceType: 'test-resource-2', + attributes: {}, + }, + resourceRef: 'resource:5', + }, + { + id: '678', + permission: { + name: 'test.permission.6', + attributes: {}, + }, + }, + ]); + + expect(mockApplyConditions).toHaveBeenCalledWith( + 'plugin-1', + [ + expect.objectContaining({ + id: '123', + resourceType: 'test-resource-1', + resourceRef: 'resource:1', + conditions: { rule: 'test-rule', params: ['no'] }, + }), + expect.objectContaining({ + id: '456', + resourceType: 'test-resource-1', + resourceRef: 'resource:4', + conditions: { rule: 'test-rule', params: ['yes'] }, + }), + ], + 'Bearer test-token', + ); + + expect(mockApplyConditions).toHaveBeenCalledWith( + 'plugin-2', + [ + expect.objectContaining({ + id: '234', + resourceType: 'test-resource-2', + resourceRef: 'resource:2', + conditions: { rule: 'test-rule', params: ['no'] }, + }), + expect.objectContaining({ + id: '567', + resourceType: 'test-resource-2', + resourceRef: 'resource:5', + conditions: { rule: 'test-rule', params: ['yes'] }, + }), + ], + 'Bearer test-token', + ); + + expect(response.status).toEqual(200); + expect(response.body).toEqual([ + { id: '123', result: AuthorizeResult.DENY }, + { id: '234', result: AuthorizeResult.DENY }, + { id: '345', result: AuthorizeResult.ALLOW }, + { id: '456', result: AuthorizeResult.ALLOW }, + { id: '567', result: AuthorizeResult.ALLOW }, + { id: '678', result: AuthorizeResult.DENY }, + ]); + }); + + it('leaves conditional results without resourceRefs unchanged', async () => { + policy.handle + .mockResolvedValueOnce({ + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceType: 'test-resource-1', + conditions: { rule: 'test-rule', params: ['yes'] }, + }) + .mockResolvedValueOnce({ + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-2', + resourceType: 'test-resource-2', + conditions: { rule: 'test-rule', params: ['yes'] }, + }) + .mockResolvedValueOnce({ + result: AuthorizeResult.ALLOW, + }) + .mockResolvedValueOnce({ + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceType: 'test-resource-1', + conditions: { rule: 'test-rule', params: ['abc'] }, + }); + + const response = await request(app) + .post('/authorize') + .auth('test-token', { type: 'bearer' }) + .send([ + { + id: '123', + permission: { + name: 'test.permission.1', + resourceType: 'test-resource-1', + attributes: {}, + }, + resourceRef: 'resource:1', + }, + { + id: '234', + permission: { + name: 'test.permission.2', + resourceType: 'test-resource-2', + attributes: {}, + }, + resourceRef: 'resource:2', + }, + { + id: '345', + permission: { + name: 'test.permission.3', + resourceType: 'test-resource-1', + attributes: {}, + }, + resourceRef: 'resource:3', + }, + { + id: '456', + permission: { + name: 'test.permission.4', + resourceType: 'test-resource-1', + attributes: {}, + }, + }, + ]); + + expect(mockApplyConditions).toHaveBeenCalledWith( + 'plugin-1', + [ + expect.objectContaining({ + id: '123', + resourceType: 'test-resource-1', + resourceRef: 'resource:1', + conditions: { rule: 'test-rule', params: ['yes'] }, + }), + ], + 'Bearer test-token', + ); + + expect(mockApplyConditions).toHaveBeenCalledWith( + 'plugin-2', + [ + expect.objectContaining({ + id: '234', + resourceType: 'test-resource-2', + resourceRef: 'resource:2', + conditions: { rule: 'test-rule', params: ['yes'] }, + }), + ], + 'Bearer test-token', + ); + + expect(response.status).toEqual(200); + expect(response.body).toEqual([ + { id: '123', result: AuthorizeResult.ALLOW }, + { id: '234', result: AuthorizeResult.ALLOW }, + { id: '345', result: AuthorizeResult.ALLOW }, + { + id: '456', + result: AuthorizeResult.CONDITIONAL, + pluginId: 'plugin-1', + resourceType: 'test-resource-1', + conditions: { rule: 'test-rule', params: ['abc'] }, + }, + ]); + }); + + it.each<[ApplyConditionsResponseEntry['result'], string]>([ + [AuthorizeResult.ALLOW, 'yes'], + [AuthorizeResult.DENY, 'no'], ])( 'applies conditions and returns %s if resourceRef is supplied', - async result => { + async (result, params) => { + policy.handle.mockResolvedValue({ + result: AuthorizeResult.CONDITIONAL, + pluginId: 'test-plugin', + resourceType: 'test-resource-1', + conditions: { rule: 'test-rule', params }, + }); + mockApplyConditions.mockResolvedValueOnce([ { id: '123', @@ -255,21 +622,19 @@ describe('createRouter', () => { ]); expect(mockApplyConditions).toHaveBeenCalledWith( + 'test-plugin', [ expect.objectContaining({ id: '123', - result: AuthorizeResult.CONDITIONAL, - pluginId: 'test-plugin', resourceType: 'test-resource-1', resourceRef: 'test/resource', - conditions: { anyOf: [{ rule: 'test-rule', params: ['abc'] }] }, + conditions: { rule: 'test-rule', params }, }), expect.objectContaining({ id: '234', - pluginId: 'test-plugin', resourceType: 'test-resource-1', resourceRef: 'test/resource', - conditions: { anyOf: [{ rule: 'test-rule', params: ['abc'] }] }, + conditions: { rule: 'test-rule', params }, }), ], 'Bearer test-token', diff --git a/plugins/permission-backend/src/service/router.ts b/plugins/permission-backend/src/service/router.ts index 0e877bc816..58438afbb5 100644 --- a/plugins/permission-backend/src/service/router.ts +++ b/plugins/permission-backend/src/service/router.ts @@ -34,10 +34,13 @@ import { Identified, } from '@backstage/plugin-permission-common'; import { + ApplyConditionsRequestEntry, + ApplyConditionsResponseEntry, PermissionPolicy, - PolicyDecision, } from '@backstage/plugin-permission-node'; import { PermissionIntegrationClient } from './PermissionIntegrationClient'; +import { memoize } from 'lodash'; +import DataLoader from 'dataloader'; const requestSchema: z.ZodSchema[]> = z.array( z.object({ @@ -73,43 +76,6 @@ export interface RouterOptions { identity: IdentityClient; } -const applyPolicy = async ( - policy: PermissionPolicy, - requests: Identified[], - user: BackstageIdentityResponse | undefined, -): Promise[]> => { - return Promise.all( - requests.map(({ id, resourceRef, ...authorizeRequest }) => - policy.handle(authorizeRequest, user).then(decision => ({ - id, - ...(decision.result === AuthorizeResult.CONDITIONAL - ? { resourceRef } - : {}), - ...decision, - })), - ), - ); -}; - -const assertMatchingResourceTypes = ( - requests: AuthorizeRequest[], - decisions: PolicyDecision[], -) => { - requests.forEach((request, index) => { - const decision = decisions[index]; - - // Sanity check that any resource provided matches the one expected by the permission - if ( - decision.result === AuthorizeResult.CONDITIONAL && - decision.resourceType !== request.permission.resourceType - ) { - throw new Error( - `Invalid resource conditions returned from permission policy for permission ${request.permission.name}`, - ); - } - }); -}; - const handleRequest = async ( requests: Identified[], user: BackstageIdentityResponse | undefined, @@ -117,11 +83,46 @@ const handleRequest = async ( permissionIntegrationClient: PermissionIntegrationClient, authHeader?: string, ): Promise[]> => { - const decisions = await applyPolicy(policy, requests, user); + const applyConditionsLoaderFor = memoize((pluginId: string) => { + return new DataLoader< + ApplyConditionsRequestEntry, + ApplyConditionsResponseEntry + >(batch => + permissionIntegrationClient.applyConditions(pluginId, batch, authHeader), + ); + }); - assertMatchingResourceTypes(requests, decisions); + return Promise.all( + requests.map(({ id, resourceRef, ...request }) => + policy.handle(request, user).then(decision => { + if (decision.result !== AuthorizeResult.CONDITIONAL) { + return { + id, + ...decision, + }; + } - return permissionIntegrationClient.applyConditions(decisions, authHeader); + if (decision.resourceType !== request.permission.resourceType) { + throw new Error( + `Invalid resource conditions returned from permission policy for permission ${request.permission.name}`, + ); + } + + if (!resourceRef) { + return { + id, + ...decision, + }; + } + + return applyConditionsLoaderFor(decision.pluginId).load({ + id, + resourceRef, + ...decision, + }); + }), + ), + ); }; /** From 1fb2e0e0b4e2ab5bd91be82310a641b7d8a2b61d Mon Sep 17 00:00:00 2001 From: MT Lewis Date: Thu, 6 Jan 2022 12:18:01 +0000 Subject: [PATCH 40/56] permission-node: wrap request and response arrays in object Signed-off-by: MT Lewis --- .../PermissionIntegrationClient.test.ts | 38 +-- .../service/PermissionIntegrationClient.ts | 44 ++-- plugins/permission-node/api-report.md | 8 +- .../createPermissionIntegrationRouter.test.ts | 217 ++++++++++-------- .../createPermissionIntegrationRouter.ts | 40 ++-- 5 files changed, 196 insertions(+), 151 deletions(-) diff --git a/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts b/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts index 814ccd3f38..4be1b55379 100644 --- a/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts +++ b/plugins/permission-backend/src/service/PermissionIntegrationClient.test.ts @@ -39,7 +39,9 @@ describe('PermissionIntegrationClient', () => { const mockApplyConditionsHandler = jest.fn( (_req, res, { json }: RestContext) => { - return res(json([{ id: '123', result: AuthorizeResult.ALLOW }])); + return res( + json({ items: [{ id: '123', result: AuthorizeResult.ALLOW }] }), + ); }, ); @@ -101,14 +103,16 @@ describe('PermissionIntegrationClient', () => { expect(mockApplyConditionsHandler).toHaveBeenCalledWith( expect.objectContaining({ - body: [ - { - id: '123', - resourceRef: 'testResource1', - resourceType: 'test-resource', - conditions: mockConditions, - }, - ], + body: { + items: [ + { + id: '123', + resourceRef: 'testResource1', + resourceType: 'test-resource', + conditions: mockConditions, + }, + ], + }, }), expect.anything(), expect.anything(), @@ -184,7 +188,9 @@ describe('PermissionIntegrationClient', () => { it('should reject invalid responses', async () => { mockApplyConditionsHandler.mockImplementationOnce( (_req, res, { json }: RestContext) => { - return res(json([{ id: '123', outcome: AuthorizeResult.ALLOW }])); + return res( + json({ items: [{ id: '123', outcome: AuthorizeResult.ALLOW }] }), + ); }, ); @@ -204,11 +210,13 @@ describe('PermissionIntegrationClient', () => { mockApplyConditionsHandler.mockImplementationOnce( (_req, res, { json }: RestContext) => { return res( - json([ - { id: '123', result: AuthorizeResult.ALLOW }, - { id: '456', result: AuthorizeResult.DENY }, - { id: '789', result: AuthorizeResult.ALLOW }, - ]), + json({ + items: [ + { id: '123', result: AuthorizeResult.ALLOW }, + { id: '456', result: AuthorizeResult.DENY }, + { id: '789', result: AuthorizeResult.ALLOW }, + ], + }), ); }, ); diff --git a/plugins/permission-backend/src/service/PermissionIntegrationClient.ts b/plugins/permission-backend/src/service/PermissionIntegrationClient.ts index f4fdb6cbfc..2b2161ee71 100644 --- a/plugins/permission-backend/src/service/PermissionIntegrationClient.ts +++ b/plugins/permission-backend/src/service/PermissionIntegrationClient.ts @@ -20,18 +20,20 @@ import { PluginEndpointDiscovery } from '@backstage/backend-common'; import { AuthorizeResult } from '@backstage/plugin-permission-common'; import { ApplyConditionsRequestEntry, - ApplyConditionsResponse, + ApplyConditionsResponseEntry, ConditionalPolicyDecision, } from '@backstage/plugin-permission-node'; -const responseSchema = z.array( - z.object({ - id: z.string(), - result: z - .literal(AuthorizeResult.ALLOW) - .or(z.literal(AuthorizeResult.DENY)), - }), -); +const responseSchema = z.object({ + items: z.array( + z.object({ + id: z.string(), + result: z + .literal(AuthorizeResult.ALLOW) + .or(z.literal(AuthorizeResult.DENY)), + }), + ), +}); export type ResourcePolicyDecision = ConditionalPolicyDecision & { resourceRef: string; @@ -48,21 +50,23 @@ export class PermissionIntegrationClient { pluginId: string, decisions: readonly ApplyConditionsRequestEntry[], authHeader?: string, - ): Promise { + ): Promise { const endpoint = `${await this.discovery.getBaseUrl( pluginId, )}/.well-known/backstage/permissions/apply-conditions`; const response = await fetch(endpoint, { method: 'POST', - body: JSON.stringify( - decisions.map(({ id, resourceRef, resourceType, conditions }) => ({ - id, - resourceRef, - resourceType, - conditions, - })), - ), + body: JSON.stringify({ + items: decisions.map( + ({ id, resourceRef, resourceType, conditions }) => ({ + id, + resourceRef, + resourceType, + conditions, + }), + ), + }), headers: { ...(authHeader ? { authorization: authHeader } : {}), 'content-type': 'application/json', @@ -75,6 +79,8 @@ export class PermissionIntegrationClient { ); } - return responseSchema.parse(await response.json()); + const result = responseSchema.parse(await response.json()); + + return result.items; } } diff --git a/plugins/permission-node/api-report.md b/plugins/permission-node/api-report.md index 7023369306..d9ea64483e 100644 --- a/plugins/permission-node/api-report.md +++ b/plugins/permission-node/api-report.md @@ -18,7 +18,9 @@ import { PluginEndpointDiscovery } from '@backstage/backend-common'; import { TokenManager } from '@backstage/backend-common'; // @public -export type ApplyConditionsRequest = ApplyConditionsRequestEntry[]; +export type ApplyConditionsRequest = { + items: ApplyConditionsRequestEntry[]; +}; // @public export type ApplyConditionsRequestEntry = Identified<{ @@ -28,7 +30,9 @@ export type ApplyConditionsRequestEntry = Identified<{ }>; // @public -export type ApplyConditionsResponse = ApplyConditionsResponseEntry[]; +export type ApplyConditionsResponse = { + items: ApplyConditionsResponseEntry[]; +}; // @public export type ApplyConditionsResponseEntry = Identified; diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts index 2e911b7cae..79bfcb3b0b 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts @@ -96,22 +96,26 @@ describe('createPermissionIntegrationRouter', () => { ])('returns 200/ALLOW when criteria match (case %#)', async conditions => { const response = await request(app) .post('/.well-known/backstage/permissions/apply-conditions') - .send([ - { - id: '123', - resourceRef: 'default:test/resource', - resourceType: 'test-resource', - conditions, - }, - ]); + .send({ + items: [ + { + id: '123', + resourceRef: 'default:test/resource', + resourceType: 'test-resource', + conditions, + }, + ], + }); expect(response.status).toEqual(200); - expect(response.body).toEqual([ - { - id: '123', - result: AuthorizeResult.ALLOW, - }, - ]); + expect(response.body).toEqual({ + items: [ + { + id: '123', + result: AuthorizeResult.ALLOW, + }, + ], + }); }); it.each([ @@ -145,19 +149,21 @@ describe('createPermissionIntegrationRouter', () => { async conditions => { const response = await request(app) .post('/.well-known/backstage/permissions/apply-conditions') - .send([ - { - id: '123', - resourceRef: 'default:test/resource', - resourceType: 'test-resource', - conditions, - }, - ]); + .send({ + items: [ + { + id: '123', + resourceRef: 'default:test/resource', + resourceType: 'test-resource', + conditions, + }, + ], + }); expect(response.status).toEqual(200); - expect(response.body).toEqual([ - { id: '123', result: AuthorizeResult.DENY }, - ]); + expect(response.body).toEqual({ + items: [{ id: '123', result: AuthorizeResult.DENY }], + }); }, ); @@ -167,54 +173,58 @@ describe('createPermissionIntegrationRouter', () => { beforeEach(async () => { response = await request(app) .post('/.well-known/backstage/permissions/apply-conditions') - .send([ - { - id: '123', - resourceRef: 'default:test/resource-1', - resourceType: 'test-resource', - conditions: { rule: 'test-rule-1', params: [] }, - }, - { - id: '234', - resourceRef: 'default:test/resource-1', - resourceType: 'test-resource', - conditions: { rule: 'test-rule-2', params: [] }, - }, - { - id: '345', - resourceRef: 'default:test/resource-2', - resourceType: 'test-resource', - conditions: { not: { rule: 'test-rule-1', params: [] } }, - }, - { - id: '456', - resourceRef: 'default:test/resource-3', - resourceType: 'test-resource', - conditions: { not: { rule: 'test-rule-2', params: [] } }, - }, - { - id: '567', - resourceRef: 'default:test/resource-4', - resourceType: 'test-resource', - conditions: { - anyOf: [ - { rule: 'test-rule-1', params: [] }, - { rule: 'test-rule-2', params: [] }, - ], + .send({ + items: [ + { + id: '123', + resourceRef: 'default:test/resource-1', + resourceType: 'test-resource', + conditions: { rule: 'test-rule-1', params: [] }, }, - }, - ]); + { + id: '234', + resourceRef: 'default:test/resource-1', + resourceType: 'test-resource', + conditions: { rule: 'test-rule-2', params: [] }, + }, + { + id: '345', + resourceRef: 'default:test/resource-2', + resourceType: 'test-resource', + conditions: { not: { rule: 'test-rule-1', params: [] } }, + }, + { + id: '456', + resourceRef: 'default:test/resource-3', + resourceType: 'test-resource', + conditions: { not: { rule: 'test-rule-2', params: [] } }, + }, + { + id: '567', + resourceRef: 'default:test/resource-4', + resourceType: 'test-resource', + conditions: { + anyOf: [ + { rule: 'test-rule-1', params: [] }, + { rule: 'test-rule-2', params: [] }, + ], + }, + }, + ], + }); }); it('processes batched requests', () => { expect(response.status).toEqual(200); - expect(response.body).toEqual([ - { id: '123', result: AuthorizeResult.ALLOW }, - { id: '234', result: AuthorizeResult.DENY }, - { id: '345', result: AuthorizeResult.DENY }, - { id: '456', result: AuthorizeResult.ALLOW }, - { id: '567', result: AuthorizeResult.ALLOW }, - ]); + expect(response.body).toEqual({ + items: [ + { id: '123', result: AuthorizeResult.ALLOW }, + { id: '234', result: AuthorizeResult.DENY }, + { id: '345', result: AuthorizeResult.DENY }, + { id: '456', result: AuthorizeResult.ALLOW }, + { id: '567', result: AuthorizeResult.ALLOW }, + ], + }); }); it('calls getResources for all required resources at once', () => { @@ -230,16 +240,18 @@ describe('createPermissionIntegrationRouter', () => { it('returns 400 when called with incorrect resource type', async () => { const response = await request(app) .post('/.well-known/backstage/permissions/apply-conditions') - .send([ - { - id: '123', - resourceRef: 'default:test/resource', - resourceType: 'test-incorrect-resource', - conditions: { - anyOf: [], + .send({ + items: [ + { + id: '123', + resourceRef: 'default:test/resource', + resourceType: 'test-incorrect-resource', + conditions: { + anyOf: [], + }, }, - }, - ]); + ], + }); expect(response.status).toEqual(400); expect(response.error && response.error.text).toMatch( @@ -254,22 +266,26 @@ describe('createPermissionIntegrationRouter', () => { const response = await request(app) .post('/.well-known/backstage/permissions/apply-conditions') - .send([ - { - id: '123', - resourceRef: 'default:test/resource', - resourceType: 'test-resource', - conditions: { rule: 'testRule1', params: [] }, - }, - ]); + .send({ + items: [ + { + id: '123', + resourceRef: 'default:test/resource', + resourceType: 'test-resource', + conditions: { rule: 'test-rule-1', params: [] }, + }, + ], + }); expect(response.status).toEqual(200); - expect(response.body).toEqual([ - { - id: '123', - result: AuthorizeResult.DENY, - }, - ]); + expect(response.body).toEqual({ + items: [ + { + id: '123', + result: AuthorizeResult.DENY, + }, + ], + }); }); it.each([ @@ -278,14 +294,17 @@ describe('createPermissionIntegrationRouter', () => { {}, { resourceType: 'test-resource-type' }, [{ resourceType: 'test-resource-type' }], - [{ resourceRef: 'test/resource-ref' }], - [ - { - resourceType: 'test-resource-type', - resourceRef: 'test/resource-ref', - }, - ], - [{ conditions: { anyOf: [] } }], + { items: [{ resourceType: 'test-resource-type' }] }, + { items: [{ resourceRef: 'test/resource-ref' }] }, + { + items: [ + { + resourceType: 'test-resource-type', + resourceRef: 'test/resource-ref', + }, + ], + }, + { items: [{ conditions: { anyOf: [] } }] }, ])(`returns 400 for invalid input %#`, async input => { const response = await request(app) .post('/.well-known/backstage/permissions/apply-conditions') diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts index 747e47b87d..4968db6100 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts @@ -48,14 +48,16 @@ const permissionCriteriaSchema: z.ZodSchema< ]), ); -const applyConditionsRequestSchema = z.array( - z.object({ - id: z.string(), - resourceRef: z.string(), - resourceType: z.string(), - conditions: permissionCriteriaSchema, - }), -); +const applyConditionsRequestSchema = z.object({ + items: z.array( + z.object({ + id: z.string(), + resourceRef: z.string(), + resourceType: z.string(), + conditions: permissionCriteriaSchema, + }), + ), +}); /** * A request to load the referenced resource and apply conditions in order to @@ -74,7 +76,9 @@ export type ApplyConditionsRequestEntry = Identified<{ * * @public */ -export type ApplyConditionsRequest = ApplyConditionsRequestEntry[]; +export type ApplyConditionsRequest = { + items: ApplyConditionsRequestEntry[]; +}; /** * The result of applying the conditions, expressed as a definitive authorize @@ -89,7 +93,9 @@ export type ApplyConditionsResponseEntry = Identified; * * @public */ -export type ApplyConditionsResponse = ApplyConditionsResponseEntry[]; +export type ApplyConditionsResponse = { + items: ApplyConditionsResponseEntry[]; +}; const applyConditions = ( criteria: PermissionCriteria, @@ -165,7 +171,9 @@ export const createPermissionIntegrationRouter = (options: { const getRule = createGetRule(rules); - const assertValidResourceTypes = (requests: ApplyConditionsRequest) => { + const assertValidResourceTypes = ( + requests: ApplyConditionsRequestEntry[], + ) => { const invalidResourceType = requests.find( request => request.resourceType !== resourceType, )?.resourceType; @@ -188,10 +196,10 @@ export const createPermissionIntegrationRouter = (options: { const body = parseResult.data; - assertValidResourceTypes(body); + assertValidResourceTypes(body.items); const resourceRefs = Array.from( - new Set(body.map(({ resourceRef }) => resourceRef)), + new Set(body.items.map(({ resourceRef }) => resourceRef)), ); const resourceArray = await getResources(resourceRefs); const resources = resourceRefs.reduce((acc, resourceRef, index) => { @@ -200,8 +208,8 @@ export const createPermissionIntegrationRouter = (options: { return acc; }, {} as Record); - return res.status(200).json( - body.map(request => ({ + return res.status(200).json({ + items: body.items.map(request => ({ id: request.id, result: applyConditions( request.conditions, @@ -211,7 +219,7 @@ export const createPermissionIntegrationRouter = (options: { ? AuthorizeResult.ALLOW : AuthorizeResult.DENY, })), - ); + }); }, ); From 34a4be296f5b3dd7d3185ead2ef35d258cd00950 Mon Sep 17 00:00:00 2001 From: MT Lewis Date: Thu, 13 Jan 2022 10:52:05 +0000 Subject: [PATCH 41/56] permission-node: list all incorrect resource types in apply-conditions handler Signed-off-by: MT Lewis --- .../createPermissionIntegrationRouter.test.ts | 22 ++++++++++++++++--- .../createPermissionIntegrationRouter.ts | 12 +++++----- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts index 79bfcb3b0b..be422c87d2 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts @@ -244,8 +244,24 @@ describe('createPermissionIntegrationRouter', () => { items: [ { id: '123', - resourceRef: 'default:test/resource', - resourceType: 'test-incorrect-resource', + resourceRef: 'default:test/resource-1', + resourceType: 'test-incorrect-resource-1', + conditions: { + anyOf: [], + }, + }, + { + id: '234', + resourceRef: 'default:test/resource-2', + resourceType: 'test-resource', + conditions: { + anyOf: [], + }, + }, + { + id: '345', + resourceRef: 'default:test/resource-3', + resourceType: 'test-incorrect-resource-2', conditions: { anyOf: [], }, @@ -255,7 +271,7 @@ describe('createPermissionIntegrationRouter', () => { expect(response.status).toEqual(400); expect(response.error && response.error.text).toMatch( - /unexpected resource type: test-incorrect-resource/i, + /unexpected resource types: test-incorrect-resource-1, test-incorrect-resource-2/i, ); }); diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts index 4968db6100..1b01660fb0 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts @@ -174,12 +174,14 @@ export const createPermissionIntegrationRouter = (options: { const assertValidResourceTypes = ( requests: ApplyConditionsRequestEntry[], ) => { - const invalidResourceType = requests.find( - request => request.resourceType !== resourceType, - )?.resourceType; + const invalidResourceTypes = requests + .filter(request => request.resourceType !== resourceType) + .map(request => request.resourceType); - if (invalidResourceType) { - throw new InputError(`Unexpected resource type: ${invalidResourceType}.`); + if (invalidResourceTypes.length) { + throw new InputError( + `Unexpected resource types: ${invalidResourceTypes.join(', ')}.`, + ); } }; From 3bb0afb54c3865ea843aa0091dfbe1f4645d825d Mon Sep 17 00:00:00 2001 From: MT Lewis Date: Thu, 13 Jan 2022 13:04:30 +0000 Subject: [PATCH 42/56] permission-node: add test for apply conditions router Signed-off-by: MT Lewis --- .../createPermissionIntegrationRouter.test.ts | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts index be422c87d2..065c30a978 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts @@ -304,6 +304,59 @@ describe('createPermissionIntegrationRouter', () => { }); }); + it('interleaves responses for present and missing resources', async () => { + mockGetResources.mockImplementationOnce(async resourceRefs => + resourceRefs.map(resourceRef => + resourceRef === 'default:test/missing-resource' + ? undefined + : { id: resourceRef }, + ), + ); + + const response = await request(app) + .post('/.well-known/backstage/permissions/apply-conditions') + .send({ + items: [ + { + id: '123', + resourceRef: 'default:test/resource-1', + resourceType: 'test-resource', + conditions: { rule: 'test-rule-1', params: [] }, + }, + { + id: '234', + resourceRef: 'default:test/missing-resource', + resourceType: 'test-resource', + conditions: { rule: 'test-rule-1', params: [] }, + }, + { + id: '345', + resourceRef: 'default:test/resource-2', + resourceType: 'test-resource', + conditions: { rule: 'test-rule-1', params: [] }, + }, + ], + }); + + expect(response.status).toEqual(200); + expect(response.body).toEqual({ + items: [ + { + id: '123', + result: AuthorizeResult.ALLOW, + }, + { + id: '234', + result: AuthorizeResult.DENY, + }, + { + id: '345', + result: AuthorizeResult.ALLOW, + }, + ], + }); + }); + it.each([ undefined, '', From 74967cf50d48f19bb9520df9659bd3209bf34f62 Mon Sep 17 00:00:00 2001 From: MT Lewis Date: Thu, 13 Jan 2022 13:04:47 +0000 Subject: [PATCH 43/56] catalog-backend: update permission integration to support batching Signed-off-by: MT Lewis --- .../src/service/NextCatalogBuilder.ts | 30 ++++--- .../src/service/NextRouter.test.ts | 87 +++++++++++++++++++ 2 files changed, 107 insertions(+), 10 deletions(-) diff --git a/plugins/catalog-backend/src/service/NextCatalogBuilder.ts b/plugins/catalog-backend/src/service/NextCatalogBuilder.ts index 391c89d83d..be75b4dfe7 100644 --- a/plugins/catalog-backend/src/service/NextCatalogBuilder.ts +++ b/plugins/catalog-backend/src/service/NextCatalogBuilder.ts @@ -25,6 +25,7 @@ import { NoForeignRootFieldsEntityPolicy, parseEntityRef, SchemaValidEntityPolicy, + stringifyEntityRef, Validators, } from '@backstage/catalog-model'; import { @@ -34,7 +35,7 @@ import { } from '@backstage/integration'; import { createHash } from 'crypto'; import { Router } from 'express'; -import lodash from 'lodash'; +import lodash, { keyBy } from 'lodash'; import { EntitiesCatalog, EntitiesSearchFilter } from '../catalog'; import { DatabaseLocationsCatalog, @@ -415,18 +416,27 @@ export class NextCatalogBuilder { ); const permissionIntegrationRouter = createPermissionIntegrationRouter({ resourceType: RESOURCE_TYPE_CATALOG_ENTITY, - getResource: async (resourceRef: string) => { - const parsed = parseEntityRef(resourceRef); + getResources: async (resourceRefs: string[]) => { + const { entities } = await entitiesCatalog.entities({ + filter: { + anyOf: resourceRefs.map(resourceRef => { + const { kind, namespace, name } = parseEntityRef(resourceRef); - const { entities } = await unauthorizedEntitiesCatalog.entities({ - filter: basicEntityFilter({ - kind: parsed.kind, - 'metadata.namespace': parsed.namespace, - 'metadata.name': parsed.name, - }), + return basicEntityFilter({ + kind, + 'metadata.namespace': namespace, + 'metadata.name': name, + }); + }), + }, }); - return entities[0]; + const entitiesByRef = keyBy(entities, stringifyEntityRef); + + return resourceRefs.map( + resourceRef => + entitiesByRef[stringifyEntityRef(parseEntityRef(resourceRef))], + ); }, rules: this.permissionRules, }); diff --git a/plugins/catalog-backend/src/service/NextRouter.test.ts b/plugins/catalog-backend/src/service/NextRouter.test.ts index 84580d0ca4..b79fba4a56 100644 --- a/plugins/catalog-backend/src/service/NextRouter.test.ts +++ b/plugins/catalog-backend/src/service/NextRouter.test.ts @@ -24,6 +24,9 @@ import { EntitiesCatalog } from '../catalog'; import { LocationService, RefreshService } from './types'; import { basicEntityFilter } from './request'; import { createNextRouter } from './NextRouter'; +import { AuthorizeResult } from '@backstage/plugin-permission-common'; +import { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node'; +import { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common'; describe('createNextRouter readonly disabled', () => { let entitiesCatalog: jest.Mocked; @@ -433,3 +436,87 @@ describe('createNextRouter readonly enabled', () => { }); }); }); + +describe('NextRouter permissioning', () => { + let entitiesCatalog: jest.Mocked; + let locationService: jest.Mocked; + let app: express.Express; + let refreshService: RefreshService; + + const fakeRule = { + name: 'FAKE_RULE', + description: 'fake rule', + apply: () => true, + toQuery: () => ({ key: '', values: [] }), + }; + + beforeAll(async () => { + entitiesCatalog = { + entities: jest.fn(), + removeEntityByUid: jest.fn(), + batchAddOrUpdateEntities: jest.fn(), + entityAncestry: jest.fn(), + }; + locationService = { + getLocation: jest.fn(), + createLocation: jest.fn(), + listLocations: jest.fn(), + deleteLocation: jest.fn(), + }; + refreshService = { refresh: jest.fn() }; + const router = await createNextRouter({ + entitiesCatalog, + locationService, + logger: getVoidLogger(), + refreshService, + config: new ConfigReader(undefined), + permissionIntegrationRouter: createPermissionIntegrationRouter({ + resourceType: RESOURCE_TYPE_CATALOG_ENTITY, + rules: [fakeRule], + getResources: jest.fn((resourceRefs: string[]) => + Promise.resolve( + resourceRefs.map(resourceRef => ({ id: resourceRef })), + ), + ), + }), + }); + app = express().use(router); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + it('accepts and evaluates conditions at the apply-conditions endpoint', async () => { + const spideySense: Entity = { + apiVersion: 'a', + kind: 'component', + metadata: { + name: 'spidey-sense', + }, + }; + entitiesCatalog.entities.mockResolvedValueOnce({ + entities: [spideySense], + pageInfo: { hasNextPage: false }, + }); + + const requestBody = { + items: [ + { + id: '123', + resourceType: 'catalog-entity', + resourceRef: 'component:default/spidey-sense', + conditions: { rule: 'FAKE_RULE', params: ['user:default/spiderman'] }, + }, + ], + }; + const response = await request(app) + .post('/.well-known/backstage/permissions/apply-conditions') + .send(requestBody); + + expect(response.status).toBe(200); + expect(response.body).toEqual({ + items: [{ id: '123', result: AuthorizeResult.ALLOW }], + }); + }); +}); From de065ce91c55033c3054b7e950418efddd7d9c9d Mon Sep 17 00:00:00 2001 From: Erik Engervall Date: Thu, 13 Jan 2022 14:06:21 +0100 Subject: [PATCH 44/56] Fix tests Signed-off-by: Erik Engervall --- .../git-release-manager/src/features/Patch/PatchBody.test.tsx | 3 +++ plugins/git-release-manager/src/test-helpers/test-helpers.ts | 2 ++ 2 files changed, 5 insertions(+) diff --git a/plugins/git-release-manager/src/features/Patch/PatchBody.test.tsx b/plugins/git-release-manager/src/features/Patch/PatchBody.test.tsx index d3e215d6d3..765cd82de2 100644 --- a/plugins/git-release-manager/src/features/Patch/PatchBody.test.tsx +++ b/plugins/git-release-manager/src/features/Patch/PatchBody.test.tsx @@ -24,6 +24,7 @@ import { mockReleaseCandidateCalver, mockReleaseVersionCalver, mockTagParts, + mockCtaMessage, } from '../../test-helpers/test-helpers'; import { mockApiClient } from '../../test-helpers/mock-api-client'; import { PatchBody } from './PatchBody'; @@ -60,6 +61,7 @@ describe('PatchBody', () => { latestRelease={mockReleaseCandidateCalver} releaseBranch={mockReleaseBranch} tagParts={mockTagParts} + ctaMessage={mockCtaMessage} />, ); @@ -77,6 +79,7 @@ describe('PatchBody', () => { releaseBranch={mockReleaseBranch} bumpedTag={mockBumpedTag} tagParts={mockTagParts} + ctaMessage={mockCtaMessage} />, ); diff --git a/plugins/git-release-manager/src/test-helpers/test-helpers.ts b/plugins/git-release-manager/src/test-helpers/test-helpers.ts index a5f0787a09..5547d889e0 100644 --- a/plugins/git-release-manager/src/test-helpers/test-helpers.ts +++ b/plugins/git-release-manager/src/test-helpers/test-helpers.ts @@ -115,6 +115,8 @@ export const mockTagParts = { patch: 1, } as CalverTagParts; +export const mockCtaMessage = 'Patch Release Candidate'; + export const mockBumpedTag = 'rc-2020.01.01_1337'; /** From 0627a63723f415dff981b9d66e568386396fd2cf Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 13 Jan 2022 14:19:51 +0100 Subject: [PATCH 45/56] STYLE: recommend prefix of type parameter names Signed-off-by: Patrik Oldsberg --- STYLE.md | 1 + 1 file changed, 1 insertion(+) diff --git a/STYLE.md b/STYLE.md index 8fbe87eb5f..d968d387fc 100644 --- a/STYLE.md +++ b/STYLE.md @@ -15,6 +15,7 @@ Our TypeScript style is inspired by the [style guidelines](https://github.com/Mi 1. Use camelCase for property names and local variables. 1. Do not use `_` as a prefix for private properties. 1. Use whole words in names when possible. +1. Give type parameters names prefixed with `T`, for example `Request`. ## Syntax and Types From b85010a0c8394880f868dd3b4c2b55c85f5f0d08 Mon Sep 17 00:00:00 2001 From: Erik Engervall Date: Thu, 13 Jan 2022 14:25:03 +0100 Subject: [PATCH 46/56] Update api-report.md Signed-off-by: Erik Engervall --- plugins/git-release-manager/api-report.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/git-release-manager/api-report.md b/plugins/git-release-manager/api-report.md index 4ed142ca04..743ea4e0f9 100644 --- a/plugins/git-release-manager/api-report.md +++ b/plugins/git-release-manager/api-report.md @@ -296,6 +296,11 @@ const mockBumpedTag = 'rc-2020.01.01_1337'; // @public (undocumented) const mockCalverProject: Project; +// Warning: (ae-missing-release-tag) "mockCtaMessage" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +const mockCtaMessage = 'Patch Release Candidate'; + // Warning: (ae-missing-release-tag) "mockDefaultBranch" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -601,6 +606,7 @@ declare namespace testHelpers_2 { mockNextGitInfoSemver, mockNextGitInfoCalver, mockTagParts, + mockCtaMessage, mockBumpedTag, createMockRelease, mockReleaseCandidateCalver, From 37914fa9e05815f337ef71f7c8865251966720ba Mon Sep 17 00:00:00 2001 From: Artur Gevorgyan Date: Thu, 13 Jan 2022 17:24:55 +0400 Subject: [PATCH 47/56] Update identity-resolver.md Signed-off-by: Artur Gevorgyan --- docs/auth/identity-resolver.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/auth/identity-resolver.md b/docs/auth/identity-resolver.md index 2c36ddcd7f..a33351e938 100644 --- a/docs/auth/identity-resolver.md +++ b/docs/auth/identity-resolver.md @@ -96,7 +96,7 @@ It can be enabled like this ```tsx // File: packages/backend/src/plugins/auth.ts -import { googleEmailSignInResolver } from '@backstage/plugin-auth-backend'; +import { googleEmailSignInResolver, createGoogleProvider } from '@backstage/plugin-auth-backend'; export default async function createPlugin({ ... From ba2dbe47d736b43c174098df4f9b6a71a2737d41 Mon Sep 17 00:00:00 2001 From: MT Lewis Date: Thu, 13 Jan 2022 13:28:51 +0000 Subject: [PATCH 48/56] permission-node: regenerate api-report Signed-off-by: MT Lewis --- plugins/permission-node/api-report.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/permission-node/api-report.md b/plugins/permission-node/api-report.md index d9ea64483e..71685c59b1 100644 --- a/plugins/permission-node/api-report.md +++ b/plugins/permission-node/api-report.md @@ -104,11 +104,6 @@ export const createPermissionIntegrationRouter: (options: { getResources: (resourceRefs: string[]) => Promise<(TResource | undefined)[]>; }) => express.Router; -// @public -export type DefinitivePolicyDecision = { - result: AuthorizeResult.ALLOW | AuthorizeResult.DENY; -}; - // @public export const createPermissionRule: < TResource, @@ -118,6 +113,11 @@ export const createPermissionRule: < rule: PermissionRule, ) => PermissionRule; +// @public +export type DefinitivePolicyDecision = { + result: AuthorizeResult.ALLOW | AuthorizeResult.DENY; +}; + // @public export const makeCreatePermissionRule: () => < TParams extends unknown[], From 9f9596f9efafea1854ac4fe41c3c9c387a66b64d Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 13 Jan 2022 13:37:57 +0100 Subject: [PATCH 49/56] azure-devops-backend: only warn if teams fail to load at startup Signed-off-by: Patrik Oldsberg --- .changeset/cold-plums-hunt.md | 5 +++++ .../src/api/PullRequestsDashboardProvider.ts | 18 ++++++++++-------- .../src/service/router.test.ts | 3 ++- .../azure-devops-backend/src/service/router.ts | 2 +- 4 files changed, 18 insertions(+), 10 deletions(-) create mode 100644 .changeset/cold-plums-hunt.md diff --git a/.changeset/cold-plums-hunt.md b/.changeset/cold-plums-hunt.md new file mode 100644 index 0000000000..a952c5e459 --- /dev/null +++ b/.changeset/cold-plums-hunt.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-azure-devops-backend': patch +--- + +Only warn if teams fail to load at startup. diff --git a/plugins/azure-devops-backend/src/api/PullRequestsDashboardProvider.ts b/plugins/azure-devops-backend/src/api/PullRequestsDashboardProvider.ts index a4879de7be..0f6dbe5b04 100644 --- a/plugins/azure-devops-backend/src/api/PullRequestsDashboardProvider.ts +++ b/plugins/azure-devops-backend/src/api/PullRequestsDashboardProvider.ts @@ -40,7 +40,11 @@ export class PullRequestsDashboardProvider { azureDevOpsApi: AzureDevOpsApi, ): Promise { const provider = new PullRequestsDashboardProvider(logger, azureDevOpsApi); - await provider.readTeams(); + try { + await provider.readTeams(); + } catch (error) { + logger.warn(`Failed to load azure team information, ${error}`); + } return provider; } @@ -124,10 +128,12 @@ export class PullRequestsDashboardProvider { }); } - public getUserTeamIds(email: string): string[] { + public async getUserTeamIds(email: string): Promise { + await this.getAllTeams(); // Make sure team members are loaded return ( - this.getTeamMembers().find(teamMember => teamMember.uniqueName === email) - ?.memberOf ?? [] + Array.from(this.teamMembers.values()).find( + teamMember => teamMember.uniqueName === email, + )?.memberOf ?? [] ); } @@ -138,8 +144,4 @@ export class PullRequestsDashboardProvider { return Array.from(this.teams.values()); } - - public getTeamMembers(): TeamMember[] { - return Array.from(this.teamMembers.values()); - } } diff --git a/plugins/azure-devops-backend/src/service/router.test.ts b/plugins/azure-devops-backend/src/service/router.test.ts index 335e581d73..e6cd856c0a 100644 --- a/plugins/azure-devops-backend/src/service/router.test.ts +++ b/plugins/azure-devops-backend/src/service/router.test.ts @@ -49,7 +49,7 @@ describe('createRouter', () => { getPullRequests: jest.fn(), getBuilds: jest.fn(), getBuildRuns: jest.fn(), - getAllTeams: jest.fn().mockReturnValue([]), + getAllTeams: jest.fn(), getTeamMembers: jest.fn(), } as any; const router = await createRouter({ @@ -411,6 +411,7 @@ describe('createRouter', () => { describe('GET /users/:userId/team-ids', () => { it('fetches a a list of teams', async () => { + azureDevOpsApi.getAllTeams.mockResolvedValue([]); const response = await request(app).get('/users/user1/team-ids'); expect(response.status).toEqual(200); }); diff --git a/plugins/azure-devops-backend/src/service/router.ts b/plugins/azure-devops-backend/src/service/router.ts index 6482ed2f59..f41209e4ff 100644 --- a/plugins/azure-devops-backend/src/service/router.ts +++ b/plugins/azure-devops-backend/src/service/router.ts @@ -176,7 +176,7 @@ export async function createRouter( router.get('/users/:userId/team-ids', async (req, res) => { const { userId } = req.params; - const teamIds = pullRequestsDashboardProvider.getUserTeamIds(userId); + const teamIds = await pullRequestsDashboardProvider.getUserTeamIds(userId); res.status(200).json(teamIds); }); From 7b8976425d070f43d0e7cbd46b3a97ee8bfd5a2c Mon Sep 17 00:00:00 2001 From: Miklos Kiss Date: Thu, 13 Jan 2022 14:22:58 +0100 Subject: [PATCH 50/56] Add clarification that Location spec is required Signed-off-by: Miklos Kiss --- docs/features/software-catalog/descriptor-format.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/features/software-catalog/descriptor-format.md b/docs/features/software-catalog/descriptor-format.md index 57473ce4c7..2b6b2049d0 100644 --- a/docs/features/software-catalog/descriptor-format.md +++ b/docs/features/software-catalog/descriptor-format.md @@ -1266,6 +1266,9 @@ shape, this kind has the following structure. Exactly equal to `backstage.io/v1alpha1` and `Location`, respectively. +### `spec` [required] +The `spec` field is required. The miniaml spec should be an empty object. + ### `spec.type` [optional] The single location type, that's common to the targets specified in the spec. If From b04011602b9cd0dcb54e2e5aa9128a826beacbf8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 13 Jan 2022 14:23:13 +0000 Subject: [PATCH 51/56] Version Packages --- .changeset/angry-tables-invite.md | 6 -- .changeset/brave-pugs-fold.md | 5 - .changeset/clean-wolves-jog.md | 5 - .changeset/cold-plums-hunt.md | 5 - .changeset/cold-steaks-flash.md | 5 - .changeset/cold-toes-sniff.md | 5 - .changeset/cool-baboons-switch.md | 5 - .changeset/dependabot-0c71dee.md | 5 - .changeset/dependabot-2af4c1d.md | 6 -- .changeset/dry-boats-tap.md | 5 - .changeset/dull-bulldogs-laugh.md | 5 - .changeset/eight-rats-raise.md | 5 - .changeset/fair-bikes-scream.md | 28 ------ .changeset/flat-shirts-watch.md | 5 - .changeset/fluffy-tomatoes-rescue.md | 5 - .changeset/four-ghosts-sniff.md | 5 - .changeset/funny-carrots-breathe.md | 5 - .changeset/funny-llamas-yell.md | 5 - .changeset/fuzzy-llamas-collect.md | 5 - .changeset/gold-birds-happen.md | 13 --- .changeset/great-points-design.md | 5 - .changeset/healthy-toes-laugh.md | 5 - .changeset/itchy-walls-count.md | 5 - .changeset/late-plums-act.md | 5 - .changeset/lazy-gorillas-tell.md | 7 -- .changeset/lazy-rockets-dress.md | 5 - .changeset/long-otters-promise.md | 6 -- .changeset/metal-worms-flash.md | 5 - .changeset/nervous-starfishes-report.md | 5 - .changeset/nervous-taxis-grin.md | 5 - .changeset/olive-laws-thank.md | 9 -- .changeset/olive-points-flash.md | 5 - .changeset/pink-suns-walk.md | 25 ----- .changeset/plenty-eyes-brush.md | 60 ------------ .changeset/popular-cycles-work.md | 5 - .changeset/quiet-carpets-shake.md | 7 -- .changeset/rotten-files-wink.md | 5 - .changeset/rotten-olives-shop.md | 5 - .changeset/selfish-bikes-sleep.md | 12 --- .changeset/seven-swans-glow.md | 8 -- .changeset/shaggy-emus-look.md | 7 -- .changeset/shiny-bugs-beam.md | 11 --- .changeset/shiny-emus-complain.md | 6 -- .changeset/short-shoes-fail.md | 5 - .changeset/silent-nails-sleep.md | 5 - .changeset/silver-falcons-nail.md | 5 - .changeset/silver-knives-change.md | 6 -- .changeset/silver-mice-bake.md | 5 - .changeset/slimy-eggs-carry.md | 7 -- .changeset/small-hotels-shake.md | 5 - .changeset/stale-gorillas-mix.md | 5 - .changeset/techdocs-light-onions-cover.md | 5 - .changeset/tender-cars-look.md | 5 - .changeset/thin-buckets-juggle.md | 5 - .changeset/three-sheep-sparkle.md | 7 -- .changeset/twelve-bears-fail.md | 6 -- .changeset/twelve-panthers-move.md | 5 - .changeset/violet-dingos-relate.md | 7 -- .changeset/warm-crews-flash.md | 5 - .changeset/warm-moles-battle.md | 5 - packages/app-defaults/CHANGELOG.md | 10 ++ packages/app-defaults/package.json | 14 +-- packages/app/CHANGELOG.md | 50 ++++++++++ packages/app/package.json | 92 +++++++++---------- packages/backend-common/CHANGELOG.md | 16 ++++ packages/backend-common/package.json | 14 +-- packages/backend-tasks/CHANGELOG.md | 9 ++ packages/backend-tasks/package.json | 12 +-- packages/backend-test-utils/CHANGELOG.md | 10 ++ packages/backend-test-utils/package.json | 10 +- packages/backend/CHANGELOG.md | 30 ++++++ packages/backend/package.json | 52 +++++------ packages/catalog-client/CHANGELOG.md | 8 ++ packages/catalog-client/package.json | 8 +- packages/catalog-model/CHANGELOG.md | 8 ++ packages/catalog-model/package.json | 8 +- packages/cli/CHANGELOG.md | 39 ++++++++ packages/cli/package.json | 22 ++--- packages/codemods/CHANGELOG.md | 9 ++ packages/codemods/package.json | 2 +- packages/config-loader/CHANGELOG.md | 8 ++ packages/config-loader/package.json | 6 +- packages/config/CHANGELOG.md | 6 ++ packages/config/package.json | 4 +- packages/core-app-api/CHANGELOG.md | 17 ++++ packages/core-app-api/package.json | 10 +- packages/core-components/CHANGELOG.md | 13 +++ packages/core-components/package.json | 14 +-- packages/core-plugin-api/CHANGELOG.md | 15 +++ packages/core-plugin-api/package.json | 10 +- packages/create-app/CHANGELOG.md | 62 +++++++++++++ packages/create-app/package.json | 2 +- packages/dev-utils/CHANGELOG.md | 14 +++ packages/dev-utils/package.json | 20 ++-- packages/e2e-test/package.json | 2 +- packages/embedded-techdocs-app/CHANGELOG.md | 17 ++++ packages/embedded-techdocs-app/package.json | 26 +++--- packages/errors/CHANGELOG.md | 8 ++ packages/errors/package.json | 4 +- packages/integration-react/CHANGELOG.md | 10 ++ packages/integration-react/package.json | 16 ++-- packages/integration/CHANGELOG.md | 9 ++ packages/integration/package.json | 10 +- packages/search-common/package.json | 2 +- packages/storybook/CHANGELOG.md | 9 ++ packages/storybook/package.json | 8 +- packages/techdocs-cli/package.json | 12 +-- packages/techdocs-common/CHANGELOG.md | 12 +++ packages/techdocs-common/package.json | 14 +-- packages/test-utils/CHANGELOG.md | 10 ++ packages/test-utils/package.json | 10 +- packages/theme/package.json | 2 +- packages/types/package.json | 2 +- packages/version-bridge/package.json | 2 +- plugins/airbrake/CHANGELOG.md | 13 +++ plugins/airbrake/package.json | 16 ++-- plugins/allure/CHANGELOG.md | 10 ++ plugins/allure/package.json | 18 ++-- plugins/analytics-module-ga/CHANGELOG.md | 9 ++ plugins/analytics-module-ga/package.json | 16 ++-- plugins/apache-airflow/CHANGELOG.md | 9 ++ plugins/apache-airflow/package.json | 14 +-- plugins/api-docs/CHANGELOG.md | 20 ++++ plugins/api-docs/package.json | 20 ++-- plugins/app-backend/package.json | 8 +- plugins/auth-backend/CHANGELOG.md | 17 ++++ plugins/auth-backend/package.json | 16 ++-- plugins/azure-devops-backend/CHANGELOG.md | 16 ++++ plugins/azure-devops-backend/package.json | 10 +- plugins/azure-devops-common/CHANGELOG.md | 8 ++ plugins/azure-devops-common/package.json | 4 +- plugins/azure-devops/CHANGELOG.md | 16 ++++ plugins/azure-devops/package.json | 22 ++--- plugins/badges-backend/CHANGELOG.md | 11 +++ plugins/badges-backend/package.json | 14 +-- plugins/badges/CHANGELOG.md | 11 +++ plugins/badges/package.json | 20 ++-- plugins/bazaar-backend/CHANGELOG.md | 10 ++ plugins/bazaar-backend/package.json | 10 +- plugins/bazaar/CHANGELOG.md | 15 +++ plugins/bazaar/package.json | 20 ++-- plugins/bitrise/CHANGELOG.md | 10 ++ plugins/bitrise/package.json | 18 ++-- .../catalog-backend-module-ldap/CHANGELOG.md | 12 +++ .../catalog-backend-module-ldap/package.json | 12 +-- .../CHANGELOG.md | 10 ++ .../package.json | 14 +-- plugins/catalog-backend/CHANGELOG.md | 26 ++++++ plugins/catalog-backend/package.json | 26 +++--- plugins/catalog-common/package.json | 4 +- plugins/catalog-graph/CHANGELOG.md | 11 +++ plugins/catalog-graph/package.json | 20 ++-- plugins/catalog-graphql/CHANGELOG.md | 13 +++ plugins/catalog-graphql/package.json | 10 +- plugins/catalog-import/CHANGELOG.md | 15 +++ plugins/catalog-import/package.json | 26 +++--- plugins/catalog-react/CHANGELOG.md | 13 +++ plugins/catalog-react/package.json | 20 ++-- plugins/catalog/CHANGELOG.md | 13 +++ plugins/catalog/package.json | 24 ++--- plugins/circleci/CHANGELOG.md | 10 ++ plugins/circleci/package.json | 18 ++-- plugins/cloudbuild/CHANGELOG.md | 10 ++ plugins/cloudbuild/package.json | 18 ++-- plugins/code-coverage-backend/CHANGELOG.md | 13 +++ plugins/code-coverage-backend/package.json | 16 ++-- plugins/code-coverage/CHANGELOG.md | 13 +++ plugins/code-coverage/package.json | 22 ++--- plugins/config-schema/CHANGELOG.md | 10 ++ plugins/config-schema/package.json | 18 ++-- plugins/cost-insights/CHANGELOG.md | 10 ++ plugins/cost-insights/package.json | 16 ++-- plugins/explore-react/CHANGELOG.md | 7 ++ plugins/explore-react/package.json | 10 +- plugins/explore/CHANGELOG.md | 11 +++ plugins/explore/package.json | 20 ++-- plugins/firehydrant/CHANGELOG.md | 9 ++ plugins/firehydrant/package.json | 16 ++-- plugins/fossa/CHANGELOG.md | 12 +++ plugins/fossa/package.json | 20 ++-- plugins/gcp-projects/CHANGELOG.md | 8 ++ plugins/gcp-projects/package.json | 14 +-- plugins/git-release-manager/CHANGELOG.md | 10 ++ plugins/git-release-manager/package.json | 16 ++-- plugins/github-actions/CHANGELOG.md | 11 +++ plugins/github-actions/package.json | 20 ++-- plugins/github-deployments/CHANGELOG.md | 13 +++ plugins/github-deployments/package.json | 24 ++--- plugins/gitops-profiles/CHANGELOG.md | 8 ++ plugins/gitops-profiles/package.json | 14 +-- plugins/gocd/CHANGELOG.md | 13 +++ plugins/gocd/package.json | 20 ++-- plugins/graphiql/CHANGELOG.md | 8 ++ plugins/graphiql/package.json | 14 +-- plugins/graphql-backend/CHANGELOG.md | 10 ++ plugins/graphql-backend/package.json | 10 +- plugins/home/CHANGELOG.md | 10 ++ plugins/home/package.json | 16 ++-- plugins/ilert/CHANGELOG.md | 12 +++ plugins/ilert/package.json | 20 ++-- plugins/jenkins-backend/package.json | 10 +- plugins/jenkins/CHANGELOG.md | 12 +++ plugins/jenkins/package.json | 20 ++-- plugins/kafka-backend/CHANGELOG.md | 10 ++ plugins/kafka-backend/package.json | 12 +-- plugins/kafka/CHANGELOG.md | 10 ++ plugins/kafka/package.json | 18 ++-- plugins/kubernetes-backend/CHANGELOG.md | 11 +++ plugins/kubernetes-backend/package.json | 12 +-- plugins/kubernetes-common/package.json | 4 +- plugins/kubernetes/CHANGELOG.md | 12 +++ plugins/kubernetes/package.json | 20 ++-- plugins/lighthouse/CHANGELOG.md | 11 +++ plugins/lighthouse/package.json | 20 ++-- plugins/newrelic-dashboard/CHANGELOG.md | 11 +++ plugins/newrelic-dashboard/package.json | 16 ++-- plugins/newrelic/CHANGELOG.md | 8 ++ plugins/newrelic/package.json | 14 +-- plugins/org/CHANGELOG.md | 20 ++++ plugins/org/package.json | 20 ++-- plugins/pagerduty/CHANGELOG.md | 11 +++ plugins/pagerduty/package.json | 18 ++-- plugins/permission-backend/CHANGELOG.md | 21 +++++ plugins/permission-backend/package.json | 16 ++-- plugins/permission-common/CHANGELOG.md | 8 ++ plugins/permission-common/package.json | 8 +- plugins/permission-node/CHANGELOG.md | 21 +++++ plugins/permission-node/package.json | 14 +-- plugins/permission-react/CHANGELOG.md | 9 ++ plugins/permission-react/package.json | 12 +-- plugins/proxy-backend/package.json | 6 +- plugins/rollbar-backend/package.json | 8 +- plugins/rollbar/CHANGELOG.md | 10 ++ plugins/rollbar/package.json | 18 ++-- .../CHANGELOG.md | 11 +++ .../package.json | 14 +-- .../CHANGELOG.md | 11 +++ .../package.json | 14 +-- plugins/scaffolder-backend/CHANGELOG.md | 18 ++++ plugins/scaffolder-backend/package.json | 22 ++--- plugins/scaffolder-common/package.json | 4 +- plugins/scaffolder/CHANGELOG.md | 16 ++++ plugins/scaffolder/package.json | 30 +++--- .../package.json | 6 +- plugins/search-backend-module-pg/package.json | 8 +- plugins/search-backend-node/CHANGELOG.md | 6 ++ plugins/search-backend-node/package.json | 6 +- plugins/search-backend/package.json | 6 +- plugins/search/CHANGELOG.md | 12 +++ plugins/search/package.json | 22 ++--- plugins/sentry/CHANGELOG.md | 10 ++ plugins/sentry/package.json | 18 ++-- plugins/shortcuts/CHANGELOG.md | 8 ++ plugins/shortcuts/package.json | 14 +-- plugins/sonarqube/CHANGELOG.md | 11 +++ plugins/sonarqube/package.json | 18 ++-- plugins/splunk-on-call/CHANGELOG.md | 11 +++ plugins/splunk-on-call/package.json | 18 ++-- .../CHANGELOG.md | 11 +++ .../package.json | 12 +-- plugins/tech-insights-backend/CHANGELOG.md | 15 +++ plugins/tech-insights-backend/package.json | 18 ++-- plugins/tech-insights-common/CHANGELOG.md | 6 ++ plugins/tech-insights-common/package.json | 4 +- plugins/tech-insights-node/package.json | 8 +- plugins/tech-insights/CHANGELOG.md | 15 +++ plugins/tech-insights/package.json | 22 ++--- plugins/tech-radar/CHANGELOG.md | 8 ++ plugins/tech-radar/package.json | 14 +-- plugins/techdocs-backend/CHANGELOG.md | 14 +++ plugins/techdocs-backend/package.json | 20 ++-- plugins/techdocs/CHANGELOG.md | 18 ++++ plugins/techdocs/package.json | 30 +++--- plugins/todo-backend/CHANGELOG.md | 13 +++ plugins/todo-backend/package.json | 16 ++-- plugins/todo/CHANGELOG.md | 11 +++ plugins/todo/package.json | 20 ++-- plugins/user-settings/CHANGELOG.md | 8 ++ plugins/user-settings/package.json | 14 +-- plugins/xcmetrics/CHANGELOG.md | 9 ++ plugins/xcmetrics/package.json | 16 ++-- yarn.lock | 37 ++++++++ 282 files changed, 2256 insertions(+), 1341 deletions(-) delete mode 100644 .changeset/angry-tables-invite.md delete mode 100644 .changeset/brave-pugs-fold.md delete mode 100644 .changeset/clean-wolves-jog.md delete mode 100644 .changeset/cold-plums-hunt.md delete mode 100644 .changeset/cold-steaks-flash.md delete mode 100644 .changeset/cold-toes-sniff.md delete mode 100644 .changeset/cool-baboons-switch.md delete mode 100644 .changeset/dependabot-0c71dee.md delete mode 100644 .changeset/dependabot-2af4c1d.md delete mode 100644 .changeset/dry-boats-tap.md delete mode 100644 .changeset/dull-bulldogs-laugh.md delete mode 100644 .changeset/eight-rats-raise.md delete mode 100644 .changeset/fair-bikes-scream.md delete mode 100644 .changeset/flat-shirts-watch.md delete mode 100644 .changeset/fluffy-tomatoes-rescue.md delete mode 100644 .changeset/four-ghosts-sniff.md delete mode 100644 .changeset/funny-carrots-breathe.md delete mode 100644 .changeset/funny-llamas-yell.md delete mode 100644 .changeset/fuzzy-llamas-collect.md delete mode 100644 .changeset/gold-birds-happen.md delete mode 100644 .changeset/great-points-design.md delete mode 100644 .changeset/healthy-toes-laugh.md delete mode 100644 .changeset/itchy-walls-count.md delete mode 100644 .changeset/late-plums-act.md delete mode 100644 .changeset/lazy-gorillas-tell.md delete mode 100644 .changeset/lazy-rockets-dress.md delete mode 100644 .changeset/long-otters-promise.md delete mode 100644 .changeset/metal-worms-flash.md delete mode 100644 .changeset/nervous-starfishes-report.md delete mode 100644 .changeset/nervous-taxis-grin.md delete mode 100644 .changeset/olive-laws-thank.md delete mode 100644 .changeset/olive-points-flash.md delete mode 100644 .changeset/pink-suns-walk.md delete mode 100644 .changeset/plenty-eyes-brush.md delete mode 100644 .changeset/popular-cycles-work.md delete mode 100644 .changeset/quiet-carpets-shake.md delete mode 100644 .changeset/rotten-files-wink.md delete mode 100644 .changeset/rotten-olives-shop.md delete mode 100644 .changeset/selfish-bikes-sleep.md delete mode 100644 .changeset/seven-swans-glow.md delete mode 100644 .changeset/shaggy-emus-look.md delete mode 100644 .changeset/shiny-bugs-beam.md delete mode 100644 .changeset/shiny-emus-complain.md delete mode 100644 .changeset/short-shoes-fail.md delete mode 100644 .changeset/silent-nails-sleep.md delete mode 100644 .changeset/silver-falcons-nail.md delete mode 100644 .changeset/silver-knives-change.md delete mode 100644 .changeset/silver-mice-bake.md delete mode 100644 .changeset/slimy-eggs-carry.md delete mode 100644 .changeset/small-hotels-shake.md delete mode 100644 .changeset/stale-gorillas-mix.md delete mode 100644 .changeset/techdocs-light-onions-cover.md delete mode 100644 .changeset/tender-cars-look.md delete mode 100644 .changeset/thin-buckets-juggle.md delete mode 100644 .changeset/three-sheep-sparkle.md delete mode 100644 .changeset/twelve-bears-fail.md delete mode 100644 .changeset/twelve-panthers-move.md delete mode 100644 .changeset/violet-dingos-relate.md delete mode 100644 .changeset/warm-crews-flash.md delete mode 100644 .changeset/warm-moles-battle.md create mode 100644 plugins/airbrake/CHANGELOG.md create mode 100644 plugins/gocd/CHANGELOG.md diff --git a/.changeset/angry-tables-invite.md b/.changeset/angry-tables-invite.md deleted file mode 100644 index a187acda78..0000000000 --- a/.changeset/angry-tables-invite.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-bazaar': patch -'@backstage/plugin-bazaar-backend': patch ---- - -Add Bazaar plugin to marketplace and some minor refactoring diff --git a/.changeset/brave-pugs-fold.md b/.changeset/brave-pugs-fold.md deleted file mode 100644 index f79867a719..0000000000 --- a/.changeset/brave-pugs-fold.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/test-utils': patch ---- - -Add new `MockConfigApi` as a more discoverable and leaner method for mocking configuration. diff --git a/.changeset/clean-wolves-jog.md b/.changeset/clean-wolves-jog.md deleted file mode 100644 index 70ab23715f..0000000000 --- a/.changeset/clean-wolves-jog.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/config': patch ---- - -The `ConfigReader#get` method now always returns a deep clone of the configuration data. diff --git a/.changeset/cold-plums-hunt.md b/.changeset/cold-plums-hunt.md deleted file mode 100644 index a952c5e459..0000000000 --- a/.changeset/cold-plums-hunt.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-azure-devops-backend': patch ---- - -Only warn if teams fail to load at startup. diff --git a/.changeset/cold-steaks-flash.md b/.changeset/cold-steaks-flash.md deleted file mode 100644 index 74cdcbdec2..0000000000 --- a/.changeset/cold-steaks-flash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -fix: Register plugin to prioritise Component kind for entityRef diff --git a/.changeset/cold-toes-sniff.md b/.changeset/cold-toes-sniff.md deleted file mode 100644 index 7fcfb54408..0000000000 --- a/.changeset/cold-toes-sniff.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/integration': patch ---- - -Adds a new GitHub credentials provider (DefaultGithubCredentialsProvider). It handles multiple app configurations. It looks up the app configuration based on the url. diff --git a/.changeset/cool-baboons-switch.md b/.changeset/cool-baboons-switch.md deleted file mode 100644 index 9bf09bab74..0000000000 --- a/.changeset/cool-baboons-switch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Add a `ProxiedSignInPage` that can be used e.g. for GCP IAP and AWS ALB diff --git a/.changeset/dependabot-0c71dee.md b/.changeset/dependabot-0c71dee.md deleted file mode 100644 index b2d7f3dc2a..0000000000 --- a/.changeset/dependabot-0c71dee.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -build(deps-dev): bump `http-errors` from 1.8.0 to 2.0.0 diff --git a/.changeset/dependabot-2af4c1d.md b/.changeset/dependabot-2af4c1d.md deleted file mode 100644 index 93dc1d1e21..0000000000 --- a/.changeset/dependabot-2af4c1d.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-bazaar': patch -'@backstage/plugin-ilert': patch ---- - -build(deps): bump `@date-io/luxon` from 1.3.13 to 2.11.1 diff --git a/.changeset/dry-boats-tap.md b/.changeset/dry-boats-tap.md deleted file mode 100644 index c69c4360b5..0000000000 --- a/.changeset/dry-boats-tap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-todo-backend': patch ---- - -Properly exported all referenced types diff --git a/.changeset/dull-bulldogs-laugh.md b/.changeset/dull-bulldogs-laugh.md deleted file mode 100644 index f49aa694b6..0000000000 --- a/.changeset/dull-bulldogs-laugh.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Create a short delay when `` is opened diff --git a/.changeset/eight-rats-raise.md b/.changeset/eight-rats-raise.md deleted file mode 100644 index 7bc2a07f04..0000000000 --- a/.changeset/eight-rats-raise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Add catalog permission rules. diff --git a/.changeset/fair-bikes-scream.md b/.changeset/fair-bikes-scream.md deleted file mode 100644 index decdfd3828..0000000000 --- a/.changeset/fair-bikes-scream.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -'@backstage/cli': minor ---- - -ESLint upgraded to version 8 and all it's plugins updated to newest version. - -If you use any custom plugins for ESLint please check compatibility. - -```diff -- "@typescript-eslint/eslint-plugin": "^v4.33.0", -- "@typescript-eslint/parser": "^v4.28.3", -+ "@typescript-eslint/eslint-plugin": "^5.9.0", -+ "@typescript-eslint/parser": "^5.9.0", -- "eslint": "^7.30.0", -+ "eslint": "^8.6.0", -- "eslint-plugin-import": "^2.20.2", -- "eslint-plugin-jest": "^24.1.0", -- "eslint-plugin-jsx-a11y": "^6.2.1", -+ "eslint-plugin-import": "^2.25.4", -+ "eslint-plugin-jest": "^25.3.4", -+ "eslint-plugin-jsx-a11y": "^6.5.1", -- "eslint-plugin-react": "^7.12.4", -- "eslint-plugin-react-hooks": "^4.0.0", -+ "eslint-plugin-react": "^7.28.0", -+ "eslint-plugin-react-hooks": "^4.3.0", -``` - -Please consult changelogs from packages if you find any problems. diff --git a/.changeset/flat-shirts-watch.md b/.changeset/flat-shirts-watch.md deleted file mode 100644 index af6ff350da..0000000000 --- a/.changeset/flat-shirts-watch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-tech-insights': patch ---- - -Added possibility to pass customized title and description for the scorecards instead of using hardcoded ones. diff --git a/.changeset/fluffy-tomatoes-rescue.md b/.changeset/fluffy-tomatoes-rescue.md deleted file mode 100644 index 4d446070a0..0000000000 --- a/.changeset/fluffy-tomatoes-rescue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-gocd': patch ---- - -Add GoCD plugin for CI/CD. diff --git a/.changeset/four-ghosts-sniff.md b/.changeset/four-ghosts-sniff.md deleted file mode 100644 index 9da0ab15ed..0000000000 --- a/.changeset/four-ghosts-sniff.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-plugin-api': minor ---- - -Removed the deprecated `OldIconComponent` type. diff --git a/.changeset/funny-carrots-breathe.md b/.changeset/funny-carrots-breathe.md deleted file mode 100644 index 5706e027e7..0000000000 --- a/.changeset/funny-carrots-breathe.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-git-release-manager': patch ---- - -Improved copy for patch CTA diff --git a/.changeset/funny-llamas-yell.md b/.changeset/funny-llamas-yell.md deleted file mode 100644 index 890caaa221..0000000000 --- a/.changeset/funny-llamas-yell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-graphql': patch ---- - -Bump graphql versions diff --git a/.changeset/fuzzy-llamas-collect.md b/.changeset/fuzzy-llamas-collect.md deleted file mode 100644 index 17ee925e56..0000000000 --- a/.changeset/fuzzy-llamas-collect.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-ldap': patch ---- - -Make sure to avoid accidental data sharing / mutation of `set` values diff --git a/.changeset/gold-birds-happen.md b/.changeset/gold-birds-happen.md deleted file mode 100644 index 7a47a45fab..0000000000 --- a/.changeset/gold-birds-happen.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@backstage/plugin-org': patch ---- - -For the component `EntityMembersListCard` you can now specify the type of members you have in a group. For example: - -```tsx - - - -``` - -If left empty it will by default use 'Members'. diff --git a/.changeset/great-points-design.md b/.changeset/great-points-design.md deleted file mode 100644 index 7ce22b1bac..0000000000 --- a/.changeset/great-points-design.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-tech-insights-backend': patch ---- - -Catch errors from a fact retriever and log them. diff --git a/.changeset/healthy-toes-laugh.md b/.changeset/healthy-toes-laugh.md deleted file mode 100644 index e0db38e5e3..0000000000 --- a/.changeset/healthy-toes-laugh.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-permission-node': patch ---- - -Add helpers for creating PermissionRules with inferred types diff --git a/.changeset/itchy-walls-count.md b/.changeset/itchy-walls-count.md deleted file mode 100644 index 46a8709573..0000000000 --- a/.changeset/itchy-walls-count.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-sonarqube': patch ---- - -Enhance token description by highlighting that the trailing colon is required. diff --git a/.changeset/late-plums-act.md b/.changeset/late-plums-act.md deleted file mode 100644 index 6822f40eeb..0000000000 --- a/.changeset/late-plums-act.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Allow a custom GithubCredentialsProvider to be passed to the GitHub processors. diff --git a/.changeset/lazy-gorillas-tell.md b/.changeset/lazy-gorillas-tell.md deleted file mode 100644 index 672d8c221b..0000000000 --- a/.changeset/lazy-gorillas-tell.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/core-plugin-api': minor ---- - -Removed previously deprecated exports: `PluginHooks`, `PluginOutput`, and `FeatureFlagOutput`. - -The deprecated `register` method of `PluginConfig` has been removed, as well as the deprecated `output` method of `BackstagePlugin`. diff --git a/.changeset/lazy-rockets-dress.md b/.changeset/lazy-rockets-dress.md deleted file mode 100644 index b11857af04..0000000000 --- a/.changeset/lazy-rockets-dress.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Fix token pass-through for software templates using beta 3 version diff --git a/.changeset/long-otters-promise.md b/.changeset/long-otters-promise.md deleted file mode 100644 index eecb97e8ac..0000000000 --- a/.changeset/long-otters-promise.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-ldap': patch -'@backstage/plugin-catalog-backend-module-msgraph': patch ---- - -Clean up API report diff --git a/.changeset/metal-worms-flash.md b/.changeset/metal-worms-flash.md deleted file mode 100644 index dd06abdb34..0000000000 --- a/.changeset/metal-worms-flash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Provide support for Bitbucket servers with custom BaseURLs. diff --git a/.changeset/nervous-starfishes-report.md b/.changeset/nervous-starfishes-report.md deleted file mode 100644 index 2ac4179a2c..0000000000 --- a/.changeset/nervous-starfishes-report.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-home': patch ---- - -Adds two new home components - CompanyLogo and Toolkit. diff --git a/.changeset/nervous-taxis-grin.md b/.changeset/nervous-taxis-grin.md deleted file mode 100644 index 76deaa2d5c..0000000000 --- a/.changeset/nervous-taxis-grin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-tech-insights-backend': patch ---- - -Modify queries to perform better by filtering on sub-queries as well diff --git a/.changeset/olive-laws-thank.md b/.changeset/olive-laws-thank.md deleted file mode 100644 index 06a94d5614..0000000000 --- a/.changeset/olive-laws-thank.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/plugin-azure-devops-backend': minor -'@backstage/plugin-azure-devops': patch -'@backstage/plugin-azure-devops-common': minor ---- - -- feat: Created PullRequestsDashboardProvider for resolving team and team member relations -- feat: Created useUserTeamIds hook. -- feat: Updated useFilterProcessor to provide teamIds for `AssignedToCurrentUsersTeams` and `CreatedByCurrentUsersTeams` filters. diff --git a/.changeset/olive-points-flash.md b/.changeset/olive-points-flash.md deleted file mode 100644 index 64b23419de..0000000000 --- a/.changeset/olive-points-flash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Switch Webpack minification to use `esbuild` instead of `terser`. diff --git a/.changeset/pink-suns-walk.md b/.changeset/pink-suns-walk.md deleted file mode 100644 index 1857b90811..0000000000 --- a/.changeset/pink-suns-walk.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@backstage/backend-common': patch -'@backstage/core-components': patch -'@backstage/create-app': patch -'@backstage/integration': patch -'@backstage/techdocs-common': patch -'@backstage/plugin-apache-airflow': patch -'@backstage/plugin-auth-backend': patch -'@backstage/plugin-azure-devops': patch -'@backstage/plugin-catalog-backend': patch -'@backstage/plugin-catalog-import': patch -'@backstage/plugin-catalog-react': patch -'@backstage/plugin-code-coverage': patch -'@backstage/plugin-code-coverage-backend': patch -'@backstage/plugin-cost-insights': patch -'@backstage/plugin-fossa': patch -'@backstage/plugin-jenkins': patch -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-scaffolder-backend': patch -'@backstage/plugin-search-backend-node': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-techdocs-backend': patch ---- - -Cleaned up API exports diff --git a/.changeset/plenty-eyes-brush.md b/.changeset/plenty-eyes-brush.md deleted file mode 100644 index 354c216c3c..0000000000 --- a/.changeset/plenty-eyes-brush.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Add permissions to create-app's PluginEnvironment - -`CatalogEnvironment` now has a `permissions` field, which means that a permission client must now be provided as part of `PluginEnvironment`. To apply these changes to an existing app, add the following to the `makeCreateEnv` function in `packages/backend/src/index.ts`: - -```diff - // packages/backend/src/index.ts - -+ import { ServerPermissionClient } from '@backstage/plugin-permission-node'; - - function makeCreateEnv(config: Config) { - ... -+ const permissions = ServerPerimssionClient.fromConfig(config, { -+ discovery, -+ tokenManager, -+ }); - - root.info(`Created UrlReader ${reader}`); - - return (plugin: string): PluginEnvironment => { - ... - return { - logger, - cache, - database, - config, - reader, - discovery, - tokenManager, - scheduler, -+ permissions, - }; - } - } -``` - -And add a permissions field to the `PluginEnvironment` type in `packages/backend/src/types.ts`: - -```diff - // packages/backend/src/types.ts - -+ import { PermissionAuthorizer } from '@backstage/plugin-permission-common'; - - export type PluginEnvironment = { - ... -+ permissions: PermissionAuthorizer; - }; -``` - -[`@backstage/plugin-permission-common`](https://www.npmjs.com/package/@backstage/plugin-permission-common) and [`@backstage/plugin-permission-node`](https://www.npmjs.com/package/@backstage/plugin-permission-node) will need to be installed as dependencies: - -```diff - // packages/backend/package.json - -+ "@backstage/plugin-permission-common": "...", -+ "@backstage/plugin-permission-node": "...", -``` diff --git a/.changeset/popular-cycles-work.md b/.changeset/popular-cycles-work.md deleted file mode 100644 index 939f59de94..0000000000 --- a/.changeset/popular-cycles-work.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -bump `logform` to use fixed version of `color` dependency diff --git a/.changeset/quiet-carpets-shake.md b/.changeset/quiet-carpets-shake.md deleted file mode 100644 index a0744651e3..0000000000 --- a/.changeset/quiet-carpets-shake.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-kubernetes': patch -'@backstage/plugin-pagerduty': patch -'@backstage/plugin-splunk-on-call': patch ---- - -Clean up emptystate.svg image, removing wrong white artifact from the background diff --git a/.changeset/rotten-files-wink.md b/.changeset/rotten-files-wink.md deleted file mode 100644 index 65bd92bcc5..0000000000 --- a/.changeset/rotten-files-wink.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Updated `ResponseErrorPanel` to not use the deprecated `data` property of `ResponseError`. diff --git a/.changeset/rotten-olives-shop.md b/.changeset/rotten-olives-shop.md deleted file mode 100644 index b7fb51ad06..0000000000 --- a/.changeset/rotten-olives-shop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Update `config/eslint.js` to forbid imports of `@material-ui/icons/` as well. diff --git a/.changeset/selfish-bikes-sleep.md b/.changeset/selfish-bikes-sleep.md deleted file mode 100644 index f05518fde1..0000000000 --- a/.changeset/selfish-bikes-sleep.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@backstage/plugin-api-docs': patch ---- - -Update @asyncapi/react-component to 1.0.0-next.26, which will fix the -`ResizeObserver loop limit exceeded` errors which we encountered in several E2E -tests. - -For more details check the following links: - -- https://github.com/backstage/backstage/pull/8088#issuecomment-991183968 -- https://github.com/asyncapi/asyncapi-react/issues/498 diff --git a/.changeset/seven-swans-glow.md b/.changeset/seven-swans-glow.md deleted file mode 100644 index 2d41b94082..0000000000 --- a/.changeset/seven-swans-glow.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-tech-insights': patch -'@backstage/plugin-tech-insights-backend': patch -'@backstage/plugin-tech-insights-common': patch -'@backstage/plugin-tech-insights-backend-module-jsonfc': patch ---- - -adding new operation to run checks for multiple entities in one request diff --git a/.changeset/shaggy-emus-look.md b/.changeset/shaggy-emus-look.md deleted file mode 100644 index df8a1fe6fe..0000000000 --- a/.changeset/shaggy-emus-look.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/core-app-api': patch ---- - -Fixed an issue where valid SAML and GitHub sessions would be considered invalid and not be stored. - -Deprecated the `SamlSession` and `GithubSession` types. diff --git a/.changeset/shiny-bugs-beam.md b/.changeset/shiny-bugs-beam.md deleted file mode 100644 index b16c8d6729..0000000000 --- a/.changeset/shiny-bugs-beam.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@backstage/plugin-permission-backend': minor -'@backstage/plugin-permission-node': minor ---- - -Optimizations to the integration between the permission backend and plugin-backends using createPermissionIntegrationRouter: - -- The permission backend already supported batched requests to authorize, but would make calls to plugin backend to apply conditions serially. Now, after applying the policy for each authorization request, the permission backend makes a single batched /apply-conditions request to each plugin backend referenced in policy decisions. -- The `getResource` method accepted by `createPermissionIntegrationRouter` has been replaced with `getResources`, to allow consumers to make batch requests to upstream data stores. When /apply-conditions is called with a batch of requests, all required resources are requested in a single invocation of `getResources`. - -Plugin owners consuming `createPermissionIntegrationRouter` should replace the `getResource` method in the options with a `getResources` method, accepting an array of resourceRefs, and returning an array of the corresponding resources. diff --git a/.changeset/shiny-emus-complain.md b/.changeset/shiny-emus-complain.md deleted file mode 100644 index 741c092e69..0000000000 --- a/.changeset/shiny-emus-complain.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-catalog-graphql': minor -'@backstage/plugin-graphql-backend': patch ---- - -chore: bumping dependencies in the GraphQL modules and bringing them up to date with the latest `graphql-modules` library diff --git a/.changeset/short-shoes-fail.md b/.changeset/short-shoes-fail.md deleted file mode 100644 index 0b45d67a32..0000000000 --- a/.changeset/short-shoes-fail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend': patch ---- - -Removed `@backstage/test-utils` dependency. diff --git a/.changeset/silent-nails-sleep.md b/.changeset/silent-nails-sleep.md deleted file mode 100644 index a1587f8427..0000000000 --- a/.changeset/silent-nails-sleep.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Allow a GitHubCredentialsProvider to be passed to the GitHub scaffolder tasks actions. diff --git a/.changeset/silver-falcons-nail.md b/.changeset/silver-falcons-nail.md deleted file mode 100644 index 970bbd7fee..0000000000 --- a/.changeset/silver-falcons-nail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Add apply-conditions endpoint for evaluating conditional permissions in catalog backend. diff --git a/.changeset/silver-knives-change.md b/.changeset/silver-knives-change.md deleted file mode 100644 index a2bbaf1e0b..0000000000 --- a/.changeset/silver-knives-change.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/cli': patch -'@backstage/backend-common': patch ---- - -Switched to using `@manypkg/get-packages` to list monorepo packages, which provides better support for different kind of monorepo setups. diff --git a/.changeset/silver-mice-bake.md b/.changeset/silver-mice-bake.md deleted file mode 100644 index 6cba2fdb0a..0000000000 --- a/.changeset/silver-mice-bake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-app-api': minor ---- - -Removed previously deprecated `ApiRegistry` export. diff --git a/.changeset/slimy-eggs-carry.md b/.changeset/slimy-eggs-carry.md deleted file mode 100644 index a58a3d8c61..0000000000 --- a/.changeset/slimy-eggs-carry.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-auth-backend': patch ---- - -Switched the secure cookie mode set on the `express-session` to use `'auto'` rather than `true`. This works around an issue where cookies would not be set if TLS termination was handled in a proxy rather than having the backend served directly with HTTPS. - -The downside of this change is that secure cookies won't be used unless the backend is directly served with HTTPS. This will be remedied in a future update that allows the backend to configured for trusted proxy mode. diff --git a/.changeset/small-hotels-shake.md b/.changeset/small-hotels-shake.md deleted file mode 100644 index 8cb052cf96..0000000000 --- a/.changeset/small-hotels-shake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Add authorization to catalog-backend entities GET endpoints diff --git a/.changeset/stale-gorillas-mix.md b/.changeset/stale-gorillas-mix.md deleted file mode 100644 index 4ffa1fd553..0000000000 --- a/.changeset/stale-gorillas-mix.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -The GithubUrlReader is switched to use the DefaultGithubCredentialsProvider diff --git a/.changeset/techdocs-light-onions-cover.md b/.changeset/techdocs-light-onions-cover.md deleted file mode 100644 index 55c0873575..0000000000 --- a/.changeset/techdocs-light-onions-cover.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Fix an issue where the TechDocs sidebar is hidden when the Backstage sidebar is pinned at smaller screen sizes diff --git a/.changeset/tender-cars-look.md b/.changeset/tender-cars-look.md deleted file mode 100644 index f20ba447d4..0000000000 --- a/.changeset/tender-cars-look.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-test-utils': patch ---- - -Bump `testcontainers` dependency to version `8.1.2` diff --git a/.changeset/thin-buckets-juggle.md b/.changeset/thin-buckets-juggle.md deleted file mode 100644 index a95f8a86ad..0000000000 --- a/.changeset/thin-buckets-juggle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-airbrake': minor ---- - -A plugin for Airbrake (https://airbrake.io/) has been created diff --git a/.changeset/three-sheep-sparkle.md b/.changeset/three-sheep-sparkle.md deleted file mode 100644 index db6d8148ce..0000000000 --- a/.changeset/three-sheep-sparkle.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': minor ---- - -In order to integrate the permissions system with the refresh endpoint in catalog-backend, a new AuthorizedRefreshService was created as a thin wrapper around the existing refresh service which performs authorization and handles the case when authorization is denied. In order to instantiate AuthorizedRefreshService, a permission client is required, which was added as a new field to `CatalogEnvironment`. - -The new `permissions` field in `CatalogEnvironment` should already receive the permission client from the `PluginEnvrionment`, so there should be no changes required to the catalog backend setup. See [the create-app changelog](https://github.com/backstage/backstage/blob/master/packages/create-app/CHANGELOG.md) for more details. diff --git a/.changeset/twelve-bears-fail.md b/.changeset/twelve-bears-fail.md deleted file mode 100644 index 6112f5a980..0000000000 --- a/.changeset/twelve-bears-fail.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/core-app-api': patch -'@backstage/core-plugin-api': patch ---- - -Removed direct and transitive MUI dependencies. diff --git a/.changeset/twelve-panthers-move.md b/.changeset/twelve-panthers-move.md deleted file mode 100644 index f52050a488..0000000000 --- a/.changeset/twelve-panthers-move.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Clean up API reports diff --git a/.changeset/violet-dingos-relate.md b/.changeset/violet-dingos-relate.md deleted file mode 100644 index c8b0c03e2c..0000000000 --- a/.changeset/violet-dingos-relate.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/errors': minor ---- - -Removed the deprecated exports `ErrorResponse` and `parseErrorResponse`. - -Removed the deprecated `constructor` and the deprecated `data` property of `ResponseError`. diff --git a/.changeset/warm-crews-flash.md b/.changeset/warm-crews-flash.md deleted file mode 100644 index b21a3ada02..0000000000 --- a/.changeset/warm-crews-flash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-kubernetes-backend': patch ---- - -Exclude the AWS session token from credential validation, because it's not necessary in this context. diff --git a/.changeset/warm-moles-battle.md b/.changeset/warm-moles-battle.md deleted file mode 100644 index 3d203ea1d3..0000000000 --- a/.changeset/warm-moles-battle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-tech-insights': patch ---- - -fix React warning because of missing `key` prop diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md index 751b758984..631a4726e1 100644 --- a/packages/app-defaults/CHANGELOG.md +++ b/packages/app-defaults/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/app-defaults +## 0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/core-app-api@0.4.0 + - @backstage/plugin-permission-react@0.2.2 + ## 0.1.3 ### Patch Changes diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index 89d83ae91f..eb65583934 100644 --- a/packages/app-defaults/package.json +++ b/packages/app-defaults/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/app-defaults", "description": "Provides the default wiring of a Backstage App", - "version": "0.1.3", + "version": "0.1.4", "private": false, "publishConfig": { "access": "public", @@ -29,10 +29,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.2", - "@backstage/core-app-api": "^0.3.0", - "@backstage/core-plugin-api": "^0.4.0", - "@backstage/plugin-permission-react": "^0.2.0", + "@backstage/core-components": "^0.8.4", + "@backstage/core-app-api": "^0.4.0", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/plugin-permission-react": "^0.2.2", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -42,8 +42,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", - "@backstage/test-utils": "^0.2.0", + "@backstage/cli": "^0.11.0", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@types/jest": "^26.0.7", diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index c14db343bc..aa2fdc5ffa 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,55 @@ # example-app +## 0.2.60 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/cli@0.11.0 + - @backstage/plugin-tech-insights@0.1.5 + - @backstage/plugin-gocd@0.1.1 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-org@0.3.34 + - @backstage/plugin-home@0.4.10 + - @backstage/plugin-azure-devops@0.1.10 + - @backstage/plugin-apache-airflow@0.1.3 + - @backstage/plugin-catalog-import@0.7.9 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/plugin-code-coverage@0.1.22 + - @backstage/plugin-cost-insights@0.11.17 + - @backstage/plugin-jenkins@0.5.17 + - @backstage/plugin-scaffolder@0.11.18 + - @backstage/plugin-techdocs@0.12.14 + - @backstage/plugin-kubernetes@0.5.4 + - @backstage/plugin-pagerduty@0.3.22 + - @backstage/plugin-api-docs@0.6.22 + - @backstage/core-app-api@0.4.0 + - @backstage/plugin-airbrake@0.1.0 + - @backstage/app-defaults@0.1.4 + - @backstage/catalog-model@0.9.9 + - @backstage/integration-react@0.1.18 + - @backstage/plugin-badges@0.2.19 + - @backstage/plugin-catalog@0.7.8 + - @backstage/plugin-catalog-graph@0.2.6 + - @backstage/plugin-circleci@0.2.34 + - @backstage/plugin-cloudbuild@0.2.32 + - @backstage/plugin-explore@0.3.25 + - @backstage/plugin-gcp-projects@0.3.13 + - @backstage/plugin-github-actions@0.4.31 + - @backstage/plugin-graphiql@0.2.27 + - @backstage/plugin-kafka@0.2.25 + - @backstage/plugin-lighthouse@0.2.34 + - @backstage/plugin-newrelic@0.3.13 + - @backstage/plugin-newrelic-dashboard@0.1.3 + - @backstage/plugin-rollbar@0.3.23 + - @backstage/plugin-search@0.5.5 + - @backstage/plugin-sentry@0.3.33 + - @backstage/plugin-shortcuts@0.1.19 + - @backstage/plugin-tech-radar@0.5.2 + - @backstage/plugin-todo@0.1.18 + - @backstage/plugin-user-settings@0.3.16 + ## 0.2.59 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index b83c43674b..bc30713a94 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,54 +1,54 @@ { "name": "example-app", - "version": "0.2.59", + "version": "0.2.60", "private": true, "bundled": true, "dependencies": { - "@backstage/app-defaults": "^0.1.3", - "@backstage/catalog-model": "^0.9.8", - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/integration-react": "^0.1.16", - "@backstage/plugin-airbrake": "^0.0.0", - "@backstage/plugin-api-docs": "^0.6.21", - "@backstage/plugin-azure-devops": "^0.1.9", - "@backstage/plugin-apache-airflow": "^0.1.2", - "@backstage/plugin-badges": "^0.2.18", - "@backstage/plugin-catalog": "^0.7.7", - "@backstage/plugin-catalog-graph": "^0.2.5", - "@backstage/plugin-catalog-import": "^0.7.8", - "@backstage/plugin-catalog-react": "^0.6.10", - "@backstage/plugin-circleci": "^0.2.33", - "@backstage/plugin-cloudbuild": "^0.2.31", - "@backstage/plugin-code-coverage": "^0.1.21", - "@backstage/plugin-cost-insights": "^0.11.16", - "@backstage/plugin-explore": "^0.3.24", - "@backstage/plugin-gcp-projects": "^0.3.12", - "@backstage/plugin-github-actions": "^0.4.30", - "@backstage/plugin-gocd": "^0.1.0", - "@backstage/plugin-graphiql": "^0.2.26", - "@backstage/plugin-home": "^0.4.9", - "@backstage/plugin-jenkins": "^0.5.16", - "@backstage/plugin-kafka": "^0.2.24", - "@backstage/plugin-kubernetes": "^0.5.3", - "@backstage/plugin-lighthouse": "^0.2.33", - "@backstage/plugin-newrelic": "^0.3.12", - "@backstage/plugin-newrelic-dashboard": "^0.1.2", - "@backstage/plugin-org": "^0.3.33", - "@backstage/plugin-pagerduty": "0.3.21", - "@backstage/plugin-rollbar": "^0.3.22", - "@backstage/plugin-scaffolder": "^0.11.17", - "@backstage/plugin-search": "^0.5.4", - "@backstage/plugin-sentry": "^0.3.32", - "@backstage/plugin-shortcuts": "^0.1.18", - "@backstage/plugin-tech-radar": "^0.5.1", - "@backstage/plugin-techdocs": "^0.12.13", - "@backstage/plugin-todo": "^0.1.17", - "@backstage/plugin-user-settings": "^0.3.15", + "@backstage/app-defaults": "^0.1.4", + "@backstage/catalog-model": "^0.9.9", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/integration-react": "^0.1.18", + "@backstage/plugin-airbrake": "^0.1.0", + "@backstage/plugin-api-docs": "^0.6.22", + "@backstage/plugin-azure-devops": "^0.1.10", + "@backstage/plugin-apache-airflow": "^0.1.3", + "@backstage/plugin-badges": "^0.2.19", + "@backstage/plugin-catalog": "^0.7.8", + "@backstage/plugin-catalog-graph": "^0.2.6", + "@backstage/plugin-catalog-import": "^0.7.9", + "@backstage/plugin-catalog-react": "^0.6.11", + "@backstage/plugin-circleci": "^0.2.34", + "@backstage/plugin-cloudbuild": "^0.2.32", + "@backstage/plugin-code-coverage": "^0.1.22", + "@backstage/plugin-cost-insights": "^0.11.17", + "@backstage/plugin-explore": "^0.3.25", + "@backstage/plugin-gcp-projects": "^0.3.13", + "@backstage/plugin-github-actions": "^0.4.31", + "@backstage/plugin-gocd": "^0.1.1", + "@backstage/plugin-graphiql": "^0.2.27", + "@backstage/plugin-home": "^0.4.10", + "@backstage/plugin-jenkins": "^0.5.17", + "@backstage/plugin-kafka": "^0.2.25", + "@backstage/plugin-kubernetes": "^0.5.4", + "@backstage/plugin-lighthouse": "^0.2.34", + "@backstage/plugin-newrelic": "^0.3.13", + "@backstage/plugin-newrelic-dashboard": "^0.1.3", + "@backstage/plugin-org": "^0.3.34", + "@backstage/plugin-pagerduty": "0.3.22", + "@backstage/plugin-rollbar": "^0.3.23", + "@backstage/plugin-scaffolder": "^0.11.18", + "@backstage/plugin-search": "^0.5.5", + "@backstage/plugin-sentry": "^0.3.33", + "@backstage/plugin-shortcuts": "^0.1.19", + "@backstage/plugin-tech-radar": "^0.5.2", + "@backstage/plugin-techdocs": "^0.12.14", + "@backstage/plugin-todo": "^0.1.18", + "@backstage/plugin-user-settings": "^0.3.16", "@backstage/search-common": "^0.2.0", - "@backstage/plugin-tech-insights": "^0.1.4", + "@backstage/plugin-tech-insights": "^0.1.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -68,7 +68,7 @@ "zen-observable": "^0.8.15" }, "devDependencies": { - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.2", "@rjsf/core": "^3.2.1", "@testing-library/cypress": "^8.0.2", "@testing-library/jest-dom": "^5.10.1", diff --git a/packages/backend-common/CHANGELOG.md b/packages/backend-common/CHANGELOG.md index 7edcbc7acf..ccba33dc34 100644 --- a/packages/backend-common/CHANGELOG.md +++ b/packages/backend-common/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/backend-common +## 0.10.3 + +### Patch Changes + +- 5b406daabe: build(deps-dev): bump `http-errors` from 1.8.0 to 2.0.0 +- 5333451def: Cleaned up API exports +- db5310e25e: bump `logform` to use fixed version of `color` dependency +- 7946418729: Switched to using `@manypkg/get-packages` to list monorepo packages, which provides better support for different kind of monorepo setups. +- 3b4d8caff6: The GithubUrlReader is switched to use the DefaultGithubCredentialsProvider +- f77bd5c8ff: Clean up API reports +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/integration@0.7.1 + - @backstage/errors@0.2.0 + - @backstage/config-loader@0.9.2 + ## 0.10.2 ### Patch Changes diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index dae5804583..a1e3533fb7 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-common", "description": "Common functionality library for Backstage backends", - "version": "0.10.2", + "version": "0.10.3", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -30,10 +30,10 @@ }, "dependencies": { "@backstage/cli-common": "^0.1.6", - "@backstage/config": "^0.1.11", - "@backstage/config-loader": "^0.9.1", - "@backstage/errors": "^0.1.5", - "@backstage/integration": "^0.7.0", + "@backstage/config": "^0.1.12", + "@backstage/config-loader": "^0.9.2", + "@backstage/errors": "^0.2.0", + "@backstage/integration": "^0.7.1", "@backstage/types": "^0.1.1", "@google-cloud/storage": "^5.8.0", "@manypkg/get-packages": "^1.1.3", @@ -81,8 +81,8 @@ } }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/test-utils": "^0.2.2", "@types/archiver": "^5.1.0", "@types/compression": "^1.7.0", "@types/concat-stream": "^1.6.0", diff --git a/packages/backend-tasks/CHANGELOG.md b/packages/backend-tasks/CHANGELOG.md index acaa41c131..4042074ebe 100644 --- a/packages/backend-tasks/CHANGELOG.md +++ b/packages/backend-tasks/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/backend-tasks +## 0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/backend-common@0.10.3 + - @backstage/errors@0.2.0 + ## 0.1.2 ### Patch Changes diff --git a/packages/backend-tasks/package.json b/packages/backend-tasks/package.json index e7af82ce95..5ffb689be9 100644 --- a/packages/backend-tasks/package.json +++ b/packages/backend-tasks/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-tasks", "description": "Common distributed task management library for Backstage backends", - "version": "0.1.2", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -29,9 +29,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.2", - "@backstage/config": "^0.1.11", - "@backstage/errors": "^0.1.4", + "@backstage/backend-common": "^0.10.3", + "@backstage/config": "^0.1.12", + "@backstage/errors": "^0.2.0", "@backstage/types": "^0.1.1", "@types/luxon": "^2.0.4", "knex": "^0.95.1", @@ -43,8 +43,8 @@ "zod": "^3.9.5" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.11", - "@backstage/cli": "^0.10.5", + "@backstage/backend-test-utils": "^0.1.13", + "@backstage/cli": "^0.11.0", "jest": "^26.0.1", "wait-for-expect": "^3.0.2" }, diff --git a/packages/backend-test-utils/CHANGELOG.md b/packages/backend-test-utils/CHANGELOG.md index f484a0fb8f..5701ed8933 100644 --- a/packages/backend-test-utils/CHANGELOG.md +++ b/packages/backend-test-utils/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/backend-test-utils +## 0.1.13 + +### Patch Changes + +- b1bc55405e: Bump `testcontainers` dependency to version `8.1.2` +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/backend-common@0.10.3 + - @backstage/cli@0.11.0 + ## 0.1.12 ### Patch Changes diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index 78daeb4efe..b3abbfca18 100644 --- a/packages/backend-test-utils/package.json +++ b/packages/backend-test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-test-utils", "description": "Test helpers library for Backstage backends", - "version": "0.1.12", + "version": "0.1.13", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -30,9 +30,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.1", - "@backstage/cli": "^0.10.4", - "@backstage/config": "^0.1.9", + "@backstage/backend-common": "^0.10.3", + "@backstage/cli": "^0.11.0", + "@backstage/config": "^0.1.12", "knex": "^0.95.1", "mysql2": "^2.2.5", "pg": "^8.3.0", @@ -41,7 +41,7 @@ "uuid": "^8.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.4", + "@backstage/cli": "^0.11.0", "jest": "^26.0.1" }, "files": [ diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index f3c2d4f861..bd9c1f3649 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,35 @@ # example-backend +## 0.2.60 + +### Patch Changes + +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/plugin-scaffolder-backend@0.15.20 + - @backstage/integration@0.7.1 + - @backstage/backend-common@0.10.3 + - @backstage/plugin-todo-backend@0.1.18 + - @backstage/plugin-catalog-backend@0.20.0 + - @backstage/plugin-tech-insights-backend@0.1.5 + - @backstage/plugin-permission-node@0.3.0 + - @backstage/plugin-auth-backend@0.6.2 + - @backstage/plugin-code-coverage-backend@0.1.19 + - @backstage/plugin-search-backend-node@0.4.4 + - @backstage/plugin-techdocs-backend@0.12.3 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.5 + - @backstage/plugin-permission-backend@0.3.0 + - @backstage/plugin-graphql-backend@0.1.11 + - @backstage/plugin-kubernetes-backend@0.4.3 + - example-app@0.2.60 + - @backstage/backend-tasks@0.1.3 + - @backstage/catalog-client@0.5.4 + - @backstage/catalog-model@0.9.9 + - @backstage/plugin-badges-backend@0.1.15 + - @backstage/plugin-kafka-backend@0.2.14 + - @backstage/plugin-permission-common@0.3.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.2.3 + ## 0.2.59 ### Patch Changes diff --git a/packages/backend/package.json b/packages/backend/package.json index 626b496509..29f9059593 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.2.59", + "version": "0.2.60", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,42 +24,42 @@ "migrate:create": "knex migrate:make -x ts" }, "dependencies": { - "@backstage/backend-common": "^0.10.1", - "@backstage/backend-tasks": "^0.1.0", - "@backstage/catalog-client": "^0.5.3", - "@backstage/catalog-model": "^0.9.8", - "@backstage/config": "^0.1.10", - "@backstage/integration": "^0.7.0", + "@backstage/backend-common": "^0.10.3", + "@backstage/backend-tasks": "^0.1.3", + "@backstage/catalog-client": "^0.5.4", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", + "@backstage/integration": "^0.7.1", "@backstage/plugin-app-backend": "^0.3.21", - "@backstage/plugin-auth-backend": "^0.6.0", - "@backstage/plugin-badges-backend": "^0.1.14", - "@backstage/plugin-catalog-backend": "^0.19.4", - "@backstage/plugin-code-coverage-backend": "^0.1.18", - "@backstage/plugin-graphql-backend": "^0.1.10", + "@backstage/plugin-auth-backend": "^0.6.2", + "@backstage/plugin-badges-backend": "^0.1.15", + "@backstage/plugin-catalog-backend": "^0.20.0", + "@backstage/plugin-code-coverage-backend": "^0.1.19", + "@backstage/plugin-graphql-backend": "^0.1.11", "@backstage/plugin-jenkins-backend": "^0.1.10", - "@backstage/plugin-kubernetes-backend": "^0.4.1", - "@backstage/plugin-kafka-backend": "^0.2.13", - "@backstage/plugin-permission-backend": "^0.2.3", - "@backstage/plugin-permission-common": "^0.3.0", - "@backstage/plugin-permission-node": "^0.2.3", + "@backstage/plugin-kubernetes-backend": "^0.4.3", + "@backstage/plugin-kafka-backend": "^0.2.14", + "@backstage/plugin-permission-backend": "^0.3.0", + "@backstage/plugin-permission-common": "^0.3.1", + "@backstage/plugin-permission-node": "^0.3.0", "@backstage/plugin-proxy-backend": "^0.2.15", "@backstage/plugin-rollbar-backend": "^0.1.18", - "@backstage/plugin-scaffolder-backend": "^0.15.19", - "@backstage/plugin-scaffolder-backend-module-rails": "^0.2.2", + "@backstage/plugin-scaffolder-backend": "^0.15.20", + "@backstage/plugin-scaffolder-backend-module-rails": "^0.2.3", "@backstage/plugin-search-backend": "^0.3.0", - "@backstage/plugin-search-backend-node": "^0.4.2", + "@backstage/plugin-search-backend-node": "^0.4.4", "@backstage/plugin-search-backend-module-elasticsearch": "^0.0.7", "@backstage/plugin-search-backend-module-pg": "^0.2.3", - "@backstage/plugin-techdocs-backend": "^0.12.2", - "@backstage/plugin-tech-insights-backend": "^0.1.4", + "@backstage/plugin-techdocs-backend": "^0.12.3", + "@backstage/plugin-tech-insights-backend": "^0.1.5", "@backstage/plugin-tech-insights-node": "^0.1.2", - "@backstage/plugin-tech-insights-backend-module-jsonfc": "^0.1.4", - "@backstage/plugin-todo-backend": "^0.1.17", + "@backstage/plugin-tech-insights-backend-module-jsonfc": "^0.1.5", + "@backstage/plugin-todo-backend": "^0.1.18", "@gitbeaker/node": "^34.6.0", "@octokit/rest": "^18.5.3", "azure-devops-node-api": "^11.0.1", "dockerode": "^3.3.1", - "example-app": "^0.2.58", + "example-app": "^0.2.60", "express": "^4.17.1", "express-promise-router": "^4.1.0", "express-prom-bundle": "^6.3.6", @@ -71,7 +71,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.10.4", + "@backstage/cli": "^0.11.0", "@types/dockerode": "^3.3.0", "@types/express": "^4.17.6", "@types/express-serve-static-core": "^4.17.5" diff --git a/packages/catalog-client/CHANGELOG.md b/packages/catalog-client/CHANGELOG.md index 6d5c3d4a94..691cdac37c 100644 --- a/packages/catalog-client/CHANGELOG.md +++ b/packages/catalog-client/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/catalog-client +## 0.5.4 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@0.2.0 + - @backstage/catalog-model@0.9.9 + ## 0.5.3 ### Patch Changes diff --git a/packages/catalog-client/package.json b/packages/catalog-client/package.json index 5ccb600e0c..97c500e4c3 100644 --- a/packages/catalog-client/package.json +++ b/packages/catalog-client/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/catalog-client", "description": "An isomorphic client for the catalog backend", - "version": "0.5.3", + "version": "0.5.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,12 +30,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/errors": "^0.1.4", + "@backstage/catalog-model": "^0.9.9", + "@backstage/errors": "^0.2.0", "cross-fetch": "^3.0.6" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.11.0", "@types/jest": "^26.0.7", "msw": "^0.35.0" }, diff --git a/packages/catalog-model/CHANGELOG.md b/packages/catalog-model/CHANGELOG.md index 8c0a65c20a..a669ef6dce 100644 --- a/packages/catalog-model/CHANGELOG.md +++ b/packages/catalog-model/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/catalog-model +## 0.9.9 + +### Patch Changes + +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/errors@0.2.0 + ## 0.9.8 ### Patch Changes diff --git a/packages/catalog-model/package.json b/packages/catalog-model/package.json index 6fdc89bdfb..c1a13d00f2 100644 --- a/packages/catalog-model/package.json +++ b/packages/catalog-model/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/catalog-model", "description": "Types and validators that help describe the model of a Backstage Catalog", - "version": "0.9.8", + "version": "0.9.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,8 +30,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/config": "^0.1.11", - "@backstage/errors": "^0.1.4", + "@backstage/config": "^0.1.12", + "@backstage/errors": "^0.2.0", "@backstage/types": "^0.1.1", "@types/json-schema": "^7.0.5", "@types/yup": "^0.29.13", @@ -42,7 +42,7 @@ "yup": "^0.32.9" }, "devDependencies": { - "@backstage/cli": "^0.10.2", + "@backstage/cli": "^0.11.0", "@types/jest": "^26.0.7", "@types/lodash": "^4.14.151", "yaml": "^1.9.2" diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index b412c1b079..f65caf08d4 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,44 @@ # @backstage/cli +## 0.11.0 + +### Minor Changes + +- 14e980acee: ESLint upgraded to version 8 and all it's plugins updated to newest version. + + If you use any custom plugins for ESLint please check compatibility. + + ```diff + - "@typescript-eslint/eslint-plugin": "^v4.33.0", + - "@typescript-eslint/parser": "^v4.28.3", + + "@typescript-eslint/eslint-plugin": "^5.9.0", + + "@typescript-eslint/parser": "^5.9.0", + - "eslint": "^7.30.0", + + "eslint": "^8.6.0", + - "eslint-plugin-import": "^2.20.2", + - "eslint-plugin-jest": "^24.1.0", + - "eslint-plugin-jsx-a11y": "^6.2.1", + + "eslint-plugin-import": "^2.25.4", + + "eslint-plugin-jest": "^25.3.4", + + "eslint-plugin-jsx-a11y": "^6.5.1", + - "eslint-plugin-react": "^7.12.4", + - "eslint-plugin-react-hooks": "^4.0.0", + + "eslint-plugin-react": "^7.28.0", + + "eslint-plugin-react-hooks": "^4.3.0", + ``` + + Please consult changelogs from packages if you find any problems. + +### Patch Changes + +- f302d24d34: Switch Webpack minification to use `esbuild` instead of `terser`. +- bee7082094: Update `config/eslint.js` to forbid imports of `@material-ui/icons/` as well. +- 7946418729: Switched to using `@manypkg/get-packages` to list monorepo packages, which provides better support for different kind of monorepo setups. +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/errors@0.2.0 + - @backstage/config-loader@0.9.2 + ## 0.10.5 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index be09563796..edb2cfb3ce 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/cli", "description": "CLI for developing Backstage plugins and apps", - "version": "0.10.5", + "version": "0.11.0", "private": false, "publishConfig": { "access": "public" @@ -29,9 +29,9 @@ }, "dependencies": { "@backstage/cli-common": "^0.1.6", - "@backstage/config": "^0.1.11", - "@backstage/config-loader": "^0.9.1", - "@backstage/errors": "^0.1.5", + "@backstage/config": "^0.1.12", + "@backstage/config-loader": "^0.9.2", + "@backstage/errors": "^0.2.0", "@backstage/types": "^0.1.1", "@hot-loader/react-dom": "^16.13.0", "@manypkg/get-packages": "^1.1.3", @@ -115,13 +115,13 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/backend-common": "^0.10.2", - "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/backend-common": "^0.10.3", + "@backstage/config": "^0.1.12", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@backstage/theme": "^0.2.14", "@types/diff": "^5.0.0", "@types/express": "^4.17.6", diff --git a/packages/codemods/CHANGELOG.md b/packages/codemods/CHANGELOG.md index 7c6ccaf9fe..c7a70212e6 100644 --- a/packages/codemods/CHANGELOG.md +++ b/packages/codemods/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/codemods +## 0.1.29 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/core-app-api@0.4.0 + ## 0.1.28 ### Patch Changes diff --git a/packages/codemods/package.json b/packages/codemods/package.json index 88ed029f00..9a3cb370b9 100644 --- a/packages/codemods/package.json +++ b/packages/codemods/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/codemods", "description": "A collection of codemods for Backstage projects", - "version": "0.1.28", + "version": "0.1.29", "private": false, "publishConfig": { "access": "public", diff --git a/packages/config-loader/CHANGELOG.md b/packages/config-loader/CHANGELOG.md index 36aae32e8b..d91ac57ab2 100644 --- a/packages/config-loader/CHANGELOG.md +++ b/packages/config-loader/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/config-loader +## 0.9.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/errors@0.2.0 + ## 0.9.1 ### Patch Changes diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index d909cde58c..6e6364c9b0 100644 --- a/packages/config-loader/package.json +++ b/packages/config-loader/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/config-loader", "description": "Config loading functionality used by Backstage backend, and CLI", - "version": "0.9.1", + "version": "0.9.2", "private": false, "publishConfig": { "access": "public", @@ -31,8 +31,8 @@ }, "dependencies": { "@backstage/cli-common": "^0.1.6", - "@backstage/config": "^0.1.11", - "@backstage/errors": "^0.1.4", + "@backstage/config": "^0.1.12", + "@backstage/errors": "^0.2.0", "@backstage/types": "^0.1.1", "@types/json-schema": "^7.0.6", "ajv": "^7.0.3", diff --git a/packages/config/CHANGELOG.md b/packages/config/CHANGELOG.md index de62de5466..05377ffff3 100644 --- a/packages/config/CHANGELOG.md +++ b/packages/config/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/config +## 0.1.12 + +### Patch Changes + +- f5343e7c1a: The `ConfigReader#get` method now always returns a deep clone of the configuration data. + ## 0.1.11 ### Patch Changes diff --git a/packages/config/package.json b/packages/config/package.json index 86e1f5d79c..29d09a5cf8 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/config", "description": "Config API used by Backstage core, backend, and CLI", - "version": "0.1.11", + "version": "0.1.12", "private": false, "publishConfig": { "access": "public", @@ -34,7 +34,7 @@ "lodash": "^4.17.21" }, "devDependencies": { - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.2", "@types/jest": "^26.0.7", "@types/node": "^14.14.32" }, diff --git a/packages/core-app-api/CHANGELOG.md b/packages/core-app-api/CHANGELOG.md index bdd3129235..b18ec0685f 100644 --- a/packages/core-app-api/CHANGELOG.md +++ b/packages/core-app-api/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/core-app-api +## 0.4.0 + +### Minor Changes + +- e2eb92c109: Removed previously deprecated `ApiRegistry` export. + +### Patch Changes + +- 34442cd5cf: Fixed an issue where valid SAML and GitHub sessions would be considered invalid and not be stored. + + Deprecated the `SamlSession` and `GithubSession` types. + +- 784d8078ab: Removed direct and transitive MUI dependencies. +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/core-plugin-api@0.5.0 + ## 0.3.1 ### Patch Changes diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index de7477771f..dbce1e62cc 100644 --- a/packages/core-app-api/package.json +++ b/packages/core-app-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-app-api", "description": "Core app API used by Backstage apps", - "version": "0.3.1", + "version": "0.4.0", "private": false, "publishConfig": { "access": "public", @@ -29,8 +29,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/config": "^0.1.11", - "@backstage/core-plugin-api": "^0.4.1", + "@backstage/config": "^0.1.12", + "@backstage/core-plugin-api": "^0.5.0", "@backstage/types": "^0.1.1", "@backstage/version-bridge": "^0.1.1", "@types/prop-types": "^15.7.3", @@ -45,8 +45,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/test-utils": "^0.2.0", + "@backstage/cli": "^0.11.0", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index 9f306bb10f..5f2e20f0a3 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/core-components +## 0.8.4 + +### Patch Changes + +- 6415189d99: Add a `ProxiedSignInPage` that can be used e.g. for GCP IAP and AWS ALB +- de2396da24: Create a short delay when `` is opened +- 5333451def: Cleaned up API exports +- e2eb92c109: Updated `ResponseErrorPanel` to not use the deprecated `data` property of `ResponseError`. +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/core-plugin-api@0.5.0 + - @backstage/errors@0.2.0 + ## 0.8.3 ### Patch Changes diff --git a/packages/core-components/package.json b/packages/core-components/package.json index cdce4497af..bdfcdc0d88 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-components", "description": "Core components used by Backstage plugins and apps", - "version": "0.8.3", + "version": "0.8.4", "private": false, "publishConfig": { "access": "public", @@ -29,9 +29,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/config": "^0.1.11", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/errors": "^0.1.5", + "@backstage/config": "^0.1.12", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/errors": "^0.2.0", "@backstage/theme": "^0.2.14", "@material-table/core": "^3.1.0", "@material-ui/core": "^4.12.2", @@ -73,9 +73,9 @@ "react-dom": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/core-app-api": "^0.3.1", - "@backstage/cli": "^0.10.5", - "@backstage/test-utils": "^0.2.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/cli": "^0.11.0", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/packages/core-plugin-api/CHANGELOG.md b/packages/core-plugin-api/CHANGELOG.md index 535be6aef6..7f081e8b45 100644 --- a/packages/core-plugin-api/CHANGELOG.md +++ b/packages/core-plugin-api/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/core-plugin-api +## 0.5.0 + +### Minor Changes + +- 784d8078ab: Removed the deprecated `OldIconComponent` type. +- e2eb92c109: Removed previously deprecated exports: `PluginHooks`, `PluginOutput`, and `FeatureFlagOutput`. + + The deprecated `register` method of `PluginConfig` has been removed, as well as the deprecated `output` method of `BackstagePlugin`. + +### Patch Changes + +- 784d8078ab: Removed direct and transitive MUI dependencies. +- Updated dependencies + - @backstage/config@0.1.12 + ## 0.4.1 ### Patch Changes diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index d284d60c6b..55ac56083b 100644 --- a/packages/core-plugin-api/package.json +++ b/packages/core-plugin-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-plugin-api", "description": "Core API used by Backstage plugins", - "version": "0.4.1", + "version": "0.5.0", "private": false, "publishConfig": { "access": "public", @@ -29,7 +29,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/config": "^0.1.11", + "@backstage/config": "^0.1.12", "@backstage/types": "^0.1.1", "@backstage/version-bridge": "^0.1.1", "history": "^5.0.0", @@ -43,9 +43,9 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/test-utils": "^0.2.0", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index f72e76b9c0..8d19c65e54 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,67 @@ # @backstage/create-app +## 0.4.12 + +### Patch Changes + +- 5333451def: Cleaned up API exports +- cd529c4094: Add permissions to create-app's PluginEnvironment + + `CatalogEnvironment` now has a `permissions` field, which means that a permission client must now be provided as part of `PluginEnvironment`. To apply these changes to an existing app, add the following to the `makeCreateEnv` function in `packages/backend/src/index.ts`: + + ```diff + // packages/backend/src/index.ts + + + import { ServerPermissionClient } from '@backstage/plugin-permission-node'; + + function makeCreateEnv(config: Config) { + ... + + const permissions = ServerPerimssionClient.fromConfig(config, { + + discovery, + + tokenManager, + + }); + + root.info(`Created UrlReader ${reader}`); + + return (plugin: string): PluginEnvironment => { + ... + return { + logger, + cache, + database, + config, + reader, + discovery, + tokenManager, + scheduler, + + permissions, + }; + } + } + ``` + + And add a permissions field to the `PluginEnvironment` type in `packages/backend/src/types.ts`: + + ```diff + // packages/backend/src/types.ts + + + import { PermissionAuthorizer } from '@backstage/plugin-permission-common'; + + export type PluginEnvironment = { + ... + + permissions: PermissionAuthorizer; + }; + ``` + + [`@backstage/plugin-permission-common`](https://www.npmjs.com/package/@backstage/plugin-permission-common) and [`@backstage/plugin-permission-node`](https://www.npmjs.com/package/@backstage/plugin-permission-node) will need to be installed as dependencies: + + ```diff + // packages/backend/package.json + + + "@backstage/plugin-permission-common": "...", + + "@backstage/plugin-permission-node": "...", + ``` + ## 0.4.11 ## 0.4.10 diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 639e0370d7..041616f90a 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/create-app", "description": "A CLI that helps you create your own Backstage app", - "version": "0.4.11", + "version": "0.4.12", "private": false, "publishConfig": { "access": "public" diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index c08bbc61fd..7e17d1a2cf 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/dev-utils +## 0.2.17 + +### Patch Changes + +- Updated dependencies + - @backstage/test-utils@0.2.2 + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/core-app-api@0.4.0 + - @backstage/app-defaults@0.1.4 + - @backstage/catalog-model@0.9.9 + - @backstage/integration-react@0.1.18 + ## 0.2.16 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 75b34baf32..afd405cbbd 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/dev-utils", "description": "Utilities for developing Backstage plugins.", - "version": "0.2.16", + "version": "0.2.17", "private": false, "publishConfig": { "access": "public", @@ -29,14 +29,14 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/app-defaults": "^0.1.3", - "@backstage/core-app-api": "^0.3.1", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/catalog-model": "^0.9.7", - "@backstage/integration-react": "^0.1.16", - "@backstage/plugin-catalog-react": "^0.6.10", - "@backstage/test-utils": "^0.2.0", + "@backstage/app-defaults": "^0.1.4", + "@backstage/core-app-api": "^0.4.0", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/catalog-model": "^0.9.9", + "@backstage/integration-react": "^0.1.18", + "@backstage/plugin-catalog-react": "^0.6.11", + "@backstage/test-utils": "^0.2.2", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -55,7 +55,7 @@ "react-dom": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", + "@backstage/cli": "^0.11.0", "@types/jest": "^26.0.7", "@types/node": "^14.14.32" }, diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json index 6c941cda58..56f0865db2 100644 --- a/packages/e2e-test/package.json +++ b/packages/e2e-test/package.json @@ -25,7 +25,7 @@ }, "devDependencies": { "@backstage/cli-common": "^0.1.1", - "@backstage/errors": "^0.1.4", + "@backstage/errors": "^0.2.0", "@types/fs-extra": "^9.0.1", "@types/node": "^14.14.32", "@types/puppeteer": "^5.4.4", diff --git a/packages/embedded-techdocs-app/CHANGELOG.md b/packages/embedded-techdocs-app/CHANGELOG.md index aa0e9ce955..29774b165f 100644 --- a/packages/embedded-techdocs-app/CHANGELOG.md +++ b/packages/embedded-techdocs-app/CHANGELOG.md @@ -1,5 +1,22 @@ # embedded-techdocs-app +## 0.2.59 + +### Patch Changes + +- Updated dependencies + - @backstage/test-utils@0.2.2 + - @backstage/config@0.1.12 + - @backstage/core-components@0.8.4 + - @backstage/cli@0.11.0 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-techdocs@0.12.14 + - @backstage/core-app-api@0.4.0 + - @backstage/app-defaults@0.1.4 + - @backstage/catalog-model@0.9.9 + - @backstage/integration-react@0.1.18 + - @backstage/plugin-catalog@0.7.8 + ## 0.2.58 ### Patch Changes diff --git a/packages/embedded-techdocs-app/package.json b/packages/embedded-techdocs-app/package.json index a1ffd9f858..a830336879 100644 --- a/packages/embedded-techdocs-app/package.json +++ b/packages/embedded-techdocs-app/package.json @@ -1,20 +1,20 @@ { "name": "embedded-techdocs-app", - "version": "0.2.58", + "version": "0.2.59", "private": true, "bundled": true, "dependencies": { - "@backstage/app-defaults": "^0.1.3", - "@backstage/catalog-model": "^0.9.7", - "@backstage/cli": "^0.10.3", - "@backstage/config": "^0.1.10", - "@backstage/core-app-api": "^0.3.0", - "@backstage/core-components": "^0.8.2", - "@backstage/core-plugin-api": "^0.4.0", - "@backstage/integration-react": "^0.1.16", - "@backstage/plugin-catalog": "^0.7.5", - "@backstage/plugin-techdocs": "^0.12.11", - "@backstage/test-utils": "^0.2.0", + "@backstage/app-defaults": "^0.1.4", + "@backstage/catalog-model": "^0.9.9", + "@backstage/cli": "^0.11.0", + "@backstage/config": "^0.1.12", + "@backstage/core-app-api": "^0.4.0", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/integration-react": "^0.1.18", + "@backstage/plugin-catalog": "^0.7.8", + "@backstage/plugin-techdocs": "^0.12.14", + "@backstage/test-utils": "^0.2.2", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -26,7 +26,7 @@ "react-use": "^17.2.4" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.11.0", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/packages/errors/CHANGELOG.md b/packages/errors/CHANGELOG.md index 02b28cdf1d..110863d347 100644 --- a/packages/errors/CHANGELOG.md +++ b/packages/errors/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/errors +## 0.2.0 + +### Minor Changes + +- e2eb92c109: Removed the deprecated exports `ErrorResponse` and `parseErrorResponse`. + + Removed the deprecated `constructor` and the deprecated `data` property of `ResponseError`. + ## 0.1.5 ### Patch Changes diff --git a/packages/errors/package.json b/packages/errors/package.json index d0d59ffd6a..d9ab7e1e6c 100644 --- a/packages/errors/package.json +++ b/packages/errors/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/errors", "description": "Common utilities for error handling within Backstage", - "version": "0.1.5", + "version": "0.2.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,7 +35,7 @@ "serialize-error": "^8.0.1" }, "devDependencies": { - "@backstage/cli": "^0.10.0", + "@backstage/cli": "^0.11.0", "@types/jest": "^26.0.7" }, "files": [ diff --git a/packages/integration-react/CHANGELOG.md b/packages/integration-react/CHANGELOG.md index 121b778143..fb5445c2d9 100644 --- a/packages/integration-react/CHANGELOG.md +++ b/packages/integration-react/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/integration-react +## 0.1.18 + +### Patch Changes + +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/integration@0.7.1 + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + ## 0.1.17 ### Patch Changes diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json index 62f9e8d593..b1bc8e4eb3 100644 --- a/packages/integration-react/package.json +++ b/packages/integration-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/integration-react", "description": "Frontend package for managing integrations towards external systems", - "version": "0.1.17", + "version": "0.1.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,10 +21,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.8.2", - "@backstage/core-plugin-api": "^0.4.0", - "@backstage/integration": "^0.7.0", + "@backstage/config": "^0.1.12", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/integration": "^0.7.1", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -35,9 +35,9 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.4", - "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/packages/integration/CHANGELOG.md b/packages/integration/CHANGELOG.md index 359d2dd11e..e2d535ada1 100644 --- a/packages/integration/CHANGELOG.md +++ b/packages/integration/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/integration +## 0.7.1 + +### Patch Changes + +- 3b4d8caff6: Adds a new GitHub credentials provider (DefaultGithubCredentialsProvider). It handles multiple app configurations. It looks up the app configuration based on the url. +- 5333451def: Cleaned up API exports +- Updated dependencies + - @backstage/config@0.1.12 + ## 0.7.0 ### Minor Changes diff --git a/packages/integration/package.json b/packages/integration/package.json index ae674d2cf1..336ed1535f 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/integration", "description": "Helpers for managing integrations towards external systems", - "version": "0.7.0", + "version": "0.7.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,7 +30,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/config": "^0.1.11", + "@backstage/config": "^0.1.12", "cross-fetch": "^3.0.6", "git-url-parse": "^11.6.0", "@octokit/rest": "^18.5.3", @@ -39,9 +39,9 @@ "lodash": "^4.17.21" }, "devDependencies": { - "@backstage/cli": "^0.10.4", - "@backstage/config-loader": "^0.9.1", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/config-loader": "^0.9.2", + "@backstage/test-utils": "^0.2.2", "@types/jest": "^26.0.7", "@types/luxon": "^2.0.4", "msw": "^0.35.0" diff --git a/packages/search-common/package.json b/packages/search-common/package.json index 51cea5a28e..87660e7ee3 100644 --- a/packages/search-common/package.json +++ b/packages/search-common/package.json @@ -39,7 +39,7 @@ "@backstage/types": "^0.1.1" }, "devDependencies": { - "@backstage/cli": "^0.10.0" + "@backstage/cli": "^0.11.0" }, "jest": { "roots": [ diff --git a/packages/storybook/CHANGELOG.md b/packages/storybook/CHANGELOG.md index f5e44f780c..c1e756bb12 100644 --- a/packages/storybook/CHANGELOG.md +++ b/packages/storybook/CHANGELOG.md @@ -1,5 +1,14 @@ # storybook +## 0.2.1 + +### Patch Changes + +- Updated dependencies + - @backstage/test-utils@0.2.2 + - @backstage/core-plugin-api@0.5.0 + - @backstage/core-app-api@0.4.0 + ## 0.2.0 ### Patch Changes diff --git a/packages/storybook/package.json b/packages/storybook/package.json index a0e9b25d76..5c4b440264 100644 --- a/packages/storybook/package.json +++ b/packages/storybook/package.json @@ -1,6 +1,6 @@ { "name": "storybook", - "version": "0.2.0", + "version": "0.2.1", "description": "Storybook build for components package", "private": true, "scripts": { @@ -9,9 +9,9 @@ }, "dependencies": { "@backstage/theme": "^0.2.0", - "@backstage/test-utils": "^0.2.1", - "@backstage/core-app-api": "^0.3.1", - "@backstage/core-plugin-api": "^0.4.1", + "@backstage/test-utils": "^0.2.2", + "@backstage/core-app-api": "^0.4.0", + "@backstage/core-plugin-api": "^0.5.0", "react": "^16.13.1", "react-dom": "^16.13.1" }, diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index b4c4ade6a3..c971a4d1df 100644 --- a/packages/techdocs-cli/package.json +++ b/packages/techdocs-cli/package.json @@ -32,7 +32,7 @@ "techdocs-cli": "bin/techdocs-cli" }, "devDependencies": { - "@backstage/cli": "^0.10.4", + "@backstage/cli": "^0.11.0", "@types/commander": "^2.12.2", "@types/fs-extra": "^9.0.6", "@types/http-proxy": "^1.17.4", @@ -41,7 +41,7 @@ "@types/react-dev-utils": "^9.0.4", "@types/serve-handler": "^6.1.0", "@types/webpack-env": "^1.15.3", - "embedded-techdocs-app": "0.2.58", + "embedded-techdocs-app": "0.2.59", "find-process": "^1.4.5", "nodemon": "^2.0.2", "ts-node": "^10.0.0" @@ -56,10 +56,10 @@ "ext": "ts" }, "dependencies": { - "@backstage/backend-common": "^0.10.1", - "@backstage/catalog-model": "^0.9.7", - "@backstage/config": "^0.1.10", - "@backstage/techdocs-common": "^0.11.2", + "@backstage/backend-common": "^0.10.3", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", + "@backstage/techdocs-common": "^0.11.3", "@types/dockerode": "^3.3.0", "commander": "^6.1.0", "dockerode": "^3.3.1", diff --git a/packages/techdocs-common/CHANGELOG.md b/packages/techdocs-common/CHANGELOG.md index 96281958b6..5a9c2f79e8 100644 --- a/packages/techdocs-common/CHANGELOG.md +++ b/packages/techdocs-common/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/techdocs-common +## 0.11.3 + +### Patch Changes + +- 5333451def: Cleaned up API exports +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/integration@0.7.1 + - @backstage/backend-common@0.10.3 + - @backstage/errors@0.2.0 + - @backstage/catalog-model@0.9.9 + ## 0.11.2 ### Patch Changes diff --git a/packages/techdocs-common/package.json b/packages/techdocs-common/package.json index f3e0f2d0d4..0b9ae3a831 100644 --- a/packages/techdocs-common/package.json +++ b/packages/techdocs-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/techdocs-common", "description": "Common functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli", - "version": "0.11.2", + "version": "0.11.3", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -38,12 +38,12 @@ "dependencies": { "@azure/identity": "^2.0.1", "@azure/storage-blob": "^12.5.0", - "@backstage/backend-common": "^0.10.1", - "@backstage/catalog-model": "^0.9.7", - "@backstage/config": "^0.1.11", - "@backstage/errors": "^0.1.5", + "@backstage/backend-common": "^0.10.3", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", + "@backstage/errors": "^0.2.0", "@backstage/search-common": "^0.2.1", - "@backstage/integration": "^0.7.0", + "@backstage/integration": "^0.7.1", "@google-cloud/storage": "^5.6.0", "@trendyol-js/openstack-swift-sdk": "^0.0.5", "@types/express": "^4.17.6", @@ -60,7 +60,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.10.4", + "@backstage/cli": "^0.11.0", "@types/fs-extra": "^9.0.5", "@types/js-yaml": "^4.0.0", "@types/mime-types": "^2.1.0", diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md index fa747f84d1..bdd7562652 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/test-utils +## 0.2.2 + +### Patch Changes + +- 2d3fd91e33: Add new `MockConfigApi` as a more discoverable and leaner method for mocking configuration. +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/core-plugin-api@0.5.0 + - @backstage/core-app-api@0.4.0 + ## 0.2.1 ### Patch Changes diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 48745f7068..d1382ada4a 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/test-utils", "description": "Utilities to test Backstage plugins and apps.", - "version": "0.2.1", + "version": "0.2.2", "private": false, "publishConfig": { "access": "public", @@ -29,9 +29,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/config": "^0.1.11", - "@backstage/core-app-api": "^0.3.0", - "@backstage/core-plugin-api": "^0.4.0", + "@backstage/config": "^0.1.12", + "@backstage/core-app-api": "^0.4.0", + "@backstage/core-plugin-api": "^0.5.0", "@backstage/theme": "^0.2.14", "@backstage/types": "^0.1.1", "@material-ui/core": "^4.12.2", @@ -48,7 +48,7 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.4", + "@backstage/cli": "^0.11.0", "@types/jest": "^26.0.7", "@types/node": "^14.14.32" }, diff --git a/packages/theme/package.json b/packages/theme/package.json index 08477dccd0..33ec467940 100644 --- a/packages/theme/package.json +++ b/packages/theme/package.json @@ -31,7 +31,7 @@ "@material-ui/core": "^4.12.2" }, "devDependencies": { - "@backstage/cli": "^0.10.0" + "@backstage/cli": "^0.11.0" }, "files": [ "dist" diff --git a/packages/types/package.json b/packages/types/package.json index 822b2d678e..fc17471869 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -31,7 +31,7 @@ }, "dependencies": {}, "devDependencies": { - "@backstage/cli": "^0.10.0", + "@backstage/cli": "^0.11.0", "@types/zen-observable": "^0.8.0", "zen-observable": "^0.8.15" }, diff --git a/packages/version-bridge/package.json b/packages/version-bridge/package.json index 0291cdc208..8164aacfae 100644 --- a/packages/version-bridge/package.json +++ b/packages/version-bridge/package.json @@ -33,7 +33,7 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", + "@backstage/cli": "^0.11.0", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2" diff --git a/plugins/airbrake/CHANGELOG.md b/plugins/airbrake/CHANGELOG.md new file mode 100644 index 0000000000..42c2b4603d --- /dev/null +++ b/plugins/airbrake/CHANGELOG.md @@ -0,0 +1,13 @@ +# @backstage/plugin-airbrake + +## 0.1.0 + +### Minor Changes + +- 04c86e5a10: A plugin for Airbrake (https://airbrake.io/) has been created + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 diff --git a/plugins/airbrake/package.json b/plugins/airbrake/package.json index 7294c97413..d343876fb5 100644 --- a/plugins/airbrake/package.json +++ b/plugins/airbrake/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-airbrake", - "version": "0.0.0", + "version": "0.1.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,8 +20,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -34,11 +34,11 @@ }, "devDependencies": { "@types/object-hash": "^2.2.1", - "@backstage/app-defaults": "^0.1.2", - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/app-defaults": "^0.1.4", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/allure/CHANGELOG.md b/plugins/allure/CHANGELOG.md index 4f3771d348..1802258402 100644 --- a/plugins/allure/CHANGELOG.md +++ b/plugins/allure/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-allure +## 0.1.11 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/catalog-model@0.9.9 + ## 0.1.10 ### Patch Changes diff --git a/plugins/allure/package.json b/plugins/allure/package.json index 54ac6ea659..79b381c319 100644 --- a/plugins/allure/package.json +++ b/plugins/allure/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-allure", "description": "A Backstage plugin that integrates with Allure", - "version": "0.1.10", + "version": "0.1.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,10 +22,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -37,10 +37,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/analytics-module-ga/CHANGELOG.md b/plugins/analytics-module-ga/CHANGELOG.md index 3721035996..75dd925060 100644 --- a/plugins/analytics-module-ga/CHANGELOG.md +++ b/plugins/analytics-module-ga/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-analytics-module-ga +## 0.1.6 + +### Patch Changes + +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + ## 0.1.5 ### Patch Changes diff --git a/plugins/analytics-module-ga/package.json b/plugins/analytics-module-ga/package.json index a17f915b16..ad4b322a7c 100644 --- a/plugins/analytics-module-ga/package.json +++ b/plugins/analytics-module-ga/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-analytics-module-ga", - "version": "0.1.5", + "version": "0.1.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,9 +21,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/config": "^0.1.5", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", + "@backstage/config": "^0.1.12", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -35,10 +35,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/apache-airflow/CHANGELOG.md b/plugins/apache-airflow/CHANGELOG.md index bb8a010fda..2a2ff1a873 100644 --- a/plugins/apache-airflow/CHANGELOG.md +++ b/plugins/apache-airflow/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-apache-airflow +## 0.1.3 + +### Patch Changes + +- 5333451def: Cleaned up API exports +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + ## 0.1.2 ### Patch Changes diff --git a/plugins/apache-airflow/package.json b/plugins/apache-airflow/package.json index d203c8de9e..c4cc9c3e23 100644 --- a/plugins/apache-airflow/package.json +++ b/plugins/apache-airflow/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-apache-airflow", - "version": "0.1.2", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,8 +20,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -33,10 +33,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index 31611f5b2c..b7f4fbc29e 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-api-docs +## 0.6.22 + +### Patch Changes + +- faf844e269: Update @asyncapi/react-component to 1.0.0-next.26, which will fix the + `ResizeObserver loop limit exceeded` errors which we encountered in several E2E + tests. + + For more details check the following links: + + - https://github.com/backstage/backstage/pull/8088#issuecomment-991183968 + - https://github.com/asyncapi/asyncapi-react/issues/498 + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/catalog-model@0.9.9 + - @backstage/plugin-catalog@0.7.8 + ## 0.6.21 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 8d190dae92..1990df89a8 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-api-docs", "description": "A Backstage plugin that helps represent API entities in the frontend", - "version": "0.6.21", + "version": "0.6.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,11 +31,11 @@ }, "dependencies": { "@asyncapi/react-component": "1.0.0-next.26", - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/plugin-catalog": "^0.7.7", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/plugin-catalog": "^0.7.8", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -54,10 +54,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index b1a01a8345..d5cbe9c07d 100644 --- a/plugins/app-backend/package.json +++ b/plugins/app-backend/package.json @@ -30,9 +30,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.1", - "@backstage/config-loader": "^0.9.1", - "@backstage/config": "^0.1.11", + "@backstage/backend-common": "^0.10.3", + "@backstage/config-loader": "^0.9.2", + "@backstage/config": "^0.1.12", "@backstage/types": "^0.1.1", "@types/express": "^4.17.6", "express": "^4.17.1", @@ -43,7 +43,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.4", + "@backstage/cli": "^0.11.0", "@backstage/types": "^0.1.1", "@types/supertest": "^2.0.8", "msw": "^0.35.0", diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index 14e56b060e..533bf10166 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-auth-backend +## 0.6.2 + +### Patch Changes + +- 5333451def: Cleaned up API exports +- da9c59d6e0: Removed `@backstage/test-utils` dependency. +- 20ca7cfa5f: Switched the secure cookie mode set on the `express-session` to use `'auto'` rather than `true`. This works around an issue where cookies would not be set if TLS termination was handled in a proxy rather than having the backend served directly with HTTPS. + + The downside of this change is that secure cookies won't be used unless the backend is directly served with HTTPS. This will be remedied in a future update that allows the backend to configured for trusted proxy mode. + +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/backend-common@0.10.3 + - @backstage/errors@0.2.0 + - @backstage/catalog-client@0.5.4 + - @backstage/catalog-model@0.9.9 + ## 0.6.1 ### Patch Changes diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 3afd6cefe3..69dd53987f 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend", "description": "A Backstage backend plugin that handles authentication", - "version": "0.6.1", + "version": "0.6.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,11 +30,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.2", - "@backstage/catalog-client": "^0.5.3", - "@backstage/catalog-model": "^0.9.8", - "@backstage/config": "^0.1.11", - "@backstage/errors": "^0.1.5", + "@backstage/backend-common": "^0.10.3", + "@backstage/catalog-client": "^0.5.4", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", + "@backstage/errors": "^0.2.0", "@backstage/types": "^0.1.1", "@google-cloud/firestore": "^4.15.1", "@types/express": "^4.17.6", @@ -73,8 +73,8 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/test-utils": "^0.2.2", "@types/body-parser": "^1.19.0", "@types/cookie-parser": "^1.4.2", "@types/express-session": "^1.17.2", diff --git a/plugins/azure-devops-backend/CHANGELOG.md b/plugins/azure-devops-backend/CHANGELOG.md index 080a4e0367..e61ccf4b72 100644 --- a/plugins/azure-devops-backend/CHANGELOG.md +++ b/plugins/azure-devops-backend/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-azure-devops-backend +## 0.3.0 + +### Minor Changes + +- a2ed2c2d69: - feat: Created PullRequestsDashboardProvider for resolving team and team member relations + - feat: Created useUserTeamIds hook. + - feat: Updated useFilterProcessor to provide teamIds for `AssignedToCurrentUsersTeams` and `CreatedByCurrentUsersTeams` filters. + +### Patch Changes + +- 9f9596f9ef: Only warn if teams fail to load at startup. +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/backend-common@0.10.3 + - @backstage/plugin-azure-devops-common@0.2.0 + ## 0.2.6 ### Patch Changes diff --git a/plugins/azure-devops-backend/package.json b/plugins/azure-devops-backend/package.json index 23ca6b694d..61f89ccf56 100644 --- a/plugins/azure-devops-backend/package.json +++ b/plugins/azure-devops-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops-backend", - "version": "0.2.6", + "version": "0.3.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,9 +20,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", - "@backstage/config": "^0.1.11", - "@backstage/plugin-azure-devops-common": "^0.1.3", + "@backstage/backend-common": "^0.10.3", + "@backstage/config": "^0.1.12", + "@backstage/plugin-azure-devops-common": "^0.2.0", "@types/express": "^4.17.6", "azure-devops-node-api": "^11.0.1", "express": "^4.17.1", @@ -32,7 +32,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.11.0", "@types/supertest": "^2.0.8", "supertest": "^6.1.6", "msw": "^0.35.0" diff --git a/plugins/azure-devops-common/CHANGELOG.md b/plugins/azure-devops-common/CHANGELOG.md index 84c2cae9a5..74129ea19e 100644 --- a/plugins/azure-devops-common/CHANGELOG.md +++ b/plugins/azure-devops-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-azure-devops-common +## 0.2.0 + +### Minor Changes + +- a2ed2c2d69: - feat: Created PullRequestsDashboardProvider for resolving team and team member relations + - feat: Created useUserTeamIds hook. + - feat: Updated useFilterProcessor to provide teamIds for `AssignedToCurrentUsersTeams` and `CreatedByCurrentUsersTeams` filters. + ## 0.1.3 ### Patch Changes diff --git a/plugins/azure-devops-common/package.json b/plugins/azure-devops-common/package.json index f8a9622bff..d8dfce0ab6 100644 --- a/plugins/azure-devops-common/package.json +++ b/plugins/azure-devops-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops-common", - "version": "0.1.3", + "version": "0.2.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,7 +29,7 @@ "clean": "backstage-cli clean" }, "devDependencies": { - "@backstage/cli": "^0.10.2" + "@backstage/cli": "^0.11.0" }, "files": [ "dist" diff --git a/plugins/azure-devops/CHANGELOG.md b/plugins/azure-devops/CHANGELOG.md index 838130d4ae..b56f391976 100644 --- a/plugins/azure-devops/CHANGELOG.md +++ b/plugins/azure-devops/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-azure-devops +## 0.1.10 + +### Patch Changes + +- a2ed2c2d69: - feat: Created PullRequestsDashboardProvider for resolving team and team member relations + - feat: Created useUserTeamIds hook. + - feat: Updated useFilterProcessor to provide teamIds for `AssignedToCurrentUsersTeams` and `CreatedByCurrentUsersTeams` filters. +- 5333451def: Cleaned up API exports +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-azure-devops-common@0.2.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/errors@0.2.0 + - @backstage/catalog-model@0.9.9 + ## 0.1.9 ### Patch Changes diff --git a/plugins/azure-devops/package.json b/plugins/azure-devops/package.json index f8cbcc430a..8e40ed60fe 100644 --- a/plugins/azure-devops/package.json +++ b/plugins/azure-devops/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops", - "version": "0.1.9", + "version": "0.1.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -27,12 +27,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.8", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/errors": "^0.1.4", - "@backstage/plugin-azure-devops-common": "^0.1.3", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/errors": "^0.2.0", + "@backstage/plugin-azure-devops-common": "^0.2.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -46,10 +46,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/badges-backend/CHANGELOG.md b/plugins/badges-backend/CHANGELOG.md index 5b37003d36..d3ebf60a3d 100644 --- a/plugins/badges-backend/CHANGELOG.md +++ b/plugins/badges-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-badges-backend +## 0.1.15 + +### Patch Changes + +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/backend-common@0.10.3 + - @backstage/errors@0.2.0 + - @backstage/catalog-client@0.5.4 + - @backstage/catalog-model@0.9.9 + ## 0.1.14 ### Patch Changes diff --git a/plugins/badges-backend/package.json b/plugins/badges-backend/package.json index fbd7b2c266..dd2a8af930 100644 --- a/plugins/badges-backend/package.json +++ b/plugins/badges-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-badges-backend", "description": "A Backstage backend plugin that generates README badges for your entities", - "version": "0.1.14", + "version": "0.1.15", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,11 +31,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", - "@backstage/catalog-client": "^0.5.3", - "@backstage/catalog-model": "^0.9.7", - "@backstage/config": "^0.1.10", - "@backstage/errors": "^0.1.5", + "@backstage/backend-common": "^0.10.3", + "@backstage/catalog-client": "^0.5.4", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", + "@backstage/errors": "^0.2.0", "@types/express": "^4.17.6", "badge-maker": "^3.3.0", "cors": "^2.8.5", @@ -45,7 +45,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.11.0", "@types/supertest": "^2.0.8", "supertest": "^6.1.3" }, diff --git a/plugins/badges/CHANGELOG.md b/plugins/badges/CHANGELOG.md index 67d54623bf..9c51905691 100644 --- a/plugins/badges/CHANGELOG.md +++ b/plugins/badges/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-badges +## 0.2.19 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/errors@0.2.0 + - @backstage/catalog-model@0.9.9 + ## 0.2.18 ### Patch Changes diff --git a/plugins/badges/package.json b/plugins/badges/package.json index f9e24f27bf..26580d63c7 100644 --- a/plugins/badges/package.json +++ b/plugins/badges/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-badges", "description": "A Backstage plugin that generates README badges for your entities", - "version": "0.2.18", + "version": "0.2.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -27,11 +27,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/errors": "^0.1.5", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/errors": "^0.2.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -43,10 +43,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/bazaar-backend/CHANGELOG.md b/plugins/bazaar-backend/CHANGELOG.md index 1a08a36b9d..eceb35eb1b 100644 --- a/plugins/bazaar-backend/CHANGELOG.md +++ b/plugins/bazaar-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-bazaar-backend +## 0.1.6 + +### Patch Changes + +- 6eb6e2dc31: Add Bazaar plugin to marketplace and some minor refactoring +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/backend-common@0.10.3 + - @backstage/backend-test-utils@0.1.13 + ## 0.1.5 ### Patch Changes diff --git a/plugins/bazaar-backend/package.json b/plugins/bazaar-backend/package.json index a7c59735ff..9c6cf17407 100644 --- a/plugins/bazaar-backend/package.json +++ b/plugins/bazaar-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar-backend", - "version": "0.1.5", + "version": "0.1.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,9 +20,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", - "@backstage/backend-test-utils": "^0.1.11", - "@backstage/config": "^0.1.5", + "@backstage/backend-common": "^0.10.3", + "@backstage/backend-test-utils": "^0.1.13", + "@backstage/config": "^0.1.12", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", @@ -31,7 +31,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3" + "@backstage/cli": "^0.11.0" }, "files": [ "dist", diff --git a/plugins/bazaar/CHANGELOG.md b/plugins/bazaar/CHANGELOG.md index 09b1f64edf..01d6f5955d 100644 --- a/plugins/bazaar/CHANGELOG.md +++ b/plugins/bazaar/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-bazaar +## 0.1.9 + +### Patch Changes + +- 6eb6e2dc31: Add Bazaar plugin to marketplace and some minor refactoring +- b47965beec: build(deps): bump `@date-io/luxon` from 1.3.13 to 2.11.1 +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/cli@0.11.0 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/catalog-client@0.5.4 + - @backstage/catalog-model@0.9.9 + - @backstage/plugin-catalog@0.7.8 + ## 0.1.8 ### Patch Changes diff --git a/plugins/bazaar/package.json b/plugins/bazaar/package.json index d081a220e7..6c2a344c19 100644 --- a/plugins/bazaar/package.json +++ b/plugins/bazaar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar", - "version": "0.1.8", + "version": "0.1.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,13 +21,13 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-client": "^0.5.3", - "@backstage/catalog-model": "^0.9.7", - "@backstage/cli": "^0.10.5", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/plugin-catalog": "^0.7.7", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-client": "^0.5.4", + "@backstage/catalog-model": "^0.9.9", + "@backstage/cli": "^0.11.0", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/plugin-catalog": "^0.7.8", + "@backstage/plugin-catalog-react": "^0.6.11", "@date-io/luxon": "2.x", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -44,8 +44,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/dev-utils": "^0.2.16", + "@backstage/cli": "^0.11.0", + "@backstage/dev-utils": "^0.2.17", "@testing-library/jest-dom": "^5.10.1", "cross-fetch": "^3.0.6" }, diff --git a/plugins/bitrise/CHANGELOG.md b/plugins/bitrise/CHANGELOG.md index 3f606353c1..626f52a06c 100644 --- a/plugins/bitrise/CHANGELOG.md +++ b/plugins/bitrise/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-bitrise +## 0.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/catalog-model@0.9.9 + ## 0.1.21 ### Patch Changes diff --git a/plugins/bitrise/package.json b/plugins/bitrise/package.json index e1dca12e2b..964f4da6d4 100644 --- a/plugins/bitrise/package.json +++ b/plugins/bitrise/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-bitrise", "description": "A Backstage plugin that integrates towards Bitrise", - "version": "0.1.21", + "version": "0.1.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,10 +21,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -40,10 +40,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/catalog-backend-module-ldap/CHANGELOG.md b/plugins/catalog-backend-module-ldap/CHANGELOG.md index b8e48924dc..b2da918f59 100644 --- a/plugins/catalog-backend-module-ldap/CHANGELOG.md +++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-backend-module-ldap +## 0.3.9 + +### Patch Changes + +- 2b19fd2e94: Make sure to avoid accidental data sharing / mutation of `set` values +- 722681b1b1: Clean up API report +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/plugin-catalog-backend@0.20.0 + - @backstage/errors@0.2.0 + - @backstage/catalog-model@0.9.9 + ## 0.3.8 ### Patch Changes diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json index 2817a0e209..ff79feaea2 100644 --- a/plugins/catalog-backend-module-ldap/package.json +++ b/plugins/catalog-backend-module-ldap/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-ldap", "description": "A Backstage catalog backend modules that helps integrate towards LDAP", - "version": "0.3.8", + "version": "0.3.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,10 +29,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/config": "^0.1.11", - "@backstage/errors": "^0.1.5", - "@backstage/plugin-catalog-backend": "^0.19.0", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", + "@backstage/errors": "^0.2.0", + "@backstage/plugin-catalog-backend": "^0.20.0", "@backstage/types": "^0.1.1", "@types/ldapjs": "^2.2.0", "ldapjs": "^2.2.0", @@ -40,7 +40,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.10.0", + "@backstage/cli": "^0.11.0", "@types/lodash": "^4.14.151" }, "files": [ diff --git a/plugins/catalog-backend-module-msgraph/CHANGELOG.md b/plugins/catalog-backend-module-msgraph/CHANGELOG.md index 3db08d02fc..17afa99b76 100644 --- a/plugins/catalog-backend-module-msgraph/CHANGELOG.md +++ b/plugins/catalog-backend-module-msgraph/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-catalog-backend-module-msgraph +## 0.2.12 + +### Patch Changes + +- 722681b1b1: Clean up API report +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/plugin-catalog-backend@0.20.0 + - @backstage/catalog-model@0.9.9 + ## 0.2.11 ### Patch Changes diff --git a/plugins/catalog-backend-module-msgraph/package.json b/plugins/catalog-backend-module-msgraph/package.json index db3e59c307..1afc377605 100644 --- a/plugins/catalog-backend-module-msgraph/package.json +++ b/plugins/catalog-backend-module-msgraph/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-msgraph", "description": "A Backstage catalog backend modules that helps integrate towards Microsoft Graph", - "version": "0.2.11", + "version": "0.2.12", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,9 +30,9 @@ }, "dependencies": { "@azure/msal-node": "^1.1.0", - "@backstage/catalog-model": "^0.9.7", - "@backstage/config": "^0.1.10", - "@backstage/plugin-catalog-backend": "^0.19.3", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", + "@backstage/plugin-catalog-backend": "^0.20.0", "@microsoft/microsoft-graph-types": "^2.6.0", "@types/node-fetch": "^2.5.12", "lodash": "^4.17.21", @@ -42,9 +42,9 @@ "qs": "^6.9.4" }, "devDependencies": { - "@backstage/backend-common": "^0.10.0", - "@backstage/cli": "^0.10.3", - "@backstage/test-utils": "^0.2.0", + "@backstage/backend-common": "^0.10.3", + "@backstage/cli": "^0.11.0", + "@backstage/test-utils": "^0.2.2", "@types/lodash": "^4.14.151", "msw": "^0.35.0" }, diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index e53bb50e1a..e329c82ac0 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-catalog-backend +## 0.20.0 + +### Minor Changes + +- cd529c4094: In order to integrate the permissions system with the refresh endpoint in catalog-backend, a new AuthorizedRefreshService was created as a thin wrapper around the existing refresh service which performs authorization and handles the case when authorization is denied. In order to instantiate AuthorizedRefreshService, a permission client is required, which was added as a new field to `CatalogEnvironment`. + + The new `permissions` field in `CatalogEnvironment` should already receive the permission client from the `PluginEnvrionment`, so there should be no changes required to the catalog backend setup. See [the create-app changelog](https://github.com/backstage/backstage/blob/master/packages/create-app/CHANGELOG.md) for more details. + +### Patch Changes + +- 0ae759dad4: Add catalog permission rules. +- 3b4d8caff6: Allow a custom GithubCredentialsProvider to be passed to the GitHub processors. +- 6fd70f8bc8: Provide support for Bitbucket servers with custom BaseURLs. +- 5333451def: Cleaned up API exports +- 730d01ab1a: Add apply-conditions endpoint for evaluating conditional permissions in catalog backend. +- 0a6c68582a: Add authorization to catalog-backend entities GET endpoints +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/integration@0.7.1 + - @backstage/backend-common@0.10.3 + - @backstage/plugin-permission-node@0.3.0 + - @backstage/errors@0.2.0 + - @backstage/catalog-client@0.5.4 + - @backstage/catalog-model@0.9.9 + - @backstage/plugin-permission-common@0.3.1 + ## 0.19.4 ### Patch Changes diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index 504e86a736..71151c460d 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend", "description": "The Backstage backend plugin that provides the Backstage catalog", - "version": "0.19.4", + "version": "0.20.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,15 +30,15 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.1", - "@backstage/catalog-client": "^0.5.3", - "@backstage/catalog-model": "^0.9.8", - "@backstage/config": "^0.1.11", - "@backstage/errors": "^0.1.5", - "@backstage/integration": "^0.7.0", + "@backstage/backend-common": "^0.10.3", + "@backstage/catalog-client": "^0.5.4", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", + "@backstage/errors": "^0.2.0", + "@backstage/integration": "^0.7.1", "@backstage/plugin-catalog-common": "^0.1.0", - "@backstage/plugin-permission-common": "^0.3.0", - "@backstage/plugin-permission-node": "^0.2.3", + "@backstage/plugin-permission-common": "^0.3.1", + "@backstage/plugin-permission-node": "^0.3.0", "@backstage/search-common": "^0.2.1", "@backstage/types": "^0.1.1", "@octokit/graphql": "^4.5.8", @@ -65,10 +65,10 @@ "yup": "^0.32.9" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.12", - "@backstage/cli": "^0.10.4", - "@backstage/plugin-permission-common": "^0.3.0", - "@backstage/test-utils": "^0.2.1", + "@backstage/backend-test-utils": "^0.1.13", + "@backstage/cli": "^0.11.0", + "@backstage/plugin-permission-common": "^0.3.1", + "@backstage/test-utils": "^0.2.2", "@types/core-js": "^2.5.4", "@types/git-url-parse": "^9.0.0", "@types/lodash": "^4.14.151", diff --git a/plugins/catalog-common/package.json b/plugins/catalog-common/package.json index da4f80cd1a..5026dc0074 100644 --- a/plugins/catalog-common/package.json +++ b/plugins/catalog-common/package.json @@ -30,10 +30,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/plugin-permission-common": "^0.3.0" + "@backstage/plugin-permission-common": "^0.3.1" }, "devDependencies": { - "@backstage/cli": "^0.10.3" + "@backstage/cli": "^0.11.0" }, "files": [ "dist" diff --git a/plugins/catalog-graph/CHANGELOG.md b/plugins/catalog-graph/CHANGELOG.md index ffbef5c63f..22020d0e97 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-catalog-graph +## 0.2.6 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/catalog-client@0.5.4 + - @backstage/catalog-model@0.9.9 + ## 0.2.5 ### Patch Changes diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index 8718172cf4..de06748c90 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-graph", - "version": "0.2.5", + "version": "0.2.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,11 +21,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-client": "^0.5.3", - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-client": "^0.5.4", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -42,10 +42,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/catalog-graphql/CHANGELOG.md b/plugins/catalog-graphql/CHANGELOG.md index fe6cc4cc00..e06952bb60 100644 --- a/plugins/catalog-graphql/CHANGELOG.md +++ b/plugins/catalog-graphql/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-graphql +## 0.3.0 + +### Minor Changes + +- 0fb17da164: chore: bumping dependencies in the GraphQL modules and bringing them up to date with the latest `graphql-modules` library + +### Patch Changes + +- cf01627a33: Bump graphql versions +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/catalog-model@0.9.9 + ## 0.2.14 ### Patch Changes diff --git a/plugins/catalog-graphql/package.json b/plugins/catalog-graphql/package.json index 8982f0fa5a..aac63bee0b 100644 --- a/plugins/catalog-graphql/package.json +++ b/plugins/catalog-graphql/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-graphql", "description": "An experimental Backstage catalog GraphQL module", - "version": "0.2.14", + "version": "0.3.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,8 +31,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/config": "^0.1.11", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", "@backstage/types": "^0.1.1", "graphql-modules": "^1.0.0", "apollo-server": "^3.0.0", @@ -43,8 +43,8 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.10.3", - "@backstage/test-utils": "^0.2.0", + "@backstage/cli": "^0.11.0", + "@backstage/test-utils": "^0.2.2", "@graphql-codegen/cli": "^2.3.1", "@graphql-codegen/typescript": "^2.4.2", "@graphql-codegen/typescript-resolvers": "^2.4.3", diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index ff675b812c..8afb610900 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-import +## 0.7.9 + +### Patch Changes + +- 5333451def: Cleaned up API exports +- Updated dependencies + - @backstage/integration@0.7.1 + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/errors@0.2.0 + - @backstage/catalog-client@0.5.4 + - @backstage/catalog-model@0.9.9 + - @backstage/integration-react@0.1.18 + ## 0.7.8 ### Patch Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index 7558ff9445..b20b4d01da 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-import", "description": "A Backstage plugin the helps you import entities into your catalog", - "version": "0.7.8", + "version": "0.7.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,14 +31,14 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-client": "^0.5.3", - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/errors": "^0.1.3", - "@backstage/integration": "^0.7.0", - "@backstage/integration-react": "^0.1.17", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-client": "^0.5.4", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/errors": "^0.2.0", + "@backstage/integration": "^0.7.1", + "@backstage/integration-react": "^0.1.18", + "@backstage/plugin-catalog-react": "^0.6.11", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -56,10 +56,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index e15a9d1c13..c201015e60 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-react +## 0.6.11 + +### Patch Changes + +- 5333451def: Cleaned up API exports +- Updated dependencies + - @backstage/integration@0.7.1 + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/errors@0.2.0 + - @backstage/catalog-client@0.5.4 + - @backstage/catalog-model@0.9.9 + ## 0.6.10 ### Patch Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index 6b76ec3925..7da6c9386b 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-react", "description": "A frontend library that helps other Backstage plugins interact with the catalog", - "version": "0.6.10", + "version": "0.6.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,12 +29,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-client": "^0.5.3", - "@backstage/catalog-model": "^0.9.8", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/errors": "^0.1.4", - "@backstage/integration": "^0.7.0", + "@backstage/catalog-client": "^0.5.4", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/errors": "^0.2.0", + "@backstage/integration": "^0.7.1", "@backstage/types": "^0.1.1", "@backstage/version-bridge": "^0.1.1", "@material-ui/core": "^4.12.2", @@ -52,9 +52,9 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index e33eccb116..3553d48da3 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog +## 0.7.8 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/errors@0.2.0 + - @backstage/catalog-client@0.5.4 + - @backstage/catalog-model@0.9.9 + - @backstage/integration-react@0.1.18 + ## 0.7.7 ### Patch Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index da7f666b35..9684cb1bd8 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog", "description": "The Backstage plugin for browsing the Backstage catalog", - "version": "0.7.7", + "version": "0.7.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,13 +31,13 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-client": "^0.5.3", - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/errors": "^0.1.3", - "@backstage/integration-react": "^0.1.17", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-client": "^0.5.4", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/errors": "^0.2.0", + "@backstage/integration-react": "^0.1.18", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -53,10 +53,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/circleci/CHANGELOG.md b/plugins/circleci/CHANGELOG.md index a3b5de58c5..b2df699f5f 100644 --- a/plugins/circleci/CHANGELOG.md +++ b/plugins/circleci/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-circleci +## 0.2.34 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/catalog-model@0.9.9 + ## 0.2.33 ### Patch Changes diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index a7e05511db..9b5bc10143 100644 --- a/plugins/circleci/package.json +++ b/plugins/circleci/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-circleci", "description": "A Backstage plugin that integrates towards Circle CI", - "version": "0.2.33", + "version": "0.2.34", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,10 +32,10 @@ "postpack": "backstage-cli postpack" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -52,10 +52,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/cloudbuild/CHANGELOG.md b/plugins/cloudbuild/CHANGELOG.md index cbd4c0bbfa..bd857ff054 100644 --- a/plugins/cloudbuild/CHANGELOG.md +++ b/plugins/cloudbuild/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-cloudbuild +## 0.2.32 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/catalog-model@0.9.9 + ## 0.2.31 ### Patch Changes diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index d0075d683e..ba2f7f608a 100644 --- a/plugins/cloudbuild/package.json +++ b/plugins/cloudbuild/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cloudbuild", "description": "A Backstage plugin that integrates towards Google Cloud Build", - "version": "0.2.31", + "version": "0.2.32", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,10 +31,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -49,10 +49,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/code-coverage-backend/CHANGELOG.md b/plugins/code-coverage-backend/CHANGELOG.md index 1fd78b862b..417cf7948e 100644 --- a/plugins/code-coverage-backend/CHANGELOG.md +++ b/plugins/code-coverage-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-code-coverage-backend +## 0.1.19 + +### Patch Changes + +- 5333451def: Cleaned up API exports +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/integration@0.7.1 + - @backstage/backend-common@0.10.3 + - @backstage/errors@0.2.0 + - @backstage/catalog-client@0.5.4 + - @backstage/catalog-model@0.9.9 + ## 0.1.18 ### Patch Changes diff --git a/plugins/code-coverage-backend/package.json b/plugins/code-coverage-backend/package.json index 4a24cada7c..78ac11c7a5 100644 --- a/plugins/code-coverage-backend/package.json +++ b/plugins/code-coverage-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-code-coverage-backend", "description": "A Backstage backend plugin that helps you keep track of your code coverage", - "version": "0.1.18", + "version": "0.1.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,12 +20,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.1", - "@backstage/catalog-client": "^0.5.3", - "@backstage/catalog-model": "^0.9.7", - "@backstage/config": "^0.1.10", - "@backstage/errors": "^0.1.5", - "@backstage/integration": "^0.7.0", + "@backstage/backend-common": "^0.10.3", + "@backstage/catalog-client": "^0.5.4", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", + "@backstage/errors": "^0.2.0", + "@backstage/integration": "^0.7.1", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", @@ -36,7 +36,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.4", + "@backstage/cli": "^0.11.0", "@types/express-xml-bodyparser": "^0.3.2", "@types/supertest": "^2.0.8", "msw": "^0.35.0", diff --git a/plugins/code-coverage/CHANGELOG.md b/plugins/code-coverage/CHANGELOG.md index 6f10ecbbf4..bec12d6c0d 100644 --- a/plugins/code-coverage/CHANGELOG.md +++ b/plugins/code-coverage/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-code-coverage +## 0.1.22 + +### Patch Changes + +- 5333451def: Cleaned up API exports +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/errors@0.2.0 + - @backstage/catalog-model@0.9.9 + ## 0.1.21 ### Patch Changes diff --git a/plugins/code-coverage/package.json b/plugins/code-coverage/package.json index e6ddcdb5f1..6a7e3740e5 100644 --- a/plugins/code-coverage/package.json +++ b/plugins/code-coverage/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-code-coverage", "description": "A Backstage plugin that helps you keep track of your code coverage", - "version": "0.1.21", + "version": "0.1.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,12 +21,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/errors": "^0.1.4", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/errors": "^0.2.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -43,10 +43,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/config-schema/CHANGELOG.md b/plugins/config-schema/CHANGELOG.md index 20b8e258d5..708ff17d0b 100644 --- a/plugins/config-schema/CHANGELOG.md +++ b/plugins/config-schema/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-config-schema +## 0.1.18 + +### Patch Changes + +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/errors@0.2.0 + ## 0.1.17 ### Patch Changes diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index 85a088b20c..f73cfbb356 100644 --- a/plugins/config-schema/package.json +++ b/plugins/config-schema/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-config-schema", "description": "A Backstage plugin that lets you browse the configuration schema of your app", - "version": "0.1.17", + "version": "0.1.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,10 +21,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/errors": "^0.1.5", + "@backstage/config": "^0.1.12", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/errors": "^0.2.0", "@backstage/theme": "^0.2.14", "@backstage/types": "^0.1.1", "@material-ui/core": "^4.12.2", @@ -38,10 +38,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/cost-insights/CHANGELOG.md b/plugins/cost-insights/CHANGELOG.md index d0a0eb400b..8456151d6f 100644 --- a/plugins/cost-insights/CHANGELOG.md +++ b/plugins/cost-insights/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-cost-insights +## 0.11.17 + +### Patch Changes + +- 5333451def: Cleaned up API exports +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + ## 0.11.16 ### Patch Changes diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index 4f9c3f55ec..2e7ec2bad6 100644 --- a/plugins/cost-insights/package.json +++ b/plugins/cost-insights/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cost-insights", "description": "A Backstage plugin that helps you keep track of your cloud spend", - "version": "0.11.16", + "version": "0.11.17", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,9 +31,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/config": "^0.1.10", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", + "@backstage/config": "^0.1.12", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -56,10 +56,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/explore-react/CHANGELOG.md b/plugins/explore-react/CHANGELOG.md index b173eca371..7f72577711 100644 --- a/plugins/explore-react/CHANGELOG.md +++ b/plugins/explore-react/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-explore-react +## 0.0.10 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@0.5.0 + ## 0.0.9 ### Patch Changes diff --git a/plugins/explore-react/package.json b/plugins/explore-react/package.json index e115678a27..a2dc776412 100644 --- a/plugins/explore-react/package.json +++ b/plugins/explore-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-explore-react", "description": "A frontend library for Backstage plugins that want to interact with the explore plugin", - "version": "0.0.9", + "version": "0.0.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,12 +29,12 @@ "postpack": "backstage-cli postpack" }, "dependencies": { - "@backstage/core-plugin-api": "^0.4.0" + "@backstage/core-plugin-api": "^0.5.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", - "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/cli": "^0.11.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/explore/CHANGELOG.md b/plugins/explore/CHANGELOG.md index 2b0c42002f..1b968e13e0 100644 --- a/plugins/explore/CHANGELOG.md +++ b/plugins/explore/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-explore +## 0.3.25 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/catalog-model@0.9.9 + - @backstage/plugin-explore-react@0.0.10 + ## 0.3.24 ### Patch Changes diff --git a/plugins/explore/package.json b/plugins/explore/package.json index 424eb84eac..aab62079e7 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-explore", "description": "A Backstage plugin for building an exploration page of your software ecosystem", - "version": "0.3.24", + "version": "0.3.25", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,11 +31,11 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/plugin-catalog-react": "^0.6.10", - "@backstage/plugin-explore-react": "^0.0.9", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/plugin-catalog-react": "^0.6.11", + "@backstage/plugin-explore-react": "^0.0.10", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -50,10 +50,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/firehydrant/CHANGELOG.md b/plugins/firehydrant/CHANGELOG.md index 8d2e3b71d8..f1b2d2ecfc 100644 --- a/plugins/firehydrant/CHANGELOG.md +++ b/plugins/firehydrant/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-firehydrant +## 0.1.12 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + ## 0.1.11 ### Patch Changes diff --git a/plugins/firehydrant/package.json b/plugins/firehydrant/package.json index 118c64c11d..9d52293cd5 100644 --- a/plugins/firehydrant/package.json +++ b/plugins/firehydrant/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-firehydrant", "description": "A Backstage plugin that integrates towards FireHydrant", - "version": "0.1.11", + "version": "0.1.12", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,9 +22,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -36,10 +36,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/fossa/CHANGELOG.md b/plugins/fossa/CHANGELOG.md index 7e62631d00..f5458f4367 100644 --- a/plugins/fossa/CHANGELOG.md +++ b/plugins/fossa/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-fossa +## 0.2.27 + +### Patch Changes + +- 5333451def: Cleaned up API exports +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/errors@0.2.0 + - @backstage/catalog-model@0.9.9 + ## 0.2.26 ### Patch Changes diff --git a/plugins/fossa/package.json b/plugins/fossa/package.json index ff5c063e15..a89286f507 100644 --- a/plugins/fossa/package.json +++ b/plugins/fossa/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-fossa", "description": "A Backstage plugin that integrates towards FOSSA", - "version": "0.2.26", + "version": "0.2.27", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,11 +32,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/errors": "^0.1.3", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/errors": "^0.2.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -50,10 +50,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/gcp-projects/CHANGELOG.md b/plugins/gcp-projects/CHANGELOG.md index 9da0972948..c0dfe5434f 100644 --- a/plugins/gcp-projects/CHANGELOG.md +++ b/plugins/gcp-projects/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-gcp-projects +## 0.3.13 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + ## 0.3.12 ### Patch Changes diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index 1b36c4a112..8aa8f6b644 100644 --- a/plugins/gcp-projects/package.json +++ b/plugins/gcp-projects/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-gcp-projects", "description": "A Backstage plugin that helps you manage projects in GCP", - "version": "0.3.12", + "version": "0.3.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,8 +31,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -44,10 +44,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/git-release-manager/CHANGELOG.md b/plugins/git-release-manager/CHANGELOG.md index 50ef4d5f26..096df63eaa 100644 --- a/plugins/git-release-manager/CHANGELOG.md +++ b/plugins/git-release-manager/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-git-release-manager +## 0.3.8 + +### Patch Changes + +- c1813739c6: Improved copy for patch CTA +- Updated dependencies + - @backstage/integration@0.7.1 + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + ## 0.3.7 ### Patch Changes diff --git a/plugins/git-release-manager/package.json b/plugins/git-release-manager/package.json index 444c77fc8a..aa31559977 100644 --- a/plugins/git-release-manager/package.json +++ b/plugins/git-release-manager/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-git-release-manager", "description": "A Backstage plugin that helps you manage releases in git", - "version": "0.3.7", + "version": "0.3.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,9 +21,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/integration": "^0.7.0", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/integration": "^0.7.1", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -40,10 +40,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/github-actions/CHANGELOG.md b/plugins/github-actions/CHANGELOG.md index a2099a5b20..7474d21b96 100644 --- a/plugins/github-actions/CHANGELOG.md +++ b/plugins/github-actions/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-github-actions +## 0.4.31 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@0.7.1 + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/catalog-model@0.9.9 + ## 0.4.30 ### Patch Changes diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index e65ed5a989..0cb2d43074 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-actions", "description": "A Backstage plugin that integrates towards GitHub Actions", - "version": "0.4.30", + "version": "0.4.31", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,11 +33,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.8", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/integration": "^0.7.0", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/integration": "^0.7.1", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -52,10 +52,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/github-deployments/CHANGELOG.md b/plugins/github-deployments/CHANGELOG.md index 94b4dadbcd..218effd052 100644 --- a/plugins/github-deployments/CHANGELOG.md +++ b/plugins/github-deployments/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-github-deployments +## 0.1.26 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@0.7.1 + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/errors@0.2.0 + - @backstage/catalog-model@0.9.9 + - @backstage/integration-react@0.1.18 + ## 0.1.25 ### Patch Changes diff --git a/plugins/github-deployments/package.json b/plugins/github-deployments/package.json index fcf452c67e..5d4fe3aa4b 100644 --- a/plugins/github-deployments/package.json +++ b/plugins/github-deployments/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-deployments", "description": "A Backstage plugin that integrates towards GitHub Deployments", - "version": "0.1.25", + "version": "0.1.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,13 +21,13 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/errors": "^0.1.3", - "@backstage/integration": "^0.7.0", - "@backstage/integration-react": "^0.1.17", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/errors": "^0.2.0", + "@backstage/integration": "^0.7.1", + "@backstage/integration-react": "^0.1.18", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -40,10 +40,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/gitops-profiles/CHANGELOG.md b/plugins/gitops-profiles/CHANGELOG.md index 58607974f5..e8c1203517 100644 --- a/plugins/gitops-profiles/CHANGELOG.md +++ b/plugins/gitops-profiles/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-gitops-profiles +## 0.3.13 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + ## 0.3.12 ### Patch Changes diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json index 345d2a812e..644644b764 100644 --- a/plugins/gitops-profiles/package.json +++ b/plugins/gitops-profiles/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-gitops-profiles", "description": "A Backstage plugin that helps you manage GitOps profiles", - "version": "0.3.12", + "version": "0.3.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,8 +32,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -45,10 +45,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/gocd/CHANGELOG.md b/plugins/gocd/CHANGELOG.md new file mode 100644 index 0000000000..6edae04378 --- /dev/null +++ b/plugins/gocd/CHANGELOG.md @@ -0,0 +1,13 @@ +# @backstage/plugin-gocd + +## 0.1.1 + +### Patch Changes + +- d9aaecd1cb: Add GoCD plugin for CI/CD. +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/errors@0.2.0 + - @backstage/catalog-model@0.9.9 diff --git a/plugins/gocd/package.json b/plugins/gocd/package.json index d07931916d..c03a8261f5 100644 --- a/plugins/gocd/package.json +++ b/plugins/gocd/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-gocd", "description": "A Backstage plugin that integrates towards GoCD", - "version": "0.1.0", + "version": "0.1.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -28,11 +28,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.1", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/errors": "^0.1.4", - "@backstage/plugin-catalog-react": "^0.6.0", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/errors": "^0.2.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -46,10 +46,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/graphiql/CHANGELOG.md b/plugins/graphiql/CHANGELOG.md index da188aee4b..f8767cb04f 100644 --- a/plugins/graphiql/CHANGELOG.md +++ b/plugins/graphiql/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-graphiql +## 0.2.27 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + ## 0.2.26 ### Patch Changes diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index 593be20c6e..25936f97a3 100644 --- a/plugins/graphiql/package.json +++ b/plugins/graphiql/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-graphiql", "description": "Backstage plugin for browsing GraphQL APIs", - "version": "0.2.26", + "version": "0.2.27", "private": false, "publishConfig": { "access": "public", @@ -31,8 +31,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -45,10 +45,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/graphql-backend/CHANGELOG.md b/plugins/graphql-backend/CHANGELOG.md index 25b60ec94a..5c41c9fb0a 100644 --- a/plugins/graphql-backend/CHANGELOG.md +++ b/plugins/graphql-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-graphql-backend +## 0.1.11 + +### Patch Changes + +- 0fb17da164: chore: bumping dependencies in the GraphQL modules and bringing them up to date with the latest `graphql-modules` library +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/backend-common@0.10.3 + - @backstage/plugin-catalog-graphql@0.3.0 + ## 0.1.10 ### Patch Changes diff --git a/plugins/graphql-backend/package.json b/plugins/graphql-backend/package.json index b341a6602c..0144b7ca93 100644 --- a/plugins/graphql-backend/package.json +++ b/plugins/graphql-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-graphql-backend", "description": "An experimental Backstage backend plugin for GraphQL", - "version": "0.1.10", + "version": "0.1.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,9 +31,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", - "@backstage/config": "^0.1.8", - "@backstage/plugin-catalog-graphql": "^0.2.14", + "@backstage/backend-common": "^0.10.3", + "@backstage/config": "^0.1.12", + "@backstage/plugin-catalog-graphql": "^0.3.0", "@graphql-tools/schema": "^8.3.1", "graphql-modules": "^1.0.0", "@types/express": "^4.17.6", @@ -48,7 +48,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.11.0", "@types/supertest": "^2.0.8", "eslint-plugin-graphql": "^4.0.0", "msw": "^0.35.0", diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index 15d4fce3de..2c7f9785b8 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-home +## 0.4.10 + +### Patch Changes + +- bdf1419d20: Adds two new home components - CompanyLogo and Toolkit. +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-search@0.5.5 + ## 0.4.9 ### Patch Changes diff --git a/plugins/home/package.json b/plugins/home/package.json index 298b1860e9..df0249a04e 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-home", "description": "A Backstage plugin that helps you build a home page", - "version": "0.4.9", + "version": "0.4.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,10 +21,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", "@backstage/theme": "^0.2.14", - "@backstage/plugin-search": "^0.5.1", + "@backstage/plugin-search": "^0.5.5", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -37,10 +37,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/ilert/CHANGELOG.md b/plugins/ilert/CHANGELOG.md index 47a07999be..6cae7a6529 100644 --- a/plugins/ilert/CHANGELOG.md +++ b/plugins/ilert/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-ilert +## 0.1.21 + +### Patch Changes + +- b47965beec: build(deps): bump `@date-io/luxon` from 1.3.13 to 2.11.1 +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/errors@0.2.0 + - @backstage/catalog-model@0.9.9 + ## 0.1.20 ### Patch Changes diff --git a/plugins/ilert/package.json b/plugins/ilert/package.json index 0a7b69b6f9..6299be9b2c 100644 --- a/plugins/ilert/package.json +++ b/plugins/ilert/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-ilert", "description": "A Backstage plugin that integrates towards iLert", - "version": "0.1.20", + "version": "0.1.21", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,11 +21,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/errors": "^0.1.3", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/errors": "^0.2.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@date-io/luxon": "2.x", "@material-ui/core": "^4.12.2", @@ -40,10 +40,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/jenkins-backend/package.json b/plugins/jenkins-backend/package.json index 4276e08c05..eabccc1416 100644 --- a/plugins/jenkins-backend/package.json +++ b/plugins/jenkins-backend/package.json @@ -22,10 +22,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", - "@backstage/catalog-client": "^0.5.3", - "@backstage/catalog-model": "^0.9.7", - "@backstage/config": "^0.1.10", + "@backstage/backend-common": "^0.10.3", + "@backstage/catalog-client": "^0.5.4", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", @@ -34,7 +34,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.11.0", "@types/jenkins": "^0.23.1", "@types/supertest": "^2.0.8", "msw": "^0.35.0", diff --git a/plugins/jenkins/CHANGELOG.md b/plugins/jenkins/CHANGELOG.md index 5881cd7ecf..20e3c433d0 100644 --- a/plugins/jenkins/CHANGELOG.md +++ b/plugins/jenkins/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-jenkins +## 0.5.17 + +### Patch Changes + +- 5333451def: Cleaned up API exports +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/errors@0.2.0 + - @backstage/catalog-model@0.9.9 + ## 0.5.16 ### Patch Changes diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index 14ff0fd2e7..ce637dba75 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-jenkins", "description": "A Backstage plugin that integrates towards Jenkins", - "version": "0.5.16", + "version": "0.5.17", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,11 +32,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/errors": "^0.1.5", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/errors": "^0.2.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -50,10 +50,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/kafka-backend/CHANGELOG.md b/plugins/kafka-backend/CHANGELOG.md index 6ec2d482b7..d6bcc20d89 100644 --- a/plugins/kafka-backend/CHANGELOG.md +++ b/plugins/kafka-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-kafka-backend +## 0.2.14 + +### Patch Changes + +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/backend-common@0.10.3 + - @backstage/errors@0.2.0 + - @backstage/catalog-model@0.9.9 + ## 0.2.13 ### Patch Changes diff --git a/plugins/kafka-backend/package.json b/plugins/kafka-backend/package.json index a26cf280c2..d0130b5370 100644 --- a/plugins/kafka-backend/package.json +++ b/plugins/kafka-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kafka-backend", "description": "A Backstage backend plugin that integrates towards Kafka", - "version": "0.2.13", + "version": "0.2.14", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,10 +32,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", - "@backstage/catalog-model": "^0.9.7", - "@backstage/config": "^0.1.10", - "@backstage/errors": "^0.1.5", + "@backstage/backend-common": "^0.10.3", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", + "@backstage/errors": "^0.2.0", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", @@ -44,7 +44,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.11.0", "@types/jest-when": "^2.7.2", "@types/lodash": "^4.14.151", "jest-when": "^3.1.0", diff --git a/plugins/kafka/CHANGELOG.md b/plugins/kafka/CHANGELOG.md index 45b122b7c1..4fb13cd517 100644 --- a/plugins/kafka/CHANGELOG.md +++ b/plugins/kafka/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-kafka +## 0.2.25 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/catalog-model@0.9.9 + ## 0.2.24 ### Patch Changes diff --git a/plugins/kafka/package.json b/plugins/kafka/package.json index 5eab137ca1..1aefb39e31 100644 --- a/plugins/kafka/package.json +++ b/plugins/kafka/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kafka", "description": "A Backstage plugin that integrates towards Kafka", - "version": "0.2.24", + "version": "0.2.25", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,10 +21,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -36,10 +36,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index faf40d12e7..aa57639849 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-kubernetes-backend +## 0.4.3 + +### Patch Changes + +- a67ec8527f: Exclude the AWS session token from credential validation, because it's not necessary in this context. +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/backend-common@0.10.3 + - @backstage/errors@0.2.0 + - @backstage/catalog-model@0.9.9 + ## 0.4.2 ### Patch Changes diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index 75ec4c3f03..f4be95dcb8 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-backend", "description": "A Backstage backend plugin that integrates towards Kubernetes", - "version": "0.4.2", + "version": "0.4.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,10 +32,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.2", - "@backstage/catalog-model": "^0.9.7", - "@backstage/config": "^0.1.10", - "@backstage/errors": "^0.1.5", + "@backstage/backend-common": "^0.10.3", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", + "@backstage/errors": "^0.2.0", "@backstage/plugin-kubernetes-common": "^0.2.1", "@google-cloud/container": "^2.2.0", "@kubernetes/client-node": "^0.16.0", @@ -55,7 +55,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", + "@backstage/cli": "^0.11.0", "@types/aws4": "^1.5.1", "supertest": "^6.1.3", "aws-sdk-mock": "^5.2.1", diff --git a/plugins/kubernetes-common/package.json b/plugins/kubernetes-common/package.json index cac133aa47..7b30ddaa9e 100644 --- a/plugins/kubernetes-common/package.json +++ b/plugins/kubernetes-common/package.json @@ -35,11 +35,11 @@ "url": "https://github.com/backstage/backstage/issues" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", + "@backstage/catalog-model": "^0.9.9", "@kubernetes/client-node": "^0.16.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5" + "@backstage/cli": "^0.11.0" }, "jest": { "roots": [ diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index 67126b4461..210ca07868 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-kubernetes +## 0.5.4 + +### Patch Changes + +- 7612e2856b: Clean up emptystate.svg image, removing wrong white artifact from the background +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/catalog-model@0.9.9 + ## 0.5.3 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 2d152c7390..937212786e 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes", "description": "A Backstage plugin that integrates towards Kubernetes", - "version": "0.5.3", + "version": "0.5.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,11 +31,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.8", - "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/plugin-kubernetes-common": "^0.2.1", "@kubernetes/client-node": "^0.16.0", "@backstage/theme": "^0.2.14", @@ -53,10 +53,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/lighthouse/CHANGELOG.md b/plugins/lighthouse/CHANGELOG.md index 83ab044467..2f6bb2b2e1 100644 --- a/plugins/lighthouse/CHANGELOG.md +++ b/plugins/lighthouse/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-lighthouse +## 0.2.34 + +### Patch Changes + +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/catalog-model@0.9.9 + ## 0.2.33 ### Patch Changes diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index 4dcf72452e..339e9bce7a 100644 --- a/plugins/lighthouse/package.json +++ b/plugins/lighthouse/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-lighthouse", "description": "A Backstage plugin that integrates towards Lighthouse", - "version": "0.2.33", + "version": "0.2.34", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,11 +32,11 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/config": "^0.1.10", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -48,10 +48,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/newrelic-dashboard/CHANGELOG.md b/plugins/newrelic-dashboard/CHANGELOG.md index 389d0f5f9d..1e796d2e53 100644 --- a/plugins/newrelic-dashboard/CHANGELOG.md +++ b/plugins/newrelic-dashboard/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-newrelic-dashboard +## 0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/errors@0.2.0 + - @backstage/catalog-model@0.9.9 + ## 0.1.2 ### Patch Changes diff --git a/plugins/newrelic-dashboard/package.json b/plugins/newrelic-dashboard/package.json index 5a0ebc10df..782a6b662b 100644 --- a/plugins/newrelic-dashboard/package.json +++ b/plugins/newrelic-dashboard/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-newrelic-dashboard", - "version": "0.1.2", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,19 +20,19 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.8", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/errors": "^0.1.5", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/errors": "^0.2.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "react-use": "^17.2.4" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/dev-utils": "^0.2.16", + "@backstage/cli": "^0.11.0", + "@backstage/dev-utils": "^0.2.17", "@testing-library/jest-dom": "^5.10.1", "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.0.6" diff --git a/plugins/newrelic/CHANGELOG.md b/plugins/newrelic/CHANGELOG.md index 19265d9e17..a4ffcd2b6e 100644 --- a/plugins/newrelic/CHANGELOG.md +++ b/plugins/newrelic/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-newrelic +## 0.3.13 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + ## 0.3.12 ### Patch Changes diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index 0caca9f96e..8ecc05449d 100644 --- a/plugins/newrelic/package.json +++ b/plugins/newrelic/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-newrelic", "description": "A Backstage plugin that integrates towards New Relic", - "version": "0.3.12", + "version": "0.3.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,8 +32,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -44,10 +44,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index 958e389a6e..e60b594a22 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-org +## 0.3.34 + +### Patch Changes + +- 3f08dcd696: For the component `EntityMembersListCard` you can now specify the type of members you have in a group. For example: + + ```tsx + + + + ``` + + If left empty it will by default use 'Members'. + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/catalog-model@0.9.9 + ## 0.3.33 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index fadca4442a..72cc6ca1e2 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-org", "description": "A Backstage plugin that helps you create entity pages for your organization", - "version": "0.3.33", + "version": "0.3.34", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,10 +21,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.8", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -39,11 +39,11 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/catalog-client": "^0.5.3", - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/catalog-client": "^0.5.4", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/pagerduty/CHANGELOG.md b/plugins/pagerduty/CHANGELOG.md index 9e55d4d587..0e43f1daee 100644 --- a/plugins/pagerduty/CHANGELOG.md +++ b/plugins/pagerduty/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-pagerduty +## 0.3.22 + +### Patch Changes + +- 7612e2856b: Clean up emptystate.svg image, removing wrong white artifact from the background +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/catalog-model@0.9.9 + ## 0.3.21 ### Patch Changes diff --git a/plugins/pagerduty/package.json b/plugins/pagerduty/package.json index 6a3ea7ebb9..d4a7c17653 100644 --- a/plugins/pagerduty/package.json +++ b/plugins/pagerduty/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-pagerduty", "description": "A Backstage plugin that integrates towards PagerDuty", - "version": "0.3.21", + "version": "0.3.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,10 +31,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -49,10 +49,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/permission-backend/CHANGELOG.md b/plugins/permission-backend/CHANGELOG.md index 76ee47ab32..d199acfea4 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-permission-backend +## 0.3.0 + +### Minor Changes + +- 419ca637c0: Optimizations to the integration between the permission backend and plugin-backends using createPermissionIntegrationRouter: + + - The permission backend already supported batched requests to authorize, but would make calls to plugin backend to apply conditions serially. Now, after applying the policy for each authorization request, the permission backend makes a single batched /apply-conditions request to each plugin backend referenced in policy decisions. + - The `getResource` method accepted by `createPermissionIntegrationRouter` has been replaced with `getResources`, to allow consumers to make batch requests to upstream data stores. When /apply-conditions is called with a batch of requests, all required resources are requested in a single invocation of `getResources`. + + Plugin owners consuming `createPermissionIntegrationRouter` should replace the `getResource` method in the options with a `getResources` method, accepting an array of resourceRefs, and returning an array of the corresponding resources. + +### Patch Changes + +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/backend-common@0.10.3 + - @backstage/plugin-permission-node@0.3.0 + - @backstage/plugin-auth-backend@0.6.2 + - @backstage/errors@0.2.0 + - @backstage/plugin-permission-common@0.3.1 + ## 0.2.3 ### Patch Changes diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index 8a9bd61445..9ce153d40a 100644 --- a/plugins/permission-backend/package.json +++ b/plugins/permission-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-backend", - "version": "0.2.3", + "version": "0.3.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -19,12 +19,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.1", - "@backstage/config": "^0.1.11", - "@backstage/errors": "^0.1.5", - "@backstage/plugin-auth-backend": "^0.6.0", - "@backstage/plugin-permission-common": "^0.3.0", - "@backstage/plugin-permission-node": "^0.2.3", + "@backstage/backend-common": "^0.10.3", + "@backstage/config": "^0.1.12", + "@backstage/errors": "^0.2.0", + "@backstage/plugin-auth-backend": "^0.6.2", + "@backstage/plugin-permission-common": "^0.3.1", + "@backstage/plugin-permission-node": "^0.3.0", "@types/express": "*", "dataloader": "^2.0.0", "express": "^4.17.1", @@ -36,7 +36,7 @@ "zod": "^3.11.6" }, "devDependencies": { - "@backstage/cli": "^0.10.4", + "@backstage/cli": "^0.11.0", "@types/lodash": "^4.14.151", "@types/supertest": "^2.0.8", "supertest": "^6.1.6", diff --git a/plugins/permission-common/CHANGELOG.md b/plugins/permission-common/CHANGELOG.md index 628ab685e0..fbf56d830f 100644 --- a/plugins/permission-common/CHANGELOG.md +++ b/plugins/permission-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-permission-common +## 0.3.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/errors@0.2.0 + ## 0.3.0 ### Minor Changes diff --git a/plugins/permission-common/package.json b/plugins/permission-common/package.json index fc6529d0d1..5722ba11b9 100644 --- a/plugins/permission-common/package.json +++ b/plugins/permission-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-permission-common", "description": "Isomorphic types and client for Backstage permissions and authorization", - "version": "0.3.0", + "version": "0.3.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { @@ -38,14 +38,14 @@ "url": "https://github.com/backstage/backstage/issues" }, "dependencies": { - "@backstage/config": "^0.1.11", - "@backstage/errors": "^0.1.5", + "@backstage/config": "^0.1.12", + "@backstage/errors": "^0.2.0", "cross-fetch": "^3.0.6", "uuid": "^8.0.0", "zod": "^3.11.6" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.11.0", "@types/jest": "^26.0.7", "msw": "^0.35.0" } diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index 377b48f45e..807efc1b59 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-permission-node +## 0.3.0 + +### Minor Changes + +- 419ca637c0: Optimizations to the integration between the permission backend and plugin-backends using createPermissionIntegrationRouter: + + - The permission backend already supported batched requests to authorize, but would make calls to plugin backend to apply conditions serially. Now, after applying the policy for each authorization request, the permission backend makes a single batched /apply-conditions request to each plugin backend referenced in policy decisions. + - The `getResource` method accepted by `createPermissionIntegrationRouter` has been replaced with `getResources`, to allow consumers to make batch requests to upstream data stores. When /apply-conditions is called with a batch of requests, all required resources are requested in a single invocation of `getResources`. + + Plugin owners consuming `createPermissionIntegrationRouter` should replace the `getResource` method in the options with a `getResources` method, accepting an array of resourceRefs, and returning an array of the corresponding resources. + +### Patch Changes + +- 9db1b86f32: Add helpers for creating PermissionRules with inferred types +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/backend-common@0.10.3 + - @backstage/plugin-auth-backend@0.6.2 + - @backstage/errors@0.2.0 + - @backstage/plugin-permission-common@0.3.1 + ## 0.2.3 ### Patch Changes diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index a5b32e2507..a492c99006 100644 --- a/plugins/permission-node/package.json +++ b/plugins/permission-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-permission-node", "description": "Common permission and authorization utilities for backend plugins", - "version": "0.2.3", + "version": "0.3.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,18 +29,18 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.1", - "@backstage/config": "^0.1.11", - "@backstage/errors": "^0.1.5", - "@backstage/plugin-auth-backend": "^0.6.0", - "@backstage/plugin-permission-common": "^0.3.0", + "@backstage/backend-common": "^0.10.3", + "@backstage/config": "^0.1.12", + "@backstage/errors": "^0.2.0", + "@backstage/plugin-auth-backend": "^0.6.2", + "@backstage/plugin-permission-common": "^0.3.1", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", "zod": "^3.11.6" }, "devDependencies": { - "@backstage/cli": "^0.10.4", + "@backstage/cli": "^0.11.0", "@types/supertest": "^2.0.8", "msw": "^0.35.0", "supertest": "^6.1.3" diff --git a/plugins/permission-react/CHANGELOG.md b/plugins/permission-react/CHANGELOG.md index a5ad489a91..0372c37f4b 100644 --- a/plugins/permission-react/CHANGELOG.md +++ b/plugins/permission-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-permission-react +## 0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-permission-common@0.3.1 + ## 0.2.1 ### Patch Changes diff --git a/plugins/permission-react/package.json b/plugins/permission-react/package.json index 23225cbf93..e29157506c 100644 --- a/plugins/permission-react/package.json +++ b/plugins/permission-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-react", - "version": "0.2.1", + "version": "0.2.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -27,9 +27,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/config": "^0.1.11", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/plugin-permission-common": "^0.3.0", + "@backstage/config": "^0.1.12", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/plugin-permission-common": "^0.3.1", "cross-fetch": "^3.0.6", "react-router": "6.0.0-beta.0", "react-use": "^17.2.4" @@ -39,8 +39,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/test-utils": "^0.2.0", + "@backstage/cli": "^0.11.0", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@types/jest": "^26.0.7" diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index fea9b93fe3..fdf4d71f36 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -29,8 +29,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", - "@backstage/config": "^0.1.8", + "@backstage/backend-common": "^0.10.3", + "@backstage/config": "^0.1.12", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", @@ -43,7 +43,7 @@ "yup": "^0.32.9" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.11.0", "@types/http-proxy-middleware": "^0.19.3", "@types/supertest": "^2.0.8", "@types/uuid": "^8.0.0", diff --git a/plugins/rollbar-backend/package.json b/plugins/rollbar-backend/package.json index 5257402661..986d78043b 100644 --- a/plugins/rollbar-backend/package.json +++ b/plugins/rollbar-backend/package.json @@ -31,8 +31,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.1", - "@backstage/config": "^0.1.10", + "@backstage/backend-common": "^0.10.3", + "@backstage/config": "^0.1.12", "@types/express": "^4.17.6", "camelcase-keys": "^6.2.2", "compression": "^1.7.4", @@ -48,8 +48,8 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.4", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/test-utils": "^0.2.2", "@types/supertest": "^2.0.8", "msw": "^0.36.3", "supertest": "^6.1.3" diff --git a/plugins/rollbar/CHANGELOG.md b/plugins/rollbar/CHANGELOG.md index 88d06fde9d..f0ee0c2658 100644 --- a/plugins/rollbar/CHANGELOG.md +++ b/plugins/rollbar/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-rollbar +## 0.3.23 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/catalog-model@0.9.9 + ## 0.3.22 ### Patch Changes diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index baae723318..4c99ba58e3 100644 --- a/plugins/rollbar/package.json +++ b/plugins/rollbar/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-rollbar", "description": "A Backstage plugin that integrates towards Rollbar", - "version": "0.3.22", + "version": "0.3.23", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,10 +32,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -50,10 +50,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md index 52a82025c9..1c4c60d8dd 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend-module-cookiecutter +## 0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/plugin-scaffolder-backend@0.15.20 + - @backstage/integration@0.7.1 + - @backstage/backend-common@0.10.3 + - @backstage/errors@0.2.0 + ## 0.1.7 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index 349cda084e..5663c5435a 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/package.json +++ b/plugins/scaffolder-backend-module-cookiecutter/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-cookiecutter", "description": "A module for the scaffolder backend that lets you template projects using cookiecutter", - "version": "0.1.7", + "version": "0.1.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,11 +20,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.1", - "@backstage/errors": "^0.1.4", - "@backstage/integration": "^0.7.0", - "@backstage/plugin-scaffolder-backend": "^0.15.19", - "@backstage/config": "^0.1.11", + "@backstage/backend-common": "^0.10.3", + "@backstage/errors": "^0.2.0", + "@backstage/integration": "^0.7.1", + "@backstage/plugin-scaffolder-backend": "^0.15.20", + "@backstage/config": "^0.1.12", "@backstage/types": "^0.1.1", "command-exists": "^1.2.9", "fs-extra": "10.0.0", @@ -32,7 +32,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.4", + "@backstage/cli": "^0.11.0", "@types/fs-extra": "^9.0.1", "@types/mock-fs": "^4.13.0", "@types/jest": "^26.0.7", diff --git a/plugins/scaffolder-backend-module-rails/CHANGELOG.md b/plugins/scaffolder-backend-module-rails/CHANGELOG.md index 70c35ba33e..7c229c38e4 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/plugin-scaffolder-backend@0.15.20 + - @backstage/integration@0.7.1 + - @backstage/backend-common@0.10.3 + - @backstage/errors@0.2.0 + ## 0.2.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index 42a910e624..79ad253a6e 100644 --- a/plugins/scaffolder-backend-module-rails/package.json +++ b/plugins/scaffolder-backend-module-rails/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-rails", "description": "A module for the scaffolder backend that lets you template projects using Rails", - "version": "0.2.2", + "version": "0.2.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,17 +21,17 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.1", - "@backstage/plugin-scaffolder-backend": "^0.15.19", - "@backstage/config": "^0.1.11", - "@backstage/errors": "^0.1.4", - "@backstage/integration": "^0.7.0", + "@backstage/backend-common": "^0.10.3", + "@backstage/plugin-scaffolder-backend": "^0.15.20", + "@backstage/config": "^0.1.12", + "@backstage/errors": "^0.2.0", + "@backstage/integration": "^0.7.1", "@backstage/types": "^0.1.1", "command-exists": "^1.2.9", "fs-extra": "^9.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.4", + "@backstage/cli": "^0.11.0", "@types/jest": "^26.0.7", "@types/node": "^14.14.32", "@types/command-exists": "^1.2.0", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index 1a138a16e0..0903b7a9ab 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-scaffolder-backend +## 0.15.20 + +### Patch Changes + +- 9fbd3b90ae: fix: Register plugin to prioritise Component kind for entityRef +- 451ef0aa07: Fix token pass-through for software templates using beta 3 version +- 5333451def: Cleaned up API exports +- 3b4d8caff6: Allow a GitHubCredentialsProvider to be passed to the GitHub scaffolder tasks actions. +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/integration@0.7.1 + - @backstage/backend-common@0.10.3 + - @backstage/plugin-catalog-backend@0.20.0 + - @backstage/errors@0.2.0 + - @backstage/catalog-client@0.5.4 + - @backstage/catalog-model@0.9.9 + - @backstage/plugin-scaffolder-backend-module-cookiecutter@0.1.8 + ## 0.15.19 ### Patch Changes diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 8fb5bdcdab..c497306d71 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend", "description": "The Backstage backend plugin that helps you create new things", - "version": "0.15.19", + "version": "0.15.20", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,15 +31,15 @@ "build:assets": "node scripts/build-nunjucks.js" }, "dependencies": { - "@backstage/backend-common": "^0.10.1", - "@backstage/catalog-client": "^0.5.3", - "@backstage/catalog-model": "^0.9.8", - "@backstage/config": "^0.1.11", - "@backstage/errors": "^0.1.5", - "@backstage/integration": "^0.7.0", - "@backstage/plugin-catalog-backend": "^0.19.4", + "@backstage/backend-common": "^0.10.3", + "@backstage/catalog-client": "^0.5.4", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", + "@backstage/errors": "^0.2.0", + "@backstage/integration": "^0.7.1", + "@backstage/plugin-catalog-backend": "^0.20.0", "@backstage/plugin-scaffolder-common": "^0.1.2", - "@backstage/plugin-scaffolder-backend-module-cookiecutter": "^0.1.7", + "@backstage/plugin-scaffolder-backend-module-cookiecutter": "^0.1.8", "@backstage/types": "^0.1.1", "@gitbeaker/core": "^34.6.0", "@gitbeaker/node": "^34.6.0", @@ -73,8 +73,8 @@ "vm2": "^3.9.5" }, "devDependencies": { - "@backstage/cli": "^0.10.4", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/test-utils": "^0.2.2", "@types/command-exists": "^1.2.0", "@types/fs-extra": "^9.0.1", "@types/git-url-parse": "^9.0.0", diff --git a/plugins/scaffolder-common/package.json b/plugins/scaffolder-common/package.json index 80644a6739..3d6b89639f 100644 --- a/plugins/scaffolder-common/package.json +++ b/plugins/scaffolder-common/package.json @@ -36,10 +36,10 @@ "url": "https://github.com/backstage/backstage/issues" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", + "@backstage/catalog-model": "^0.9.9", "@backstage/types": "^0.1.1" }, "devDependencies": { - "@backstage/cli": "^0.10.4" + "@backstage/cli": "^0.11.0" } } diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index 429aa3b77e..cc1c85580f 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-scaffolder +## 0.11.18 + +### Patch Changes + +- 5333451def: Cleaned up API exports +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/integration@0.7.1 + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/errors@0.2.0 + - @backstage/catalog-client@0.5.4 + - @backstage/catalog-model@0.9.9 + - @backstage/integration-react@0.1.18 + ## 0.11.17 ### Patch Changes diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 6c76010bec..448726ef2f 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder", "description": "The Backstage plugin that helps you create new things", - "version": "0.11.17", + "version": "0.11.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,15 +31,15 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-client": "^0.5.3", - "@backstage/catalog-model": "^0.9.7", - "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/errors": "^0.1.5", - "@backstage/integration": "^0.7.0", - "@backstage/integration-react": "^0.1.17", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-client": "^0.5.4", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/errors": "^0.2.0", + "@backstage/integration": "^0.7.1", + "@backstage/integration-react": "^0.1.18", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/plugin-scaffolder-common": "^0.1.2", "@backstage/theme": "^0.2.14", "@backstage/types": "^0.1.1", @@ -67,11 +67,11 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/plugin-catalog": "^0.7.7", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/plugin-catalog": "^0.7.8", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/search-backend-module-elasticsearch/package.json b/plugins/search-backend-module-elasticsearch/package.json index d9b478dc3a..b5cf2117b9 100644 --- a/plugins/search-backend-module-elasticsearch/package.json +++ b/plugins/search-backend-module-elasticsearch/package.json @@ -20,7 +20,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/config": "^0.1.8", + "@backstage/config": "^0.1.12", "@backstage/search-common": "^0.2.0", "@elastic/elasticsearch": "7.13.0", "@acuris/aws-es-connection": "^2.2.0", @@ -30,8 +30,8 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/backend-common": "^0.10.0", - "@backstage/cli": "^0.10.3", + "@backstage/backend-common": "^0.10.3", + "@backstage/cli": "^0.11.0", "@elastic/elasticsearch-mock": "^0.3.0" }, "files": [ diff --git a/plugins/search-backend-module-pg/package.json b/plugins/search-backend-module-pg/package.json index 79c7619ea4..29b6fae66e 100644 --- a/plugins/search-backend-module-pg/package.json +++ b/plugins/search-backend-module-pg/package.json @@ -20,15 +20,15 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", + "@backstage/backend-common": "^0.10.3", "@backstage/search-common": "^0.2.0", - "@backstage/plugin-search-backend-node": "^0.4.2", + "@backstage/plugin-search-backend-node": "^0.4.4", "lodash": "^4.17.21", "knex": "^0.95.1" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.11", - "@backstage/cli": "^0.10.3" + "@backstage/backend-test-utils": "^0.1.13", + "@backstage/cli": "^0.11.0" }, "files": [ "dist", diff --git a/plugins/search-backend-node/CHANGELOG.md b/plugins/search-backend-node/CHANGELOG.md index d4f4381f83..9fb673bb4e 100644 --- a/plugins/search-backend-node/CHANGELOG.md +++ b/plugins/search-backend-node/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/plugin-search-backend-node +## 0.4.4 + +### Patch Changes + +- 5333451def: Cleaned up API exports + ## 0.4.3 ### Patch Changes diff --git a/plugins/search-backend-node/package.json b/plugins/search-backend-node/package.json index 88d3af13ed..894893232a 100644 --- a/plugins/search-backend-node/package.json +++ b/plugins/search-backend-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-node", "description": "A library for Backstage backend plugins that want to interact with the search backend plugin", - "version": "0.4.3", + "version": "0.4.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -26,8 +26,8 @@ "@types/lunr": "^2.3.3" }, "devDependencies": { - "@backstage/backend-common": "^0.10.0", - "@backstage/cli": "^0.10.3" + "@backstage/backend-common": "^0.10.3", + "@backstage/cli": "^0.11.0" }, "files": [ "dist" diff --git a/plugins/search-backend/package.json b/plugins/search-backend/package.json index c67d1ef047..cb19b14c8a 100644 --- a/plugins/search-backend/package.json +++ b/plugins/search-backend/package.json @@ -20,9 +20,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", + "@backstage/backend-common": "^0.10.3", "@backstage/search-common": "^0.2.0", - "@backstage/plugin-search-backend-node": "^0.4.2", + "@backstage/plugin-search-backend-node": "^0.4.4", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", @@ -30,7 +30,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.11.0", "@types/supertest": "^2.0.8", "supertest": "^6.1.3" }, diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index 8baec7afa5..8787178093 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-search +## 0.5.5 + +### Patch Changes + +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/errors@0.2.0 + - @backstage/catalog-model@0.9.9 + ## 0.5.4 ### Patch Changes diff --git a/plugins/search/package.json b/plugins/search/package.json index f4880f86b3..57b349407f 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search", "description": "The Backstage plugin that provides your backstage app with search", - "version": "0.5.4", + "version": "0.5.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,12 +30,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/errors": "^0.1.4", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/errors": "^0.2.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/search-common": "^0.2.1", "@backstage/theme": "^0.2.14", "@backstage/types": "^0.1.1", @@ -52,10 +52,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/sentry/CHANGELOG.md b/plugins/sentry/CHANGELOG.md index e01cac2d53..828fbbf52f 100644 --- a/plugins/sentry/CHANGELOG.md +++ b/plugins/sentry/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-sentry +## 0.3.33 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/catalog-model@0.9.9 + ## 0.3.32 ### Patch Changes diff --git a/plugins/sentry/package.json b/plugins/sentry/package.json index 20bfdf22b0..6ae891a21d 100644 --- a/plugins/sentry/package.json +++ b/plugins/sentry/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-sentry", "description": "A Backstage plugin that integrates towards Sentry", - "version": "0.3.32", + "version": "0.3.33", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,10 +32,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -49,10 +49,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/shortcuts/CHANGELOG.md b/plugins/shortcuts/CHANGELOG.md index 1378e08dc3..ac26db7e95 100644 --- a/plugins/shortcuts/CHANGELOG.md +++ b/plugins/shortcuts/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-shortcuts +## 0.1.19 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + ## 0.1.18 ### Patch Changes diff --git a/plugins/shortcuts/package.json b/plugins/shortcuts/package.json index b38d66f6b9..c133c6134e 100644 --- a/plugins/shortcuts/package.json +++ b/plugins/shortcuts/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-shortcuts", "description": "A Backstage plugin that provides a shortcuts feature to the sidebar", - "version": "0.1.18", + "version": "0.1.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,8 +21,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", "@backstage/theme": "^0.2.14", "@backstage/types": "^0.1.1", "@material-ui/core": "^4.12.2", @@ -39,10 +39,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/sonarqube/CHANGELOG.md b/plugins/sonarqube/CHANGELOG.md index 0e83dcf0d7..f5eba462af 100644 --- a/plugins/sonarqube/CHANGELOG.md +++ b/plugins/sonarqube/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-sonarqube +## 0.2.12 + +### Patch Changes + +- 3423b3b24d: Enhance token description by highlighting that the trailing colon is required. +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/catalog-model@0.9.9 + ## 0.2.11 ### Patch Changes diff --git a/plugins/sonarqube/package.json b/plugins/sonarqube/package.json index 7523e79779..479daa0948 100644 --- a/plugins/sonarqube/package.json +++ b/plugins/sonarqube/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-sonarqube", "description": "", - "version": "0.2.11", + "version": "0.2.12", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,10 +33,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -50,10 +50,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/splunk-on-call/CHANGELOG.md b/plugins/splunk-on-call/CHANGELOG.md index 20b2171f55..1a36413841 100644 --- a/plugins/splunk-on-call/CHANGELOG.md +++ b/plugins/splunk-on-call/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-splunk-on-call +## 0.3.19 + +### Patch Changes + +- 7612e2856b: Clean up emptystate.svg image, removing wrong white artifact from the background +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/catalog-model@0.9.9 + ## 0.3.18 ### Patch Changes diff --git a/plugins/splunk-on-call/package.json b/plugins/splunk-on-call/package.json index 7f18330d7d..efd429bc69 100644 --- a/plugins/splunk-on-call/package.json +++ b/plugins/splunk-on-call/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-splunk-on-call", "description": "A Backstage plugin that integrates towards Splunk On-Call", - "version": "0.3.18", + "version": "0.3.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,10 +31,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/plugin-catalog-react": "^0.6.10", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -48,10 +48,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md b/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md index 544bfc3c2b..7666d101e0 100644 --- a/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md +++ b/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-tech-insights-backend-module-jsonfc +## 0.1.5 + +### Patch Changes + +- a60eb0f0dd: adding new operation to run checks for multiple entities in one request +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/backend-common@0.10.3 + - @backstage/plugin-tech-insights-common@0.2.1 + - @backstage/errors@0.2.0 + ## 0.1.4 ### Patch Changes diff --git a/plugins/tech-insights-backend-module-jsonfc/package.json b/plugins/tech-insights-backend-module-jsonfc/package.json index 30f00f4210..914c5bb284 100644 --- a/plugins/tech-insights-backend-module-jsonfc/package.json +++ b/plugins/tech-insights-backend-module-jsonfc/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights-backend-module-jsonfc", - "version": "0.1.4", + "version": "0.1.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,10 +31,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.1", - "@backstage/config": "^0.1.8", - "@backstage/errors": "^0.1.5", - "@backstage/plugin-tech-insights-common": "^0.2.0", + "@backstage/backend-common": "^0.10.3", + "@backstage/config": "^0.1.12", + "@backstage/errors": "^0.2.0", + "@backstage/plugin-tech-insights-common": "^0.2.1", "@backstage/plugin-tech-insights-node": "^0.1.2", "ajv": "^7.0.3", "json-rules-engine": "^6.1.2", @@ -43,7 +43,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.10.4", + "@backstage/cli": "^0.11.0", "@types/node-cron": "^2.0.4" }, "files": [ diff --git a/plugins/tech-insights-backend/CHANGELOG.md b/plugins/tech-insights-backend/CHANGELOG.md index ccc54f6a84..a4371a9723 100644 --- a/plugins/tech-insights-backend/CHANGELOG.md +++ b/plugins/tech-insights-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-tech-insights-backend +## 0.1.5 + +### Patch Changes + +- 19f0f93504: Catch errors from a fact retriever and log them. +- 10f26e8883: Modify queries to perform better by filtering on sub-queries as well +- a60eb0f0dd: adding new operation to run checks for multiple entities in one request +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/backend-common@0.10.3 + - @backstage/plugin-tech-insights-common@0.2.1 + - @backstage/errors@0.2.0 + - @backstage/catalog-client@0.5.4 + - @backstage/catalog-model@0.9.9 + ## 0.1.4 ### Patch Changes diff --git a/plugins/tech-insights-backend/package.json b/plugins/tech-insights-backend/package.json index c3c7a33bf1..bf435bbf92 100644 --- a/plugins/tech-insights-backend/package.json +++ b/plugins/tech-insights-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights-backend", - "version": "0.1.4", + "version": "0.1.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,12 +31,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", - "@backstage/catalog-client": "^0.5.3", - "@backstage/catalog-model": "^0.9.7", - "@backstage/config": "^0.1.8", - "@backstage/errors": "^0.1.5", - "@backstage/plugin-tech-insights-common": "^0.2.0", + "@backstage/backend-common": "^0.10.3", + "@backstage/catalog-client": "^0.5.4", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", + "@backstage/errors": "^0.2.0", + "@backstage/plugin-tech-insights-common": "^0.2.1", "@backstage/plugin-tech-insights-node": "^0.1.2", "@types/express": "^4.17.6", "express": "^4.17.1", @@ -51,8 +51,8 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.11", - "@backstage/cli": "^0.10.3", + "@backstage/backend-test-utils": "^0.1.13", + "@backstage/cli": "^0.11.0", "@types/supertest": "^2.0.8", "@types/node-cron": "^3.0.0", "@types/semver": "^7.3.8", diff --git a/plugins/tech-insights-common/CHANGELOG.md b/plugins/tech-insights-common/CHANGELOG.md index 9e72ce8ace..947c22756f 100644 --- a/plugins/tech-insights-common/CHANGELOG.md +++ b/plugins/tech-insights-common/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/plugin-tech-insights-common +## 0.2.1 + +### Patch Changes + +- a60eb0f0dd: adding new operation to run checks for multiple entities in one request + ## 0.2.0 ### Minor Changes diff --git a/plugins/tech-insights-common/package.json b/plugins/tech-insights-common/package.json index 7bf668a24e..ce71a63ae8 100644 --- a/plugins/tech-insights-common/package.json +++ b/plugins/tech-insights-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights-common", - "version": "0.2.0", + "version": "0.2.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,7 +35,7 @@ "@backstage/types": "^0.1.1" }, "devDependencies": { - "@backstage/cli": "^0.10.0" + "@backstage/cli": "^0.11.0" }, "files": [ "dist" diff --git a/plugins/tech-insights-node/package.json b/plugins/tech-insights-node/package.json index 7fd120d73b..34c13aa57e 100644 --- a/plugins/tech-insights-node/package.json +++ b/plugins/tech-insights-node/package.json @@ -30,15 +30,15 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", - "@backstage/config": "^0.1.8", - "@backstage/plugin-tech-insights-common": "^0.2.0", + "@backstage/backend-common": "^0.10.3", + "@backstage/config": "^0.1.12", + "@backstage/plugin-tech-insights-common": "^0.2.1", "@types/luxon": "^2.0.5", "luxon": "^2.0.2", "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.10.3" + "@backstage/cli": "^0.11.0" }, "files": [ "dist" diff --git a/plugins/tech-insights/CHANGELOG.md b/plugins/tech-insights/CHANGELOG.md index 47baf0943c..1f630036d4 100644 --- a/plugins/tech-insights/CHANGELOG.md +++ b/plugins/tech-insights/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-tech-insights +## 0.1.5 + +### Patch Changes + +- 34883f5c9e: Added possibility to pass customized title and description for the scorecards instead of using hardcoded ones. +- a60eb0f0dd: adding new operation to run checks for multiple entities in one request +- 48580d0fbb: fix React warning because of missing `key` prop +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/plugin-tech-insights-common@0.2.1 + - @backstage/errors@0.2.0 + - @backstage/catalog-model@0.9.9 + ## 0.1.4 ### Patch Changes diff --git a/plugins/tech-insights/package.json b/plugins/tech-insights/package.json index e6bf9d3947..8310cc5544 100644 --- a/plugins/tech-insights/package.json +++ b/plugins/tech-insights/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights", - "version": "0.1.4", + "version": "0.1.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,12 +20,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/errors": "^0.1.4", - "@backstage/plugin-catalog-react": "^0.6.10", - "@backstage/plugin-tech-insights-common": "^0.2.0", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/errors": "^0.2.0", + "@backstage/plugin-catalog-react": "^0.6.11", + "@backstage/plugin-tech-insights-common": "^0.2.1", "@backstage/theme": "^0.2.14", "@backstage/types": "^0.1.1", "@material-ui/core": "^4.12.2", @@ -39,10 +39,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/tech-radar/CHANGELOG.md b/plugins/tech-radar/CHANGELOG.md index cf7eb04197..e2ecdbfcf9 100644 --- a/plugins/tech-radar/CHANGELOG.md +++ b/plugins/tech-radar/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-tech-radar +## 0.5.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + ## 0.5.1 ### Patch Changes diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index 45df565b81..17d5874b88 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-tech-radar", "description": "A Backstage plugin that lets you display a Tech Radar for your organization", - "version": "0.5.1", + "version": "0.5.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,8 +31,8 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -46,10 +46,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index 256a402a24..ce4557cf80 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-techdocs-backend +## 0.12.3 + +### Patch Changes + +- 5333451def: Cleaned up API exports +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/integration@0.7.1 + - @backstage/backend-common@0.10.3 + - @backstage/techdocs-common@0.11.3 + - @backstage/errors@0.2.0 + - @backstage/catalog-client@0.5.4 + - @backstage/catalog-model@0.9.9 + ## 0.12.2 ### Patch Changes diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index 0d5a86ffc7..0040d2e7e4 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-backend", "description": "The Backstage backend plugin that renders technical documentation for your components", - "version": "0.12.2", + "version": "0.12.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,14 +31,14 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.1", - "@backstage/catalog-client": "^0.5.3", - "@backstage/catalog-model": "^0.9.7", - "@backstage/config": "^0.1.11", - "@backstage/errors": "^0.1.5", - "@backstage/integration": "^0.7.0", + "@backstage/backend-common": "^0.10.3", + "@backstage/catalog-client": "^0.5.4", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", + "@backstage/errors": "^0.2.0", + "@backstage/integration": "^0.7.1", "@backstage/search-common": "^0.2.1", - "@backstage/techdocs-common": "^0.11.2", + "@backstage/techdocs-common": "^0.11.3", "@types/express": "^4.17.6", "cross-fetch": "^3.0.6", "dockerode": "^3.3.1", @@ -52,8 +52,8 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.10.4", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/test-utils": "^0.2.2", "@types/dockerode": "^3.3.0", "msw": "^0.35.0", "supertest": "^6.1.3" diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index a72c3e3313..4031dfc29d 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-techdocs +## 0.12.14 + +### Patch Changes + +- 5333451def: Cleaned up API exports +- 1628ca3f49: Fix an issue where the TechDocs sidebar is hidden when the Backstage sidebar is pinned at smaller screen sizes +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/integration@0.7.1 + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/errors@0.2.0 + - @backstage/catalog-model@0.9.9 + - @backstage/integration-react@0.1.18 + - @backstage/plugin-catalog@0.7.8 + - @backstage/plugin-search@0.5.5 + ## 0.12.13 ### Patch Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 300c662225..3d633f5ef3 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs", "description": "The Backstage plugin that renders technical documentation for your components", - "version": "0.12.13", + "version": "0.12.14", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,16 +32,16 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.8", - "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/errors": "^0.1.5", - "@backstage/integration": "^0.7.0", - "@backstage/integration-react": "^0.1.17", - "@backstage/plugin-catalog": "^0.7.7", - "@backstage/plugin-catalog-react": "^0.6.10", - "@backstage/plugin-search": "^0.5.4", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/errors": "^0.2.0", + "@backstage/integration": "^0.7.1", + "@backstage/integration-react": "^0.1.18", + "@backstage/plugin-catalog": "^0.7.8", + "@backstage/plugin-catalog-react": "^0.6.11", + "@backstage/plugin-search": "^0.5.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -62,10 +62,10 @@ "react-dom": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/todo-backend/CHANGELOG.md b/plugins/todo-backend/CHANGELOG.md index 41ffd3e79d..f70a914ca0 100644 --- a/plugins/todo-backend/CHANGELOG.md +++ b/plugins/todo-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-todo-backend +## 0.1.18 + +### Patch Changes + +- 2260702efd: Properly exported all referenced types +- Updated dependencies + - @backstage/config@0.1.12 + - @backstage/integration@0.7.1 + - @backstage/backend-common@0.10.3 + - @backstage/errors@0.2.0 + - @backstage/catalog-client@0.5.4 + - @backstage/catalog-model@0.9.9 + ## 0.1.17 ### Patch Changes diff --git a/plugins/todo-backend/package.json b/plugins/todo-backend/package.json index 7368f69fd8..fb7e3b795f 100644 --- a/plugins/todo-backend/package.json +++ b/plugins/todo-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-todo-backend", "description": "A Backstage backend plugin that lets you browse TODO comments in your source code", - "version": "0.1.17", + "version": "0.1.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -25,12 +25,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.1", - "@backstage/catalog-client": "^0.5.3", - "@backstage/catalog-model": "^0.9.7", - "@backstage/config": "^0.1.10", - "@backstage/errors": "^0.1.3", - "@backstage/integration": "^0.7.0", + "@backstage/backend-common": "^0.10.3", + "@backstage/catalog-client": "^0.5.4", + "@backstage/catalog-model": "^0.9.9", + "@backstage/config": "^0.1.12", + "@backstage/errors": "^0.2.0", + "@backstage/integration": "^0.7.1", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", @@ -39,7 +39,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.4", + "@backstage/cli": "^0.11.0", "@types/supertest": "^2.0.8", "msw": "^0.35.0", "supertest": "^6.1.3" diff --git a/plugins/todo/CHANGELOG.md b/plugins/todo/CHANGELOG.md index e5b6723744..4931561fe8 100644 --- a/plugins/todo/CHANGELOG.md +++ b/plugins/todo/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-todo +## 0.1.18 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/plugin-catalog-react@0.6.11 + - @backstage/errors@0.2.0 + - @backstage/catalog-model@0.9.9 + ## 0.1.17 ### Patch Changes diff --git a/plugins/todo/package.json b/plugins/todo/package.json index 7d06199a64..91f7c7c5b6 100644 --- a/plugins/todo/package.json +++ b/plugins/todo/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-todo", "description": "A Backstage plugin that lets you browse TODO comments in your source code", - "version": "0.1.17", + "version": "0.1.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -27,11 +27,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/errors": "^0.1.3", - "@backstage/plugin-catalog-react": "^0.6.8", + "@backstage/catalog-model": "^0.9.9", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/errors": "^0.2.0", + "@backstage/plugin-catalog-react": "^0.6.11", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -42,10 +42,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/user-settings/CHANGELOG.md b/plugins/user-settings/CHANGELOG.md index feb61f79e8..31bf596795 100644 --- a/plugins/user-settings/CHANGELOG.md +++ b/plugins/user-settings/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-user-settings +## 0.3.16 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + ## 0.3.15 ### Patch Changes diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index c8fa6d2070..a51caebf10 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-user-settings", "description": "A Backstage plugin that provides a settings page", - "version": "0.3.15", + "version": "0.3.16", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,8 +31,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -44,10 +44,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/xcmetrics/CHANGELOG.md b/plugins/xcmetrics/CHANGELOG.md index 7f66a5c224..00b1360490 100644 --- a/plugins/xcmetrics/CHANGELOG.md +++ b/plugins/xcmetrics/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-xcmetrics +## 0.2.15 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.8.4 + - @backstage/core-plugin-api@0.5.0 + - @backstage/errors@0.2.0 + ## 0.2.14 ### Patch Changes diff --git a/plugins/xcmetrics/package.json b/plugins/xcmetrics/package.json index 333826ba87..f76927cac4 100644 --- a/plugins/xcmetrics/package.json +++ b/plugins/xcmetrics/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-xcmetrics", "description": "A Backstage plugin that shows XCode build metrics for your components", - "version": "0.2.14", + "version": "0.2.15", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,9 +21,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.3", - "@backstage/core-plugin-api": "^0.4.1", - "@backstage/errors": "^0.1.3", + "@backstage/core-components": "^0.8.4", + "@backstage/core-plugin-api": "^0.5.0", + "@backstage/errors": "^0.2.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -37,10 +37,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.5", - "@backstage/core-app-api": "^0.3.1", - "@backstage/dev-utils": "^0.2.16", - "@backstage/test-utils": "^0.2.1", + "@backstage/cli": "^0.11.0", + "@backstage/core-app-api": "^0.4.0", + "@backstage/dev-utils": "^0.2.17", + "@backstage/test-utils": "^0.2.2", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/yarn.lock b/yarn.lock index ca58fc8ea3..c8c2cc5530 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2294,6 +2294,43 @@ "@babel/helper-validator-identifier" "^7.16.7" to-fast-properties "^2.0.0" +"@backstage/core-app-api@^0.3.0": + version "0.3.1" + resolved "https://registry.npmjs.org/@backstage/core-app-api/-/core-app-api-0.3.1.tgz#eceee31852908fcc35edf198f4b06424b8cad2c9" + integrity sha512-q0Nm9lNghMMaHWG32MjTkfeHUWMMzDZ5EJIfxwXmizMoO6bmiyMja8sRuQznZHPEP0kzwe3cZwPvwafgY4UU/g== + dependencies: + "@backstage/app-defaults" "^0.1.3" + "@backstage/config" "^0.1.11" + "@backstage/core-components" "^0.8.3" + "@backstage/core-plugin-api" "^0.4.1" + "@backstage/theme" "^0.2.14" + "@backstage/types" "^0.1.1" + "@backstage/version-bridge" "^0.1.1" + "@material-ui/core" "^4.12.2" + "@material-ui/icons" "^4.9.1" + "@types/prop-types" "^15.7.3" + prop-types "^15.7.2" + react-router-dom "6.0.0-beta.0" + react-use "^17.2.4" + zen-observable "^0.8.15" + zod "^3.11.6" + +"@backstage/core-plugin-api@^0.4.0", "@backstage/core-plugin-api@^0.4.1": + version "0.4.1" + resolved "https://registry.npmjs.org/@backstage/core-plugin-api/-/core-plugin-api-0.4.1.tgz#c0a13504bdfa61ae3d0db96934cd6c32a7574446" + integrity sha512-IIb7XTcquTPaSIlamMKUgeTs5uLqkKN0Nw32QdTZhKgFkFFVzWC0AwN+henkaMNBZFdGb0ttPzrvNXGj5E6dGg== + dependencies: + "@backstage/config" "^0.1.11" + "@backstage/theme" "^0.2.14" + "@backstage/types" "^0.1.1" + "@backstage/version-bridge" "^0.1.1" + "@material-ui/core" "^4.12.2" + history "^5.0.0" + prop-types "^15.7.2" + react-router-dom "6.0.0-beta.0" + react-use "^17.2.4" + zen-observable "^0.8.15" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" From d78909c35e7ed51b727a4b2f6b62744bafeb8dca Mon Sep 17 00:00:00 2001 From: Miklos Kiss Date: Thu, 13 Jan 2022 15:39:52 +0100 Subject: [PATCH 52/56] Fix typo Signed-off-by: Miklos Kiss --- docs/features/software-catalog/descriptor-format.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/software-catalog/descriptor-format.md b/docs/features/software-catalog/descriptor-format.md index 2b6b2049d0..a5f50b1998 100644 --- a/docs/features/software-catalog/descriptor-format.md +++ b/docs/features/software-catalog/descriptor-format.md @@ -1267,7 +1267,7 @@ shape, this kind has the following structure. Exactly equal to `backstage.io/v1alpha1` and `Location`, respectively. ### `spec` [required] -The `spec` field is required. The miniaml spec should be an empty object. +The `spec` field is required. The minimal spec should be an empty object. ### `spec.type` [optional] From e683a479d1b8759204cb413c78eeb9820e2db2ef Mon Sep 17 00:00:00 2001 From: Miklos Kiss Date: Thu, 13 Jan 2022 16:01:34 +0100 Subject: [PATCH 53/56] Fix formatting Signed-off-by: Miklos Kiss --- docs/features/software-catalog/descriptor-format.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/features/software-catalog/descriptor-format.md b/docs/features/software-catalog/descriptor-format.md index a5f50b1998..ec4e13c1d4 100644 --- a/docs/features/software-catalog/descriptor-format.md +++ b/docs/features/software-catalog/descriptor-format.md @@ -1267,6 +1267,7 @@ shape, this kind has the following structure. Exactly equal to `backstage.io/v1alpha1` and `Location`, respectively. ### `spec` [required] + The `spec` field is required. The minimal spec should be an empty object. ### `spec.type` [optional] From 94d24c751da0f6b1ac65a544425a849cae76812c Mon Sep 17 00:00:00 2001 From: MT Lewis Date: Thu, 13 Jan 2022 17:10:45 +0000 Subject: [PATCH 54/56] catalog-backend: fix getResources The getResources method in catalog-backend should use the unauthorizedEntitiesCatalog to load resources, otherwise we end up authorizing access to entities during application of conditions. Signed-off-by: MT Lewis --- plugins/catalog-backend/src/service/NextCatalogBuilder.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/catalog-backend/src/service/NextCatalogBuilder.ts b/plugins/catalog-backend/src/service/NextCatalogBuilder.ts index be75b4dfe7..18ee1e2042 100644 --- a/plugins/catalog-backend/src/service/NextCatalogBuilder.ts +++ b/plugins/catalog-backend/src/service/NextCatalogBuilder.ts @@ -417,7 +417,7 @@ export class NextCatalogBuilder { const permissionIntegrationRouter = createPermissionIntegrationRouter({ resourceType: RESOURCE_TYPE_CATALOG_ENTITY, getResources: async (resourceRefs: string[]) => { - const { entities } = await entitiesCatalog.entities({ + const { entities } = await unauthorizedEntitiesCatalog.entities({ filter: { anyOf: resourceRefs.map(resourceRef => { const { kind, namespace, name } = parseEntityRef(resourceRef); From 68edbbeafd7da722cbaae1660e3e1a9f3a591c53 Mon Sep 17 00:00:00 2001 From: MT Lewis Date: Thu, 13 Jan 2022 17:26:04 +0000 Subject: [PATCH 55/56] catalog-backend: add changeset Signed-off-by: MT Lewis --- .changeset/neat-rice-stare.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/neat-rice-stare.md diff --git a/.changeset/neat-rice-stare.md b/.changeset/neat-rice-stare.md new file mode 100644 index 0000000000..3f373cbf90 --- /dev/null +++ b/.changeset/neat-rice-stare.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Fix bug with resource loading in permission integration From a4487f70509dc73cad6d4787099039b780f05e7f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Jan 2022 04:10:17 +0000 Subject: [PATCH 56/56] build(deps): bump @roadiehq/backstage-plugin-github-insights Bumps [@roadiehq/backstage-plugin-github-insights](https://github.com/RoadieHQ/roadie-backstage-plugins/tree/HEAD/plugins/frontend/backstage-plugin-github-insights) from 1.4.2 to 1.4.3. - [Release notes](https://github.com/RoadieHQ/roadie-backstage-plugins/releases) - [Changelog](https://github.com/RoadieHQ/roadie-backstage-plugins/blob/main/plugins/frontend/backstage-plugin-github-insights/CHANGELOG.md) - [Commits](https://github.com/RoadieHQ/roadie-backstage-plugins/commits/HEAD/plugins/frontend/backstage-plugin-github-insights) --- updated-dependencies: - dependency-name: "@roadiehq/backstage-plugin-github-insights" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- yarn.lock | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index c8c2cc5530..b995fc1993 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5377,12 +5377,11 @@ integrity sha512-8UiDeDbjCImFSfOegGu13otQ7OdP9FOYpcLjeouppnhs+MPeIEAtYS+jCcBKmi3reyTagC15/KVSRhde1wS1vg== "@roadiehq/backstage-plugin-github-insights@^1.4.2": - version "1.4.2" - resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-github-insights/-/backstage-plugin-github-insights-1.4.2.tgz#462e2868a1b4cee338032e4715ad797db71ebd22" - integrity sha512-hIGOhzyK1rC3JI+y/yI303whdRJTN4KXCYHekcdchjlTKB31SMU4lER0sBacCyiov1vAl+LkDmdubESSLou/Hw== + version "1.4.3" + resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-github-insights/-/backstage-plugin-github-insights-1.4.3.tgz#c83fd94dc7266330b464686c5f283fa07f5f2be9" + integrity sha512-khvXVgp+GTwXULTG4jfzB6uQtzPbjgZhfudE04hc/O3FWU4Wyrcmc/UTTu1nFah7m6yL6pwfEdC3auKXPr07lQ== dependencies: "@backstage/catalog-model" "^0.9.7" - "@backstage/core-app-api" "^0.3.0" "@backstage/core-components" "^0.8.0" "@backstage/core-plugin-api" "^0.4.0" "@backstage/integration-react" "^0.1.10"