From 94b28d43c885ecedd870b961cbb2596c2848649d Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Wed, 26 Feb 2025 08:24:09 +0000 Subject: [PATCH 1/7] Move font weight and family back to each components Signed-off-by: Charles de Dreuille --- packages/canon/src/components/Box/styles.css | 1 + .../canon/src/components/Checkbox/styles.css | 1 + .../src/components/Input/Input.styles.css | 1 + .../canon/src/components/Table/styles.css | 2 ++ packages/canon/src/css/base.css | 26 ------------------- packages/canon/src/css/core.css | 2 +- 6 files changed, 6 insertions(+), 27 deletions(-) delete mode 100644 packages/canon/src/css/base.css diff --git a/packages/canon/src/components/Box/styles.css b/packages/canon/src/components/Box/styles.css index f3b24793cf..7a01d5aa3a 100644 --- a/packages/canon/src/components/Box/styles.css +++ b/packages/canon/src/components/Box/styles.css @@ -1,4 +1,5 @@ .canon-Box { font-family: var(--canon-font-regular); + font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-primary); } diff --git a/packages/canon/src/components/Checkbox/styles.css b/packages/canon/src/components/Checkbox/styles.css index 386c6f4671..f026740698 100644 --- a/packages/canon/src/components/Checkbox/styles.css +++ b/packages/canon/src/components/Checkbox/styles.css @@ -24,6 +24,7 @@ gap: var(--canon-space-2); font-size: var(--canon-font-size-xs); font-family: var(--canon-font-regular); + font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-primary); user-select: none; diff --git a/packages/canon/src/components/Input/Input.styles.css b/packages/canon/src/components/Input/Input.styles.css index fa196cfa20..4e3e6771ab 100644 --- a/packages/canon/src/components/Input/Input.styles.css +++ b/packages/canon/src/components/Input/Input.styles.css @@ -20,6 +20,7 @@ padding: 0 var(--canon-space-4); background-color: var(--canon-bg-elevated); font-size: var(--canon-font-size-3); + font-family: var(--canon-font-regular); font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-primary); transition: border-color 0.2s ease-in-out, outline-color 0.2s ease-in-out; diff --git a/packages/canon/src/components/Table/styles.css b/packages/canon/src/components/Table/styles.css index 6bb470a423..b834485ff5 100644 --- a/packages/canon/src/components/Table/styles.css +++ b/packages/canon/src/components/Table/styles.css @@ -7,6 +7,8 @@ padding-bottom: var(--canon-space-0_5); padding-top: var(--canon-space-0_5); font-size: var(--canon-font-size-3); + font-family: var(--canon-font-regular); + font-weight: var(--canon-font-weight-regular); table { width: 100%; diff --git a/packages/canon/src/css/base.css b/packages/canon/src/css/base.css deleted file mode 100644 index b8bd0c4f81..0000000000 --- a/packages/canon/src/css/base.css +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2024 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 './normalize.css'; - -@layer base { - *, - html, - body { - font-family: var(--canon-font-regular); - font-weight: var(--canon-font-weight-regular); - } -} diff --git a/packages/canon/src/css/core.css b/packages/canon/src/css/core.css index cc0e5ab85a..ded8fcaa6e 100644 --- a/packages/canon/src/css/core.css +++ b/packages/canon/src/css/core.css @@ -15,7 +15,7 @@ */ /* Normalize */ -@import './base.css'; +@import './normalize.css'; @import './utilities.css'; /* Light theme tokens */ From 89e86863e88b6cec42421e6e07da8a51b1e2aafc Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Wed, 26 Feb 2025 08:40:12 +0000 Subject: [PATCH 2/7] Create gold-donkeys-flow.md Signed-off-by: Charles de Dreuille --- .changeset/gold-donkeys-flow.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/gold-donkeys-flow.md diff --git a/.changeset/gold-donkeys-flow.md b/.changeset/gold-donkeys-flow.md new file mode 100644 index 0000000000..3fa7b4568e --- /dev/null +++ b/.changeset/gold-donkeys-flow.md @@ -0,0 +1,5 @@ +--- +'@backstage/canon': patch +--- + +To avoid conflicts with Backstage, we removed global styles and set font-family and font-weight for each components. From 7956beb0291a320116f3fdc510f33a7156aa8ebb Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 27 Feb 2025 12:52:31 +0100 Subject: [PATCH 3/7] auth-backend: deprecations everywhere Signed-off-by: Patrik Oldsberg --- .changeset/short-moose-attend.md | 9 +++++++++ plugins/auth-backend/report.api.md | 16 ++++++++-------- .../src/lib/catalog/CatalogIdentityClient.ts | 1 + .../src/providers/atlassian/provider.ts | 1 + .../auth-backend/src/providers/auth0/provider.ts | 1 + .../src/providers/aws-alb/provider.ts | 1 + .../src/providers/azure-easyauth/provider.ts | 1 + .../src/providers/bitbucket/provider.ts | 1 + .../src/providers/cloudflare-access/provider.ts | 1 + .../providers/createAuthProviderIntegration.ts | 1 + .../src/providers/gcp-iap/provider.ts | 1 + .../src/providers/github/provider.ts | 6 +++++- .../src/providers/gitlab/provider.ts | 1 + .../src/providers/google/provider.ts | 1 + .../src/providers/microsoft/provider.ts | 1 + .../src/providers/oauth2-proxy/provider.ts | 1 + .../src/providers/oauth2/provider.ts | 1 + .../auth-backend/src/providers/oidc/provider.ts | 1 + .../auth-backend/src/providers/okta/provider.ts | 1 + .../src/providers/onelogin/provider.ts | 1 + plugins/auth-backend/src/providers/providers.ts | 2 ++ plugins/auth-backend/src/providers/router.ts | 10 ++++++++-- .../auth-backend/src/providers/saml/provider.ts | 5 ++++- 23 files changed, 53 insertions(+), 12 deletions(-) create mode 100644 .changeset/short-moose-attend.md diff --git a/.changeset/short-moose-attend.md b/.changeset/short-moose-attend.md new file mode 100644 index 0000000000..a6ed564917 --- /dev/null +++ b/.changeset/short-moose-attend.md @@ -0,0 +1,9 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +Marked the remaining exports related to `createRouter` and the old backend system as deprecated. + +For more information about migrating to the new backend system, see the [migration guide](https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin). + +Support for the old backend system will be removed in the next release of this plugin. diff --git a/plugins/auth-backend/report.api.md b/plugins/auth-backend/report.api.md index 20690528d1..457a906f58 100644 --- a/plugins/auth-backend/report.api.md +++ b/plugins/auth-backend/report.api.md @@ -121,7 +121,7 @@ export type BitbucketServerOAuthResult = { refreshToken?: string; }; -// @public +// @public @deprecated export class CatalogIdentityClient { constructor(options: { catalogApi: CatalogApi; @@ -176,7 +176,7 @@ export type CloudflareAccessResult = { // @public @deprecated (undocumented) export type CookieConfigurer = CookieConfigurer_2; -// @public +// @public @deprecated export function createAuthProviderIntegration< TCreateOptions extends unknown[], TResolvers extends { @@ -190,13 +190,13 @@ export function createAuthProviderIntegration< resolvers: Readonly; }>; -// @public (undocumented) +// @public @deprecated (undocumented) export function createOriginFilter(config: Config): (origin: string) => boolean; // @public @deprecated (undocumented) export function createRouter(options: RouterOptions): Promise; -// @public +// @public @deprecated export const defaultAuthProviderFactories: { [providerId: string]: AuthProviderFactory_2; }; @@ -219,7 +219,7 @@ export type GcpIapTokenInfo = GcpIapTokenInfo_2; // @public export function getDefaultOwnershipEntityRefs(entity: Entity): string[]; -// @public (undocumented) +// @public @deprecated (undocumented) export type GithubOAuthResult = { fullProfile: Profile; params: { @@ -361,12 +361,12 @@ export const prepareBackstageIdentityResponse: typeof prepareBackstageIdentityRe // @public @deprecated (undocumented) export type ProfileInfo = ProfileInfo_2; -// @public (undocumented) +// @public @deprecated (undocumented) export type ProviderFactories = { [s: string]: AuthProviderFactory_2; }; -// @public +// @public @deprecated export const providers: Readonly<{ atlassian: Readonly<{ create: ( @@ -676,7 +676,7 @@ export interface RouterOptions { tokenManager?: TokenManager; } -// @public (undocumented) +// @public @deprecated (undocumented) export type SamlAuthResult = { fullProfile: any; }; diff --git a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts index e91108dbf2..252cae88af 100644 --- a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts +++ b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts @@ -38,6 +38,7 @@ import { * A catalog client tailored for reading out identity data from the catalog. * * @public + * @deprecated Use the provided `AuthResolverContext` instead, see https://backstage.io/docs/auth/identity-resolver#building-custom-resolvers */ export class CatalogIdentityClient { private readonly catalogApi: CatalogApi; diff --git a/plugins/auth-backend/src/providers/atlassian/provider.ts b/plugins/auth-backend/src/providers/atlassian/provider.ts index 22db26fd85..539f055f75 100644 --- a/plugins/auth-backend/src/providers/atlassian/provider.ts +++ b/plugins/auth-backend/src/providers/atlassian/provider.ts @@ -31,6 +31,7 @@ import { AuthHandler } from '../types'; * Auth provider integration for Atlassian auth * * @public + * @deprecated Migrate the auth plugin to the new backend system https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin */ export const atlassian = createAuthProviderIntegration({ create(options?: { diff --git a/plugins/auth-backend/src/providers/auth0/provider.ts b/plugins/auth-backend/src/providers/auth0/provider.ts index 44e7c5bb6e..9ae31b305d 100644 --- a/plugins/auth-backend/src/providers/auth0/provider.ts +++ b/plugins/auth-backend/src/providers/auth0/provider.ts @@ -47,6 +47,7 @@ export type Auth0AuthProviderOptions = OAuthProviderOptions & { * Auth provider integration for auth0 auth * * @public + * @deprecated Migrate the auth plugin to the new backend system https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin */ export const auth0 = createAuthProviderIntegration({ create(options?: { diff --git a/plugins/auth-backend/src/providers/aws-alb/provider.ts b/plugins/auth-backend/src/providers/aws-alb/provider.ts index c09f307e96..18d4f42f32 100644 --- a/plugins/auth-backend/src/providers/aws-alb/provider.ts +++ b/plugins/auth-backend/src/providers/aws-alb/provider.ts @@ -29,6 +29,7 @@ import { createAuthProviderIntegration } from '../createAuthProviderIntegration' * Auth provider integration for AWS ALB auth * * @public + * @deprecated Migrate the auth plugin to the new backend system https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin */ export const awsAlb = createAuthProviderIntegration({ create(options?: { diff --git a/plugins/auth-backend/src/providers/azure-easyauth/provider.ts b/plugins/auth-backend/src/providers/azure-easyauth/provider.ts index 92c5c183f9..5e61b8bf8a 100644 --- a/plugins/auth-backend/src/providers/azure-easyauth/provider.ts +++ b/plugins/auth-backend/src/providers/azure-easyauth/provider.ts @@ -31,6 +31,7 @@ export type EasyAuthResult = AzureEasyAuthResult; * Auth provider integration for Azure EasyAuth * * @public + * @deprecated Migrate the auth plugin to the new backend system https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin */ export const easyAuth = createAuthProviderIntegration({ create(options?: { diff --git a/plugins/auth-backend/src/providers/bitbucket/provider.ts b/plugins/auth-backend/src/providers/bitbucket/provider.ts index 2cebb15861..69ac2cf23b 100644 --- a/plugins/auth-backend/src/providers/bitbucket/provider.ts +++ b/plugins/auth-backend/src/providers/bitbucket/provider.ts @@ -69,6 +69,7 @@ export type BitbucketPassportProfile = PassportProfile & { * Auth provider integration for Bitbucket auth * * @public + * @deprecated Migrate the auth plugin to the new backend system https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin */ export const bitbucket = createAuthProviderIntegration({ create(options?: { diff --git a/plugins/auth-backend/src/providers/cloudflare-access/provider.ts b/plugins/auth-backend/src/providers/cloudflare-access/provider.ts index cbc9a99517..4710d60d47 100644 --- a/plugins/auth-backend/src/providers/cloudflare-access/provider.ts +++ b/plugins/auth-backend/src/providers/cloudflare-access/provider.ts @@ -125,6 +125,7 @@ export type CloudflareAccessResult = { * Auth provider integration for Cloudflare Access auth * * @public + * @deprecated Migrate the auth plugin to the new backend system https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin */ export const cfAccess = createAuthProviderIntegration({ create(options: { diff --git a/plugins/auth-backend/src/providers/createAuthProviderIntegration.ts b/plugins/auth-backend/src/providers/createAuthProviderIntegration.ts index 9846bb8bf9..2f7bb4a4ec 100644 --- a/plugins/auth-backend/src/providers/createAuthProviderIntegration.ts +++ b/plugins/auth-backend/src/providers/createAuthProviderIntegration.ts @@ -27,6 +27,7 @@ import { * supplies built-in sign-in resolvers for the specific provider. * * @public + * @deprecated Migrate the auth plugin to the new backend system https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin */ export function createAuthProviderIntegration< TCreateOptions extends unknown[], diff --git a/plugins/auth-backend/src/providers/gcp-iap/provider.ts b/plugins/auth-backend/src/providers/gcp-iap/provider.ts index e0c5b62d47..f40cb4ed25 100644 --- a/plugins/auth-backend/src/providers/gcp-iap/provider.ts +++ b/plugins/auth-backend/src/providers/gcp-iap/provider.ts @@ -27,6 +27,7 @@ import { GcpIapResult } from './types'; * Auth provider integration for Google Identity-Aware Proxy auth * * @public + * @deprecated Migrate the auth plugin to the new backend system https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin */ export const gcpIap = createAuthProviderIntegration({ create(options: { diff --git a/plugins/auth-backend/src/providers/github/provider.ts b/plugins/auth-backend/src/providers/github/provider.ts index 51595b0428..6c6738ad57 100644 --- a/plugins/auth-backend/src/providers/github/provider.ts +++ b/plugins/auth-backend/src/providers/github/provider.ts @@ -25,7 +25,10 @@ import { } from '@backstage/plugin-auth-node'; import { githubAuthenticator } from '@backstage/plugin-auth-backend-module-github-provider'; -/** @public */ +/** + * @public + * @deprecated Migrate the auth plugin to the new backend system https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin + */ export type GithubOAuthResult = { fullProfile: PassportProfile; params: { @@ -41,6 +44,7 @@ export type GithubOAuthResult = { * Auth provider integration for GitHub auth * * @public + * @deprecated Migrate the auth plugin to the new backend system https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin */ export const github = createAuthProviderIntegration({ create(options?: { diff --git a/plugins/auth-backend/src/providers/gitlab/provider.ts b/plugins/auth-backend/src/providers/gitlab/provider.ts index 899338adce..503145a805 100644 --- a/plugins/auth-backend/src/providers/gitlab/provider.ts +++ b/plugins/auth-backend/src/providers/gitlab/provider.ts @@ -31,6 +31,7 @@ import { gitlabAuthenticator } from '@backstage/plugin-auth-backend-module-gitla * Auth provider integration for GitLab auth * * @public + * @deprecated Migrate the auth plugin to the new backend system https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin */ export const gitlab = createAuthProviderIntegration({ create(options?: { diff --git a/plugins/auth-backend/src/providers/google/provider.ts b/plugins/auth-backend/src/providers/google/provider.ts index b5e6e7127c..99a9c40ecb 100644 --- a/plugins/auth-backend/src/providers/google/provider.ts +++ b/plugins/auth-backend/src/providers/google/provider.ts @@ -36,6 +36,7 @@ import { AuthHandler } from '../types'; * Auth provider integration for Google auth * * @public + * @deprecated Migrate the auth plugin to the new backend system https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin */ export const google = createAuthProviderIntegration({ create(options?: { diff --git a/plugins/auth-backend/src/providers/microsoft/provider.ts b/plugins/auth-backend/src/providers/microsoft/provider.ts index f0b019d1c7..f461fe8341 100644 --- a/plugins/auth-backend/src/providers/microsoft/provider.ts +++ b/plugins/auth-backend/src/providers/microsoft/provider.ts @@ -36,6 +36,7 @@ import { * Auth provider integration for Microsoft auth * * @public + * @deprecated Migrate the auth plugin to the new backend system https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin */ export const microsoft = createAuthProviderIntegration({ create(options?: { diff --git a/plugins/auth-backend/src/providers/oauth2-proxy/provider.ts b/plugins/auth-backend/src/providers/oauth2-proxy/provider.ts index 4200355c1a..cbd02d18ea 100644 --- a/plugins/auth-backend/src/providers/oauth2-proxy/provider.ts +++ b/plugins/auth-backend/src/providers/oauth2-proxy/provider.ts @@ -29,6 +29,7 @@ import { * Auth provider integration for oauth2-proxy auth * * @public + * @deprecated Migrate the auth plugin to the new backend system https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin */ export const oauth2Proxy = createAuthProviderIntegration({ create(options: { diff --git a/plugins/auth-backend/src/providers/oauth2/provider.ts b/plugins/auth-backend/src/providers/oauth2/provider.ts index 3a00de1f95..b9ab928730 100644 --- a/plugins/auth-backend/src/providers/oauth2/provider.ts +++ b/plugins/auth-backend/src/providers/oauth2/provider.ts @@ -31,6 +31,7 @@ import { oauth2Authenticator } from '@backstage/plugin-auth-backend-module-oauth * Auth provider integration for generic OAuth2 auth * * @public + * @deprecated Migrate the auth plugin to the new backend system https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin */ export const oauth2 = createAuthProviderIntegration({ create(options?: { diff --git a/plugins/auth-backend/src/providers/oidc/provider.ts b/plugins/auth-backend/src/providers/oidc/provider.ts index 40e837b0b0..6caf97ef7c 100644 --- a/plugins/auth-backend/src/providers/oidc/provider.ts +++ b/plugins/auth-backend/src/providers/oidc/provider.ts @@ -37,6 +37,7 @@ import { * Auth provider integration for generic OpenID Connect auth * * @public + * @deprecated Migrate the auth plugin to the new backend system https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin */ export const oidc = createAuthProviderIntegration({ create(options?: { diff --git a/plugins/auth-backend/src/providers/okta/provider.ts b/plugins/auth-backend/src/providers/okta/provider.ts index 463afc2bf4..5746e12710 100644 --- a/plugins/auth-backend/src/providers/okta/provider.ts +++ b/plugins/auth-backend/src/providers/okta/provider.ts @@ -36,6 +36,7 @@ import { * Auth provider integration for Okta auth * * @public + * @deprecated Migrate the auth plugin to the new backend system https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin */ export const okta = createAuthProviderIntegration({ create(options?: { diff --git a/plugins/auth-backend/src/providers/onelogin/provider.ts b/plugins/auth-backend/src/providers/onelogin/provider.ts index ab5995da4c..808e6c15d3 100644 --- a/plugins/auth-backend/src/providers/onelogin/provider.ts +++ b/plugins/auth-backend/src/providers/onelogin/provider.ts @@ -31,6 +31,7 @@ import { AuthHandler } from '../types'; * Auth provider integration for OneLogin auth * * @public + * @deprecated Migrate the auth plugin to the new backend system https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin */ export const onelogin = createAuthProviderIntegration({ create(options?: { diff --git a/plugins/auth-backend/src/providers/providers.ts b/plugins/auth-backend/src/providers/providers.ts index 76ac51f662..ce513e6ac7 100644 --- a/plugins/auth-backend/src/providers/providers.ts +++ b/plugins/auth-backend/src/providers/providers.ts @@ -38,6 +38,7 @@ import { AuthProviderFactory } from '@backstage/plugin-auth-node'; * All built-in auth provider integrations. * * @public + * @deprecated Migrate the auth plugin to the new backend system https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin */ export const providers = Object.freeze({ atlassian, @@ -64,6 +65,7 @@ export const providers = Object.freeze({ * All auth provider factories that are installed by default. * * @public + * @deprecated Migrate the auth plugin to the new backend system https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin */ export const defaultAuthProviderFactories: { [providerId: string]: AuthProviderFactory; diff --git a/plugins/auth-backend/src/providers/router.ts b/plugins/auth-backend/src/providers/router.ts index 2867611075..ceab20553d 100644 --- a/plugins/auth-backend/src/providers/router.ts +++ b/plugins/auth-backend/src/providers/router.ts @@ -34,7 +34,10 @@ import { Minimatch } from 'minimatch'; import { CatalogAuthResolverContext } from '../lib/resolvers/CatalogAuthResolverContext'; import { TokenIssuer } from '../identity/types'; -/** @public */ +/** + * @public + * @deprecated Migrate the auth plugin to the new backend system https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin + */ export type ProviderFactories = { [s: string]: AuthProviderFactory }; export function bindProviderRouters( @@ -145,7 +148,10 @@ export function bindProviderRouters( } } -/** @public */ +/** + * @public + * @deprecated this export will be removed + */ export function createOriginFilter( config: Config, ): (origin: string) => boolean { diff --git a/plugins/auth-backend/src/providers/saml/provider.ts b/plugins/auth-backend/src/providers/saml/provider.ts index 83166456c7..7797de897b 100644 --- a/plugins/auth-backend/src/providers/saml/provider.ts +++ b/plugins/auth-backend/src/providers/saml/provider.ts @@ -37,7 +37,10 @@ import { SignInResolver, } from '@backstage/plugin-auth-node'; -/** @public */ +/** + * @public + * @deprecated Migrate the auth plugin to the new backend system https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin + */ export type SamlAuthResult = { fullProfile: any; }; From b6702ea5a2478aaf7b70f5823f42d6b45b62f836 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 27 Feb 2025 13:38:19 +0100 Subject: [PATCH 4/7] auth-backend: move getDefaultOwnershipEntityRefs to resolver context Signed-off-by: Patrik Oldsberg --- .changeset/four-readers-vanish.md | 5 ++++ .changeset/silver-fishes-shop.md | 23 ++++++++++++++++++ docs/auth/identity-resolver.md | 17 +++++++------ .../src/authenticator.test.ts | 2 ++ plugins/auth-backend/report.api.md | 2 +- .../resolvers/CatalogAuthResolverContext.ts | 24 ++++++++++++------- .../src/providers/oidc/provider.test.ts | 1 + plugins/auth-node/report.api.md | 3 +++ plugins/auth-node/src/types.ts | 8 +++++++ 9 files changed, 66 insertions(+), 19 deletions(-) create mode 100644 .changeset/four-readers-vanish.md create mode 100644 .changeset/silver-fishes-shop.md diff --git a/.changeset/four-readers-vanish.md b/.changeset/four-readers-vanish.md new file mode 100644 index 0000000000..6a1d4ffb5a --- /dev/null +++ b/.changeset/four-readers-vanish.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-node': patch +--- + +Added `AuthResolverContext.resolveOwnershipEntityRefs` as a way of accessing the default ownership resolution logic in sign-in resolvers, replacing `getDefaultOwnershipEntityRefs` from `@backstage/plugin-auth-backend`. diff --git a/.changeset/silver-fishes-shop.md b/.changeset/silver-fishes-shop.md new file mode 100644 index 0000000000..a757cc9b42 --- /dev/null +++ b/.changeset/silver-fishes-shop.md @@ -0,0 +1,23 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +Deprecated `getDefaultOwnershipEntityRefs` in favor of the new `.resolveOwnershipEntityRefs(...)` method in the `AuthResolverContext`. + +The following code in a custom sign-in resolver: + +```ts +import { getDefaultOwnershipEntityRefs } from '@backstage/plugin-auth-backend'; + +// ... + +const ent = getDefaultOwnershipEntityRefs(entity); +``` + +Can be replaced with the following: + +```ts +const { ownershipEntityRefs: ent } = await ctx.resolveOwnershipEntityRefs( + entity, +); +``` diff --git a/docs/auth/identity-resolver.md b/docs/auth/identity-resolver.md index 84e8726042..cce8f08b7a 100644 --- a/docs/auth/identity-resolver.md +++ b/docs/auth/identity-resolver.md @@ -298,10 +298,9 @@ of lower-level calls: ```ts // File: packages/backend/src/plugins/auth.ts -import { getDefaultOwnershipEntityRefs } from '@backstage/plugin-auth-backend'; // ... -async signInResolver({ profile: { email} }, ctx) { +async signInResolver({ profile: { email } }, ctx) { if (!email) { throw new Error('User profile contained no email'); } @@ -323,19 +322,19 @@ async signInResolver({ profile: { email} }, ctx) { // // You might also replace it if you for example want to filter out certain groups. // - // Note that `getDefaultOwnershipEntityRefs` only includes groups to which the - // user has a direct MEMBER_OF relationship. It's perfectly fine to include - // groups that the user is transitively part of in the claims array, but the - // catalog doesn't currently provide a direct way of accessing this list of - // groups. - const ownershipRefs = getDefaultOwnershipEntityRefs(entity); + // Note that `ctx.resolveOwnershipEntityRefs(...)` by default only includes groups + // to which the user has a direct MEMBER_OF relationship. + // It's perfectly fine to include groups that the user is transitively part of + // in the claims array, but the catalog doesn't currently provide a direct + // way of accessing this list of groups. + const { ownershipEntityRefs } = await ctx.resolveOwnershipEntityRefs(entity); // The last step is to issue the token, where we might provide more options in the // future. return ctx.issueToken({ claims: { sub: stringifyEntityRef(entity), - ent: ownershipRefs, + ent: ownershipEntityRefs, }, }); } diff --git a/plugins/auth-backend-module-vmware-cloud-provider/src/authenticator.test.ts b/plugins/auth-backend-module-vmware-cloud-provider/src/authenticator.test.ts index 0e363d4700..552c3068aa 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/src/authenticator.test.ts +++ b/plugins/auth-backend-module-vmware-cloud-provider/src/authenticator.test.ts @@ -235,6 +235,7 @@ describe('vmwareCloudAuthenticator', () => { signInWithCatalogUser: jest.fn().mockResolvedValue({ token: 'backstageToken', }), + resolveOwnershipEntityRefs: jest.fn(), }; oAuthState = { @@ -432,6 +433,7 @@ describe('vmwareCloudAuthenticator', () => { signInWithCatalogUser: jest.fn().mockResolvedValue({ token: 'backstageToken', }), + resolveOwnershipEntityRefs: jest.fn(), }; refreshRequest = { diff --git a/plugins/auth-backend/report.api.md b/plugins/auth-backend/report.api.md index 20690528d1..6187032d12 100644 --- a/plugins/auth-backend/report.api.md +++ b/plugins/auth-backend/report.api.md @@ -216,7 +216,7 @@ export type GcpIapResult = GcpIapResult_2; // @public @deprecated export type GcpIapTokenInfo = GcpIapTokenInfo_2; -// @public +// @public @deprecated export function getDefaultOwnershipEntityRefs(entity: Entity): string[]; // @public (undocumented) diff --git a/plugins/auth-backend/src/lib/resolvers/CatalogAuthResolverContext.ts b/plugins/auth-backend/src/lib/resolvers/CatalogAuthResolverContext.ts index 51b374b468..7f66179d81 100644 --- a/plugins/auth-backend/src/lib/resolvers/CatalogAuthResolverContext.ts +++ b/plugins/auth-backend/src/lib/resolvers/CatalogAuthResolverContext.ts @@ -46,6 +46,7 @@ import { CatalogIdentityClient } from '../catalog'; * A reference to the entity itself will also be included in the returned array. * * @public + * @deprecated use `ctx.resolveOwnershipEntityRefs(entity)` from the provided `AuthResolverContext` instead. */ export function getDefaultOwnershipEntityRefs(entity: Entity) { const membershipRefs = @@ -164,21 +165,26 @@ export class CatalogAuthResolverContext implements AuthResolverContext { async signInWithCatalogUser(query: AuthResolverCatalogUserQuery) { const { entity } = await this.findCatalogUser(query); - let ent: string[]; - if (this.ownershipResolver) { - const { ownershipEntityRefs } = - await this.ownershipResolver.resolveOwnershipEntityRefs(entity); - ent = ownershipEntityRefs; - } else { - ent = getDefaultOwnershipEntityRefs(entity); - } + + const { ownershipEntityRefs } = await this.resolveOwnershipEntityRefs( + entity, + ); const token = await this.tokenIssuer.issueToken({ claims: { sub: stringifyEntityRef(entity), - ent, + ent: ownershipEntityRefs, }, }); return { token }; } + + async resolveOwnershipEntityRefs( + entity: Entity, + ): Promise<{ ownershipEntityRefs: string[] }> { + if (this.ownershipResolver) { + return this.ownershipResolver.resolveOwnershipEntityRefs(entity); + } + return { ownershipEntityRefs: getDefaultOwnershipEntityRefs(entity) }; + } } diff --git a/plugins/auth-backend/src/providers/oidc/provider.test.ts b/plugins/auth-backend/src/providers/oidc/provider.test.ts index 89cf9c3b2c..773c5c8bb9 100644 --- a/plugins/auth-backend/src/providers/oidc/provider.test.ts +++ b/plugins/auth-backend/src/providers/oidc/provider.test.ts @@ -119,6 +119,7 @@ describe('oidc.create', () => { issueToken: jest.fn(), findCatalogUser: jest.fn(), signInWithCatalogUser: jest.fn(), + resolveOwnershipEntityRefs: jest.fn(), }, }; }); diff --git a/plugins/auth-node/report.api.md b/plugins/auth-node/report.api.md index 3b467c077f..f693683920 100644 --- a/plugins/auth-node/report.api.md +++ b/plugins/auth-node/report.api.md @@ -113,6 +113,9 @@ export type AuthResolverContext = { signInWithCatalogUser( query: AuthResolverCatalogUserQuery, ): Promise; + resolveOwnershipEntityRefs(entity: Entity): Promise<{ + ownershipEntityRefs: string[]; + }>; }; // @public diff --git a/plugins/auth-node/src/types.ts b/plugins/auth-node/src/types.ts index 845fd7b0cb..abcc6a2185 100644 --- a/plugins/auth-node/src/types.ts +++ b/plugins/auth-node/src/types.ts @@ -161,6 +161,14 @@ export type AuthResolverContext = { signInWithCatalogUser( query: AuthResolverCatalogUserQuery, ): Promise; + + /** + * Resolves the ownership entity references for the provided entity. + * This will use the `AuthOwnershipResolver` if one is installed, and otherwise fall back to the default resolution logic. + */ + resolveOwnershipEntityRefs( + entity: Entity, + ): Promise<{ ownershipEntityRefs: string[] }>; }; /** From 2d8b0e4d161dd16653ad3dc10a706f6fdc189d27 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 27 Feb 2025 15:23:38 +0100 Subject: [PATCH 5/7] proxy-backend: remove support for old backend system Signed-off-by: Patrik Oldsberg --- .changeset/olive-carrots-move.md | 7 + packages/backend-legacy/package.json | 1 - packages/backend-legacy/src/index.ts | 3 - packages/backend-legacy/src/plugins/proxy.ts | 29 -- plugins/proxy-backend/dev/index.ts | 2 +- plugins/proxy-backend/package.json | 19 +- plugins/proxy-backend/report-alpha.api.md | 13 - plugins/proxy-backend/report.api.md | 24 -- plugins/proxy-backend/src/alpha.ts | 21 -- plugins/proxy-backend/src/index.ts | 1 - plugins/proxy-backend/src/plugin.ts | 7 +- .../src/service/router.config.test.ts | 2 +- .../src/service/router.credentials.test.ts | 2 +- .../proxy-backend/src/service/router.test.ts | 300 +++++++++++------- plugins/proxy-backend/src/service/router.ts | 77 ++--- yarn.lock | 52 --- 16 files changed, 234 insertions(+), 326 deletions(-) create mode 100644 .changeset/olive-carrots-move.md delete mode 100644 packages/backend-legacy/src/plugins/proxy.ts delete mode 100644 plugins/proxy-backend/report-alpha.api.md delete mode 100644 plugins/proxy-backend/src/alpha.ts diff --git a/.changeset/olive-carrots-move.md b/.changeset/olive-carrots-move.md new file mode 100644 index 0000000000..b2cf4337b2 --- /dev/null +++ b/.changeset/olive-carrots-move.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-proxy-backend': minor +--- + +**BREAKING**: Removed support for the old backend system. + +As part of this change the plugin export from `/alpha` as been removed. If you are currently importing `@backstage/plugin-proxy-backend/alpha`, please update your import to `@backstage/plugin-proxy-backend`. diff --git a/packages/backend-legacy/package.json b/packages/backend-legacy/package.json index 45701ac660..e97f04a5ee 100644 --- a/packages/backend-legacy/package.json +++ b/packages/backend-legacy/package.json @@ -48,7 +48,6 @@ "@backstage/plugin-permission-backend": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", "@backstage/plugin-permission-node": "workspace:^", - "@backstage/plugin-proxy-backend": "workspace:^", "@backstage/plugin-scaffolder-backend": "workspace:^", "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "workspace:^", "@backstage/plugin-scaffolder-backend-module-gitlab": "workspace:^", diff --git a/packages/backend-legacy/src/index.ts b/packages/backend-legacy/src/index.ts index c883603efb..4632cddc56 100644 --- a/packages/backend-legacy/src/index.ts +++ b/packages/backend-legacy/src/index.ts @@ -42,7 +42,6 @@ import catalog from './plugins/catalog'; import events from './plugins/events'; import kubernetes from './plugins/kubernetes'; import scaffolder from './plugins/scaffolder'; -import proxy from './plugins/proxy'; import search from './plugins/search'; import techdocs from './plugins/techdocs'; import app from './plugins/app'; @@ -129,7 +128,6 @@ async function main() { const catalogEnv = useHotMemoize(module, () => createEnv('catalog')); const scaffolderEnv = useHotMemoize(module, () => createEnv('scaffolder')); const authEnv = useHotMemoize(module, () => createEnv('auth')); - const proxyEnv = useHotMemoize(module, () => createEnv('proxy')); const searchEnv = useHotMemoize(module, () => createEnv('search')); const techdocsEnv = useHotMemoize(module, () => createEnv('techdocs')); const kubernetesEnv = useHotMemoize(module, () => createEnv('kubernetes')); @@ -145,7 +143,6 @@ async function main() { apiRouter.use('/search', await search(searchEnv)); apiRouter.use('/techdocs', await techdocs(techdocsEnv)); apiRouter.use('/kubernetes', await kubernetes(kubernetesEnv)); - apiRouter.use('/proxy', await proxy(proxyEnv)); apiRouter.use('/permission', await permission(permissionEnv)); apiRouter.use(notFoundHandler()); diff --git a/packages/backend-legacy/src/plugins/proxy.ts b/packages/backend-legacy/src/plugins/proxy.ts deleted file mode 100644 index 273e791f1c..0000000000 --- a/packages/backend-legacy/src/plugins/proxy.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2020 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 { createRouter } from '@backstage/plugin-proxy-backend'; -import { Router } from 'express'; -import { PluginEnvironment } from '../types'; - -export default async function createPlugin( - env: PluginEnvironment, -): Promise { - return await createRouter({ - logger: env.logger, - config: env.config, - discovery: env.discovery, - }); -} diff --git a/plugins/proxy-backend/dev/index.ts b/plugins/proxy-backend/dev/index.ts index 4e4f84056a..e0e3f8fd43 100644 --- a/plugins/proxy-backend/dev/index.ts +++ b/plugins/proxy-backend/dev/index.ts @@ -19,7 +19,7 @@ import { createBackendModule } from '@backstage/backend-plugin-api'; import { proxyEndpointsExtensionPoint } from '@backstage/plugin-proxy-node/alpha'; const backend = createBackend(); -backend.add(import('../src/alpha')); +backend.add(import('../src')); backend.add( createBackendModule({ diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index da550487c8..69978f2a4e 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -24,16 +24,12 @@ "license": "Apache-2.0", "exports": { ".": "./src/index.ts", - "./alpha": "./src/alpha.ts", "./package.json": "./package.json" }, "main": "src/index.ts", "types": "src/index.ts", "typesVersions": { "*": { - "alpha": [ - "src/alpha.ts" - ], "package.json": [ "package.json" ] @@ -53,21 +49,11 @@ "test": "backstage-cli package test" }, "dependencies": { - "@backstage/backend-common": "^0.25.0", "@backstage/backend-plugin-api": "workspace:^", - "@backstage/config": "workspace:^", "@backstage/plugin-proxy-node": "workspace:^", "@backstage/types": "workspace:^", - "@types/express": "^4.17.6", - "express": "^4.17.1", "express-promise-router": "^4.1.0", - "http-proxy-middleware": "^2.0.0", - "morgan": "^1.10.0", - "uuid": "^11.0.0", - "winston": "^3.2.1", - "yaml": "^2.0.0", - "yn": "^4.0.0", - "yup": "^1.0.0" + "http-proxy-middleware": "^2.0.0" }, "devDependencies": { "@backstage/backend-app-api": "workspace:^", @@ -76,8 +62,9 @@ "@backstage/cli": "workspace:^", "@backstage/config-loader": "workspace:^", "@backstage/errors": "workspace:^", + "@types/express": "^4.17.6", "@types/http-proxy-middleware": "^1.0.0", - "@types/yup": "^0.32.0", + "express": "^4.17.1", "msw": "^2.0.0" }, "configSchema": "config.d.ts" diff --git a/plugins/proxy-backend/report-alpha.api.md b/plugins/proxy-backend/report-alpha.api.md deleted file mode 100644 index 4b3b1dfdc6..0000000000 --- a/plugins/proxy-backend/report-alpha.api.md +++ /dev/null @@ -1,13 +0,0 @@ -## API Report File for "@backstage/plugin-proxy-backend" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts -import { BackendFeature } from '@backstage/backend-plugin-api'; - -// @alpha (undocumented) -const _feature: BackendFeature; -export default _feature; - -// (No @packageDocumentation comment for this package) -``` diff --git a/plugins/proxy-backend/report.api.md b/plugins/proxy-backend/report.api.md index 90e7f54378..b0b38a8451 100644 --- a/plugins/proxy-backend/report.api.md +++ b/plugins/proxy-backend/report.api.md @@ -4,32 +4,8 @@ ```ts import { BackendFeature } from '@backstage/backend-plugin-api'; -import { DiscoveryService } from '@backstage/backend-plugin-api'; -import express from 'express'; -import { Logger } from 'winston'; -import { ProxyConfig } from '@backstage/plugin-proxy-node/alpha'; -import { RootConfigService } from '@backstage/backend-plugin-api'; - -// @public @deprecated -export function createRouter(options: RouterOptions): Promise; // @public const proxyPlugin: BackendFeature; export default proxyPlugin; - -// @public @deprecated (undocumented) -export interface RouterOptions { - // (undocumented) - additionalEndpoints?: ProxyConfig; - // (undocumented) - config: RootConfigService; - // (undocumented) - discovery: DiscoveryService; - // (undocumented) - logger: Logger; - // (undocumented) - reviveConsumedRequestBodies?: boolean; - // (undocumented) - skipInvalidProxies?: boolean; -} ``` diff --git a/plugins/proxy-backend/src/alpha.ts b/plugins/proxy-backend/src/alpha.ts deleted file mode 100644 index 6efe450ac3..0000000000 --- a/plugins/proxy-backend/src/alpha.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2023 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 { proxyPlugin } from './plugin'; - -/** @alpha */ -const _feature = proxyPlugin; -export default _feature; diff --git a/plugins/proxy-backend/src/index.ts b/plugins/proxy-backend/src/index.ts index ae0b6235f9..6383d3fa55 100644 --- a/plugins/proxy-backend/src/index.ts +++ b/plugins/proxy-backend/src/index.ts @@ -21,4 +21,3 @@ */ export { proxyPlugin as default } from './plugin'; -export * from './service'; diff --git a/plugins/proxy-backend/src/plugin.ts b/plugins/proxy-backend/src/plugin.ts index 52c1c26acd..6124b0bc66 100644 --- a/plugins/proxy-backend/src/plugin.ts +++ b/plugins/proxy-backend/src/plugin.ts @@ -14,12 +14,11 @@ * limitations under the License. */ -import { loggerToWinstonLogger } from '@backstage/backend-common'; import { createBackendPlugin, coreServices, } from '@backstage/backend-plugin-api'; -import { createRouterInternal } from './service/router'; +import { createRouter } from './service/router'; import { proxyEndpointsExtensionPoint } from '@backstage/plugin-proxy-node/alpha'; /** @@ -45,10 +44,10 @@ export const proxyPlugin = createBackendPlugin({ httpRouter: coreServices.httpRouter, }, async init({ config, discovery, logger, httpRouter }) { - await createRouterInternal({ + await createRouter({ config, discovery, - logger: loggerToWinstonLogger(logger), + logger, httpRouterService: httpRouter, additionalEndpoints, }); diff --git a/plugins/proxy-backend/src/service/router.config.test.ts b/plugins/proxy-backend/src/service/router.config.test.ts index d862107e00..6f81659ceb 100644 --- a/plugins/proxy-backend/src/service/router.config.test.ts +++ b/plugins/proxy-backend/src/service/router.config.test.ts @@ -60,7 +60,7 @@ describe('createRouter reloadable configuration', () => { const backend = await startTestBackend({ features: [ - import('../alpha'), + import('..'), createServiceFactory({ service: coreServices.rootConfig, deps: {}, diff --git a/plugins/proxy-backend/src/service/router.credentials.test.ts b/plugins/proxy-backend/src/service/router.credentials.test.ts index 6d1f529b30..6ed7e636ec 100644 --- a/plugins/proxy-backend/src/service/router.credentials.test.ts +++ b/plugins/proxy-backend/src/service/router.credentials.test.ts @@ -77,7 +77,7 @@ describe('credentials', () => { const backend = await startTestBackend({ features: [ - import('../alpha'), + import('..'), mockServices.rootConfig.factory({ data: config }), authServiceFactory, httpAuthServiceFactory, diff --git a/plugins/proxy-backend/src/service/router.test.ts b/plugins/proxy-backend/src/service/router.test.ts index 8dcabed16b..66d6de2f28 100644 --- a/plugins/proxy-backend/src/service/router.test.ts +++ b/plugins/proxy-backend/src/service/router.test.ts @@ -14,12 +14,7 @@ * limitations under the License. */ -import { - HostDiscovery, - loggerToWinstonLogger, -} from '@backstage/backend-common'; import { mockServices } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; import { Request, Response } from 'express'; import * as http from 'http'; import { @@ -39,27 +34,37 @@ const mockCreateProxyMiddleware = createProxyMiddleware as jest.MockedFunction< >; describe('createRouter', () => { + const deps = { + logger: mockServices.logger.mock(), + discovery: mockServices.discovery(), + httpRouterService: mockServices.httpRouter.mock(), + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + describe('where all proxy config are valid', () => { - const logger = loggerToWinstonLogger(mockServices.logger.mock()); - const config = new ConfigReader({ - backend: { - baseUrl: 'https://example.com:7007', - listen: { - port: 7007, + const config = mockServices.rootConfig({ + data: { + backend: { + baseUrl: 'https://example.com:7007', + listen: { + port: 7007, + }, }, - }, - proxy: { - endpoints: { - '/test': { - target: 'https://example.com', - headers: { - Authorization: 'Bearer supersecret', + proxy: { + endpoints: { + '/test': { + target: 'https://example.com', + headers: { + Authorization: 'Bearer supersecret', + }, }, }, }, }, }); - const discovery = HostDiscovery.fromConfig(config); beforeEach(() => { mockCreateProxyMiddleware.mockClear(); @@ -67,29 +72,29 @@ describe('createRouter', () => { it('works', async () => { const router = await createRouter({ + ...deps, config, - logger, - discovery, }); expect(router).toBeDefined(); }); it('supports deprecated proxy configuration', async () => { const router = await createRouter({ + ...deps, config: mockServices.rootConfig({ data: { proxy: { - '/test': { - target: 'https://example.com', - headers: { - Authorization: 'Bearer supersecret', + endpoints: { + '/test': { + target: 'https://example.com', + headers: { + Authorization: 'Bearer supersecret', + }, }, }, }, }, }), - logger, - discovery, }); expect(router).toBeDefined(); expect(mockCreateProxyMiddleware).toHaveBeenCalledWith( @@ -102,10 +107,22 @@ describe('createRouter', () => { it('revives request bodies when set', async () => { const router = await createRouter({ - config, - logger, - discovery, - reviveConsumedRequestBodies: true, + ...deps, + config: mockServices.rootConfig({ + data: { + proxy: { + endpoints: { + '/test': { + target: 'https://example.com', + headers: { + Authorization: 'Bearer supersecret', + }, + }, + }, + reviveConsumedRequestBodies: true, + }, + }, + }), }); expect(router).toBeDefined(); @@ -120,8 +137,7 @@ describe('createRouter', () => { it('does not revive request bodies when not set', async () => { const router = await createRouter({ config, - logger, - discovery, + ...deps, }); expect(router).toBeDefined(); @@ -133,32 +149,30 @@ describe('createRouter', () => { describe('where buildMiddleware would fail', () => { it('throws an error if skip failures is not set', async () => { - const logger = loggerToWinstonLogger(mockServices.logger.mock()); - logger.warn = jest.fn(); - const config = new ConfigReader({ - backend: { - baseUrl: 'https://example.com:7007', - listen: { - port: 7007, + const config = mockServices.rootConfig({ + data: { + backend: { + baseUrl: 'https://example.com:7007', + listen: { + port: 7007, + }, }, - }, - // no target would cause the buildMiddleware to fail - proxy: { - endpoints: { - '/test': { - headers: { - Authorization: 'Bearer supersecret', + // no target would cause the buildMiddleware to fail + proxy: { + endpoints: { + '/test': { + headers: { + Authorization: 'Bearer supersecret', + }, }, }, }, }, }); - const discovery = HostDiscovery.fromConfig(config); await expect( createRouter({ + ...deps, config, - logger, - discovery, }), ).rejects.toThrow( new Error( @@ -168,34 +182,32 @@ describe('createRouter', () => { }); it('works if skip failures is set', async () => { - const logger = loggerToWinstonLogger(mockServices.logger.mock()); - logger.warn = jest.fn(); - const config = new ConfigReader({ - backend: { - baseUrl: 'https://example.com:7007', - listen: { - port: 7007, - }, - }, - // no target would cause the buildMiddleware to fail - proxy: { - endpoints: { - '/test': { - headers: { - Authorization: 'Bearer supersecret', - }, + const config = mockServices.rootConfig({ + data: { + backend: { + baseUrl: 'https://example.com:7007', + listen: { + port: 7007, }, }, + // no target would cause the buildMiddleware to fail + proxy: { + endpoints: { + '/test': { + headers: { + Authorization: 'Bearer supersecret', + }, + }, + }, + skipInvalidProxies: true, + }, }, }); - const discovery = HostDiscovery.fromConfig(config); const router = await createRouter({ + ...deps, config, - logger, - discovery, - skipInvalidProxies: true, }); - expect((logger.warn as jest.Mock).mock.calls[0][0]).toEqual( + expect(deps.logger.warn.mock.calls[0][0]).toEqual( 'skipped configuring /test due to Proxy target for route "/test" must be a string, but is of type undefined', ); expect(router).toBeDefined(); @@ -204,14 +216,21 @@ describe('createRouter', () => { }); describe('buildMiddleware', () => { - const logger = loggerToWinstonLogger(mockServices.logger.mock()); + const logger = mockServices.logger.mock(); + const httpRouterService = mockServices.httpRouter.mock(); beforeEach(() => { mockCreateProxyMiddleware.mockClear(); }); it('accepts strings prefixed by /', async () => { - buildMiddleware('/proxy', logger, '/test', 'http://mocked'); + buildMiddleware( + '/proxy', + logger, + '/test', + 'http://mocked', + httpRouterService, + ); expect(createProxyMiddleware).toHaveBeenCalledTimes(1); @@ -227,11 +246,20 @@ describe('buildMiddleware', () => { expect(fullConfig.pathRewrite).toEqual({ '^/proxy/test/?': '/' }); expect(fullConfig.changeOrigin).toBe(true); - expect(fullConfig.logProvider!(logger)).toBe(logger); + + expect(logger.info).not.toHaveBeenCalled(); + fullConfig.logProvider!({} as any).log('test'); + expect(logger.info).toHaveBeenCalledWith('test'); }); it('accepts routes not prefixed with / when path is not suffixed with /', async () => { - buildMiddleware('/proxy', logger, 'test', 'http://mocked'); + buildMiddleware( + '/proxy', + logger, + 'test', + 'http://mocked', + httpRouterService, + ); expect(createProxyMiddleware).toHaveBeenCalledTimes(1); @@ -247,11 +275,16 @@ describe('buildMiddleware', () => { expect(fullConfig.pathRewrite).toEqual({ '^/proxy/test/?': '/' }); expect(fullConfig.changeOrigin).toBe(true); - expect(fullConfig.logProvider!(logger)).toBe(logger); }); it('accepts routes prefixed with / when path is suffixed with /', async () => { - buildMiddleware('/proxy/', logger, '/test', 'http://mocked'); + buildMiddleware( + '/proxy/', + logger, + '/test', + 'http://mocked', + httpRouterService, + ); expect(createProxyMiddleware).toHaveBeenCalledTimes(1); @@ -267,14 +300,19 @@ describe('buildMiddleware', () => { expect(fullConfig.pathRewrite).toEqual({ '^/proxy/test/?': '/' }); expect(fullConfig.changeOrigin).toBe(true); - expect(fullConfig.logProvider!(logger)).toBe(logger); }); it('limits allowedMethods', async () => { - buildMiddleware('/proxy', logger, '/test', { - target: 'http://mocked', - allowedMethods: ['GET', 'DELETE'], - }); + buildMiddleware( + '/proxy', + logger, + '/test', + { + target: 'http://mocked', + allowedMethods: ['GET', 'DELETE'], + }, + httpRouterService, + ); expect(createProxyMiddleware).toHaveBeenCalledTimes(1); @@ -290,13 +328,18 @@ describe('buildMiddleware', () => { expect(fullConfig.pathRewrite).toEqual({ '^/proxy/test/?': '/' }); expect(fullConfig.changeOrigin).toBe(true); - expect(fullConfig.logProvider!(logger)).toBe(logger); }); it('permits default headers', async () => { - buildMiddleware('/proxy', logger, '/test', { - target: 'http://mocked', - }); + buildMiddleware( + '/proxy', + logger, + '/test', + { + target: 'http://mocked', + }, + httpRouterService, + ); expect(createProxyMiddleware).toHaveBeenCalledTimes(1); @@ -334,12 +377,18 @@ describe('buildMiddleware', () => { }); it('permits default and configured headers', async () => { - buildMiddleware('/proxy', logger, '/test', { - target: 'http://mocked', - headers: { - Authorization: 'my-token', + buildMiddleware( + '/proxy', + logger, + '/test', + { + target: 'http://mocked', + headers: { + Authorization: 'my-token', + }, }, - }); + httpRouterService, + ); expect(createProxyMiddleware).toHaveBeenCalledTimes(1); @@ -367,10 +416,16 @@ describe('buildMiddleware', () => { }); it('permits configured headers', async () => { - buildMiddleware('/proxy', logger, '/test', { - target: 'http://mocked', - allowedHeaders: ['authorization', 'cookie'], - }); + buildMiddleware( + '/proxy', + logger, + '/test', + { + target: 'http://mocked', + allowedHeaders: ['authorization', 'cookie'], + }, + httpRouterService, + ); expect(createProxyMiddleware).toHaveBeenCalledTimes(1); @@ -399,9 +454,15 @@ describe('buildMiddleware', () => { }); it('responds default headers', async () => { - buildMiddleware('/proxy', logger, '/test', { - target: 'http://mocked', - }); + buildMiddleware( + '/proxy', + logger, + '/test', + { + target: 'http://mocked', + }, + httpRouterService, + ); expect(createProxyMiddleware).toHaveBeenCalledTimes(1); @@ -441,10 +502,16 @@ describe('buildMiddleware', () => { }); it('responds configured headers', async () => { - buildMiddleware('/proxy', logger, '/test', { - target: 'http://mocked', - allowedHeaders: ['set-cookie'], - }); + buildMiddleware( + '/proxy', + logger, + '/test', + { + target: 'http://mocked', + allowedHeaders: ['set-cookie'], + }, + httpRouterService, + ); expect(createProxyMiddleware).toHaveBeenCalledTimes(1); @@ -477,6 +544,7 @@ describe('buildMiddleware', () => { { target: 'http://mocked', }, + httpRouterService, true, ); @@ -497,9 +565,15 @@ describe('buildMiddleware', () => { }); it('does not revive request body when not configured', async () => { - buildMiddleware('/proxy', logger, '/test', { - target: 'http://mocked', - }); + buildMiddleware( + '/proxy', + logger, + '/test', + { + target: 'http://mocked', + }, + httpRouterService, + ); expect(createProxyMiddleware).toHaveBeenCalledTimes(1); @@ -511,10 +585,22 @@ describe('buildMiddleware', () => { it('rejects malformed target URLs', async () => { expect(() => - buildMiddleware('/proxy', logger, '/test', 'backstage.io'), + buildMiddleware( + '/proxy', + logger, + '/test', + 'backstage.io', + httpRouterService, + ), ).toThrow(/Proxy target is not a valid URL/); expect(() => - buildMiddleware('/proxy', logger, '/test', { target: 'backstage.io' }), + buildMiddleware( + '/proxy', + logger, + '/test', + { target: 'backstage.io' }, + httpRouterService, + ), ).toThrow(/Proxy target is not a valid URL/); }); }); diff --git a/plugins/proxy-backend/src/service/router.ts b/plugins/proxy-backend/src/service/router.ts index 934b1fcecb..a6a52db63a 100644 --- a/plugins/proxy-backend/src/service/router.ts +++ b/plugins/proxy-backend/src/service/router.ts @@ -14,20 +14,19 @@ * limitations under the License. */ -import { Config } from '@backstage/config'; -import express from 'express'; +import type express from 'express'; import Router from 'express-promise-router'; import { createProxyMiddleware, fixRequestBody, RequestHandler, } from 'http-proxy-middleware'; -import { Logger } from 'winston'; import http from 'http'; import { JsonObject } from '@backstage/types'; import { DiscoveryService, HttpRouterService, + LoggerService, RootConfigService, } from '@backstage/backend-plugin-api'; import { ProxyConfig } from '@backstage/plugin-proxy-node/alpha'; @@ -54,15 +53,13 @@ const safeForwardHeaders = [ ]; /** - * @public - * @deprecated Please migrate to the new backend system as this will be removed in the future. + * @internal */ export interface RouterOptions { - logger: Logger; + logger: LoggerService; config: RootConfigService; discovery: DiscoveryService; - skipInvalidProxies?: boolean; - reviveConsumedRequestBodies?: boolean; + httpRouterService: HttpRouterService; additionalEndpoints?: ProxyConfig; } @@ -70,11 +67,11 @@ export interface RouterOptions { // given config. export function buildMiddleware( pathPrefix: string, - logger: Logger, + logger: LoggerService, route: string, config: string | ProxyConfig, + httpRouterService: HttpRouterService, reviveConsumedRequestBodies?: boolean, - httpRouterService?: HttpRouterService, ): RequestHandler { let fullConfig: ProxyConfig; let credentialsPolicy: string; @@ -100,7 +97,7 @@ export function buildMiddleware( } if (credentialsPolicy === 'dangerously-allow-unauthenticated') { - httpRouterService?.addAuthPolicy({ + httpRouterService.addAuthPolicy({ path: route, allow: 'unauthenticated', }); @@ -154,7 +151,13 @@ export function buildMiddleware( } // Attach the logger to the proxy config - fullConfig.logProvider = () => logger; + fullConfig.logProvider = () => ({ + log: logger.info.bind(logger), + debug: logger.debug.bind(logger), + info: logger.info.bind(logger), + warn: logger.warn.bind(logger), + error: logger.error.bind(logger), + }); // http-proxy-middleware uses this log level to check if it should log the // requests that it proxies. Setting this to the most verbose log level // ensures that it always logs these requests. Our logger ends up deciding @@ -229,7 +232,10 @@ export function buildMiddleware( return createProxyMiddleware(filter, fullConfig); } -function readProxyConfig(config: Config, logger: Logger): JsonObject { +function readProxyConfig( + config: RootConfigService, + logger: LoggerService, +): JsonObject { const endpoints = config .getOptionalConfig('proxy.endpoints') ?.get(); @@ -256,49 +262,16 @@ function readProxyConfig(config: Config, logger: Logger): JsonObject { return rootEndpoints; } -/** - * Creates a new - * {@link https://expressjs.com/en/api.html#router | "express router"} that - * proxies each target configured under the `proxy.endpoints` key of the config. - * - * @remarks - * - * Example configuration: - * - * ```yaml - * proxy: - * endpoints: - * # Option 1: Simple URL String - * simple-example: http://simple.example.com:8080 - * # Option 2: `http-proxy-middleware` compatible object - * '/larger-example/v1': - * target: http://larger.example.com:8080/svc.v1 - * headers: - * Authorization: Bearer ${EXAMPLE_AUTH_TOKEN} - * ``` - * - * @see https://backstage.io/docs/plugins/proxying - * @public - * @deprecated Please migrate to the new backend system as this will be removed in the future. - */ +/** @internal */ export async function createRouter( options: RouterOptions, -): Promise { - return createRouterInternal(options); -} - -export async function createRouterInternal( - options: RouterOptions & { httpRouterService?: HttpRouterService }, ): Promise { const router = Router(); let currentRouter = Router(); const skipInvalidProxies = - options.skipInvalidProxies ?? - options.config.getOptionalBoolean('proxy.skipInvalidProxies') ?? - false; + options.config.getOptionalBoolean('proxy.skipInvalidProxies') ?? false; const reviveConsumedRequestBodies = - options.reviveConsumedRequestBodies ?? options.config.getOptionalBoolean('proxy.reviveConsumedRequestBodies') ?? false; const proxyOptions = { @@ -345,7 +318,7 @@ export async function createRouterInternal( }); } - options.httpRouterService?.use(router); + options.httpRouterService.use(router); return router; } @@ -353,12 +326,12 @@ function configureMiddlewares( options: { reviveConsumedRequestBodies: boolean; skipInvalidProxies: boolean; - logger: Logger; + logger: LoggerService; }, router: express.Router, pathPrefix: string, proxyConfig: ProxyConfig, - httpRouterService?: HttpRouterService, + httpRouterService: HttpRouterService, ) { Object.entries(proxyConfig).forEach(([route, proxyRouteConfig]) => { try { @@ -369,8 +342,8 @@ function configureMiddlewares( options.logger, route, proxyRouteConfig, - options.reviveConsumedRequestBodies, httpRouterService, + options.reviveConsumedRequestBodies, ), ); } catch (e) { diff --git a/yarn.lock b/yarn.lock index 6df31ca425..b85ee80a51 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7054,29 +7054,20 @@ __metadata: resolution: "@backstage/plugin-proxy-backend@workspace:plugins/proxy-backend" dependencies: "@backstage/backend-app-api": "workspace:^" - "@backstage/backend-common": ^0.25.0 "@backstage/backend-defaults": "workspace:^" "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-test-utils": "workspace:^" "@backstage/cli": "workspace:^" - "@backstage/config": "workspace:^" "@backstage/config-loader": "workspace:^" "@backstage/errors": "workspace:^" "@backstage/plugin-proxy-node": "workspace:^" "@backstage/types": "workspace:^" "@types/express": ^4.17.6 "@types/http-proxy-middleware": ^1.0.0 - "@types/yup": ^0.32.0 express: ^4.17.1 express-promise-router: ^4.1.0 http-proxy-middleware: ^2.0.0 - morgan: ^1.10.0 msw: ^2.0.0 - uuid: ^11.0.0 - winston: ^3.2.1 - yaml: ^2.0.0 - yn: ^4.0.0 - yup: ^1.0.0 languageName: unknown linkType: soft @@ -20752,15 +20743,6 @@ __metadata: languageName: node linkType: hard -"@types/yup@npm:^0.32.0": - version: 0.32.0 - resolution: "@types/yup@npm:0.32.0" - dependencies: - yup: "*" - checksum: 5b30f1118bca288d949bcd4c7e17d1425ffa320eddd751a78c895b158fae0b6cbf242ced45ad47e9e70643c9475da09a7ad004192fb6f2111791d37e6a627e73 - languageName: node - linkType: hard - "@types/zen-observable@npm:^0.8.0": version: 0.8.7 resolution: "@types/zen-observable@npm:0.8.7" @@ -28684,7 +28666,6 @@ __metadata: "@backstage/plugin-permission-backend": "workspace:^" "@backstage/plugin-permission-common": "workspace:^" "@backstage/plugin-permission-node": "workspace:^" - "@backstage/plugin-proxy-backend": "workspace:^" "@backstage/plugin-scaffolder-backend": "workspace:^" "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "workspace:^" "@backstage/plugin-scaffolder-backend-module-gitlab": "workspace:^" @@ -40224,13 +40205,6 @@ __metadata: languageName: node linkType: hard -"property-expr@npm:^2.0.5": - version: 2.0.6 - resolution: "property-expr@npm:2.0.6" - checksum: 89977f4bb230736c1876f460dd7ca9328034502fd92e738deb40516d16564b850c0bbc4e052c3df88b5b8cd58e51c93b46a94bea049a3f23f4a022c038864cab - languageName: node - linkType: hard - "property-information@npm:^5.0.0": version: 5.6.0 resolution: "property-information@npm:5.6.0" @@ -44997,13 +44971,6 @@ __metadata: languageName: node linkType: hard -"tiny-case@npm:^1.0.3": - version: 1.0.3 - resolution: "tiny-case@npm:1.0.3" - checksum: 3f7a30c39d5b0e1bc097b0b271bec14eb5b836093db034f35a0de26c14422380b50dc12bfd37498cf35b192f5df06f28a710712c87ead68872a9e37ad6f6049d - languageName: node - linkType: hard - "tiny-glob@npm:0.2.9": version: 0.2.9 resolution: "tiny-glob@npm:0.2.9" @@ -45149,13 +45116,6 @@ __metadata: languageName: node linkType: hard -"toposort@npm:^2.0.2": - version: 2.0.2 - resolution: "toposort@npm:2.0.2" - checksum: d64c74b570391c9432873f48e231b439ee56bc49f7cb9780b505cfdf5cb832f808d0bae072515d93834dd6bceca5bb34448b5b4b408335e4d4716eaf68195dcb - languageName: node - linkType: hard - "tosource@npm:^2.0.0-alpha.3": version: 2.0.0-alpha.3 resolution: "tosource@npm:2.0.0-alpha.3" @@ -47844,18 +47804,6 @@ __metadata: languageName: node linkType: hard -"yup@npm:*, yup@npm:^1.0.0": - version: 1.4.0 - resolution: "yup@npm:1.4.0" - dependencies: - property-expr: ^2.0.5 - tiny-case: ^1.0.3 - toposort: ^2.0.2 - type-fest: ^2.19.0 - checksum: 20a2ee0c1e891979ca16b34805b3a3be9ab4bea6ea3d2f9005b998b4dc992d0e4d7b53e5f4d8d9423420046630fb44fdf0ecf7e83bc34dd83392bca046c5229d - languageName: node - linkType: hard - "zen-observable@npm:^0.10.0": version: 0.10.0 resolution: "zen-observable@npm:0.10.0" From ba63794eb2a3483f43fed36f174af2965638f52b Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Thu, 27 Feb 2025 12:27:29 -0600 Subject: [PATCH 6/7] Added Catalog Collator filter example Signed-off-by: Andre Wanlin --- docs/features/search/collators.md | 40 +++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/docs/features/search/collators.md b/docs/features/search/collators.md index 0282bc845e..834a14437a 100644 --- a/docs/features/search/collators.md +++ b/docs/features/search/collators.md @@ -35,6 +35,10 @@ backend.start(); ### Configuring the Catalog Collator +The following sections outlines the available configurations for this collator. + +#### Scheduling + The default schedule for the Catalog Collator is to run every 10 minutes, you can provide your own schedule by adding it to your config: ```yaml title="app-config.yaml @@ -50,6 +54,42 @@ search: timeout: { minutes: 3 } ``` +#### Filtering + +You may wish to collate specific subsets of entities in your Catalog, this can be accomplished using the `filter` configuration option. Here's a basic example: + +```yaml title"app-config.yaml" +search: + collators: + catalog: + filter: + kind: ['component', 'api'] + spec.lifecycle: production +``` + +The above example will only collate entities that are `kind` equal to `component` or `api` AND have a `spec.lifecycle` set to `production` + +You can also apply a more advanced filter like this: + +```yaml title"app-config.yaml" +search: + collators: + catalog: + filter: + - kind: ['API'] + spec.type: openapi + - kind: ['Component'] + spec.lifecycle: experimental +``` + +Now with this example it will collate all entities that are `kind` equal to `api` with a `spec.type` equal to `openapi` OR all entities that are `kind` equal to `component` AND have a `spec.lifecycle` set to `experimental` + +:::tip + +The filter configuration is implemented using the `EntityFilterQuery` syntax. The [reference documentation on `EntityFilterQuery`](https://backstage.io/docs/reference/catalog-client.entityfilterquery/) provides more details. + +::: + ## TechDocs The TechDocs collator will index all the TechDocs in your Catalog. It is installed by default but if you need to add it manually here's how. From f571d10497f723aafd8d7be68182083304d18cd8 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Thu, 27 Feb 2025 12:30:33 -0600 Subject: [PATCH 7/7] Removed legacy example Signed-off-by: Andre Wanlin --- docs/features/search/how-to-guides.md | 34 --------------------------- 1 file changed, 34 deletions(-) diff --git a/docs/features/search/how-to-guides.md b/docs/features/search/how-to-guides.md index 007b108df5..0476ef6c24 100644 --- a/docs/features/search/how-to-guides.md +++ b/docs/features/search/how-to-guides.md @@ -111,40 +111,6 @@ indexBuilder.addCollator({ }); ``` -## How to limit what can be searched in the Software Catalog - -The Software Catalog includes a wealth of information about the components, -systems, groups, users, and other aspects of your software ecosystem. However, -you may not always want _every_ aspect to appear when a user searches the -catalog. Examples include: - -- Entities of kind `Location`, which are often not useful to Backstage users. -- Entities of kind `User` or `Group`, if you'd prefer that users and groups be - exposed to search in a different way (or not at all). - -It's possible to write your own [Collator](./concepts.md#collators) to control -exactly what's available to search, (or a [Decorator](./concepts.md#decorators) -to filter things out here and there), but the `DefaultCatalogCollator` that's -provided by `@backstage/plugin-catalog-backend` offers some configuration too! - -```ts title="packages/backend/src/plugins/search.ts" -indexBuilder.addCollator({ - defaultRefreshIntervalSeconds: 600, - collator: DefaultCatalogCollator.fromConfig(env.config, { - discovery: env.discovery, - tokenManager: env.tokenManager, - /* highlight-add-start */ - filter: { - kind: ['API', 'Component', 'Domain', 'Group', 'System', 'User'], - }, - /* highlight-add-end */ - }), -}); -``` - -As shown above, you can add a catalog entity filter to narrow down what catalog -entities are indexed by the search engine. - ## How to customize search results highlighting styling The default highlighting styling for matched terms in search results is your