` tags to avoid word break.
diff --git a/.changeset/thick-pillows-develop.md b/.changeset/thick-pillows-develop.md
new file mode 100644
index 0000000000..9be71da55d
--- /dev/null
+++ b/.changeset/thick-pillows-develop.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-tech-insights-backend': patch
+---
+
+Added support for the new `AuthService`.
diff --git a/.changeset/thick-pillows-punch.md b/.changeset/thick-pillows-punch.md
deleted file mode 100644
index def589d3f8..0000000000
--- a/.changeset/thick-pillows-punch.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-scaffolder-node': patch
----
-
-Add gitea as new type to be used from integrations configuration
diff --git a/.changeset/thin-spiders-do.md b/.changeset/thin-spiders-do.md
new file mode 100644
index 0000000000..df8672fd6c
--- /dev/null
+++ b/.changeset/thin-spiders-do.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-catalog-backend-module-backstage-openapi': patch
+---
+
+Migrated to use new auth service.
diff --git a/.changeset/thin-turtles-float.md b/.changeset/thin-turtles-float.md
deleted file mode 100644
index 7416093e17..0000000000
--- a/.changeset/thin-turtles-float.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-kubernetes-backend': patch
----
-
-Clusters in the catalog can now specify a human-readable title via `metadata.title`.
diff --git a/.changeset/thirty-bags-try.md b/.changeset/thirty-bags-try.md
deleted file mode 100644
index 98d6c5620b..0000000000
--- a/.changeset/thirty-bags-try.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-'@backstage/plugin-catalog-backend': minor
-'@backstage/plugin-catalog-node': minor
----
-
-Adds support for supplying field validators to the new backend's catalog plugin. If you're using entity policies, you should use the new `transformLegacyPolicyToProcessor` function to install them as processors instead.
-
-```ts
-import {
- catalogProcessingExtensionPoint,
- catalogModelExtensionPoint,
-} from '@backstage/plugin-catalog-node/alpha';
-import {myPolicy} from './my-policy';
-
-export const catalogModulePolicyProvider = createBackendModule({
- pluginId: 'catalog',
- moduleId: 'internal-policy-provider',
- register(reg) {
- reg.registerInit({
- deps: {
- modelExtensions: catalogModelExtensionPoint,
- processingExtensions: catalogProcessingExtensionPoint,
- },
- async init({ modelExtensions, processingExtensions }) {
- modelExtensions.setFieldValidators({
- ...
- });
- processingExtensions.addProcessors(transformLegacyPolicyToProcessor(myPolicy))
- },
- });
- },
-});
-```
diff --git a/.changeset/thirty-bikes-stare.md b/.changeset/thirty-bikes-stare.md
new file mode 100644
index 0000000000..d8249299a7
--- /dev/null
+++ b/.changeset/thirty-bikes-stare.md
@@ -0,0 +1,7 @@
+---
+'@backstage/plugin-scaffolder-node-test-utils': patch
+'@backstage/plugin-scaffolder-backend': patch
+'@backstage/plugin-scaffolder-node': patch
+---
+
+Made "checkpoint" on scaffolder action context non-optional
diff --git a/.changeset/thirty-dolls-admire.md b/.changeset/thirty-dolls-admire.md
deleted file mode 100644
index 1011508a98..0000000000
--- a/.changeset/thirty-dolls-admire.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-catalog-backend-module-github': minor
----
-
-Prevent Entity Providers from eliminating Users and Groups from the DB when the synchronisation fails
diff --git a/.changeset/thirty-shirts-allow.md b/.changeset/thirty-shirts-allow.md
new file mode 100644
index 0000000000..b84a3a621e
--- /dev/null
+++ b/.changeset/thirty-shirts-allow.md
@@ -0,0 +1,7 @@
+---
+'@backstage/backend-common': patch
+---
+
+Added a `createLegacyAuthAdapters` function that can be used as a compatibility adapter for backend plugins who want to start using the new [`auth`](https://backstage.io/docs/backend-system/core-services/auth/) and [`httpAuth`](https://backstage.io/docs/backend-system/core-services/http-auth) services that were created as part of [BEP-0003](https://github.com/backstage/backstage/tree/master/beps/0003-auth-architecture-evolution).
+
+See the [Auth Service Migration tutorial](https://backstage.io/docs/tutorials/auth-service-migration) for more information on the usage of this adapter.
diff --git a/.changeset/tidy-cooks-mix.md b/.changeset/tidy-cooks-mix.md
deleted file mode 100644
index 873de64a45..0000000000
--- a/.changeset/tidy-cooks-mix.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-'@backstage/plugin-azure-sites-backend': patch
-'@backstage/plugin-azure-sites-common': patch
-'@backstage/plugin-azure-sites': patch
----
-
-Azure Sites `start` and `stop` action is now protected with the Permissions framework.
-
-The below example describes an action that forbids anyone but the owner of the catalog entity to trigger actions towards a site tied to an entity.
-
-```typescript
- // packages/backend/src/plugins/permission.ts
- import { azureSitesActionPermission } from '@backstage/plugin-azure-sites-common';
- ...
- class TestPermissionPolicy implements PermissionPolicy {
- async handle(request: PolicyQuery, user?: BackstageIdentityResponse): Promise {
- if (isPermission(request.permission, azureSitesActionPermission)) {
- return createCatalogConditionalDecision(
- request.permission,
- catalogConditions.isEntityOwner({
- claims: user?.identity.ownershipEntityRefs ?? [],
- }),
- );
- }
- ...
- return {
- result: AuthorizeResult.ALLOW,
- };
- }
- ...
- }
-```
diff --git a/.changeset/tidy-cooks-mixed.md b/.changeset/tidy-cooks-mixed.md
deleted file mode 100644
index a72f1ee0df..0000000000
--- a/.changeset/tidy-cooks-mixed.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-'@backstage/plugin-azure-sites-backend': minor
----
-
-**BREAKING**: `catalogApi` and `permissionsApi` are now a requirement to be passed through to the `createRouter` function.
-
-You can fix the typescript issues by passing through the required dependencies like the below `diff` shows:
-
-```diff
- import {
- createRouter,
- AzureSitesApi,
- } from '@backstage/plugin-azure-sites-backend';
- import { Router } from 'express';
- import { PluginEnvironment } from '../types';
-
- export default async function createPlugin(
- env: PluginEnvironment,
- ): Promise {
-+ const catalogClient = new CatalogClient({
-+ discoveryApi: env.discovery,
-+ });
-
- return await createRouter({
- logger: env.logger,
- azureSitesApi: AzureSitesApi.fromConfig(env.config),
-+ catalogApi: catalogClient,
-+ permissionsApi: env.permissions,
- });
- }
-```
diff --git a/.changeset/tidy-cycles-obey.md b/.changeset/tidy-cycles-obey.md
deleted file mode 100644
index 4a002269e1..0000000000
--- a/.changeset/tidy-cycles-obey.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-'@backstage/plugin-scaffolder-react': patch
-'@backstage/plugin-scaffolder': patch
----
-
-Remove unused deps
diff --git a/.changeset/tidy-peaches-nail.md b/.changeset/tidy-peaches-nail.md
deleted file mode 100644
index d044a6bfaa..0000000000
--- a/.changeset/tidy-peaches-nail.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-kubernetes-backend': patch
----
-
-Clusters in the app-config can now specify a `title` property for human readability.
diff --git a/.changeset/tiny-books-destroy.md b/.changeset/tiny-books-destroy.md
new file mode 100644
index 0000000000..2516080ec5
--- /dev/null
+++ b/.changeset/tiny-books-destroy.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-catalog-backend': patch
+---
+
+Add index for original value in search table for faster entity facet response
diff --git a/.changeset/tiny-bugs-enjoy.md b/.changeset/tiny-bugs-enjoy.md
new file mode 100644
index 0000000000..963ccc2a1f
--- /dev/null
+++ b/.changeset/tiny-bugs-enjoy.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-adr-backend': patch
+---
+
+Migrated `DefaultAdrCollatorFactory` to support new auth services.
diff --git a/.changeset/tiny-donuts-drive.md b/.changeset/tiny-donuts-drive.md
deleted file mode 100644
index aadac7a276..0000000000
--- a/.changeset/tiny-donuts-drive.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-'@backstage/plugin-kubernetes-backend': patch
----
-
-Backstage will log a warning whenever duplicate cluster names are detected --
-even if clusters sharing the same name come from separate locators.
diff --git a/.changeset/tiny-kiwis-know.md b/.changeset/tiny-kiwis-know.md
deleted file mode 100644
index add4736527..0000000000
--- a/.changeset/tiny-kiwis-know.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/cli': patch
----
-
-Updated dependencies in frontend plugin templates
diff --git a/.changeset/tough-drinks-scream.md b/.changeset/tough-drinks-scream.md
deleted file mode 100644
index 3d2f154016..0000000000
--- a/.changeset/tough-drinks-scream.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-'@backstage/plugin-cloudbuild': minor
----
-
-Changed build list view to automatically filter builds based on repository name matching component-info's metadata.name.
-Added optional `google.com/cloudbuild-repo-name` annotation which allows you to specify a different repository to filter on.
-Added optional `google.com/cloudbuild-trigger-name` annotation which allows you to filter based on a trigger name instead of a repo name.
-Updated the ReadMe with information about the filtering and some other minor verbiage updates.
-Changed `substitutions.BRANCH_NAME` to `substitutions.REF_NAME` so that the Ref field is populated properly.
-Added optional `google.com/cloudbuild-location` annotation which allows you to specify the Cloud Build location of your builds. Default is global scope.
-Changed build list view to show builds in a specific location if the location annotation is used.
-Updated ReadMe with information about the use of the location filtering.
diff --git a/.changeset/tricky-months-hug.md b/.changeset/tricky-months-hug.md
new file mode 100644
index 0000000000..ae1bd85532
--- /dev/null
+++ b/.changeset/tricky-months-hug.md
@@ -0,0 +1,8 @@
+---
+'@backstage/plugin-auth-backend-module-oauth2-proxy-provider': patch
+'@backstage/plugin-auth-backend-module-aws-alb-provider': patch
+'@backstage/plugin-auth-backend-module-gcp-iap-provider': patch
+'@backstage/plugin-auth-node': patch
+---
+
+Fix issue with `providerInfo` not being set properly for some proxy providers, by making `providerInfo` an explicit optional return from `authenticate`
diff --git a/.changeset/twelve-berries-cross.md b/.changeset/twelve-berries-cross.md
new file mode 100644
index 0000000000..9862f465d2
--- /dev/null
+++ b/.changeset/twelve-berries-cross.md
@@ -0,0 +1,5 @@
+---
+'@backstage/backend-app-api': patch
+---
+
+Make sure to not filter out schemas in `createConfigSecretEnumerator`
diff --git a/.changeset/twelve-hounds-know.md b/.changeset/twelve-hounds-know.md
deleted file mode 100644
index 3c95c71ddb..0000000000
--- a/.changeset/twelve-hounds-know.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-scaffolder-react': minor
----
-
-Use more distinguishable icons for link (`Link`) and text output (`Description`).
diff --git a/.changeset/twelve-pens-rescue.md b/.changeset/twelve-pens-rescue.md
deleted file mode 100644
index 9d40fb2851..0000000000
--- a/.changeset/twelve-pens-rescue.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-'@backstage/frontend-plugin-api': patch
-'@backstage/frontend-app-api': patch
-'@backstage/core-compat-api': patch
----
-
-Allow external route refs in the new system to have a `defaultTarget` pointing to a route that it'll resolve to by default if no explicit bindings were made by the adopter.
diff --git a/.changeset/twelve-shirts-buy.md b/.changeset/twelve-shirts-buy.md
deleted file mode 100644
index 6183c7dabd..0000000000
--- a/.changeset/twelve-shirts-buy.md
+++ /dev/null
@@ -1,15 +0,0 @@
----
-'@backstage/plugin-catalog-backend': patch
-'@backstage/plugin-catalog-node': patch
----
-
-Add support for `onProcessingError` handler at the catalog plugin (new backend system).
-
-You can use `setOnProcessingErrorHandler` at the `catalogProcessingExtensionPoint`
-as replacement for
-
-```ts
-catalogBuilder.subscribe({
- onProcessingError: hander,
-});
-```
diff --git a/.changeset/twelve-weeks-march.md b/.changeset/twelve-weeks-march.md
deleted file mode 100644
index 4d9fff5b34..0000000000
--- a/.changeset/twelve-weeks-march.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-scaffolder-react': patch
----
-
-Fix issue where `ui:schema` was replaced with an empty object if `dependencies` is defined
diff --git a/.changeset/twenty-taxis-mate.md b/.changeset/twenty-taxis-mate.md
deleted file mode 100644
index 65ed158e9b..0000000000
--- a/.changeset/twenty-taxis-mate.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/core-compat-api': patch
----
-
-Plugins converted by `convertLegacyApp` now have their `routes` and `externalRoutes` included as well, allowing them to be used to bind external routes in configuration.
diff --git a/.changeset/two-coats-smile.md b/.changeset/two-coats-smile.md
deleted file mode 100644
index 65abb7a1eb..0000000000
--- a/.changeset/two-coats-smile.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/cli': patch
----
-
-Updated the backend module template to make the module instance the package default export.
diff --git a/.changeset/two-geese-explain.md b/.changeset/two-geese-explain.md
deleted file mode 100644
index 12ae307cfe..0000000000
--- a/.changeset/two-geese-explain.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/cli': patch
----
-
-Fixed an issue that would cause an invalid `__backstage-autodetected-plugins__.js` to be written when using experimental module discovery.
diff --git a/.changeset/two-planets-beam.md b/.changeset/two-planets-beam.md
new file mode 100644
index 0000000000..d500d22853
--- /dev/null
+++ b/.changeset/two-planets-beam.md
@@ -0,0 +1,6 @@
+---
+'@backstage/plugin-kubernetes-common': patch
+'@backstage/plugin-kubernetes-react': patch
+---
+
+Add support to fetch data for Daemon Sets and display an accordion in the same way as with Deployments
diff --git a/.changeset/two-singers-learn.md b/.changeset/two-singers-learn.md
deleted file mode 100644
index f5c2a78ab0..0000000000
--- a/.changeset/two-singers-learn.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-devtools': patch
----
-
-Added alpha support for the New Frontend System (Declarative Integration)
diff --git a/.changeset/two-snails-fry.md b/.changeset/two-snails-fry.md
new file mode 100644
index 0000000000..979134f98e
--- /dev/null
+++ b/.changeset/two-snails-fry.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-badges-backend': patch
+---
+
+Migrated to support new auth services.
diff --git a/.changeset/unlucky-jobs-report.md b/.changeset/unlucky-jobs-report.md
new file mode 100644
index 0000000000..4eab12d53e
--- /dev/null
+++ b/.changeset/unlucky-jobs-report.md
@@ -0,0 +1,7 @@
+---
+'@backstage/plugin-permission-backend': patch
+---
+
+Migrated to use the new auth services introduced in [BEP-0003](https://github.com/backstage/backstage/blob/master/beps/0003-auth-architecture-evolution/README.md).
+
+The `createRouter` function now accepts `auth`, `httpAuth` and `userInfo` options. Theses are used internally to support the new backend system, and can be ignored.
diff --git a/.changeset/unlucky-lizards-suffer.md b/.changeset/unlucky-lizards-suffer.md
new file mode 100644
index 0000000000..15862e1736
--- /dev/null
+++ b/.changeset/unlucky-lizards-suffer.md
@@ -0,0 +1,6 @@
+---
+'@backstage/plugin-cicd-statistics-module-gitlab': patch
+'@backstage/plugin-github-pull-requests-board': patch
+---
+
+Align `p-limit` dependency version to v3
diff --git a/.changeset/unlucky-pens-search.md b/.changeset/unlucky-pens-search.md
deleted file mode 100644
index 4786c14691..0000000000
--- a/.changeset/unlucky-pens-search.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-'@backstage/plugin-scaffolder-backend': patch
----
-
-When using node 20+ the `scaffolder-backend` will now throw an error at startup if the `--no-node-snapshot` option was
-not provided to node.
diff --git a/.changeset/unlucky-wasps-tan.md b/.changeset/unlucky-wasps-tan.md
deleted file mode 100644
index 97813cb416..0000000000
--- a/.changeset/unlucky-wasps-tan.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-scaffolder-backend-module-bitbucket': patch
----
-
-Enhanced the pull request action to allow for adding new content to the PR as described in this issue #21762
diff --git a/.changeset/violet-rocks-rescue.md b/.changeset/violet-rocks-rescue.md
new file mode 100644
index 0000000000..91fbcdd871
--- /dev/null
+++ b/.changeset/violet-rocks-rescue.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-search-backend-node': patch
+---
+
+Exports `QueryTranslator`, `QueryRequestOptions` and `SearchEngine` types. These new types were extracted from the `@backstage/plugin-search-common` package and the `token` property was deprecated in favor of the a new credentials one.
diff --git a/.changeset/warm-maps-scream.md b/.changeset/warm-maps-scream.md
deleted file mode 100644
index 3ea5d93b03..0000000000
--- a/.changeset/warm-maps-scream.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-'@backstage/plugin-azure-devops': patch
-'@backstage/plugin-devtools': patch
-'@backstage/plugin-linguist': patch
----
-
-Updated imports from named to default imports to help with the Material UI v4 to v5 migration
diff --git a/.changeset/weak-flowers-repeat.md b/.changeset/weak-flowers-repeat.md
deleted file mode 100644
index d1705343bc..0000000000
--- a/.changeset/weak-flowers-repeat.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-'@backstage/plugin-scaffolder-backend-module-gitea': patch
----
-
-- Fix issue for infinite loop when repository already exists
-- Log the root cause of error reported by `checkGiteaOrg`
diff --git a/.changeset/weak-news-jam.md b/.changeset/weak-news-jam.md
deleted file mode 100644
index a1f44082da..0000000000
--- a/.changeset/weak-news-jam.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-scaffolder-react': patch
----
-
-Fix bug that erroneously caused a separator or a 0 to render in the TemplateCard for Templates with empty links
diff --git a/.changeset/wet-emus-work.md b/.changeset/wet-emus-work.md
deleted file mode 100644
index 413670a325..0000000000
--- a/.changeset/wet-emus-work.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/core-compat-api': patch
----
-
-collectLegacyRoutes throws in case invalid element is found
diff --git a/.changeset/wet-lions-crash.md b/.changeset/wet-lions-crash.md
deleted file mode 100644
index 795e60588d..0000000000
--- a/.changeset/wet-lions-crash.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-catalog-backend-module-puppetdb': patch
----
-
-Added `latest_report_status` parameter from the PuppetDB node api and added it as a tag to the nodes. The status is valuable information as it displays which nodes are compliant to your configuration and which ones are failing are making changes.
diff --git a/.changeset/wet-sheep-reply.md b/.changeset/wet-sheep-reply.md
new file mode 100644
index 0000000000..27635b133e
--- /dev/null
+++ b/.changeset/wet-sheep-reply.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-catalog': patch
+---
+
+Allow the `spec.target` field to be searchable in the catalog table for locations. Previously, only the `spec.targets` field was be searchable. This makes locations generated by providers such as the `GithubEntityProvider` searchable in the catalog table. [#23098](https://github.com/backstage/backstage/issues/23098)
diff --git a/.changeset/wicked-dolphins-wash.md b/.changeset/wicked-dolphins-wash.md
deleted file mode 100644
index 9258913c41..0000000000
--- a/.changeset/wicked-dolphins-wash.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-kubernetes-backend': patch
----
-
-On LocalKubectlProxyClusterLocator, when resolving localhost, IPv4 address is placed before IPv6 address, ignoring the order from the DNS resolver. This change is necessary since by default kubectl proxy listen on IPv4
diff --git a/.changeset/wicked-elephants-scream.md b/.changeset/wicked-elephants-scream.md
deleted file mode 100644
index f002a48ba8..0000000000
--- a/.changeset/wicked-elephants-scream.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-azure-devops': patch
----
-
-Prefer `dev.azure.com/build-definition` annotation when it is provided, as it is more specific than `dev.azure.com/project-repo`. This can also be used as a filter for mono-repos.
diff --git a/.changeset/wild-owls-doubt.md b/.changeset/wild-owls-doubt.md
deleted file mode 100644
index 84abffb159..0000000000
--- a/.changeset/wild-owls-doubt.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-'@backstage/plugin-scaffolder-backend': minor
----
-
-The built-in module list has been trimmed down when using the new Backend System. Provider specific modules should now be installed with `backend.add` to provide additional actions to the scaffolder. These modules are as follows:
-
-- `@backstage/plugin-scaffolder-backend-module-github`
-- `@backstage/plugin-scaffolder-backend-module-gitlab`
-- `@backstage/plugin-scaffolder-backend-module-bitbucket`
-- `@backstage/plugin-scaffolder-backend-module-gitea`
-- `@backstage/plugin-scaffolder-backend-module-gerrit`
-- `@backstage/plugin-scaffolder-backend-module-confluence-to-markdown`
-- `@backstage/plugin-scaffolder-backend-module-cookiecutter`
-- `@backstage/plugin-scaffolder-backend-module-rails`
-- `@backstage/plugin-scaffolder-backend-module-sentry`
-- `@backstage/plugin-scaffolder-backend-module-yeoman`
diff --git a/.changeset/wise-flies-laugh.md b/.changeset/wise-flies-laugh.md
deleted file mode 100644
index 4b31b4e9ba..0000000000
--- a/.changeset/wise-flies-laugh.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-home': patch
----
-
-Added filter support for HomePageVisitedByType in order to enable filtering entities from the list
diff --git a/.changeset/wise-papayas-cough.md b/.changeset/wise-papayas-cough.md
deleted file mode 100644
index 955e7fefcc..0000000000
--- a/.changeset/wise-papayas-cough.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/backend-common': patch
----
-
-Add a config declaration for `workingDirectory`
diff --git a/.changeset/young-flies-wash.md b/.changeset/young-flies-wash.md
new file mode 100644
index 0000000000..dcedc9bb7c
--- /dev/null
+++ b/.changeset/young-flies-wash.md
@@ -0,0 +1,35 @@
+---
+'@backstage/plugin-events-backend': minor
+---
+
+BREAKING CHANGE: Migrate `HttpPostIngressEventPublisher` and `eventsPlugin` to use `EventsService`.
+
+Uses the `EventsService` instead of `EventBroker` at `HttpPostIngressEventPublisher`,
+dropping the use of `EventPublisher` including `setEventBroker(..)`.
+
+Now, `HttpPostIngressEventPublisher.fromConfig` requires `events: EventsService` as option.
+
+```diff
+ const http = HttpPostIngressEventPublisher.fromConfig({
+ config: env.config,
++ events: env.events,
+ logger: env.logger,
+ });
+ http.bind(eventsRouter);
+
+ // e.g. at packages/backend/src/plugins/events.ts
+- await new EventsBackend(env.logger)
+- .setEventBroker(env.eventBroker)
+- .addPublishers(http)
+- .start();
+
+ // or for other kinds of setups
+- await Promise.all(http.map(publisher => publisher.setEventBroker(eventBroker)));
+```
+
+`eventsPlugin` uses the `eventsServiceRef` as dependency.
+Unsupported (and deprecated) extension point methods will throw an error to prevent unintended behavior.
+
+```ts
+import { eventsServiceRef } from '@backstage/plugin-events-node';
+```
diff --git a/.changeset/young-ladybugs-decide.md b/.changeset/young-ladybugs-decide.md
deleted file mode 100644
index 53284cbc37..0000000000
--- a/.changeset/young-ladybugs-decide.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-'@backstage/plugin-scaffolder-backend': patch
-'@backstage/plugin-scaffolder-node': patch
----
-
-Add option to configure nunjucks with the `trimBlocks` and `lstripBlocks` options in the fetch:template action
diff --git a/.changeset/young-rules-repeat.md b/.changeset/young-rules-repeat.md
deleted file mode 100644
index 6fb17f0608..0000000000
--- a/.changeset/young-rules-repeat.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/eslint-plugin': patch
----
-
-Added new `@backstage/no-top-level-material-ui-4-imports` rule that forbids top level imports from Material UI v4 packages
diff --git a/.eslintrc.js b/.eslintrc.js
index 2df965ab73..01cad187be 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -23,8 +23,11 @@ module.exports = {
'notice/notice': [
'error',
{
- // eslint-disable-next-line no-restricted-syntax
- templateFile: path.resolve(__dirname, './scripts/copyright-header.txt'),
+ templateFile: path.resolve(
+ // eslint-disable-next-line no-restricted-syntax
+ __dirname,
+ './scripts/templates/copyright-header.txt'
+ ),
onNonMatchingHeader: 'replace',
},
],
diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index 247ce66010..0000000000
--- a/.gitattributes
+++ /dev/null
@@ -1,3 +0,0 @@
-**/api-report*.md linguist-generated=true
-**/cli-report.md linguist-generated=true
-**/knip-report.md linguist-generated=true
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 75416ace16..4d18392945 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -8,6 +8,7 @@
yarn.lock @backstage/maintainers @backstage-service
*/yarn.lock @backstage/maintainers @backstage-service
/.changeset/*.md
+/beps/0001-notifications-system @backstage/maintainers @backstage/notifications-maintainers
/docs/assets/search @backstage/discoverability-maintainers
/docs/features/search @backstage/discoverability-maintainers
/docs/features/techdocs @backstage/techdocs-maintainers
@@ -66,6 +67,8 @@ yarn.lock @backstage/maintainers @backst
/plugins/linguist @backstage/maintainers @backstage/reviewers @awanlin
/plugins/linguist-backend @backstage/maintainers @backstage/reviewers @awanlin
/plugins/linguist-common @backstage/maintainers @backstage/reviewers @awanlin
+/plugins/notifications @backstage/maintainers @backstage/notifications-maintainers
+/plugins/notifications-* @backstage/maintainers @backstage/notifications-maintainers
/plugins/octopus-deploy @backstage/maintainers @backstage/reviewers @jmezach
/plugins/permission-* @backstage/permission-maintainers
/plugins/playlist @backstage/maintainers @backstage/reviewers @kuangp
@@ -76,6 +79,8 @@ yarn.lock @backstage/maintainers @backst
/plugins/scaffolder-* @backstage/maintainers @backstage/reviewers @backstage/scaffolder-maintainers
/plugins/search @backstage/discoverability-maintainers
/plugins/search-* @backstage/discoverability-maintainers
+/plugins/signals @backstage/maintainers @backstage/notifications-maintainers
+/plugins/signals-* @backstage/maintainers @backstage/notifications-maintainers
/plugins/sonarqube @backstage/maintainers @backstage/reviewers @backstage/sda-se-reviewers
/plugins/stack-overflow @backstage/discoverability-maintainers
/plugins/stack-overflow-backend @backstage/discoverability-maintainers
diff --git a/.github/renovate.json5 b/.github/renovate.json5
index 5d979d5f22..a9cb54912a 100644
--- a/.github/renovate.json5
+++ b/.github/renovate.json5
@@ -3,13 +3,16 @@
labels: ['dependencies'],
- extends: [
- 'config:best-practices',
- ':gitSignOff',
- 'default:pinDigestsDisabled',
- ],
+ extends: ['config:best-practices', ':gitSignOff'],
// do not pin dev dependencies, which are part of the best-practices preset
- ignorePresets: [':pinDevDependencies', ':pinDigest'],
+ ignorePresets: [':pinDevDependencies', ':pinDigest', 'docker:pinDigests'],
+
+ constraints: {
+ // TODO(freben): Remove this later; it addresses a temporary issue in corepack
+ // https://github.com/nodejs/corepack/issues/379
+ // https://github.com/renovatebot/renovate/discussions/27465
+ corepack: '0.24.1',
+ },
// the default limit are 10 PRs
prConcurrentLimit: 20,
@@ -42,5 +45,26 @@
matchSourceUrls: ['https://github.com/yarnpkg/berry'],
enabled: false,
},
+ // ESM only majors, that we're not ready for yet
+ {
+ matchPackageNames: ['node-fetch'],
+ allowedVersions: '<3.0.0',
+ },
+ {
+ matchPackageNames: ['inquirer', '@types/inquirer'],
+ allowedVersions: '<9.0.0',
+ },
+ {
+ matchPackageNames: ['ora'],
+ allowedVersions: '<5.0.0',
+ },
+ {
+ matchPackageNames: ['p-limit'],
+ allowedVersions: '<4.0.0',
+ },
+ {
+ matchPackageNames: ['p-queue'],
+ allowedVersions: '<7.0.0',
+ },
],
}
diff --git a/.github/workflows/deploy_docker-image.yml b/.github/workflows/deploy_docker-image.yml
index eef70ff02c..f6cd52b284 100644
--- a/.github/workflows/deploy_docker-image.yml
+++ b/.github/workflows/deploy_docker-image.yml
@@ -5,6 +5,10 @@ on:
repository_dispatch:
types: [release-published]
+env:
+ RELEASE_VERSION: v${{ github.event.client_payload.version }}
+ TAG_VERSION: ghcr.io/${{ github.repository_owner }}/backstage:${{ github.event.client_payload.version }}
+
jobs:
build:
runs-on: ubuntu-latest
@@ -24,7 +28,7 @@ jobs:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
path: backstage
- ref: v${{ github.event.client_payload.version }}
+ ref: ${{ github.event.client_payload.version && env.RELEASE_VERSION || github.ref }}
- name: use node.js ${{ matrix.node-version }}
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
@@ -61,10 +65,10 @@ jobs:
with:
context: './example-app'
file: ./example-app/packages/backend/Dockerfile
- push: ${{ (github.event_name == "repository_dispatch") && (github.event.action == "release-published") }}
+ push: ${{ (github.event_name == 'repository_dispatch') && (github.event.action == 'release-published') }}
platforms: linux/amd64,linux/arm64
tags: |
ghcr.io/${{ github.repository_owner }}/backstage:latest
- ghcr.io/${{ github.repository_owner }}/backstage:${{ github.event.client_payload.version }}
+ ${{ github.event.client_payload.version && env.TAG_VERSION || '' }}
labels: |
org.opencontainers.image.description=Docker image generated from the latest Backstage release; this contains what you would get out of the box by running npx @backstage/create-app and building a Docker image from the generated source. This is meant to ease the process of evaluating Backstage for the first time, but also has the severe limitation that there is no way to install additional plugins relevant to your infrastructure.
diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml
index 621776d69b..d94373e9d1 100644
--- a/.github/workflows/scorecard.yml
+++ b/.github/workflows/scorecard.yml
@@ -66,6 +66,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: 'Upload to code-scanning'
- uses: github/codeql-action/upload-sarif@379614612a29c9e28f31f39a59013eb8012a51f0 # v3.24.3
+ uses: github/codeql-action/upload-sarif@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5
with:
sarif_file: results.sarif
diff --git a/.github/workflows/sync_snyk-monitor.yml b/.github/workflows/sync_snyk-monitor.yml
index 7ee4e72d38..c5374951d7 100644
--- a/.github/workflows/sync_snyk-monitor.yml
+++ b/.github/workflows/sync_snyk-monitor.yml
@@ -58,6 +58,6 @@ jobs:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
NODE_OPTIONS: --max-old-space-size=7168
- name: Upload Snyk report
- uses: github/codeql-action/upload-sarif@379614612a29c9e28f31f39a59013eb8012a51f0 # v3.24.3
+ uses: github/codeql-action/upload-sarif@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5
with:
sarif_file: snyk.sarif
diff --git a/.github/workflows/uffizzi-preview.yaml b/.github/workflows/uffizzi-preview.yaml
index 9db724fa96..3125504dc8 100644
--- a/.github/workflows/uffizzi-preview.yaml
+++ b/.github/workflows/uffizzi-preview.yaml
@@ -76,7 +76,7 @@ jobs:
- name: Cache Manifests File
if: ${{ steps.event.outputs.ACTION != 'closed' }}
- uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0
+ uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1
with:
path: manifests.rendered.yml
key: ${{ steps.hash.outputs.MANIFESTS_FILE_HASH }}
@@ -140,7 +140,7 @@ jobs:
- name: Fetch cached Manifests File
id: cache
- uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4
+ uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4
with:
path: manifests.rendered.yml
key: ${{ needs.cache-manifests-file.outputs.manifests-cache-key }}
diff --git a/.github/workflows/verify_codeql.yml b/.github/workflows/verify_codeql.yml
index 7c7ef286db..dabbff24db 100644
--- a/.github/workflows/verify_codeql.yml
+++ b/.github/workflows/verify_codeql.yml
@@ -55,7 +55,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@379614612a29c9e28f31f39a59013eb8012a51f0 # v3.24.3
+ uses: github/codeql-action/init@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -66,7 +66,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
- uses: github/codeql-action/autobuild@379614612a29c9e28f31f39a59013eb8012a51f0 # v3.24.3
+ uses: github/codeql-action/autobuild@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -80,4 +80,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@379614612a29c9e28f31f39a59013eb8012a51f0 # v3.24.3
+ uses: github/codeql-action/analyze@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5
diff --git a/.github/workflows/verify_storybook.yml b/.github/workflows/verify_storybook.yml
index 70fb16ac48..e12aba2e0e 100644
--- a/.github/workflows/verify_storybook.yml
+++ b/.github/workflows/verify_storybook.yml
@@ -51,7 +51,7 @@ jobs:
- run: yarn build-storybook
- - uses: chromaui/action@c9067691aca4a28d6fbb40d9eea6e144369fbcae # v10
+ - uses: chromaui/action@fd0e276c344bab4dc69a023fdf89ffb9b79b3b31 # v11
with:
token: ${{ secrets.GITHUB_TOKEN }}
# projectToken intentionally shared to allow collaborators to run Chromatic on forks
diff --git a/.prettierignore b/.prettierignore
index c561036ebb..3a16bd1388 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -11,6 +11,7 @@ cli-report.md
plugins/scaffolder-backend/sample-templates
.vscode
dist-types
+.eslintrc.js
# reduce the barrier for adopters to add themselves
ADOPTERS.md
diff --git a/ADOPTERS.md b/ADOPTERS.md
index 8f3f93658b..fa6c3579d4 100644
--- a/ADOPTERS.md
+++ b/ADOPTERS.md
@@ -262,4 +262,5 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/
| [Gynzy](https://gynzy.com) | [Stef Louwers](https://github.com/fhp) | We are building an internal developer portal to get an overview of all our software components. |
| [Cielo](https://www.cielo.com.br) | [@Alex Silva](https://github.com/narokwq) | We are using as our Internal Developer Portal, it provides developers with the resources, information, and tools they need to build high-quality applications and adhere to organizational standards and security practices. |
| [Giant Swarm](https://giantswarm.io) | [Lucas Weatherhog](https://github.com/weatherhog) | At Giant Swarm we are using Backstage as our internal developer portal. Heavily using the service catalog and the TechDocs plugin. Further looking into adopting functionalities of our Web UI into Backstage to have a single pane of glass for our core business, managing all our components, and helping developers to be more productive. |
-| [WD Studios](https://wdstudios.tech) | [Mikael Aboagye](https://github.com/JailbreakPapa) | We are using Backstage as our main internal developer portal for our Programmers and Studio Partners. It's really proven its worth at our studio with on-boarding new programmers!
+| [WD Studios](https://wdstudios.tech) | [Mikael Aboagye](https://github.com/JailbreakPapa) | We are using Backstage as our main internal developer portal for our Programmers and Studio Partners. It's really proven its worth at our studio with on-boarding new programmers! |
+| [Fortnox](https://www.fortnox.se) | [@magnusp](https://github.com/magnusp) | With Backstage we consolidate our internal tools into a single pane of glass and let the catalog drive our user interface. Our software templates onboard our services and teams onto Backstage, and with Techdocs we are letting our developers get back in control of their own documentation. |
diff --git a/OWNERS.md b/OWNERS.md
index e9e14aaf83..4ef6b2ccab 100644
--- a/OWNERS.md
+++ b/OWNERS.md
@@ -73,17 +73,14 @@ Team: @backstage/permission-maintainers
Scope: The Permission Framework and plugins integrating with the permission framework
-| Name | Organization | Team | GitHub | Discord |
-| -------------------- | ------------ | --------------- | ----------------------------------------------- | ---------------- |
-| Ainhoa Larumbe | Spotify | Imaginary Goats | [ainhoaL](http://github.com/ainhoaL) | ainhoa#8085 |
-| Claire Casey | Spotify | Imaginary Goats | [clairelcasey](http://github.com/clairelcasey) | clairecasey#2710 |
-| Eric Peterson | Spotify | Imaginary Goats | [iamEAP](http://github.com/iamEAP) | iamEAP#3058 |
-| Harry Hogg | Spotify | Imaginary Goats | [HHogg](http://github.com/HHogg) | simplex#3451 |
-| Joon Park | Spotify | Imaginary Goats | [Joonpark13](http://github.com/Joonpark13) | Sixpool#5060 |
-| Lynette Lopez | Spotify | Imaginary Goats | [lynettelopez](https://github.com/lynettelopez) | lynettelopez |
-| Mike Lewis | Spotify | Imaginary Goats | [mtlewis](http://github.com/mtlewis) | mtlewis#3658 |
-| Tim Hansen | Spotify | Imaginary Goats | [timbonicus](http://github.com/timbonicus) | timbonicus#6871 |
-| Vincenzo Scamporlino | Spotify | Imaginary Goats | [vinzscam](http://github.com/vinzscam) | vinzscam#6944 |
+| Name | Organization | Team | GitHub | Discord |
+| -------------------- | ------------ | --------------- | ------------------------------------------ | ------------- |
+| Ainhoa Larumbe | Spotify | Imaginary Goats | [ainhoaL](http://github.com/ainhoaL) | ainhoa#8085 |
+| Eric Peterson | Spotify | Imaginary Goats | [iamEAP](http://github.com/iamEAP) | iamEAP#3058 |
+| Harry Hogg | Spotify | Imaginary Goats | [HHogg](http://github.com/HHogg) | simplex#3451 |
+| Joon Park | Spotify | Imaginary Goats | [Joonpark13](http://github.com/Joonpark13) | Sixpool#5060 |
+| Mike Lewis | Spotify | Imaginary Goats | [mtlewis](http://github.com/mtlewis) | mtlewis#3658 |
+| Vincenzo Scamporlino | Spotify | Imaginary Goats | [vinzscam](http://github.com/vinzscam) | vinzscam#6944 |
### TechDocs
@@ -107,15 +104,39 @@ Scope: The TechDocs plugin and related tooling
These incubating project areas have shared ownership with @backstage/maintainers.
+### Community Plugins
+
+Team: @backstage/community-plugins-maintainers
+
+Scope: Tooling and Community Repo Maintainers for the Backstage [Community Plugins repository](https://github.com/backstage/community-plugins)
+
+| Name | Organization | GitHub | Discord |
+| -------------------- | ------------ | ------------------------------------------- | ------------ |
+| Bethany Griggs | Red Hat | [BethGriggs](https://github.com/BethGriggs) | `bethgriggs` |
+| Tomas Kral | Red Hat | [kadel](https://github.com/kadel) | `tomkral` |
+| André Wanlin | Spotify | [awanlin](https://github.com/awanlin) | `ahhhndre` |
+| Philipp Hugenroth | Spotify | [tudi2d](https://github.com/tudi2d) | `tudi2d` |
+| Vincenzo Scamporlino | Spotify | [vinzscam](https://github.com/vinzscam) | `vinzscam` |
+
+### Notifications
+
+Team: @backstage/notifications-maintainers
+
+Scope: The Notifications and Signals plugins and libraries
+
+| Name | Organization | GitHub | Discord |
+| ----------- | ------------ | ------------------------------------------- | --------- |
+| Marek Libra | RedHat | [mareklibra](https://github.com/mareklibra) | `marekli` |
+
### OpenAPI Tooling
Team: @backstage/openapi-tooling-maintainers
Scope: Tooling for frontend and backend schema-first OpenAPI development.
-| Name | Organization | GitHub | Discord |
-| -------------- | ------------ | --------------------------------------- | ------------- |
-| Aramis Sennyey | | [sennyeya](https://github.com/sennyeya) | `Aramis#7984` |
+| Name | Organization | GitHub | Discord |
+| -------------- | ------------ | ----------------------------------------------------- | ------------- |
+| Aramis Sennyey | | [aramissennyeydd](https://github.com/aramissennyeydd) | `Aramis#7984` |
### Scaffolder
@@ -143,7 +164,7 @@ Scope: The Scaffolder frontend and backend plugins, and related tooling.
| Alex Crome | | [afscrome](https://github.com/afscrome) | `afscrome` |
| Andre Wanlin | Spotify | [awanlin](https://github.com/awanlin) | `ahhhndre` |
| Andrew Thauer | Wealthsimple | [andrewthauer](https://github.com/andrewthauer) | `andrewthauer#3060` |
-| Aramis Sennyey | | [sennyeya](https://github.com/sennyeya) | `Aramis#7984` |
+| Aramis Sennyey | | [aramissennyeydd](https://github.com/aramissennyeydd) | `Aramis#7984` |
| Brian Fletcher | Roadie.io | [punkle](https://github.com/punkle) | `Brian Fletcher#7051` |
| Carlos Esteban Lopez Jaramillo | VMWare | [luchillo17](https://github.com/luchillo17) | `luchillo17#8777` |
| David Tuite | Roadie.io | [dtuite](https://github.com/dtuite) | `David Tuite (roadie.io)#1010` |
diff --git a/app-config.yaml b/app-config.yaml
index c53a6475f4..7950768350 100644
--- a/app-config.yaml
+++ b/app-config.yaml
@@ -32,6 +32,12 @@ backend:
# auth:
# keys:
# - secret: ${BACKEND_SECRET}
+
+ auth:
+ # TODO: once plugins have been migrated we can remove this, but right now it
+ # is require for the backend-next to work in this repo
+ dangerouslyDisableDefaultAuthPolicy: true
+
baseUrl: http://localhost:7007
listen:
port: 7007
@@ -236,7 +242,7 @@ catalog:
- Domain
- Location
providers:
- openapi:
+ backstageOpenapi:
plugins:
- catalog
- search
@@ -391,8 +397,9 @@ auth:
clientId: ${AUTH_ATLASSIAN_CLIENT_ID}
clientSecret: ${AUTH_ATLASSIAN_CLIENT_SECRET}
scopes: ${AUTH_ATLASSIAN_SCOPES}
- myproxy:
- development: {}
+ myproxy: {}
+ guest: {}
+
costInsights:
engineerCost: 200000
engineerThreshold: 0.5
diff --git a/beps/0001-notifications-system/README.md b/beps/0001-notifications-system/README.md
index e3507d05fa..e071b36a06 100644
--- a/beps/0001-notifications-system/README.md
+++ b/beps/0001-notifications-system/README.md
@@ -96,7 +96,6 @@ The notification backend stores notification using the [database service](https:
- ID
- Read date
-- Done date
- Saved status
- Creation date
- Updated date (optional, for scoped notifications)
@@ -104,7 +103,8 @@ The notification backend stores notification using the [database service](https:
- Title
- Description (optional)
- Origin
- - Link
+ - Link (optional)
+ - Additional links (optional)
- Recipients
- Severity (optional, default normal)
- Topic (optional)
@@ -113,6 +113,10 @@ The notification backend stores notification using the [database service](https:
The recipients is **not** a list of users, but rather a filter that describes who should receive the notification. It must be possible to evaluate this filter in a database query, so that we can efficiently fetch all notifications for a given user. The same filter will also be used by the signal backend to determine which users should receive a signal.
+The read date is a timestamp of marking the notifications as read by the user. If missing, the notification is still unread.
+
+The saved status is a timestamp indicating when/if the user marked the notification for better visibility in the future (to "pin" the message). Can be undefined.
+
The title is mandatory human-readable text shortly describing the notifications.
The description is an optional human-readable text providing more details to the user.
@@ -143,6 +147,8 @@ The link is a relative or absolute URL. As an example, it can be used:
- by an external system to request an action within an asynchronous task
- by a BE plugin to provide link to other part of the Backstage UI (i.e. to the Catalog)
+The additional links are an array of title-URL pairs. They can represent immediate actions on the notification (i.e. yes-no) or lead the user to additional details.
+
The `notification-backend` does not provide any new permissions, since creating notifications can only be done by other backend plugins, while reading notifications can only be done by the authenticated user. It is possible that we want to add a permissions for reading notifications, in particular for admin and impersonation use cases, but that is not part of this proposal or the initial implementation.
The `notification-backend` shall provide necessary parameters for paging and filtering notifications from the frontend.
@@ -228,7 +234,7 @@ interface NotificationService {
Each notification is always routed to individual users unless it's a broadcast. The `notification-backend` will figure out which users will receive a notification based on the `recipients` parameter, resolving it to the concrete list of users at the time of sending the notification.
-Each notification contains a `title` and a `link` for user to see further information. The `created`, `id`, `read` and `saved` properties are handled by the backend based and cannot be changed during the notification creation.
+Each notification contains a human readable `title`, `origin` and optionally `link` for additional details. The `created`, `id`, `read` and `saved` properties are handled by the backend based and cannot be passed during the notification creation.
Calling `sendNotification` should never throw an error so that it doesn't block the current processing. Notifications should be considered as second-level citizens that are not critical if not delivered.
@@ -273,37 +279,31 @@ Example signal payload for a new notification:
Notification frontend shows users their own notifications in its own page and the number of unread notifications in the main menu item.
-By default, notifications that are `undone` will be shown in the notifications view. The notification `read` status is indicated by the UI.
+Notifications are set to `read` when the `Mark as read` action is triggered by the user (bulk or single).
-Notifications are set to `read` when the notification link is opened or the notification is set as `done` by the user.
+Notifications can be saved for better visibility in the future.
-Notifications can be set to `done` by the user, and they are filtered out of the main view.
+Notifications can be filtered by `read`, `saved`, `content` (text search in title or description), `created` (since multiple predefined options) and `severity`.
-Notifications can be saved for later use by the user.
-
-Notifications can be filtered by their `read`, `done` and `saved` statuses.
-
-Notifications are displayed in pages.
-
-User can search for notifications based on their title and description.
+Notifications are displayed in pages. To do so, the backend needs to implement filtering and sorting.
The following frontend API is added as part of this proposal.
#### `NotificationsApi`
```ts
-export type NotificationType = 'undone' | 'done' | 'saved';
+export type NotificationSeverity = 'critical' | 'high' | 'normal' | 'low';
export type GetNotificationsOptions = {
- type?: NotificationType;
offset?: number;
limit?: number;
search?: string;
+ createdSince?: Date;
+ severity?: NotificationSeverity;
};
export type NotificationUpdateOptions = {
ids: string[];
- done?: boolean;
read?: boolean;
saved?: boolean;
};
@@ -358,7 +358,7 @@ interface SignalApi {
- Replace absent signal service with long polling. This requires changes to the `signals` plugin as well.
- Render dynamic values with various different React elements such as the `EntityRefLink` for entity references (for example `{{ user:default/john.doe }}`) in the notification payload
-- Handle `link` values that use route references. For example instead hard-coding link to `/catalog/default/component/artist-web` it should be possible to use `catalogPlugin.catalogEntity` route reference as a link of the notification. This should also allow using parameters to be passed to the route reference
+- Handle `link` values that use route references. For example instead hard-coding link to `/catalog/default/component/artist-web` it should be possible to use `catalogPlugin.catalogEntity` route reference as a link of the notification. This should also allow using parameters to be passed to the route reference. Links to external systems are still supported.
- Add support for `analyticsApi` to notification actions like marking notifications done, saved or opening links in the notifications
- Add support for user settings to control how notifications are shown to the user and which notifications user wants to receive. This should also include support for different `NotificationProcessor`s that can send notification to external systems
- Add a sound to be played when notification is received
diff --git a/beps/0003-auth-architecture-evolution/README.md b/beps/0003-auth-architecture-evolution/README.md
index dc475fa14d..403390e567 100644
--- a/beps/0003-auth-architecture-evolution/README.md
+++ b/beps/0003-auth-architecture-evolution/README.md
@@ -68,9 +68,9 @@ Two new backend service interfaces are introduced to support these new features.
The proposed design leaves the decision for how different endpoints are protected to the implementation of the plugin backends themselves. This includes whether particular routes should allow anonymous access, access from users authenticated via a cookie, or perhaps only allow access from other plugin backends and external services. This means that integrators do not need to - and do not have the ability to - configure access controls of individual endpoints, except for what the permission system already provides, and what is made available through static configuration or extension points.
-In order to allow for cookie-based authentication of incoming user requests, the `auth` plugin backend is extended to be able to issue user tokens with reduced scope, which in turn integrate with the new `AuthService` and `HttpAuthService`. The ability to use cookie auth for requests is an opt-in per route and is only be permitted for read methods (`GET`, `HEAD`, `OPTIONS`). The actual implementation of cookie-based flows will be up to each plugin, but with significant help from the new auth service interfaces.
+To ensure a secure-by-default design, there is a default access control policy that applies to all plugin routes, known as the "default auth policy". This policy is to only allow access from authenticated users and services, and is implemented in the `HttpRouterService` interface. In order to allow either unauthenticated access or cookie-based access, a plugin must opt-out of the default auth policy for specific path prefixes, effectively leaving the access control implementation to the plugin itself. This is done through the new `addAuthPolicy` method that is added to the `HttpRouterService` interface.
-In order to allow either unauthenticated access or cookie-based access, a plugin must explicitly opt-in the specific path prefixes that these should be available at. This is done through a new method that is added to the `HttpRouterService` interface.
+In order to allow for cookie-based authentication of incoming user requests, the `AuthService` is able to issue user tokens with limited scope. These limited scope tokens can still be used to fetch user information and in on-behalf-of service calls, but they are rejected by the default auth policy. The `HttpAuthService` provides a standardized way of handling cookies, which integrates with the `'user-cookie'` auth policy. The limited tokens can also be used in other contexts where it is beneficial to avoid storing full user credentials, but instead use credentials that can be upgraded in a controlled manner, such as scaffolder tasks. The `AuthService` implementation can choose to have a longer expiry of the limited tokens compared to the full user tokens, but this is not a requirement.
For service-to-service communication we will move away from reusing user tokens in upstream requests. We will instead implement an "On-Behalf-Of" flow where incoming user credentials are encapsulated in a service token for the upstream request. In line with this the new auth service interfaces will aim to make it difficult to directly forward credentials from incoming requests, and instead encourage that plugin backends issue new service credentials for upstream requests.
@@ -98,7 +98,7 @@ export type BackstageUserPrincipal = {
};
export type BackstageServicePrincipal = {
- type: 'user';
+ type: 'service';
// Exact format TBD, possibly 'plugin:' or 'external:'
subject: string;
@@ -110,6 +110,8 @@ export type BackstageServicePrincipal = {
export type BackstageCredentials = {
$$type: '@backstage/BackstageCredentials';
+ expiresAt?: Date;
+
principal: TPrincipal;
};
@@ -120,13 +122,20 @@ export type BackstagePrincipalTypes = {
};
export interface AuthService {
- authenticate(token: string): Promise;
+ authenticate(
+ token: string,
+ options?: {
+ allowLimitedAccess?: boolean;
+ },
+ ): Promise;
isPrincipal(
credentials: BackstageCredentials,
type: TType,
): credentials is BackstageCredentials;
+ getNoneCredentials(): Promise>;
+
getOwnServiceCredentials(): Promise<
BackstageCredentials
>;
@@ -135,6 +144,10 @@ export interface AuthService {
onBehalfOf: BackstageCredentials;
targetPluginId: string;
}): Promise<{ token: string }>;
+
+ getLimitedUserToken(
+ credentials: BackstageCredentials,
+ ): Promise<{ token: string; expiresAt: Date }>;
}
```
@@ -149,6 +162,7 @@ export interface BackstageUserInfo {
}
export interface UserInfoService {
+ // The implementation of this method should support both regular and limited user credentials
getUserInfo(credentials: BackstageCredentials): Promise;
}
```
@@ -159,7 +173,7 @@ The `UserInfoService` is exported by `@backstage/auth-node`, and the initial imp
> Open question: Should this instead be added to the `HttpAuthService`? It may fit a bit better there, but on the other hand it might make sense to add additional policies unrelated to authentication too, such as rate limiting.
-The `HttpRouterService` interface will be extended with the ability to opt-out of the default protection of endpoints, enabling either cookie auth or unauthenticated access.
+The `HttpRouterService` interface will be extended with the ability to opt-out of the default protection of endpoints, enabling cookie or unauthenticated access.
```ts
export interface HttpRouterServiceAuthPolicy {
@@ -201,7 +215,7 @@ export default createBackendPlugin({
This is expected to be the pattern for the vast majority of plugins.
-#### A plugin with an endpoint that only allows cookie auth
+#### A plugin with a cookie-based authentication endpoint
```ts
export default createBackendPlugin({
@@ -209,11 +223,25 @@ export default createBackendPlugin({
register(env) {
env.registerInit({
deps: {
+ auth: coreServices.auth,
+ httpAuth: coreServices.httpAuth,
http: coreServices.httpRouter,
},
- async init({ http }) {
+ async init({ auth, httpAuth, http }) {
+ const router = Router();
+
+ // Endpoint that sets the cookie for the user
+ router.get('/cookie', async (req, res) => {
+ const { expiresAt } = await httpAuth.issueUserCookie(res);
+
+ res.json({ expiresAt: expiresAt.toISOString() });
+ });
+
+ // Endpoint protected by cookie auth
+ router.get('/static', express.static(/* ... */));
+
// The order of these two calls does not matter
- http.use(await createRouter(/* ... */));
+ http.use(router);
http.addAuthPolicy({
path: '/static',
allow: 'user-cookie',
@@ -224,7 +252,7 @@ export default createBackendPlugin({
});
```
-#### A plugin that allows both public access and cookie auth
+#### A plugin that disabled the default auth policy and handles auth by itself
```ts
export default createBackendPlugin({
@@ -236,15 +264,8 @@ export default createBackendPlugin({
},
async init({ http }) {
http.use(await createRouter(/* ... */));
-
http.addAuthPolicy({
path: '/',
- allow: 'user-cookie',
- });
-
- // Unauthenticated access takes precedence, the /public endpoint does not require cookie auth
- http.addAuthPolicy({
- path: '/public',
allow: 'unauthenticated',
});
},
@@ -274,16 +295,19 @@ export interface HttpAuthService {
req: Request,
options?: {
allow?: Array;
- allowedAuthMethods?: Array<'token' | 'cookie'>;
+ allowLimitedAccess?: boolean;
},
): Promise<
BackstageCredentials
>;
- // The cookie issued by this method must be consumable by the `credentials` method, which in turn
- // should create a credentials object that can be passed to the `getPluginRequestToken` method.
- // The issued token must then in turn be a valid token for a user principal with full access.
- issueUserCookie(res: Response): Promise;
+ issueUserCookie(
+ res: Response,
+ options?: {
+ // If credentials are not provided, they will be read from the request
+ credentials?: BackstageCredentials;
+ },
+ ): Promise<{ expiresAt: Date }>;
}
```
@@ -377,41 +401,22 @@ router.get('/read-data', (req, res) => {
});
```
-#### Issuing a cookie and allowing user cookie auth on a separate endpoint
+#### Using limited user tokens to access user info
```ts
-router.get('/cookie', async (req, res) => {
- await httpAuth.issueUserCookie(res); // If this is a service call it'll throw
- res.json({ ok: true });
+router.get('/read-data', (req, res) => {
+ const credentials = await httpAuth.credentials(req, {
+ allow: ['user'],
+ allowLimitedAccess: true,
+ });
+
+ const { userEntityRef, ownershipEntityRefs } = await userInfo.getUserInfo(
+ credentials,
+ );
+
+ console.log(`User ref=${userEntityRef} ownership=${ownershipEntityRefs}`);
+ // ...
});
-
-// Allowing cookie auth is a separate step where you call the addAuthPolicy method
-// of the httpRouter API in your plugin setup code.
-httpRouter.addAuthPolicy({
- path: '/static',
- allow: 'user-cookie',
-});
-
-// Separate endpoint that serves static content, allowing user cookie auth as
-// well as the default user and service auth methods
-router.use('/static', express.static(staticContentDir));
-```
-
-#### Passing along user identity from a cookie in an upstream request
-
-```ts
-router.get(
- '/read-data',
- httpAuth.middleware({ allow: ['user-cookie'] }),
- (req, res) => {
- const credentials = await httpAuth.credentials(req, { allow: ['user'] });
- const { ownershipEntityRefs } = await userInfo.getUserInfo(credentials);
- console.log(
- `User ref=${credentials.userEntityRef} ownership=${ownershipEntityRefs}`,
- );
- // ...
- },
-);
```
### Access Control Configuration
@@ -425,6 +430,79 @@ backend:
The exact impact that this has is that it disables the check in the `HttpRouterService` implementation, effectively applying the `unauthenticated` access level to all routes. Furthermore, it will also change `AuthService` so that the `getPluginRequestToken()` method will now issue an empty token for a `'none'` principal, rather than throwing.
+### Token Details
+
+Note that this section is NOT normative. It illustrates the token shapes and major token flows that are involved in this proposal, but intentionally leaves out some low level details and is subject to change.
+
+#### Backstage Identity Tokens
+
+These are the regular tokens, commonly in short referred to just as "Backstage Tokens", that the auth backend generates for the user during sign-in. These are sent along with calls to backend plugins to identify the user. This BEP does not aim to change the shape of these tokens; this section is only here for informative purposes to convey what pieces of information that are at play.
+
+This is a JWT token.
+
+```yaml
+# Header
+{
+ "alg": "ES256",
+ "kid": "4f5a0543-894a-4176-b0b7-699a7026b72f"
+}
+# Payload
+{
+ "iss": "http://localhost:7007/api/auth",
+ "sub": "user:default/example-user",
+ "ent": ["user:default/example-user", "group:default/my-team"],
+ "aud": "backstage",
+ "iat": 1708333140,
+ "exp": 1708336740
+}
+```
+
+The key ID is some random UUID. The `iss` (issuer) is the external base URL of your auth backend. Note that it uses the `ES256` asymmetric signature algorithm, and the auth backend exposes a JWKS that contains the public parts of the signing keys. The `sub` is an entity ref denoting who the signed in user is, and the `ent` is an array of entity refs that they claim ownership through. The `aud` (audience) is hardcoded to the string `"backstage"` always.
+
+#### Legacy Service Tokens
+
+These are the tokens that have been used for backend-to-backend communications before this BEP, and they will likely have changes as part of this work.
+
+This is a JWT token.
+
+```yaml
+# Header
+{
+ "alg": "HS256"
+}
+# Payload
+{
+ "sub": "backstage-server",
+ "exp": 1708337056
+}
+```
+
+Note that unlike the identity token in the previous section, it uses the `HS256` symmetric signature algorithm. The key used is the first of the `backend.auth.keys` entries in your `app-config`, which is a shared secret among all backend plugins, enabling them to know that the caller is a legitimate one. But the token does not contain any information about who the caller is (it's just a generic `"backstage-server"`), nor who the receiver (audience) is.
+
+#### New Cookie Token Flow
+
+Some plugins serve static content that the browser engine requests directly, e.g. the TechDocs plugin. Those calls cannot easily have a bearer token attached to them. For these use cases a cookie based flow will be used instead.
+
+
+
+The frontend part of the plugin ensures that a cookie endpoint on the backend part of the plugin is called before attempting to render static content. This endpoint validates the user's identity token and sets a corresponding cookie on the response. Subsequent requests for getting static content will automatically have this cookie attached to them by the browser.
+
+We intentionally do not specify here how the cookie token is acquired. It might be issued by the plugin itself or by the auth backend depending on how the architecture evolves, but this does not have any effect on plugin code.
+
+The cookie token contains the user's identifying information just like the identity cookie but is severely limited. It has the plugin itself specified as its audience. Thus, this token is not usable in any bearer token context, nor as a cookie toward any other plugin.
+
+#### New Service OBO Token Flow
+
+When a backend service needs to in turn make a request to another upstream service to fulfil the original request, it uses an On-Behalf-Of (OBO) token for the purpose.
+
+
+
+The initial request in this picture is a frontend plugin, but the same concept applies if it is initiated by a service. The scaffolder backend in this example acquires an OBO token to be able to talk to the catalog plugin.
+
+We intentionally do not specify here how the OBO token is acquired. It might be issued by the plugin itself or by the auth backend depending on how the architecture evolves, but this does not have any effect on plugin code.
+
+The OBO token specifies the target service as its audience and itself as the subject, but additionally also contains the original caller's identifying information. Thus, the target service can identify who the nearest caller is but also apply permissions that are relevant to the original caller. The token is thus scoped to not be usable toward other backend plugins.
+
## Release Plan
The existing `IdentityService` and `TokenManagerService` will be deprecated and instead implemented in terms of the new `AuthService`.
@@ -433,10 +511,11 @@ The new `AuthService` and `HttpAuthService` will need backwards compatible imple
The backwards compatibility helpers will have the following behavior for each individual service call:
-- `auth.authenticate(token)`: If the decoded token has the `backstage` audience, authenticate the token for a user principal using `identity.getIdentity(...)`, otherwise authenticate it using `tokenManager.authenticate(...)` and return a service principal with the subject `external:backstage-plugin`. If a no-op token manager is used then anything but a user token will be treated as a valid service token, which is consistent with existing behavior.
+- `auth.authenticate(token, options)`: If the decoded token has the `backstage` audience, authenticate the token for a user principal using `identity.getIdentity(...)`, otherwise authenticate it using `tokenManager.authenticate(...)` and return a service principal with the subject `external:backstage-plugin`. If a no-op token manager is used then anything but a user token will be treated as a valid service token, which is consistent with existing behavior. The limited access option is ignored.
- `auth.getOwnServiceCredentials()`: Use original implementation.
- `auth.isPrincipal()`: Use original implementation.
- `auth.getPluginRequestToken(options)`: Same behavior as the original implementation, using the `tokenManager` to issue service tokens, with the exception that a `none` principal will translate to an empty token rather than an error in order to properly forward calls with a no-op token manager.
+- `auth.getLimitedUserToken(credentials)`: This is a no-op and returns the underlying user token with full scope.
- `httpAuth.credentials(...)`: Use original implementation.
- `httpAuth.issueUserCookie(...)`: This is a no-op as we do not need to support cookie auth in the legacy adapter.
@@ -475,9 +554,9 @@ Cons:
- Can be extremely confusing because the top-level middleware for more lax access will also apply to the more strict access levels. For example
```ts
- const cookieRouter = Router();
- cookieRouter.use(rateLimit());
- http.useWithCookieAuthentication(cookieRouter);
+ const publicRouter = Router();
+ publicRouter.use(rateLimit());
+ http.useWithoutAuthentication(publicRouter);
const mainRouter = Router();
// rateLimit() will apply here too
@@ -487,7 +566,7 @@ Cons:
This applied to any similar way of structuring this API, such as a single `.use()` method with additional options:
```ts
-http.use(cookieRouter, { allow: ['user-cookie'] });
+http.use(publicRouter, { allow: ['unauthenticated'] });
```
#### Separate configuration on different paths for `use`
diff --git a/beps/0003-auth-architecture-evolution/token-sequence-cookie.drawio.svg b/beps/0003-auth-architecture-evolution/token-sequence-cookie.drawio.svg
new file mode 100644
index 0000000000..b20b528c35
--- /dev/null
+++ b/beps/0003-auth-architecture-evolution/token-sequence-cookie.drawio.svg
@@ -0,0 +1,203 @@
+
diff --git a/beps/0003-auth-architecture-evolution/token-sequence-obo.drawio.svg b/beps/0003-auth-architecture-evolution/token-sequence-obo.drawio.svg
new file mode 100644
index 0000000000..f337f8b572
--- /dev/null
+++ b/beps/0003-auth-architecture-evolution/token-sequence-obo.drawio.svg
@@ -0,0 +1,203 @@
+
diff --git a/beps/0004-scaffolder-task-idempotency/README.md b/beps/0004-scaffolder-task-idempotency/README.md
index a7e592af39..03569de3d6 100644
--- a/beps/0004-scaffolder-task-idempotency/README.md
+++ b/beps/0004-scaffolder-task-idempotency/README.md
@@ -4,7 +4,8 @@ status: provisional
authors:
- 'bnechyporenko@bol.com'
- 'benjaminl@spotify.com'
-owners:
+owners:
+ - @backstage/scaffolder-maintainers
project-areas:
- scaffolder
creation-date: 2024-01-31
@@ -153,7 +154,7 @@ export function createGithubRepoCreateAction(options: {
username: owner,
});
- await ctx.checkpoint('v1.task.checkpoint.repo.creation', async () => {
+ await ctx.checkpoint('repo.creation', async () => {
const repoCreationPromise =
user.data.type === 'Organization'
? client.rest.repos.createInOrg({
@@ -168,19 +169,16 @@ export function createGithubRepoCreateAction(options: {
});
if (secrets) {
- await ctx.checkpoint(
- 'v1.task.checkpoint.repo.create.variables',
- async () => {
- for (const [key, value] of Object.entries(repoVariables ?? {})) {
- await client.rest.actions.createRepoVariable({
- owner,
- repo,
- name: key,
- value: value,
- });
- }
- },
- );
+ await ctx.checkpoint('repo.create.variables', async () => {
+ for (const [key, value] of Object.entries(repoVariables ?? {})) {
+ await client.rest.actions.createRepoVariable({
+ owner,
+ repo,
+ name: key,
+ value: value,
+ });
+ }
+ });
}
ctx.output('remoteUrl', newRepo.clone_url);
@@ -204,7 +202,7 @@ Checkpoints will allow action authors to create actions where code paths are ign
This will be provided on a context object and action of author provide a key and a callback.
```typescript
-await ctx.checkpoint('v1.task.checkpoint.repo.creation', async () => {
+await ctx.checkpoint('repo.creation', async () => {
const { repoUrl } = await client.rest.Repository.create({});
return { repoUrl };
});
@@ -215,7 +213,7 @@ It's going look like:
```json
{
- "v1.task.checkpoint.repo.creation": {
+ "repo.creation": {
"status": "success",
"result": {
"repoUrl": "https://github.com/backstage/backstage.git"
@@ -224,6 +222,43 @@ It's going look like:
}
```
+or a failed attempt as:
+
+```json
+{
+ "repo.creation": {
+ "status": "failed",
+ "reason": "Namespace is not valid"
+ }
+}
+```
+
+DatabaseTaskStore will provide two extra methods `saveTaskState` and `getTaskState`. The type of state in API will be
+represented as `JsonObject`.
+
+Task state will be stored in the extra column `state` in the table `tasks` with the next structure:
+
+```json
+{
+ "state": {
+ "checkpoints": {
+ "repo.creation": {
+ "status": "success",
+ "result": {
+ "repoUrl": "https://github.com/backstage/backstage.git"
+ }
+ },
+ "repo.add.member": {
+ "status": "success",
+ "result": {
+ "id": "2345"
+ }
+ }
+ }
+ }
+}
+```
+
## Release Plan