Merge branch 'master' into feature/multiple_ldap_users_groups
Signed-off-by: Jente Sondervorst <jentesondervorst@gmail.com>
This commit is contained in:
@@ -71,7 +71,7 @@ This provider includes several resolvers out of the box that you can use:
|
||||
- `emailLocalPartMatchingUserEntityName`: Matches the [local part](https://en.wikipedia.org/wiki/Email_address#Local-part) of the email address from the auth provider with the User entity that has a matching `name`. If no match is found it will throw a `NotFoundError`.
|
||||
- `usernameMatchingUserEntityName`: Matches the username from the auth provider with the User entity that has a matching `name`. If no match is found it will throw a `NotFoundError`.
|
||||
|
||||
:::note
|
||||
:::note Note
|
||||
|
||||
The resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`.
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import { coreServices } from '@backstage/backend-plugin-api';
|
||||
- [Permissions Service](./permissions.md) - Permission system integration for authorization of user actions.
|
||||
- [Plugin Metadata Service](./plugin-metadata.md) - Built-in service for accessing metadata about the current plugin.
|
||||
- [Root Config Service](./root-config.md) - Access to static configuration.
|
||||
- [Root Health Service](./root-health.md) - Health check endpoints for the backend.
|
||||
- [Root Http Router Service](./root-http-router.md) - HTTP route registration for root services.
|
||||
- [Root Lifecycle Service](./root-lifecycle.md) - Registration of backend startup and shutdown lifecycle hooks.
|
||||
- [Root Logger Service](./root-logger.md) - Root-level logging.
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
---
|
||||
id: root-health
|
||||
title: Root Health Service
|
||||
sidebar_label: Health
|
||||
description: Documentation for the Health service
|
||||
---
|
||||
|
||||
The Root Health service provides some health check endpoints for the backend. By default, the `rootHttpRouter` exposes a `/.backstage/health/v1/readiness` and `/.backstage/health/v1/liveness` endpoints, which return a JSON object with the status of the backend services according the implementation of the Root Health Service.
|
||||
|
||||
## Configuring the service
|
||||
|
||||
The following example shows how you can override the root health service implementation.
|
||||
|
||||
```ts
|
||||
import { RootHealthService, coreServices } from '@backstage/backend-plugin-api';
|
||||
|
||||
const backend = createBackend();
|
||||
|
||||
class MyRootHealthService implements RootHealthService {
|
||||
async getLiveness() {
|
||||
// provide your own implementation
|
||||
return { status: 200, payload: { status: 'ok' } };
|
||||
}
|
||||
|
||||
async getReadiness() {
|
||||
// provide your own implementation
|
||||
return { status: 200, payload: { status: 'ok' } };
|
||||
}
|
||||
}
|
||||
|
||||
backend.add(
|
||||
createServiceFactory({
|
||||
service: coreServices.rootHealth,
|
||||
deps: {},
|
||||
async factory({}) {
|
||||
return new MyRootHealthService();
|
||||
},
|
||||
}),
|
||||
);
|
||||
```
|
||||
@@ -425,6 +425,10 @@ value. These are special in that they form the entity's unique
|
||||
The return type is JSON, as a single [`Entity`](descriptor-format.md), or a 404
|
||||
error if there was no entity with that reference triplet.
|
||||
|
||||
### `GET /entities/by-name/{kind}/{namespace}/{name}/ancestry`
|
||||
|
||||
Get an entity's ancestry by entity ref.
|
||||
|
||||
### `POST /entities/by-refs`
|
||||
|
||||
Gets a batch of entities by their entity refs. This is useful in contexts where
|
||||
@@ -456,6 +460,31 @@ where the `items` array has _the same length_ and _the same order_ as the input
|
||||
`entityRefs` array. Each element contains the corresponding entity data, or
|
||||
`null` if no entity existed in the catalog with that ref.
|
||||
|
||||
### `POST /refresh`
|
||||
|
||||
Refresh the entity related to `entityRef`.
|
||||
|
||||
Request body is JSON, on the form
|
||||
|
||||
```json
|
||||
{
|
||||
"entityRef": "<string>"
|
||||
}
|
||||
```
|
||||
|
||||
### `POST /validate-entity`
|
||||
|
||||
Validate that a passed in entity has no errors in schema.
|
||||
|
||||
Request body is JSON, on the form
|
||||
|
||||
```json
|
||||
{
|
||||
"location": "<string>",
|
||||
"entity": {}
|
||||
}
|
||||
```
|
||||
|
||||
## Locations
|
||||
|
||||
### `GET /locations`
|
||||
@@ -504,6 +533,23 @@ Response type is JSON, on the form
|
||||
}
|
||||
```
|
||||
|
||||
### `GET /entity-facets?facet=<string>&facet=<string>&filter=<string>&filter=<string>`
|
||||
|
||||
Get all entity facets that match the given filters.
|
||||
|
||||
Response type is JSON, on the form
|
||||
|
||||
```json
|
||||
{
|
||||
"facets": [
|
||||
{
|
||||
"value": "<string>",
|
||||
"count": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `POST /locations`
|
||||
|
||||
Adds a location to be ingested by the catalog.
|
||||
@@ -542,7 +588,59 @@ If the location already exists the response will be `HTTP/1.1 409 Conflict` and
|
||||
|
||||
Supports the `?dryRun=true` query parameter, which will perform validation and not write anything to the database. In the event of successfully passing validation, the `entities` field of the response JSON will be populated with entities present in the location.
|
||||
|
||||
### `DELETE /locations/<uid>`
|
||||
### `POST /analyze-location`
|
||||
|
||||
Validate a given location.
|
||||
|
||||
Request body is JSON, on the form
|
||||
|
||||
```json
|
||||
{
|
||||
"location": {
|
||||
"type": "<string>",
|
||||
"target": "<string>"
|
||||
},
|
||||
"catalogFileName": "<string>"
|
||||
}
|
||||
```
|
||||
|
||||
And Response type is JSON, on the form
|
||||
|
||||
```json
|
||||
{
|
||||
"generateEntities": [
|
||||
{
|
||||
"fields": [
|
||||
{
|
||||
"description": "<string>",
|
||||
"value": "<string>",
|
||||
"state": "needsUserInput",
|
||||
"field": "<string>"
|
||||
},
|
||||
{
|
||||
"description": "<string>",
|
||||
"value": {},
|
||||
"state": "analysisSuggestedNoValue",
|
||||
"field": "<string>"
|
||||
}
|
||||
],
|
||||
"entity": {}
|
||||
}
|
||||
],
|
||||
"existingEntityFiles": [
|
||||
{
|
||||
"entity": "<Entity>",
|
||||
"isRegistered": "<boolean>",
|
||||
"location": {
|
||||
"target": "<string>",
|
||||
"type": "<string>"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `DELETE /locations/{id}`
|
||||
|
||||
Delete a location by its id. On success response code will be `HTTP/1.1 204 No Content`.
|
||||
|
||||
|
||||
@@ -177,3 +177,106 @@ here.
|
||||
Setting this value too low risks exhausting rate limits on external systems that
|
||||
are queried by processors, such as version control systems housing catalog-info
|
||||
files.
|
||||
|
||||
## Subscribing to Catalog Errors
|
||||
|
||||
Catalog errors are published to the [events plugin](https://github.com/backstage/backstage/tree/master/plugins/events-node): `@backstage/plugin-events-node`. You can subscribe to events and respond to errors, for example you may wish to log them.
|
||||
|
||||
The first step is to add the events backend plugin to your Backstage application. Navigate to your Backstage application directory and add the plugin package.
|
||||
|
||||
```ts
|
||||
# From your Backstage root directory
|
||||
yarn --cwd packages/backend add @backstage/plugin-events-node
|
||||
```
|
||||
|
||||
Now you can install the events backend plugin in your backend.
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
backend.add(import('@backstage/plugin-events-backend/alpha'));
|
||||
```
|
||||
|
||||
### Logging Errors
|
||||
|
||||
If you want to log catalog errors you can install the `@backstage/plugin-catalog-backend-module-logs` module.
|
||||
|
||||
Install the catalog logs module.
|
||||
|
||||
```ts
|
||||
# From your Backstage root directory
|
||||
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-logs
|
||||
```
|
||||
|
||||
Add the module to your backend.
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
backend.add(import('@backstage/plugin-catalog-backend-module-logs'));
|
||||
```
|
||||
|
||||
This will log errors with a level of `warn`.
|
||||
|
||||
You should now see logs as the catalog emits events. Example:
|
||||
|
||||
```
|
||||
[1] 2024-06-07T00:00:28.787Z events warn Policy check failed for user:default/guest; caused by Error: Malformed envelope, /metadata/tags must be array entity=user:default/guest location=file:/Users/foobar/code/backstage-demo-instance/examples/org.yaml
|
||||
```
|
||||
|
||||
### Custom Error Handling
|
||||
|
||||
If you wish to handle catalog errors with specific logic different from logging the errors the following should help you get started. For example, you may wish to send a notification or create a ticket for someone to investigate.
|
||||
|
||||
Create a backend module that subscribes to the catalog error events. The topic is `experimental.catalog.errors`.
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
import { CATALOG_ERRORS_TOPIC } from '@backstage/plugin-catalog-backend';
|
||||
import {
|
||||
coreServices,
|
||||
createBackendModule,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { eventsServiceRef, EventParams } from '@backstage/plugin-events-node';
|
||||
|
||||
interface EventsPayload {
|
||||
entity: string;
|
||||
location?: string;
|
||||
errors: Error[];
|
||||
}
|
||||
|
||||
interface EventsParamsWithPayload extends EventParams {
|
||||
eventPayload: EventsPayload;
|
||||
}
|
||||
|
||||
const eventsModuleCatalogErrors = createBackendModule({
|
||||
pluginId: 'events',
|
||||
moduleId: 'catalog-errors',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
events: eventsServiceRef,
|
||||
logger: coreServices.logger,
|
||||
},
|
||||
async init({ events, logger }) {
|
||||
events.subscribe({
|
||||
id: 'catalog',
|
||||
topics: [CATALOG_ERRORS_TOPIC],
|
||||
async onEvent(params: EventParams): Promise<void> {
|
||||
const event = params as EventsParamsWithPayload;
|
||||
const { entity, location, errors } = event.eventPayload;
|
||||
// Add custom logic here for responding to errors
|
||||
for (const error of errors) {
|
||||
logger.warn(error.message, {
|
||||
entity,
|
||||
location,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Now install your module.
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
backend.add(eventsModuleCatalogErrors);
|
||||
```
|
||||
|
||||
@@ -197,13 +197,15 @@ cannot be parsed successfully, etc.
|
||||
|
||||
There are two main ways that these errors are surfaced.
|
||||
|
||||
First, the catalog backend will produce detailed logs that should contain
|
||||
sufficient information for a reader to find the causes for errors. Since these
|
||||
logs are typically not easily found by end users, this can mainly be a useful
|
||||
First, the catalog backend will emit events using the [events backend plugin](https://github.com/backstage/backstage/tree/master/plugins/events-node). You can subscribe to the events. The events should contain
|
||||
sufficient information for a reader to find the causes for errors. See the [configuration documentation](./configuration.md#subscribing-to-catalog-errors) for how to subscribe and log these error events.
|
||||
Since these events are typically not easily found by end users, this can mainly be a useful
|
||||
tool for Backstage operators who want to debug problems either with statically
|
||||
registered entities that are under their control, or to help end users find
|
||||
problems.
|
||||
|
||||
> Prior to Backstage version v1.26.0 and `@backstage/plugin-catalog-backend` v1.21.9 catalog errors were logged by default.
|
||||
|
||||
Second, for most classes of errors, the entity itself will contain a status
|
||||
field that describes the problem. The contents of this field is shown at the top
|
||||
of your entity page in Backstage, if you have placed the corresponding error
|
||||
|
||||
@@ -256,3 +256,51 @@ spec:
|
||||
input:
|
||||
url: ${{ '/root' if parameters.path !== true else parameters.path }}
|
||||
```
|
||||
|
||||
## Use placeholders to reference remote files
|
||||
|
||||
#### Note: testing of this functionality is not yet supported using _create/edit_
|
||||
|
||||
### template.yaml
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
parameters:
|
||||
- $yaml: https://github.com/example/path/to/example.yaml
|
||||
- title: Fill in some steps
|
||||
properties:
|
||||
path:
|
||||
title: path
|
||||
type: string
|
||||
|
||||
steps:
|
||||
- $yaml: https://github.com//example/path/to/action.yaml
|
||||
|
||||
- id: fetch
|
||||
name: Fetch template
|
||||
action: fetch:template
|
||||
input:
|
||||
url: ${{ parameters.path if parameters.path else '/root' }}
|
||||
```
|
||||
|
||||
### example.yaml
|
||||
|
||||
```yaml
|
||||
title: Provide simple information
|
||||
required:
|
||||
- url
|
||||
properties:
|
||||
url:
|
||||
title: url
|
||||
type: string
|
||||
```
|
||||
|
||||
### action.yaml
|
||||
|
||||
```yaml
|
||||
id: publish
|
||||
name: Publish files
|
||||
action: publish:github
|
||||
input:
|
||||
repoUrl: ${{ parameters.url }}
|
||||
```
|
||||
|
||||
@@ -226,7 +226,6 @@ should have something similar to the below in
|
||||
|
||||
```ts
|
||||
return await createRouter({
|
||||
containerRunner,
|
||||
catalogClient,
|
||||
logger: env.logger,
|
||||
config: env.config,
|
||||
|
||||
@@ -102,7 +102,7 @@ See [TechDocs Architecture](architecture.md) to get an overview of where the bel
|
||||
|
||||
## Get involved
|
||||
|
||||
Reach out to us in the **#docs-like-code** channel of our
|
||||
Reach out to us in the **#techdocs** channel of our
|
||||
[Discord chatroom](https://github.com/backstage/backstage#community).
|
||||
|
||||
## Done
|
||||
|
||||
@@ -142,7 +142,6 @@ export default async function createPlugin(
|
||||
// Generators are used for generating documentation sites.
|
||||
const generators = await Generators.fromConfig(env.config, {
|
||||
logger: env.logger,
|
||||
containerRunner,
|
||||
});
|
||||
|
||||
// Publisher is used for
|
||||
|
||||
@@ -150,6 +150,18 @@ microsoftGraphOrg:
|
||||
loadPhotos: false
|
||||
```
|
||||
|
||||
If you are using `userGroupMember`, the configuration for `loadPhotos` should still be managed under `users:` while omitting `search` and `filters`.
|
||||
|
||||
```yaml
|
||||
microsoftGraphOrg:
|
||||
providerId:
|
||||
user:
|
||||
loadPhotos: false
|
||||
userGroupMember:
|
||||
filter: "displayName eq 'Backstage Users'"
|
||||
search: '"description:One" AND ("displayName:Video" OR "displayName:Drive")'
|
||||
```
|
||||
|
||||
## Customizing Transformation
|
||||
|
||||
Ingested entities can be customized by providing custom transformers.
|
||||
|
||||
@@ -120,8 +120,8 @@ export default async function createPlugin(
|
||||
}),
|
||||
// optional: alternatively, use schedule
|
||||
scheduler: env.scheduler,
|
||||
events: env.events,
|
||||
});
|
||||
env.eventBroker.subscribe(gitlabProvider);
|
||||
builder.addEntityProvider(gitlabProvider);
|
||||
/* highlight-add-end */
|
||||
const { processingEngine, router } = await builder.build();
|
||||
|
||||
@@ -130,9 +130,9 @@ export default async function createPlugin(
|
||||
}),
|
||||
// optional: alternatively, use schedule
|
||||
scheduler: env.scheduler,
|
||||
events: env.events,
|
||||
},
|
||||
);
|
||||
env.eventBroker.subscribe(gitlabOrgProvider);
|
||||
builder.addEntityProvider(gitlabOrgProvider);
|
||||
/* highlight-add-end */
|
||||
const { processingEngine, router } = await builder.build();
|
||||
|
||||
@@ -309,11 +309,11 @@ map:
|
||||
In case you want to customize the ingested entities, the provider allows to pass
|
||||
transformers for users and groups.
|
||||
|
||||
Transformers can be configured by extending `ldapOrgEntityProviderTransformExtensionPoint`. Here is an example:
|
||||
Transformers can be configured by extending `ldapOrgEntityProviderTransformsExtensionPoint`. Here is an example:
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
import { createBackendModule } from '@backstage/backend-plugin-api';
|
||||
import { ldapOrgEntityProviderTransformExtensionPoint } from '@backstage/plugin-catalog-backend-module-ldap';
|
||||
import { ldapOrgEntityProviderTransformsExtensionPoint } from '@backstage/plugin-catalog-backend-module-ldap';
|
||||
import { myUserTransformer, myGroupTransformer } from './transformers';
|
||||
|
||||
backend.add(
|
||||
@@ -324,7 +324,7 @@ backend.add(
|
||||
env.registerInit({
|
||||
deps: {
|
||||
/* highlight-add-start */
|
||||
ldapTransformers: ldapOrgEntityProviderTransformExtensionPoint,
|
||||
ldapTransformers: ldapOrgEntityProviderTransformsExtensionPoint,
|
||||
/* highlight-add-end */
|
||||
},
|
||||
async init({ ldapTransformers }) {
|
||||
|
||||
@@ -281,14 +281,14 @@ export async function createRouter(
|
||||
allow: ['user'],
|
||||
});
|
||||
|
||||
const userInfo = await userInfo.getUserInfo(credentials);
|
||||
const user = await userInfo.getUserInfo(credentials);
|
||||
|
||||
res.json({
|
||||
// The catalog entity ref of the user.
|
||||
userEntityRef: userInfo.userEntityRef,
|
||||
userEntityRef: user.userEntityRef,
|
||||
|
||||
// The list of entities that this user or any teams this user is a part of owns.
|
||||
ownershipEntityRefs: userInfo.ownershipEntityRefs,
|
||||
ownershipEntityRefs: user.ownershipEntityRefs,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,202 @@
|
||||
---
|
||||
id: v1.28.0
|
||||
title: v1.28.0
|
||||
description: Backstage Release v1.28.0
|
||||
---
|
||||
|
||||
These are the release notes for the v1.28.0 release of [Backstage](https://backstage.io/).
|
||||
|
||||
A huge thanks to the whole team of maintainers and contributors as well as the amazing Backstage Community for the hard work in getting this release developed and done.
|
||||
|
||||
## Highlights
|
||||
|
||||
### **BREAKING**: Proxy backend plugin protected by default
|
||||
|
||||
The proxy backend plugin is now protected by Backstage auth, by default. Unless specifically configured (see below), all proxy endpoints will reject requests immediately unless a valid Backstage user or service token is passed along with the request. This aligns the proxy with how other Backstage backends behave out of the box, and serves to protect your upstreams from unauthorized access.
|
||||
|
||||
Here's an example of how to configure:
|
||||
|
||||
```diff
|
||||
proxy:
|
||||
endpoints:
|
||||
'/pagerduty':
|
||||
target: https://api.pagerduty.com
|
||||
+ credentials: require
|
||||
headers:
|
||||
Authorization: Token token=${PAGERDUTY_TOKEN}
|
||||
```
|
||||
|
||||
There are three `credentials` settings:
|
||||
|
||||
- `require`: Callers need Backstage credentials. These are not forwarded to the target.
|
||||
- `forward`: Callers need Backstage credentials, which are forwarded to the target.
|
||||
- `dangerously-allow-unauthenticated`: No Backstage credentials needed. Target can apply its own checks. Incoming tokens of any sort will be allowed but ignored, and will also be forwarded if `allowedHeaders: ['Authorization']` is included.
|
||||
|
||||
The new default is `require`, replacing the old `dangerously-allow-unauthenticated`. This means some previously permitted requests may now result in `401 Unauthorized` responses. This does not apply if `backend.auth.dangerouslyDisableDefaultAuthPolicy` is set to `true`.
|
||||
|
||||
For proxy endpoints still requiring unauthenticated access, add `credentials: dangerously-allow-unauthenticated` in your app-config.
|
||||
|
||||
See [the proxy documentation](https://backstage.io/docs/plugins/proxying/) for more information.
|
||||
|
||||
### **BREAKING**: Gerrit integration breaking changes
|
||||
|
||||
- The `workdir` argument have been removed from The `GerritUrlReader` constructor;
|
||||
- The Gerrit `readTree` implementation will now only use the Gitiles api, so the support for using git to clone the repo has been removed;
|
||||
- The `gitilesBaseUrl` is now mandatory for the Gerrit integration and the ability to override this requirement using the `DISABLE_GERRIT_GITILES_REQUIREMENT` environment variable has been removed.
|
||||
|
||||
Contributed by [@anicke](https://github.com/anicke) in [#25123](https://github.com/backstage/backstage/pull/25123).
|
||||
|
||||
### **BREAKING**: Github integration breaking changes
|
||||
|
||||
- Removed deprecated code from when casing was changed from `GitHub` to `Github` nearly two years ago. The following items have been removed:
|
||||
- `getGitHubFileFetchUrl` (use `getGithubFileFetchUrl` instead)
|
||||
- `GitHubIntegrationConfig` (use `GithubIntegrationConfig` instead)
|
||||
- `GitHubIntegration` (use `GithubIntegration` instead)
|
||||
- `readGitHubIntegrationConfig` (use `readGithubIntegrationConfig` instead)
|
||||
- `readGitHubIntegrationConfigs` (use `readGithubIntegrationConfigs` instead)
|
||||
- `replaceGitHubUrlType` (use `replaceGithubUrlType` instead)
|
||||
|
||||
Contributed by [@awanlin](https://github.com/awanlin) in [#25100](https://github.com/backstage/backstage/pull/25100).
|
||||
|
||||
### **BREAKING**: OAuth Scope Updates
|
||||
|
||||
The way that OAuth-based auth providers handle scopes has received several updates. There is now a new `.additionalScopes` configuration for all OAuth providers, which can be used to request additional scopes for all sessions. Many providers already had a similar configuration, but in most cases this did not work correctly as scopes requested by the client would override the configured set.
|
||||
|
||||
Many providers now also have a set of required scopes that will always be present. This is in contrast to the previous solution where the client would be responsible for including a set of baseline scopes.
|
||||
|
||||
A bug has also been fixed in the handling of persistent scopes, which could break session refresh for some providers, such as GitHub.
|
||||
|
||||
### **BREAKING**: User Info service
|
||||
|
||||
Limited-access user tokens (as used in cookies) no longer contain the `ent` ownership claim. This is notably used by TechDocs and the app-backend. If you use those services, you may want to log out and in again.
|
||||
|
||||
Background: As part of the previous auth improvements, we added the `coreServices.userInfo` service. This service can extract user details from incoming credentials - notably the so-called `ent` claim with its ownership information.
|
||||
|
||||
In this release, the auth backend part of this has been implemented, such that the information returned by your sign-in resolver gets persisted and can be acquired after the fact. With this in place, we could finally start slimming down on token sizes, starting with the cookie tokens. Unfortunately this has to be done in such a way that it’s breaking in the short term.
|
||||
|
||||
If any issues persist, try clearing your cookies, and then reach out to us on Discord or with an issue if necessary.
|
||||
|
||||
Contributed by [@kuangp](https://github.com/kuangp) in [#24729](https://github.com/backstage/backstage/pull/24729).
|
||||
|
||||
### New Backend System API movement towards 1.0 release
|
||||
|
||||
As part of finalizing the [New Backend System](https://backstage.io/docs/backend-system/), we are restructuring the out-of-the-box functionality a bit. As part of this release, you will see a large amount of deprecations on the `@backstage/backend-common` package (which will be deleted in a future release), and also on the `@backstage/backend-app-api` package (which is just being slimmed down to its essentials). Instead, you will see that the `@backstage/backend-defaults` package has received new subpath exports that neatly arrange all of these factories and default implementations.
|
||||
|
||||
As an example, the `rootLoggerServiceFactory` export on `@backstage/backend-app-api` has been deprecated, and should now be imported from `@backstage/backend-defaults/rootLogger`. Most other deprecations follow the same pattern. Each deprecated symbol should have a deprecation message on it, which clearly states from where you should now be importing that particular functionality instead.
|
||||
|
||||
This rearrangement was one of the crucial final pieces for settling the API surfaces of this backend system! We hope you’ll find it neater and clearer to understand.
|
||||
|
||||
Please update deprecated imports in your own repo code as soon as convenient, to avoid the breaking changes in future releases when these symbols are finally removed.
|
||||
|
||||
You will also note that backend features (plugins and modules) no longer are returned as functions, which simplifies interacting with features! You may see this in your editor in the form of deprecations, whose message tells you to remove the trailing parentheses.
|
||||
|
||||
Your code may be changed in the following way as an example:
|
||||
|
||||
```diff
|
||||
await startTestBackend({
|
||||
features: [
|
||||
// service - stays unchanged
|
||||
eventsServiceFactory(),
|
||||
// module - remove parentheses
|
||||
- catalogModuleBitbucketCloudEntityProvider(),
|
||||
+ catalogModuleBitbucketCloudEntityProvider,
|
||||
```
|
||||
|
||||
In related news, we have unified some type names. The `UrlReader` types are now properly prefixed with the service name, so you’ll see that for example `ReadTreeOptions` is now `UrlReaderServiceReadTreeOptions`. Functions better follow the proper naming convention for their arguments, for example `BackendPluginConfig` now becoming `CreateBackendPluginOptions`.
|
||||
|
||||
### Package Metadata - Important for Package Publishers!
|
||||
|
||||
All `@backstage/*` packages now include a new set of metadata in `package.json` that helps associate related plugin packages with each other. This metadata is also required for all packages published through the `@backstage/cli` to the Backstage ecosystem. For this purpose, a new `--publish` flag has been added to the `repo fix` command. You can read more about this requirement and how to generate the metadata in the documentation section on [Metadata for Published Packages](https://backstage.io/docs/tooling/package-metadata#metadata-for-published-packages).
|
||||
|
||||
### Other Auth Improvements
|
||||
|
||||
The OneLogin auth implementation now lives in its own module, `@backstage/plugin-auth-backend-module-onelogin-provider`.
|
||||
|
||||
In some special use cases such as when you have read-replica databases, you may desire to not use the builtin zero-config plugin-to-plugin auth system that stores keys in the database. For those cases, there is now a new static mode where you supply key pairs in config that are used for this purpose. The howto is [in the docs](https://backstage.io/docs/auth/service-to-service-auth#static-keys-for-plugin-to-plugin-auth).
|
||||
|
||||
There is also a new general `jwks` external access method for those of you who want to externally call Backstage plugins using already-established token flows! Check out [the docs](https://backstage.io/docs/auth/service-to-service-auth#jwks-token-auth).
|
||||
|
||||
Contributed by [@ryan-hanchett](https://github.com/ryan-hanchett) in [#24681](https://github.com/backstage/backstage/pull/24681).
|
||||
|
||||
### Scaffolder `ui:widget: password` notice
|
||||
|
||||
Using `ui:widget: password` does not treat the input as a secret in the Scaffolder, and can lead to exposing some secrets in plaintext, this implementation has been overridden to provide warnings to users that mistakenly use this component and will now render a warning message along with rendering the input in plaintext for additional indication.
|
||||
|
||||
Please use the `ui:field: Secret` option instead, as is mentioned in the [using secrets](https://backstage.io/docs/features/software-templates/writing-templates/#using-secrets) documentation.
|
||||
|
||||
### New Scaffolder Permissions
|
||||
|
||||
The Scaffolder plugin has been upgraded to include additional permissions:
|
||||
|
||||
- `scaffolder.task.create`
|
||||
- `scaffolder.task.cancel`
|
||||
- `scaffolder.task.read`
|
||||
|
||||
The new permissions allow you to control who should have read or write access to tasks.
|
||||
|
||||
Contributed by [@Zaperex](https://github.com/Zaperex) in [#24518](https://github.com/backstage/backstage/pull/24518).
|
||||
|
||||
### Route bindings via app-config
|
||||
|
||||
It is now possible to configure route bindings through static configuration, using the `app.routes.bindings` key. For example:
|
||||
|
||||
```yaml
|
||||
app:
|
||||
routes:
|
||||
bindings:
|
||||
catalog.createComponent: catalog-import.importPage
|
||||
```
|
||||
|
||||
Is the equivalent of the following:
|
||||
|
||||
```ts
|
||||
const app = createApp({
|
||||
// ...
|
||||
bindRoutes({ bind }) {
|
||||
bind(catalogPlugin.externalRoutes, {
|
||||
createComponent: catalogImportPlugin.routes.importPage,
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Additionally, the following default targets have been added for external routes.
|
||||
|
||||
- For catalog:
|
||||
- `createComponent` binds to the Scaffolder page.
|
||||
- `viewTechDoc` binds to the TechDocs entity documentation page.
|
||||
- `createFromTemplate` binds to the Scaffolder selected template page
|
||||
- For scaffolder:
|
||||
- `registerComponent` binds to the catalog import page.
|
||||
- `viewTechDoc` binds to the TechDocs entity documentation page.
|
||||
|
||||
## Security Fixes
|
||||
|
||||
This release does not contain any security fixes.
|
||||
|
||||
## Upgrade path
|
||||
|
||||
We recommend that you keep your Backstage project up to date with this latest release. For more guidance on how to upgrade, check out the documentation for [keeping Backstage updated](https://backstage.io/docs/getting-started/keeping-backstage-updated).
|
||||
|
||||
### Test utilities
|
||||
|
||||
There is now a `TestCaches` class in `@backstage/backend-test-utils` that functions just like `TestDatabases`. This may help in testing out cache based flows against actual cache implementations, using `testcontainers` if available!
|
||||
|
||||
### Notifications improvements
|
||||
|
||||
The notifications system has received numerous updates, including the ability to perform in-flight processing of notifications. The related signals subsystem now also powers real time updates of the user settings plugin. Thanks to the notifications maintainers for their tireless efforts in this exciting area!
|
||||
|
||||
## Links and References
|
||||
|
||||
Below you can find a list of links and references to help you learn about and start using this new release.
|
||||
|
||||
- [Backstage official website](https://backstage.io/), [documentation](https://backstage.io/docs/), and [getting started guide](https://backstage.io/docs/getting-started/)
|
||||
- [GitHub repository](https://github.com/backstage/backstage)
|
||||
- Backstage's [versioning and support policy](https://backstage.io/docs/overview/versioning-policy)
|
||||
- [Community Discord](https://discord.gg/backstage-687207715902193673) for discussions and support
|
||||
- [Changelog](https://github.com/backstage/backstage/tree/master/docs/releases/v1.28.0-changelog.md)
|
||||
- Backstage [Demos](https://backstage.io/demos), [Blog](https://backstage.io/blog), [Roadmap](https://backstage.io/docs/overview/roadmap) and [Plugins](https://backstage.io/plugins)
|
||||
|
||||
Sign up for our [newsletter](https://info.backstage.spotify.com/newsletter_subscribe) if you want to be informed about what is happening in the world of Backstage.
|
||||
|
||||
Big shoutout to all 64 of you amazing folks who chipped in on this release 🙏: [@acierto](https://github.com/acierto), [@adityak60](https://github.com/adityak60), [@adsk-mukul](https://github.com/adsk-mukul), [@alexef](https://github.com/alexef), [@andrei-ivanovici](https://github.com/andrei-ivanovici), [@anicke](https://github.com/anicke), [@aramissennyeydd](https://github.com/aramissennyeydd), [@awanlin](https://github.com/awanlin), [@benjdlambert](https://github.com/benjdlambert), [@benjidotsh](https://github.com/benjidotsh), [@bethgriggs](https://github.com/bethgriggs), [@brianphillips](https://github.com/brianphillips), [@brunobastosg](https://github.com/brunobastosg), [@camilaibs](https://github.com/camilaibs), [@cjlee01](https://github.com/cjlee01), [@cmoulliard](https://github.com/cmoulliard), [@davidfestal](https://github.com/davidfestal), [@debsmita1](https://github.com/debsmita1), [@drodil](https://github.com/drodil), [@dweber019](https://github.com/dweber019), [@elaine-mattos](https://github.com/elaine-mattos), [@erik-adsk](https://github.com/erik-adsk), [@fabian-m-95](https://github.com/fabian-m-95), [@freben](https://github.com/freben), [@grantila](https://github.com/grantila), [@huggingpixels](https://github.com/huggingpixels), [@ismailmmd](https://github.com/ismailmmd), [@jeevaramanathan](https://github.com/jeevaramanathan), [@johanhammar](https://github.com/johanhammar), [@jslott2sigma](https://github.com/jslott2sigma), [@julien-hery](https://github.com/julien-hery), [@kalleericson](https://github.com/kalleericson), [@kissmikijr](https://github.com/kissmikijr), [@kuangp](https://github.com/kuangp), [@maetis](https://github.com/maetis), [@marcpalm](https://github.com/marcpalm), [@marcuseide](https://github.com/marcuseide), [@mareklibra](https://github.com/mareklibra), [@mario-mui](https://github.com/mario-mui), [@matteosilv](https://github.com/matteosilv), [@mclarke47](https://github.com/mclarke47), [@npiyush97](https://github.com/npiyush97), [@nurbaysymbat](https://github.com/nurbaysymbat), [@parsifal-m](https://github.com/parsifal-m), [@piatkiewicz](https://github.com/piatkiewicz), [@raffitamizian](https://github.com/raffitamizian), [@rbillon59](https://github.com/rbillon59), [@rewixe](https://github.com/rewixe), [@rugvip](https://github.com/rugvip), [@ryan-hanchett](https://github.com/ryan-hanchett), [@sblausten](https://github.com/sblausten), [@snowblitzer](https://github.com/snowblitzer), [@stanislav-c](https://github.com/stanislav-c), [@stephenglass](https://github.com/stephenglass), [@stijnbrouwers](https://github.com/stijnbrouwers), [@suniljose25](https://github.com/suniljose25), [@tcardonne](https://github.com/tcardonne), [@vadave](https://github.com/vadave), [@veenarm](https://github.com/veenarm), [@vinisdl](https://github.com/vinisdl), [@vinzscam](https://github.com/vinzscam), [@waldirmontoya25](https://github.com/waldirmontoya25), [@ydayagi](https://github.com/ydayagi), [@zaperex](https://github.com/zaperex).
|
||||
Reference in New Issue
Block a user