Merge branch 'master' of https://github.com/backstage/backstage into update/review-explode
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Added `MyGroupsSidebarItem` to the sidebar in the `create-app` template
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/backend-plugin-api': patch
|
||||
'@backstage/backend-defaults': patch
|
||||
---
|
||||
|
||||
Added a new Root Health Service which adds new endpoints for health checks.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': minor
|
||||
---
|
||||
|
||||
Use virtualization with `EntityPicker` as done earlier with `MultiEntityPicker` to fix performance issues with large data sets. `VirtualizedListbox` extracted into reusable component.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs': patch
|
||||
---
|
||||
|
||||
Fixed an issue that was causing techdocs pages unnecessarily re-render on navigate.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/backend-test-utils': patch
|
||||
'@backstage/backend-defaults': patch
|
||||
'@backstage/backend-app-api': patch
|
||||
---
|
||||
|
||||
The `ServiceFactoryTest.get` method was deprecated and the `ServiceFactoryTest.getSubject` should be used instead. The `getSubject` method has the same behavior, but has a better method name to indicate that the service instance returned is the subject currently being tested.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-auth-backend-module-atlassian-provider': patch
|
||||
---
|
||||
|
||||
Fix several issues with the Atlassian auth provider (type definition, profile url, profile transformation, scopes)
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
---
|
||||
|
||||
Deprecate legacy status check factory, handler and types.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-msgraph': patch
|
||||
---
|
||||
|
||||
Adds a dynamic provider for the plugin-catalog-backend-module-msgraph. Configuration is now runtime configurable through the ProviderConfigTransformer.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs-react': patch
|
||||
---
|
||||
|
||||
Resolved the issue where changes in TechDoc add-ons, including the TextSize add-on, were not reapplying during navigation
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/backend-defaults': minor
|
||||
'@backstage/backend-app-api': minor
|
||||
---
|
||||
|
||||
**BREAKING**: Removed the depreacted `getPath` option from `httpRouterServiceFactory`, as well as the `HttpRouterFactoryOptions` type.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Bumped create-app version.
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-ldap': patch
|
||||
'@backstage/backend-plugin-api': patch
|
||||
'@backstage/backend-defaults': patch
|
||||
'@backstage/backend-tasks': patch
|
||||
---
|
||||
|
||||
Fix bug where ISO durations could no longer be used for schedules
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
Updated `catalog:write` scaffolder action to show correct file path location in log message
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-github': patch
|
||||
---
|
||||
|
||||
Fixed bug resulting from missing required owner and repo arguments in `getEnvironmentPublicKey` in action `github:environment:create`.
|
||||
|
||||
Adding environment secrets now works as expected.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
---
|
||||
|
||||
Fixed bug where `<Select>` component with empty string as placeholder gave an error
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs': patch
|
||||
---
|
||||
|
||||
Improve default sorting of docs table
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs-backend': patch
|
||||
'@backstage/plugin-techdocs-node': patch
|
||||
---
|
||||
|
||||
Adds extension point for publishers to the techdocs backend
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-bitbucket-server': patch
|
||||
---
|
||||
|
||||
Instead of using hardcoded `targetBranch` now fetch the default branch from Bitbucket repository.
|
||||
This prevents from errors when no `targetBranch` is provided and the default repository branch is different from `master`, for example: `main`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Added the Catalog logs module to the `create-app` template
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
'@backstage/core-app-api': minor
|
||||
'@backstage/frontend-app-api': patch
|
||||
---
|
||||
|
||||
Allow for the disabling of external routes through config, which was rendered impossible after the introduction of default targets.
|
||||
|
||||
```yaml
|
||||
app:
|
||||
routes:
|
||||
bindings:
|
||||
# This has the effect of removing the button for registering new
|
||||
# catalog entities in the scaffolder template list view
|
||||
scaffolder.registerComponent: false
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-org': patch
|
||||
---
|
||||
|
||||
The `useGetEntities` hook could result in requests to `/api/catalog/entities` where the headers exceed the default maximum Node.js header size of 16KB. The hook logic has been adjusted to batch the requests.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-gitlab': patch
|
||||
---
|
||||
|
||||
The Gitlab configuration supports an additional optional boolean key `catalog.providers.gitlab.<your-org>.restrictUsersToGroup`. Setting this to `true` will make Backstage only import users from the group defined in the `group` key, instead of all users in the organisation (self-hosted) or of the root group (SaaS). It will default to false, keeping the original implementation intact, when not explicitly set.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-test-utils': patch
|
||||
---
|
||||
|
||||
The function `isDockerDisabledForTests` is deprecated and will no longer be exported in the near future as it should only be used internally.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
enable resizing of the task log stream viewer
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-ldap': minor
|
||||
---
|
||||
|
||||
**BREAKING**: `readLdapOrg` and the `LdapProviderConfig` type now always accept arrays of user and group configs, not just single items.
|
||||
|
||||
Added support for single ldap catalog provider to provide list and undefined user and group bindings next to standard single one.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-app-api': patch
|
||||
---
|
||||
|
||||
Updated config schema to support app.routes.bindings
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/integration': minor
|
||||
---
|
||||
|
||||
Add support for `token` for `bitbucketCloud` integration
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-react': patch
|
||||
'@backstage/plugin-catalog': patch
|
||||
---
|
||||
|
||||
Support i18n for catalog and catalog-react plugins
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
- remove unused dependencies `winston` and `yn` from the template of backend plugins;
|
||||
- update `msw` to version `2.3.1` in the template of backend plugins;
|
||||
starting with v1 and switching later to v2 is tedious and not straight forward; it's easier to start with v2;
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Updated the scaffolding output message for `plugin-common` in `backstage-cli`. Now, when executing `backstage-cli new` to create a new `plugin-common` package, the output message accurately reflects the action by displaying `Creating common plugin package...` instead of the previous, less accurate `Creating backend plugin...`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': minor
|
||||
---
|
||||
|
||||
Use virtualization with `MultiEntityPicker`. Fixes performance issues with large data sets.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-azure': patch
|
||||
'@backstage/plugin-scaffolder-node': patch
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Fixed a bug where the `RepoUrlPicker` would still require the `owner` field for `azure`
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Update default backend plugin created by the cli to use non-deprecated error handling middleware
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
Added a documentation how to use checkpoints
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-bitbucket-cloud': patch
|
||||
'@backstage/plugin-bitbucket-cloud-common': patch
|
||||
---
|
||||
|
||||
Add support for `autocomplete` handler to provide autocomplete options for `RepoUrlPicker`
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-org': patch
|
||||
---
|
||||
|
||||
Added `relationType` property to EntityMembersListCard component that allows for display users related to a group via some other relationship aside from `memberOf`.
|
||||
|
||||
Also, as a side effect, the `relationsType` property has been deprecated in favor of a more accurately named `relationAggregation` property.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-react': patch
|
||||
---
|
||||
|
||||
Make EntityOwnerPicker display metadata.title or spec.profile.displayName for mode=only-owners instead of metadata.name
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs': patch
|
||||
---
|
||||
|
||||
Fix double scrollbar bug in reader
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-notifications': patch
|
||||
---
|
||||
|
||||
The toolbar on the Notifications page is hidden when there are no listed notifications.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-aws': patch
|
||||
---
|
||||
|
||||
Export `defaultEksClusterEntityTransformer` to allow library consumers to layer additional changes on top of the default transformer.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs-node': patch
|
||||
---
|
||||
|
||||
Bumps default version of techdocs docker image to latest
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
---
|
||||
|
||||
Modified the `Select` component to take in a `data-testid` parameter ensuring backwards compatibility with default value corresponding to previously hardcoded `data-testid` of "select".
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-github': patch
|
||||
---
|
||||
|
||||
Adds support for `repository` events.
|
||||
|
||||
The provider adds a subscription to the topic `github.repository`.
|
||||
|
||||
Hereby, it supports events of type `repository` with actions
|
||||
|
||||
- `archived`
|
||||
- `deleted`
|
||||
- `edited`
|
||||
- `renamed`
|
||||
- `transferred`
|
||||
- `unarchived`
|
||||
|
||||
Actions skipped as they don't require entity changes:
|
||||
|
||||
- `created`
|
||||
- `privatized`
|
||||
- `publicized`
|
||||
|
||||
If the config option `validateLocationsExist` is enabled, an API request
|
||||
is necessary and will be executed.
|
||||
This affects the actions `renamed`, `transferred`, and `unarchive`
|
||||
of event type `repository`.
|
||||
|
||||
Catalog entities related to the `GithubEntityProvider` instance will be adjusted
|
||||
according to action and its meaning for them.
|
||||
@@ -0,0 +1,258 @@
|
||||
{
|
||||
"mode": "pre",
|
||||
"tag": "next",
|
||||
"initialVersions": {
|
||||
"example-app": "0.2.98",
|
||||
"@backstage/app-defaults": "1.5.6",
|
||||
"example-app-next": "0.0.12",
|
||||
"app-next-example-plugin": "0.0.12",
|
||||
"example-backend": "0.0.27",
|
||||
"@backstage/backend-app-api": "0.7.6",
|
||||
"@backstage/backend-common": "0.23.0",
|
||||
"@backstage/backend-defaults": "0.3.0",
|
||||
"@backstage/backend-dev-utils": "0.1.4",
|
||||
"@backstage/backend-dynamic-feature-service": "0.2.11",
|
||||
"example-backend-legacy": "0.2.99",
|
||||
"@backstage/backend-openapi-utils": "0.1.12",
|
||||
"@backstage/backend-plugin-api": "0.6.19",
|
||||
"@backstage/backend-tasks": "0.5.24",
|
||||
"@backstage/backend-test-utils": "0.4.0",
|
||||
"@backstage/catalog-client": "1.6.5",
|
||||
"@backstage/catalog-model": "1.5.0",
|
||||
"@backstage/cli": "0.26.7",
|
||||
"@backstage/cli-common": "0.1.14",
|
||||
"@backstage/cli-node": "0.2.6",
|
||||
"@backstage/codemods": "0.1.49",
|
||||
"@backstage/config": "1.2.0",
|
||||
"@backstage/config-loader": "1.8.1",
|
||||
"@backstage/core-app-api": "1.12.6",
|
||||
"@backstage/core-compat-api": "0.2.6",
|
||||
"@backstage/core-components": "0.14.8",
|
||||
"@backstage/core-plugin-api": "1.9.3",
|
||||
"@backstage/create-app": "0.5.16",
|
||||
"@backstage/dev-utils": "1.0.33",
|
||||
"e2e-test": "0.2.17",
|
||||
"@backstage/e2e-test-utils": "0.1.1",
|
||||
"@backstage/errors": "1.2.4",
|
||||
"@backstage/eslint-plugin": "0.1.8",
|
||||
"@backstage/frontend-app-api": "0.7.1",
|
||||
"@backstage/frontend-plugin-api": "0.6.6",
|
||||
"@backstage/frontend-test-utils": "0.1.8",
|
||||
"@backstage/integration": "1.12.0",
|
||||
"@backstage/integration-aws-node": "0.1.12",
|
||||
"@backstage/integration-react": "1.1.28",
|
||||
"@backstage/release-manifests": "0.0.11",
|
||||
"@backstage/repo-tools": "0.9.1",
|
||||
"@techdocs/cli": "1.8.12",
|
||||
"techdocs-cli-embedded-app": "0.2.97",
|
||||
"@backstage/test-utils": "1.5.6",
|
||||
"@backstage/theme": "0.5.6",
|
||||
"@backstage/types": "1.1.1",
|
||||
"@backstage/version-bridge": "1.0.8",
|
||||
"yarn-plugin-backstage": "0.0.1",
|
||||
"@backstage/plugin-api-docs": "0.11.6",
|
||||
"@backstage/plugin-api-docs-module-protoc-gen-doc": "0.1.7",
|
||||
"@backstage/plugin-app-backend": "0.3.68",
|
||||
"@backstage/plugin-app-node": "0.1.19",
|
||||
"@backstage/plugin-app-visualizer": "0.1.7",
|
||||
"@backstage/plugin-auth-backend": "0.22.6",
|
||||
"@backstage/plugin-auth-backend-module-atlassian-provider": "0.2.0",
|
||||
"@backstage/plugin-auth-backend-module-aws-alb-provider": "0.1.11",
|
||||
"@backstage/plugin-auth-backend-module-azure-easyauth-provider": "0.1.2",
|
||||
"@backstage/plugin-auth-backend-module-bitbucket-provider": "0.1.2",
|
||||
"@backstage/plugin-auth-backend-module-cloudflare-access-provider": "0.1.2",
|
||||
"@backstage/plugin-auth-backend-module-gcp-iap-provider": "0.2.14",
|
||||
"@backstage/plugin-auth-backend-module-github-provider": "0.1.16",
|
||||
"@backstage/plugin-auth-backend-module-gitlab-provider": "0.1.16",
|
||||
"@backstage/plugin-auth-backend-module-google-provider": "0.1.16",
|
||||
"@backstage/plugin-auth-backend-module-guest-provider": "0.1.5",
|
||||
"@backstage/plugin-auth-backend-module-microsoft-provider": "0.1.14",
|
||||
"@backstage/plugin-auth-backend-module-oauth2-provider": "0.2.0",
|
||||
"@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "0.1.12",
|
||||
"@backstage/plugin-auth-backend-module-oidc-provider": "0.2.0",
|
||||
"@backstage/plugin-auth-backend-module-okta-provider": "0.0.12",
|
||||
"@backstage/plugin-auth-backend-module-onelogin-provider": "0.1.0",
|
||||
"@backstage/plugin-auth-backend-module-pinniped-provider": "0.1.13",
|
||||
"@backstage/plugin-auth-backend-module-vmware-cloud-provider": "0.2.0",
|
||||
"@backstage/plugin-auth-node": "0.4.14",
|
||||
"@backstage/plugin-auth-react": "0.1.3",
|
||||
"@backstage/plugin-bitbucket-cloud-common": "0.2.20",
|
||||
"@backstage/plugin-catalog": "1.21.0",
|
||||
"@backstage/plugin-catalog-backend": "1.23.0",
|
||||
"@backstage/plugin-catalog-backend-module-aws": "0.3.14",
|
||||
"@backstage/plugin-catalog-backend-module-azure": "0.1.39",
|
||||
"@backstage/plugin-catalog-backend-module-backstage-openapi": "0.2.2",
|
||||
"@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.2.6",
|
||||
"@backstage/plugin-catalog-backend-module-bitbucket-server": "0.1.33",
|
||||
"@backstage/plugin-catalog-backend-module-gcp": "0.1.20",
|
||||
"@backstage/plugin-catalog-backend-module-gerrit": "0.1.36",
|
||||
"@backstage/plugin-catalog-backend-module-github": "0.6.2",
|
||||
"@backstage/plugin-catalog-backend-module-github-org": "0.1.14",
|
||||
"@backstage/plugin-catalog-backend-module-gitlab": "0.3.18",
|
||||
"@backstage/plugin-catalog-backend-module-gitlab-org": "0.0.2",
|
||||
"@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.4.24",
|
||||
"@backstage/plugin-catalog-backend-module-ldap": "0.6.0",
|
||||
"@backstage/plugin-catalog-backend-module-msgraph": "0.5.27",
|
||||
"@backstage/plugin-catalog-backend-module-openapi": "0.1.37",
|
||||
"@backstage/plugin-catalog-backend-module-puppetdb": "0.1.25",
|
||||
"@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.1.17",
|
||||
"@backstage/plugin-catalog-backend-module-unprocessed": "0.4.6",
|
||||
"@backstage/plugin-catalog-common": "1.0.24",
|
||||
"@backstage/plugin-catalog-graph": "0.4.6",
|
||||
"@backstage/plugin-catalog-import": "0.12.0",
|
||||
"@backstage/plugin-catalog-node": "1.12.1",
|
||||
"@backstage/plugin-catalog-react": "1.12.1",
|
||||
"@backstage/plugin-catalog-unprocessed-entities": "0.2.5",
|
||||
"@backstage/plugin-catalog-unprocessed-entities-common": "0.0.2",
|
||||
"@backstage/plugin-config-schema": "0.1.56",
|
||||
"@backstage/plugin-devtools": "0.1.15",
|
||||
"@backstage/plugin-devtools-backend": "0.3.5",
|
||||
"@backstage/plugin-devtools-common": "0.1.10",
|
||||
"@backstage/plugin-events-backend": "0.3.6",
|
||||
"@backstage/plugin-events-backend-module-aws-sqs": "0.3.5",
|
||||
"@backstage/plugin-events-backend-module-azure": "0.2.5",
|
||||
"@backstage/plugin-events-backend-module-bitbucket-cloud": "0.2.5",
|
||||
"@backstage/plugin-events-backend-module-gerrit": "0.2.5",
|
||||
"@backstage/plugin-events-backend-module-github": "0.2.5",
|
||||
"@backstage/plugin-events-backend-module-gitlab": "0.2.5",
|
||||
"@backstage/plugin-events-backend-test-utils": "0.1.29",
|
||||
"@backstage/plugin-events-node": "0.3.5",
|
||||
"@internal/plugin-todo-list": "1.0.28",
|
||||
"@internal/plugin-todo-list-backend": "1.0.28",
|
||||
"@internal/plugin-todo-list-common": "1.0.19",
|
||||
"@backstage/plugin-home": "0.7.5",
|
||||
"@backstage/plugin-home-react": "0.1.14",
|
||||
"@backstage/plugin-kubernetes": "0.11.11",
|
||||
"@backstage/plugin-kubernetes-backend": "0.18.0",
|
||||
"@backstage/plugin-kubernetes-cluster": "0.0.12",
|
||||
"@backstage/plugin-kubernetes-common": "0.8.0",
|
||||
"@backstage/plugin-kubernetes-node": "0.1.13",
|
||||
"@backstage/plugin-kubernetes-react": "0.4.0",
|
||||
"@backstage/plugin-notifications": "0.2.2",
|
||||
"@backstage/plugin-notifications-backend": "0.3.0",
|
||||
"@backstage/plugin-notifications-backend-module-email": "0.1.0",
|
||||
"@backstage/plugin-notifications-common": "0.0.4",
|
||||
"@backstage/plugin-notifications-node": "0.2.0",
|
||||
"@backstage/plugin-org": "0.6.26",
|
||||
"@backstage/plugin-org-react": "0.1.25",
|
||||
"@backstage/plugin-permission-backend": "0.5.43",
|
||||
"@backstage/plugin-permission-backend-module-allow-all-policy": "0.1.16",
|
||||
"@backstage/plugin-permission-common": "0.7.14",
|
||||
"@backstage/plugin-permission-node": "0.7.30",
|
||||
"@backstage/plugin-permission-react": "0.4.23",
|
||||
"@backstage/plugin-proxy-backend": "0.5.0",
|
||||
"@backstage/plugin-scaffolder": "1.21.0",
|
||||
"@backstage/plugin-scaffolder-backend": "1.22.9",
|
||||
"@backstage/plugin-scaffolder-backend-module-azure": "0.1.11",
|
||||
"@backstage/plugin-scaffolder-backend-module-bitbucket": "0.2.9",
|
||||
"@backstage/plugin-scaffolder-backend-module-bitbucket-cloud": "0.1.9",
|
||||
"@backstage/plugin-scaffolder-backend-module-bitbucket-server": "0.1.9",
|
||||
"@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "0.2.20",
|
||||
"@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.2.43",
|
||||
"@backstage/plugin-scaffolder-backend-module-gerrit": "0.1.11",
|
||||
"@backstage/plugin-scaffolder-backend-module-gitea": "0.1.9",
|
||||
"@backstage/plugin-scaffolder-backend-module-github": "0.3.0",
|
||||
"@backstage/plugin-scaffolder-backend-module-gitlab": "0.4.1",
|
||||
"@backstage/plugin-scaffolder-backend-module-notifications": "0.0.2",
|
||||
"@backstage/plugin-scaffolder-backend-module-rails": "0.4.36",
|
||||
"@backstage/plugin-scaffolder-backend-module-sentry": "0.1.27",
|
||||
"@backstage/plugin-scaffolder-backend-module-yeoman": "0.3.2",
|
||||
"@backstage/plugin-scaffolder-common": "1.5.3",
|
||||
"@backstage/plugin-scaffolder-node": "0.4.5",
|
||||
"@backstage/plugin-scaffolder-node-test-utils": "0.1.5",
|
||||
"@backstage/plugin-scaffolder-react": "1.9.0",
|
||||
"@backstage/plugin-search": "1.4.12",
|
||||
"@backstage/plugin-search-backend": "1.5.10",
|
||||
"@backstage/plugin-search-backend-module-catalog": "0.1.25",
|
||||
"@backstage/plugin-search-backend-module-elasticsearch": "1.5.0",
|
||||
"@backstage/plugin-search-backend-module-explore": "0.1.25",
|
||||
"@backstage/plugin-search-backend-module-pg": "0.5.28",
|
||||
"@backstage/plugin-search-backend-module-stack-overflow-collator": "0.1.12",
|
||||
"@backstage/plugin-search-backend-module-techdocs": "0.1.24",
|
||||
"@backstage/plugin-search-backend-node": "1.2.24",
|
||||
"@backstage/plugin-search-common": "1.2.12",
|
||||
"@backstage/plugin-search-react": "1.7.12",
|
||||
"@backstage/plugin-signals": "0.0.7",
|
||||
"@backstage/plugin-signals-backend": "0.1.5",
|
||||
"@backstage/plugin-signals-node": "0.1.5",
|
||||
"@backstage/plugin-signals-react": "0.0.4",
|
||||
"@backstage/plugin-techdocs": "1.10.6",
|
||||
"@backstage/plugin-techdocs-addons-test-utils": "1.0.33",
|
||||
"@backstage/plugin-techdocs-backend": "1.10.6",
|
||||
"@backstage/plugin-techdocs-module-addons-contrib": "1.1.11",
|
||||
"@backstage/plugin-techdocs-node": "1.12.5",
|
||||
"@backstage/plugin-techdocs-react": "1.2.5",
|
||||
"@backstage/plugin-user-settings": "0.8.7",
|
||||
"@backstage/plugin-user-settings-backend": "0.2.18",
|
||||
"@backstage/plugin-user-settings-common": "0.0.1",
|
||||
"@backstage/plugin-catalog-backend-module-logs": "0.0.0",
|
||||
"@backstage/plugin-scaffolder-backend-module-gcp": "0.0.1-next.1"
|
||||
},
|
||||
"changesets": [
|
||||
"bright-fireants-sit",
|
||||
"bright-panthers-leave",
|
||||
"calm-jeans-ring",
|
||||
"chilly-roses-trade",
|
||||
"clever-waves-judge",
|
||||
"create-app-1719320674",
|
||||
"curvy-teachers-smell",
|
||||
"eighty-games-wink",
|
||||
"eleven-radios-begin",
|
||||
"fair-fans-flow",
|
||||
"fair-pillows-know",
|
||||
"fair-rockets-leave",
|
||||
"fair-spoons-work",
|
||||
"famous-dodos-crash",
|
||||
"fast-pens-smell",
|
||||
"fifty-pumpkins-smell",
|
||||
"friendly-bulldogs-pay",
|
||||
"friendly-experts-fail",
|
||||
"friendly-masks-type",
|
||||
"friendly-oranges-greet",
|
||||
"friendly-stingrays-occur",
|
||||
"funny-laws-tease",
|
||||
"gentle-avocados-obey",
|
||||
"grumpy-wolves-hang",
|
||||
"heavy-moose-pull",
|
||||
"honest-pears-run",
|
||||
"khaki-rivers-obey",
|
||||
"kind-dancers-boil",
|
||||
"light-avocados-worry",
|
||||
"little-games-fail",
|
||||
"metal-jokes-add",
|
||||
"metal-parents-brush",
|
||||
"metal-suits-drum",
|
||||
"moody-llamas-breathe",
|
||||
"neat-dingos-tickle",
|
||||
"new-sheep-arrive",
|
||||
"poor-cheetahs-raise",
|
||||
"rare-peas-dream",
|
||||
"renovate-7b61228",
|
||||
"renovate-ced359b",
|
||||
"rich-bears-march",
|
||||
"selfish-turtles-jog",
|
||||
"serious-kings-trade",
|
||||
"sharp-rice-tickle",
|
||||
"short-flowers-cry",
|
||||
"shy-hounds-battle",
|
||||
"silent-experts-move",
|
||||
"silent-lobsters-tease",
|
||||
"silent-moose-eat",
|
||||
"soft-clocks-bake",
|
||||
"sour-jokes-sneeze",
|
||||
"spotty-crabs-shop",
|
||||
"swift-dots-cough",
|
||||
"ten-dancers-drum",
|
||||
"ten-nails-hear",
|
||||
"ten-pots-walk",
|
||||
"thick-lizards-divide",
|
||||
"thick-moose-decide",
|
||||
"three-carpets-smoke",
|
||||
"tough-lies-mate",
|
||||
"weak-boats-float",
|
||||
"yellow-cows-kick",
|
||||
"young-donuts-swim",
|
||||
"young-fishes-lie",
|
||||
"young-houses-unite"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
Updated dependency `esbuild` to `^0.21.0`.
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
'@backstage/plugin-home-react': patch
|
||||
'@backstage/plugin-home': patch
|
||||
'@backstage/plugin-scaffolder-react': patch
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Updated dependency `@rjsf/utils` to `5.18.5`.
|
||||
Updated dependency `@rjsf/core` to `5.18.5`.
|
||||
Updated dependency `@rjsf/material-ui` to `5.18.5`.
|
||||
Updated dependency `@rjsf/validator-ajv8` to `5.18.5`.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': minor
|
||||
'@backstage/plugin-scaffolder-node': patch
|
||||
---
|
||||
|
||||
Add support for `autocomplete` extension point to provide additional `autocomplete` handlers
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-test-utils': patch
|
||||
---
|
||||
|
||||
Added mock for the Root Health Service in `mockServices`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes-react': patch
|
||||
---
|
||||
|
||||
Add a namespace label to RolloutDrawer
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-github': minor
|
||||
---
|
||||
|
||||
Adds support for custom tag policies when creating GitHub environments.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes-react': patch
|
||||
---
|
||||
|
||||
Fix the `HTML` markup of the `FixDialog` component, `ul` and `li` are not allowed inside a `p` tag.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Fix a few minor issues with the backend template that were causing failing linting checks in the main repo.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
The `backendPlugin` and `backendModule` factory now includes a step for automatically adding the new backend plugin/module to the `index.ts` file of the backend.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Support `catalogFilter` array on `OwnedEntityPicker`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-notifications-backend': patch
|
||||
---
|
||||
|
||||
Added an option to filter notifications by topic
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-github': patch
|
||||
---
|
||||
|
||||
Added action to enable GitHub Pages on a repo
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-auth-node': patch
|
||||
---
|
||||
|
||||
Fix issues with Atlassian OAuth provider: retrieve the email and photo that were not in arrays but rather in single props.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-react': minor
|
||||
---
|
||||
|
||||
Improve validation error display text in scaffolder
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
'@backstage/backend-plugin-api': patch
|
||||
---
|
||||
|
||||
All service config types were renamed to option types in order to standardize frontend and backend `create*` function signatures:
|
||||
|
||||
- The `ServiceRefConfig` type was renamed to`ServiceRefOptions`;
|
||||
- The `RootServiceFactoryConfig` type was renamed to `RootServiceFactoryOptions`;
|
||||
- The `PluginServiceFactoryConfig` type was renamed to `PluginServiceFactoryOptions`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-github': patch
|
||||
---
|
||||
|
||||
Fixed issue with octokit call missing owner and repo when creating environment variables and secrets using github:environment:create action
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-github': patch
|
||||
---
|
||||
|
||||
Adds `requireLastPushApproval` input property to configure Branch Protection Settings in `github:publish` action
|
||||
|
||||
Adds `requireLastPushApproval` input property to configure Branch Protection Settings in `github:repo:push` action
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-logs': patch
|
||||
---
|
||||
|
||||
Creates a new module to make logging catalog errors simple. This module subscribes to catalog events and logs them.
|
||||
|
||||
See [Backstage documentation](https://backstage.io/docs/features/software-catalog/configuration#subscribing-to-catalog-errors) for details on how to install
|
||||
and configure the plugin.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-search': patch
|
||||
---
|
||||
|
||||
Update deps in search api extension to include fetch api
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-gitlab': patch
|
||||
---
|
||||
|
||||
Added support for passing `variables` to `gitlab:pipeline:trigger`
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-gcp': minor
|
||||
'@backstage/plugin-scaffolder-backend': minor
|
||||
'@backstage/plugin-scaffolder-node': patch
|
||||
---
|
||||
|
||||
Serialization of the scaffolder workspace into GCP bucket
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Added the Postgres Search Engine to the `create-app` template
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': minor
|
||||
'@backstage/backend-test-utils': patch
|
||||
'@backstage/backend-defaults': patch
|
||||
'@backstage/backend-common': patch
|
||||
---
|
||||
|
||||
bumped better-sqlite3 from ^9.0.0 to ^11.0.0
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-notifications-backend-module-email': patch
|
||||
'@backstage/plugin-notifications-common': patch
|
||||
'@backstage/plugin-notifications-node': patch
|
||||
---
|
||||
|
||||
Move notification processor filter parsing to common package
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-react': patch
|
||||
---
|
||||
|
||||
disables rendering of output box if no output is returned
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-node-test-utils': patch
|
||||
---
|
||||
|
||||
Filename and imports correction for mockActionContext.ts
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-react': minor
|
||||
'@backstage/plugin-scaffolder': minor
|
||||
---
|
||||
|
||||
Add support for `bitbucketCloud` autocomplete in `RepoUrlPicker`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
Fix user entity not being fetched for scaffolder dry runner
|
||||
@@ -12,27 +12,33 @@ jobs:
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
# Setup node & install deps before checkout, keeping install quick
|
||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
with:
|
||||
node-version: 18.x
|
||||
- name: Install dependencies
|
||||
# Just the deps for the assemble manifest script
|
||||
run: npm install semver@7.3.5 fs-extra@10.0.0 @manypkg/get-packages@1.1.1
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
with:
|
||||
path: backstage
|
||||
# 'v' prefix is added here for the tag, we keep it out of the manifest logic
|
||||
ref: v${{ github.event.client_payload.version }}
|
||||
|
||||
- name: use node.js 18.x
|
||||
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
with:
|
||||
node-version: 18.x
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@a674369920067381b450d398b27df7039b7ef635 # v0.6.5
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v18.x
|
||||
|
||||
- name: Build yarn plugin
|
||||
working-directory: packages/yarn-plugin
|
||||
run: yarn build
|
||||
|
||||
# Checkout backstage/versions into /backstage/versions, which is where store the output
|
||||
- name: Checkout versions
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
with:
|
||||
repository: backstage/versions
|
||||
path: backstage/versions
|
||||
path: versions
|
||||
token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }}
|
||||
|
||||
- name: Configure Git
|
||||
@@ -43,11 +49,23 @@ jobs:
|
||||
- name: Create release
|
||||
# This grabs the scripts from master in order to support backfills
|
||||
run: |
|
||||
cd backstage
|
||||
mkdir -p scripts
|
||||
wget -O scripts/assemble-manifest.js https://raw.githubusercontent.com/backstage/backstage/master/scripts/assemble-manifest.js
|
||||
node scripts/assemble-manifest.js ${{ github.event.client_payload.version }}
|
||||
cd versions
|
||||
|
||||
# Copies the build output of the yarn-plugin package to the appropriate
|
||||
# directory, allowing the plugin to be installed with a command like
|
||||
# `yarn plugin import https://versions.backstage.io/v1/tags/main/yarn-plugin`
|
||||
- name: Add yarn plugin to release
|
||||
working-directory: packages/yarn-plugin
|
||||
run: >-
|
||||
cp
|
||||
bundles/@yarnpkg/plugin-backstage.js
|
||||
../../versions/v1/releases/${{ github.event.client_payload.version }}/yarn-plugin
|
||||
|
||||
- name: Commit to versions repo
|
||||
working-directory: versions
|
||||
run: |
|
||||
git add .
|
||||
git commit -am "${{ github.event.client_payload.version }}"
|
||||
git push
|
||||
@@ -65,7 +83,7 @@ jobs:
|
||||
workflow_id: 'release.yml',
|
||||
ref: 'master',
|
||||
inputs: {
|
||||
version: require('./backstage/packages/create-app/package.json').version,
|
||||
releaseVersion: require('./backstage/package.json').version
|
||||
version: require('./packages/create-app/package.json').version,
|
||||
releaseVersion: require('./package.json').version
|
||||
},
|
||||
});
|
||||
|
||||
@@ -94,6 +94,7 @@ typings/
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
.envrc
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
@@ -271,3 +271,6 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/
|
||||
| [Scania](https://www.scania.com) | [Santosh Rangavajjula](https://linkedin.com/in/rsbth) | We are implementing backstage at Scania to consolidate operational information from Gitlab, Jira, Confluence, Artifactory, Servicenow and other tools into one place. |
|
||||
| [Senora.dev](https://senora.dev) | [Shaked Braimok Yosef](https://github.com/ShakedBraimok) | We are using Backstage as a service catalog for our costumers. |
|
||||
| [Covestro](https://www.covestro.com) | [Julien Gedeon](https://github.com/cvvcv1) | We use Backstage as our Internal developer portal for the Digital R&D department. |
|
||||
| [Grupo OLX](https://www.olx.com.br/) | [@marciorgb](https://github.com/marciorgb), [@jeffbraga](https://github.com/jeffbraga), [@rogerfernandes](https://github.com/rogerfernandes), [@stockrt](https://github.com/stockrt) | At Grupo OLX, we are using Backstage to reduce friction and enhance developer autonomy by creating Golden Paths, which automate previously manual processes. Additionally, Backstage's catalog integrates various views of our organizational structure and workflows, offering a comprehensive overview of how different components interconnect. |
|
||||
| [DPG Media](https://www.dpgmediagroup.com) | [@benjidotsh](https://github.com/benjidotsh), [@lvstb](https://github.com/lvstb), [@ssliman](https://github.com/ssliman), [@edewel-beep](https://github.com/edewel-beep) | Access to infrastructure, documentation and internal tooling |
|
||||
| [Baloise](https://www.baloise.ch) | [@dweber019](https://github.com/dweber019), [@mikevader](https://github.com/mikevader) | We are using Backstage as internal developer protal for use cases like software catalog, documentation, infrastructure. |
|
||||
|
||||
@@ -159,6 +159,18 @@ Scope: The Scaffolder frontend and backend plugins, and related tooling.
|
||||
| ------------------- | ------------ | ------------------------------------- | ---------------- |
|
||||
| Bogdan Nechyporenko | Bol.com | [acierto](https://github.com/acierto) | `bogdan_haarlem` |
|
||||
|
||||
### Documentation
|
||||
|
||||
Team: @backstage/documentation-maintainers
|
||||
|
||||
Scope: The Backstage Documentation
|
||||
|
||||
| Name | Organization | GitHub | Discord |
|
||||
| --------------- | ------------- | ----------------------------------------------------- | ------------- |
|
||||
| Andre Wanlin | Spotify | [awanlin](https://github.com/awanlin) | `ahhhndre` |
|
||||
| Aramis Sennyey | | [aramissennyeydd](https://github.com/aramissennyeydd) | `Aramis#7984` |
|
||||
| Peter Macdonald | VodafoneZiggo | [Parsifal-M](https://github.com/Parsifal-M) | `parsifal` |
|
||||
|
||||
## Sponsors
|
||||
|
||||
| Name | Organization | GitHub | Email |
|
||||
@@ -187,6 +199,7 @@ Scope: The Scaffolder frontend and backend plugins, and related tooling.
|
||||
| Mark Avery | Cvent | [webark](https://github.com/webark) | `webark#8471` |
|
||||
| Miklós Kiss | Roadie.io | [kissmikijr](https://github.com/kissmikijr) | `Miklos#7416` |
|
||||
| Patrick Jungermann | Bonial International GmbH | [pjungermann](https://github.com/pjungermann) | `pjungermann#6933` |
|
||||
| Peter Macdonald | VodafoneZiggo | [Parsifal-M](https://github.com/Parsifal-M) | `parsifal` |
|
||||
| Phil Kuang | FactSet Research Systems | [kuangp](https://github.com/kuangp) | `pkuang#3202` |
|
||||
| Sebastian Poxhofer | N26 | [secustor](https://github.com/secustor) | `secustor` |
|
||||
| Taras Mankovski | Frontside | [taras](https://github.com/taras) | `tarasm#1256` |
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
[](https://backstage.io/)
|
||||
|
||||
# [Backstage](https://backstage.io)
|
||||
|
||||
Français \| [English](README.md) \| [한국어](README-ko_kr.md) \| [中文版](README-zh_Hans.md)
|
||||
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
[](https://www.cncf.io/projects)
|
||||
[](https://discord.gg/backstage-687207715902193673)
|
||||

|
||||
[](https://codecov.io/gh/backstage/backstage)
|
||||
[](https://github.com/backstage/backstage/releases)
|
||||
[](https://app.uffizzi.com/ephemeral-environments/backstage/backstage)
|
||||
[](https://bestpractices.coreinfrastructure.org/projects/7678)
|
||||
[](https://securityscorecards.dev/viewer/?uri=github.com/backstage/backstage)
|
||||
|
||||
## Qu'est-ce que Backstage?
|
||||
|
||||
[Backstage](https://backstage.io/) est un framework open source conçu pour créer des portails à destination des développeurs. Avec l'idée de fournir un catalogue d'applications centralisé, Backstage remet de l'ordre dans vos microservices et votre infrastructure, ce qui permet à vos équipes produit de coder rapidement et de manière efficace sans perdre en autonomie.
|
||||
|
||||
Backstage rassemble tous vos outils d'infrastructure, services et documentations pour créer un environnement de développement fluide de bout en bout.
|
||||
|
||||

|
||||
|
||||
Out-of-the-box, Backstage comprend :
|
||||
|
||||
- [Backstage Software Catalog](https://backstage.io/docs/features/software-catalog/) pour gérer tous vos logiciels tels que les microservices, les bibliothèques, les pipelines de données, les sites web et les modèles ML.
|
||||
- [Backstage Software Templates](https://backstage.io/docs/features/software-templates/) pour créer rapidement de nouveaux projets et uniformiser vos outils selon les meilleures pratiques de votre organisation.
|
||||
- [Backstage TechDocs](https://backstage.io/docs/features/techdocs/) pour faciliter la création, la maintenance, la recherche et l'utilisation de la documentation technique, en adoptant une approche "docs like code".
|
||||
- De plus, un écosystème croissant de [plugins open source](https://github.com/backstage/backstage/tree/master/plugins) qui étendent davantage la personnalisation et les fonctionnalités de Backstage.
|
||||
|
||||
Backstage a été initialement développé par Spotify, mais il est désormais hébergé par la [Cloud Native Computing Foundation (CNCF)](https://www.cncf.io) en tant que projet en stade d'incubation. Pour en savoir plus, consultez l'[annonce](https://backstage.io/blog/2022/03/16/backstage-turns-two#out-of-the-sandbox-and-into-incubation).
|
||||
|
||||
## Roadmap du projet
|
||||
|
||||
Pour des informations sur la roadmap détaillée du projet, y compris les jalons atteints, consultez [la Roadmap](https://backstage.io/docs/overview/roadmap).
|
||||
|
||||
## Démarrage
|
||||
|
||||
Pour commencer à utiliser Backstage, consultez [Getting Started documentation](https://backstage.io/docs/getting-started).
|
||||
|
||||
## Documentation
|
||||
|
||||
La documentation de Backstage inclus:
|
||||
|
||||
- [Main documentation](https://backstage.io/docs)
|
||||
- [Software Catalog](https://backstage.io/docs/features/software-catalog/)
|
||||
- [Architecture](https://backstage.io/docs/overview/architecture-overview) ([Decisions](https://backstage.io/docs/architecture-decisions/))
|
||||
- [Designing for Backstage](https://backstage.io/docs/dls/design)
|
||||
- [Storybook - UI components](https://backstage.io/storybook)
|
||||
|
||||
## Communauté
|
||||
|
||||
Si vous voulez contribuer et vous impliquer dans notre communauté, voici les ressources à votre disposition :
|
||||
|
||||
- [Discord chatroom](https://discord.gg/backstage-687207715902193673) - Pour obtenir de l'aide ou discuter du projet
|
||||
- [Contributing to Backstage](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md) - Rendez-vous ici si vous souhaitez contribuer
|
||||
- [RFCs](https://github.com/backstage/backstage/labels/rfc) - Contribuez à définir la direction technique
|
||||
- [FAQ](https://backstage.io/docs/FAQ)
|
||||
- [Code of Conduct](CODE_OF_CONDUCT.md) - C'est comme ça qu'on fonctionne
|
||||
- [Adopters](ADOPTERS.md) - Les entreprises utilisant déjà Backstage
|
||||
- [Blog](https://backstage.io/blog/) - Annonces et mises à jour
|
||||
- [Newsletter](https://spoti.fi/backstagenewsletter) - Abonnez-vous à notre newsletter par mail
|
||||
- [Backstage Community Sessions](https://github.com/backstage/community) - Participez aux rencontres mensuelles et découvrez la communauté Backstage
|
||||
- Donnez-nous une étoile ⭐️ - Si vous utilisez Backstage ou si vous trouvez que c'est un projet intéressant, nous apprécierions beaucoup votre soutien ❤️
|
||||
|
||||
## Licence
|
||||
|
||||
Copyright 2020-2024 © Les auteurs de Backstage. Tous droits réservés. La Linux Foundation détient des marques déposées et utilise des marques commerciales. Pour une liste des marques de commerce de la Linux Foundation, veuillez consulter notre page d'utilisation des marques: https://www.linuxfoundation.org/trademark-usage
|
||||
|
||||
Sous licence Apache, version 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
## Sécurité
|
||||
|
||||
Veuillez signaler les problèmes de sécurité sensibles en utilisant le [programme de bug-bounty](https://hackerone.com/spotify) de Spotify plutôt que GitHub.
|
||||
|
||||
Pour plus de détails, consultez notre processus complet de [publication de sécurité](SECURITY.md).
|
||||
@@ -1,8 +1,11 @@
|
||||
[](https://backstage.io/)
|
||||
|
||||
> [!NOTE]
|
||||
> 🏖 From July 1st through 16th, due to maintainers being on summer vacations, expect the project to move a little slower than normal, and support to be limited. Normal service will resume after that! 🏝
|
||||
|
||||
# [Backstage](https://backstage.io)
|
||||
|
||||
English \| [한국어](README-ko_kr.md) \| [中文版](README-zh_Hans.md)
|
||||
English \| [한국어](README-ko_kr.md) \| [中文版](README-zh_Hans.md) \| [Français](README-fr_FR.md)
|
||||
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
[](https://www.cncf.io/projects)
|
||||
@@ -55,7 +58,7 @@ To engage with our community, you can use the following resources:
|
||||
- [Discord chatroom](https://discord.gg/backstage-687207715902193673) - Get support or discuss the project
|
||||
- [Contributing to Backstage](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md) - Start here if you want to contribute
|
||||
- [RFCs](https://github.com/backstage/backstage/labels/rfc) - Help shape the technical direction
|
||||
- [FAQ](https://backstage.io/docs/FAQ) - Frequently Asked Questions
|
||||
- [FAQ](https://backstage.io/docs/faq) - Frequently Asked Questions
|
||||
- [Code of Conduct](CODE_OF_CONDUCT.md) - This is how we roll
|
||||
- [Adopters](ADOPTERS.md) - Companies already using Backstage
|
||||
- [Blog](https://backstage.io/blog/) - Announcements and updates
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Backstage Notifications System
|
||||
status: provisional
|
||||
status: implementable
|
||||
authors:
|
||||
- '@Rugvip'
|
||||
- '@drodil'
|
||||
|
||||
@@ -156,12 +156,247 @@ Each plugin is required to provide manifest file (metadata) in predefined format
|
||||
|
||||
Plugin discovery is a pre-requisite for Plugin registry. This should be responsible for scanning for available plugins and generating/modifying the plugin registry to always keep it up to date.
|
||||
|
||||
### CLI
|
||||
|
||||
The following sections contains proposal of new CLI scripts to support the dynamic frontend plugins.
|
||||
|
||||
#### Static and Dynamic Plugin Build Differences
|
||||
|
||||
The major difference between static and dynamic plugins lies in their dependencies and how they are "installed" into a Backstage instance and whether they are bundled into final JS output during the build.
|
||||
|
||||
While static plugins can define their dependencies using the dependencies field inside `package.json`, dynamic (module federation-based) plugins can't.
|
||||
|
||||
A dynamic plugin requires all dependencies to be present in the build output. Module sharing is then used to optimize the "output size" at runtime. If a shared package is not found in the browser scope, or if the version range does not match the requirement, it falls back and loads additional JS assets from the "private" build and adds them to the scope.
|
||||
|
||||
Webpack is also not the best tool for building traditional NPM packages. Dependencies can be externalized, but Webpack brings additional code into the bundles. Using Webpack external dependencies also conflicts with module federation shared modules. Externals will not be included even as a shared module fallback. As a result, such shared module can't be used because the dependency will not be defined in the init container.
|
||||
|
||||
If the vision is to still support "static" plugins installed via NPM, it makes sense to keep the static and dynamic plugin builds separate and build two different bundles. Both can still be published as a single NPM package (not recommended), but to achieve optimal performance for both, there cannot be a shared output.
|
||||
|
||||
#### Dynamic export CLI
|
||||
|
||||
```sh
|
||||
backstage-cli plugin export-dynamic
|
||||
```
|
||||
|
||||
Similar to the current build command, instead of producing static plugin output, it builds a dynamic plugin using Webpack and module federation plugins.
|
||||
|
||||
**Internal arguments**
|
||||
|
||||
Some configuration is required, but they can be internal using the script `cwd`.
|
||||
|
||||
- _path_
|
||||
- path to the plugin `package.json`
|
||||
- _export-name_
|
||||
- Export name from where the plugin root is accessible
|
||||
- defaults to `pluginEntry`
|
||||
|
||||
**Shared modules**
|
||||
|
||||
> NOTE: Details of module sharing are described in the [Module sharing](#module-sharing) section.
|
||||
|
||||
Short summary of dependency sharing:
|
||||
|
||||
- Predefined set of singleton packages
|
||||
- Generated granular config of modules for MUI dependencies
|
||||
- Share all other dependencies listed in package.json
|
||||
|
||||
To allow additional customization of module sharing, extra configuration will be required. The extra module haring configuration can be embedded inside `package.json`.
|
||||
|
||||
- [Schema proposal draft](./dependency-sharing-schema.json)
|
||||
- [Config draft](./share-config-sample.json)
|
||||
|
||||
#### Generate module sharing map
|
||||
|
||||
> NOTE: RedHat has similar internal generators that are used in combination with Scalprum. These can be built upon, moved to Scalprum, and exposed. If there is interest, the Backstage maintainers do not have to be responsible for maintaining the source code.
|
||||
|
||||
A simple program to traverse the AST and find exports from the `main` or `module` script of a dependency. Any exposed modules from the dependency entry will be traced to their source files, and a module map can be generated.
|
||||
|
||||
> NOTE: It is important that import paths in source code are also directly targeting the "traced" modules or are transformed at build time.
|
||||
|
||||
**The script should be triggered by the plugin build cli**
|
||||
|
||||
Generates a module map (exported module source file location) for module sharing.
|
||||
|
||||
**Arguments**
|
||||
|
||||
- _path_
|
||||
- path to the module root (directory with package.json)
|
||||
|
||||
[module map generator using TS example](#simplistic-minimal-example-of-module-map-generator)
|
||||
|
||||
### Dynamic assets server
|
||||
|
||||
A simple static asset server is sufficient to serve the dynamic assets. The asset server can collect the necessary metadata at boot or runtime. The asset server can be added to the `app-backend`
|
||||
|
||||
It's important to consider old deployments as part of this storage, to make sure that dynamic chunks are still available to users who have not yet refreshed the page to load the latest version of the app.
|
||||
|
||||
#### Plugin separation
|
||||
|
||||
- Each plugin should be separated into a directory.
|
||||
- Each plugin can be viewed as a `private` workspace package in a npm workspaces environment.
|
||||
|
||||
```sh
|
||||
path/to/assets/plugin/dynamic-plugins/
|
||||
└── dynamic-backstage.plugin-user-settings
|
||||
├── dist
|
||||
├── package.json
|
||||
└── plugin-manifest.json
|
||||
```
|
||||
|
||||
#### Boot time initialization
|
||||
|
||||
**Dynamically build plugins**
|
||||
|
||||
Only dynamic plugins can be hosted in the backend. The plugins has to provide the [manifest](#plugin-manifest). It the manifest is not found, plugin will not be considered dynamic and will be enabled for loading.
|
||||
|
||||
**File system assets management**
|
||||
|
||||
Once plugins are installed and fully dynamic, the asset server has to "discover" what plugins are loadable.
|
||||
|
||||
This can be done by scanning the "assets" (dynamic-plugins in the dir example) for individual plugin manifests. Simple `glob` lookup for `path/dynamic-plugins/**/plugins-manifest.json` pattern should give required results.
|
||||
|
||||
With this data the assets server should be able to generate a "plugin registry" with necessary metadata for the frontend. See the [Plugin Registry](#plugin-registry-1) for format details.
|
||||
|
||||
The during the collection, the program can also add the `assetHost` prefix to the manifest location attribute described in the [webpack configuration](#sample-webpack-configuration) section.
|
||||
|
||||
**Alternative means of assets management**
|
||||
|
||||
To manage the assets by other means than just using filesystem, the file system should be treated only as an entry point for the plugins. Leveraging other means such as DB/cache/object storage should be also an option. The storage method should be mandated as long as a plugin registry and assets are available.
|
||||
|
||||
**Singleton dependencies verification (optional)**
|
||||
|
||||
With [module sharing](#module-sharing) and its singleton option, it is critical that the singleton dependencies versions are matching.
|
||||
|
||||
The singleton configuration from the shell application can be extracted as well as from all dynamic plugins (included in the generated [manifest](#plugin-manifest)). A semver check can be used to prevent a plugin from initializing if a version mismatch is found. A version check also has to be made between plugins. New plugin singleton dependencies must match both the shell and all previously loaded plugins.
|
||||
|
||||
#### Runtime updates
|
||||
|
||||
It is fully expected that plugins can be added or removed at the asset server runtime. The same tasks can be performed as during boot time initialization. It is critical that the plugin registry is not cached and updated immediately if assets change.
|
||||
|
||||
The server **should not remove older JS/CSS assets** immediately after updates. It is highly likely user can have older version still loaded in their browsers. A retention period is required for the assets. Using proper content hashes for builds will help with keep the duplicate assets to a minimum.
|
||||
|
||||
#### Asset server API
|
||||
|
||||
> NOTE Routes names are purely arbitrary at this point.
|
||||
|
||||
The API can be very simplistic
|
||||
|
||||
_GET /dynamic-plugins/plugin-registry_
|
||||
|
||||
Returns generated [Plugin Registry](#plugin-registry-1).
|
||||
|
||||
\*GET /dynamic-plugins/assets/\*\*
|
||||
|
||||
Static assets endpoint. Can be handled via the `express.static` middleware.
|
||||
|
||||
### Plugin loading
|
||||
|
||||
> NOTE: Only viable for the new frontend plugin system.
|
||||
|
||||
The feature loader is a perfect place to initialize a new dynamic plugin as it already accepts async loaders.
|
||||
|
||||
An example of [integration with scalprum](https://github.com/backstage/backstage/commit/23085aa8dfbc73d4648c100cf06b6b67e8e31764).
|
||||
|
||||
#### Integration to core
|
||||
|
||||
**Dynamic Feature configuration**
|
||||
|
||||
The dynamic remote loading can be added directly into the [`createApp`](https://github.com/backstage/backstage/blob/master/packages/frontend-app-api/src/wiring/createApp.tsx#L234) function.
|
||||
|
||||
The current `feature` type can be expanded with a `DynamicFrontendFeature` type:
|
||||
|
||||
```ts
|
||||
// current
|
||||
type Features: (FrontendFeature | CreateAppFeatureLoader)[];
|
||||
|
||||
// with dynamic plugins
|
||||
type DynamicFrontendFeature = {
|
||||
name: string;
|
||||
manifestLocation: string // URI with host enhanced with the "DEFAULT_API_PATH" or "assetHost" prefix
|
||||
}
|
||||
|
||||
type Features: (FrontendFeature | CreateAppFeatureLoader | DynamicFrontendFeature)[];
|
||||
```
|
||||
|
||||
**Dynamic Feature boot loading**
|
||||
|
||||
Scalprum can be initialized with the metadata originating from the dynamic backend plugin. In order to properly load a plugin with `publicPath` set to `auto`, a small transformation of the manifest has to happen before it is loaded. A sample Scalprum config with such transformation:
|
||||
|
||||
```TS
|
||||
import { initialize } from '@scalprum/core';
|
||||
import { ScalprumProviderProps } from '@scalprum/react-core';
|
||||
|
||||
// get the pluginRegistry from the backend plugin
|
||||
const pluginRegistry = await loadRemoteConfig()
|
||||
|
||||
const pluginSDKOptions: ScalprumProviderProps['pluginSDKOptions'] = {
|
||||
pluginLoaderOptions: {
|
||||
transformPluginManifest: manifest => {
|
||||
return {
|
||||
...manifest,
|
||||
loadScripts: manifest.loadScripts.map(script => {
|
||||
// Any additional transformations can happen here in case the manifest format needs to be adjusted further.
|
||||
// the init scripts URL is enhanced with the asset location to add the host:
|
||||
return `${manifest.customProperties.assetHost ?? DEFAULT_API_PATH}${script}`;
|
||||
}),
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Initialize Scalprum instance
|
||||
const scalprum = initialize({
|
||||
appsConfig: pluginRegistry,
|
||||
pluginLoaderOptions: pluginSDKOptions.pluginLoaderOptions,
|
||||
});
|
||||
```
|
||||
|
||||
Because the [`appLoader`](https://github.com/backstage/backstage/blob/master/packages/frontend-app-api/src/wiring/createApp.tsx#L193) is already async, it is a perfect place to load the plugin registry and init the dynamic plugins.
|
||||
|
||||
Initializing the dynamic feature is just a case of mapping the `DynamicFrontendFeature` to `FrontendFeature` via Scalprum:
|
||||
|
||||
```ts
|
||||
import { processManifest, getModule } from '@scalprum/core';
|
||||
// a ID of the module withing module federation container, can be customized, depends on the build
|
||||
const DEFAULT_MODULE_NAME = 'pluginEntry';
|
||||
|
||||
async function loadScalprumFeature({ manifestLocation, name }) {
|
||||
// initialize dynamic remote within scalprum cache
|
||||
await processManifest(manifestLocation, name, DEFAULT_MODULE_NAME);
|
||||
// gets the actual JS module from scalprum
|
||||
const feature = await getModule<FrontendFeature>(name, DEFAULT_MODULE_NAME);
|
||||
|
||||
return feature;
|
||||
}
|
||||
const providedFeatures: FrontendFeature[] = [];
|
||||
for (const entry of options?.features ?? []) {
|
||||
if ('manifestLocation' in entry && 'name' in entry) {
|
||||
// some error handling required
|
||||
const dynamicFeature = loadScalprumFeature(entry);
|
||||
providedFeatures.push(dynamicFeature);
|
||||
} else if ('load' in entry) {
|
||||
// plugin with load function
|
||||
} else {
|
||||
// #static plugin
|
||||
}
|
||||
}
|
||||
|
||||
const app = createSpecializedApp({
|
||||
icons: options?.icons,
|
||||
config,
|
||||
features: [...discoveredFeatures, ...providedFeatures],
|
||||
bindRoutes: options?.bindRoutes,
|
||||
}).createRoot();
|
||||
```
|
||||
|
||||
The federated modules are now available as if they were static plugins.
|
||||
|
||||
## Design Details
|
||||
|
||||
> NOTE The details are based on the Janus implementation of dynamic frontend plugins. The implementation leverages [Scalprum](https://github.com/scalprum/scaffolding) which is a Webpack based dynamic plugin manager for React applications.
|
||||
|
||||
### Module federation implementation experiments
|
||||
|
||||
> NOTE Experiments were tested and documented. Decision was mated to leverage [Scalprum](https://github.com/scalprum/scaffolding) and [dynamic-plugins-sdk](https://github.com/openshift/dynamic-plugin-sdk). Instead of native webpack module federation the [@module-federation/enhanced](https://www.npmjs.com/package/@module-federation/enhanced) plugin will be used to ensure future compatibility with other bundlers.
|
||||
|
||||
Test should consist of trying to run permutations of webpack/Rspack/vite based shell apps/plugins and discover if we can freely choose any tool, or if we should restrict the tooling to just a subset of the available options.
|
||||
|
||||
The outcome of initial testing is positive and it is possible to mix and match different build tools and consume different remote modules in a single shell application.
|
||||
@@ -217,70 +452,7 @@ This config ensures that only those modules (from @mui/material) that are used i
|
||||
|
||||
This can be checked by debugging network traffic and shared scopes:
|
||||
|
||||

|
||||
|
||||
#### Limitations
|
||||
|
||||
A limitation of module sharing is that each module name can only appear once in each context. This means that if you're trying to build a bundle of shared modules with a deeper dependency tree, you may end up needing to resolve conflicts by renaming some modules that appear multiple times with different versions. This will in turn limit sharing of those modules with other bundles.
|
||||
|
||||
There is also a conflict with the chunk splitting currently used in the Backstage CLI that means that some singleton modules need to be configured to be eagerly loaded. More broadly we may also want to re-evaluate the chunk splitting strategy in the Backstage CLI when adding support for module federation.
|
||||
|
||||
### Plugin manifest
|
||||
|
||||
Each plugin should have a manifest file with important metadata. This metadata is used to load the remote assets to browser. The plugin manifest should be part of a build output.
|
||||
|
||||
A manifest should have:
|
||||
|
||||
- name of plugin
|
||||
- how can be the init container accessed
|
||||
- what is the base URL (assets pathname)
|
||||
- name of the entry script(s)
|
||||
|
||||
#### Scalprum compatible manifest
|
||||
|
||||
```TS
|
||||
type PluginManifest = {
|
||||
name: string;
|
||||
version: string;
|
||||
dependencies?: Record<string, string>;
|
||||
customProperties?: AnyObject;
|
||||
baseURL: string;
|
||||
extensions: Extension[];
|
||||
loadScripts: string[];
|
||||
registrationMethod: 'callback' | 'custom';
|
||||
buildHash?: string;
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
{
|
||||
"name": "backstage.plugin-github-actions",
|
||||
"version": "0.6.6",
|
||||
"extensions": [],
|
||||
"registrationMethod": "callback", // where container init is available in browser
|
||||
"baseURL": "auto",
|
||||
"loadScripts": [
|
||||
"backstage.plugin-github-actions.804b91040fcbca6585ce.js"
|
||||
],
|
||||
"buildHash": "804b91040fcbca6585ce1bcd4b1f8aa2"
|
||||
}
|
||||
```
|
||||
|
||||
##### `registrationMethod`
|
||||
|
||||
Refers to [webpack output.libraryTarget](https://webpack.js.org/configuration/output/#outputlibrarytarget).
|
||||
|
||||
Callback refers to `jsonp` and a the `custom` is used if other available target configuration has been picked.
|
||||
|
||||
It is recommended to use either `global` or `jsonp` as these are environment agnostic (browser VS node). `jsonp` requires additional configurations. The `global` is preferable due to its simplicity.
|
||||
|
||||
##### `baseURL`
|
||||
|
||||
The `baseURL` is derived from [webpack public path](https://webpack.js.org/configuration/output/#outputpublicpath)
|
||||
|
||||
The public path can also be set to `auto` to remove the need to specify origin or pathname and resolve the pathname at runtime.
|
||||
|
||||
In Scalprum, some manifest [post processing](https://github.com/janus-idp/backstage-showcase/blob/main/packages/app/src/components/DynamicRoot/DynamicRoot.tsx#L323) is required to load the initial scripts if the `auto` baseURL is chosen.
|
||||

|
||||
|
||||
### Plugin registry
|
||||
|
||||
@@ -290,6 +462,7 @@ Plugin registry can be fairly simplistic. It can be as simple as JSON file conta
|
||||
type RegistryEntry = {
|
||||
name: string // plugin name
|
||||
manifestLocation: string // path to the manifest resource
|
||||
assetHost: string // host part of URL to deal with the `auto` publicPath
|
||||
}
|
||||
|
||||
// object for easy access
|
||||
@@ -308,7 +481,8 @@ Example of such registry
|
||||
{
|
||||
"backstage.plugin-github-actions": {
|
||||
"name": "backstage.plugin-github-actions",
|
||||
"manifestLocation": "https://foo-bar.com/api/plugin-storage/plugin-manifest.json"
|
||||
"manifestLocation": "/api/plugin-storage/plugin-manifest.json",
|
||||
"assetHost": "https://foo-bar.com"
|
||||
},
|
||||
// ..rest of plugins
|
||||
}
|
||||
@@ -318,6 +492,7 @@ Example of such registry
|
||||
{
|
||||
"name": "backstage.plugin-github-actions",
|
||||
"manifestLocation": "https://foo-bar.com/api/plugin-storage/plugin-manifest.json"
|
||||
"assetHost": "https://foo-bar.com"
|
||||
},
|
||||
// ...rest of plugins
|
||||
]
|
||||
@@ -353,7 +528,6 @@ Example of registry with embedded manifests
|
||||
"pluginManifest": {
|
||||
"name": "backstage.plugin-github-actions",
|
||||
"version": "0.6.6",
|
||||
"extensions": [],
|
||||
"registrationMethod": "callback",
|
||||
"baseURL": "auto",
|
||||
"loadScripts": [
|
||||
@@ -372,7 +546,6 @@ Example of registry with embedded manifests
|
||||
"pluginManifest": {
|
||||
"name": "backstage.plugin-github-actions",
|
||||
"version": "0.6.6",
|
||||
"extensions": [],
|
||||
"registrationMethod": "callback",
|
||||
"baseURL": "auto",
|
||||
"loadScripts": [
|
||||
@@ -386,155 +559,374 @@ Example of registry with embedded manifests
|
||||
|
||||
```
|
||||
|
||||
### Webpack build configuration
|
||||
### Frontend plugin build configuration
|
||||
|
||||
> NOTE This is a sample current configuration in the Janus project. It uses Scalprum webpack based build plugin to generate the output. It does not take the [all options](#Module-federation-implementation-experiments) in consideration. This section will likely change considerably.
|
||||
#### Build tooling
|
||||
|
||||
Part of a Scalprum tooling is also [dynamic-plugins-sdk](https://github.com/openshift/dynamic-plugin-sdk). Right now the package is a part of a different project, but that is about to change. More details in the [Scalprum roadmap](https://github.com/scalprum/scaffolding/blob/main/ROADMAP.md).
|
||||
- webpack module bundler as a base
|
||||
- use `@openshift/dynamic-plugin-sdk-webpack` to build dynamic frontend output
|
||||
- with `@module-federation/enhanced` plugins instead of native webpack
|
||||
|
||||
#### Sample plugin configuration using Scalprum SDK
|
||||
#### Module sharing
|
||||
|
||||
Webpack allows for dependency/module sharing across different remote modules. For performance's sake, all dependencies should be shared. The sharing is version-restricted, and there can be multiple versions of the same package at the same time. This ensures that remote modules will have the necessary dependency version available, either from the shared scope or as a fallback from the respective build.
|
||||
|
||||
**Singleton sharing**
|
||||
|
||||
Singleton sharing is necessary for context sharing between remote modules and between remote modules and shell application.
|
||||
|
||||
Only a minimal set of dependencies should be shared as singletons as it gives access to all packages to the parent context. Also **version checking is disabled for singleton packages!**
|
||||
|
||||
Singleton "must have" list:
|
||||
|
||||
- @scalprum/core
|
||||
- @scalprum/react-core
|
||||
- @openshift/dynamic-plugin-sdk
|
||||
- react
|
||||
- react-dom
|
||||
- react-router-dom
|
||||
|
||||
Singleton "might have to" list:
|
||||
|
||||
- @material-ui/core/styles
|
||||
- @material-ui/styles
|
||||
|
||||
**@mui/_ and @material-ui/_ like packages**
|
||||
|
||||
> NOTE: Can leverage [Generate module sharing map](#generate-module-sharing-map).
|
||||
|
||||
Component libraries are usually large (thousands of svg icons in @mui/icons) and it is inefficient to share them as a whole. **Tree shaking is disabled for shared modules**. That means sharing large packages in multiple versions will result in a bloated JS in browsers.
|
||||
|
||||
Sharing components like these can be done on module level. Instead of sharing the entire package, share its individual components:
|
||||
|
||||
```js
|
||||
const shared = {
|
||||
// will result in bloated bundles and degraded performance
|
||||
'@mui/material': {
|
||||
requiredVersion: 'x.x.x', // semver
|
||||
},
|
||||
// sharing per module level, only button module is included in the output
|
||||
'@mui/material/Button': {
|
||||
version: 'x.x.x', // might have to specifically set the version
|
||||
requiredVersion: 'x.x.x', // semver
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
Sharing dependencies on module level leads to optimal bundle size. Even if all modules from a dependency are listed, Webpack will only bundle modules that are discovered in the source files. That means the list can be generated at build time with no risk of bloating the output with unused modules.
|
||||
|
||||
The module sharing "matching" is based on import paths. If relative import paths are used `import {foo} from 'bar'` it will not be matched to the absolute import path of a shared module `import foo from 'bar/foo'`. Therefore absolute import paths have to enforced or path transformation has to happen at build time. For JS builds, babel can be used, for ts builds a `ts-patch` utility with custom plugins is an option.
|
||||
|
||||
#### Limitations
|
||||
|
||||
A limitation of module sharing is that each module name can only appear once in each context. This means that if you're trying to build a bundle of shared modules with a deeper dependency tree, you may end up needing to resolve conflicts by renaming some modules that appear multiple times with different versions. This will in turn limit sharing of those modules with other bundles.
|
||||
|
||||
There is also a conflict with the chunk splitting currently used in the Backstage CLI that means that some singleton modules need to be configured to be eagerly loaded. More broadly we may also want to re-evaluate the chunk splitting strategy in the Backstage CLI when adding support for module federation.
|
||||
|
||||
#### Webpack chunk optimization
|
||||
|
||||
Custom webpack chunk splitting configuration can be problematic, especially when modifying runtime and vendor chunks. Module federation creates its own chunks. Shared modules that are not set up to be eagerly loaded (using the `eager` configuration) **cannot be included inside the entry script**. With a custom chunk splitting setup, they can potentially be forced into the entry script, causing runtime errors. On the other hand, some critical runtime code that has to be in the entry script, cna be forced out of it. This is particularly problematic for the "shell" application.
|
||||
|
||||
Chunk optimization should be disabled for the initial implementation.
|
||||
|
||||
#### Webpack Public path option
|
||||
|
||||
The `publicPath` output config in webpack is a mandatory attribute for federated modules. However, at build time, it is impossible to guess where the assets are served from. From origin to the pathname, this is specific to each installation.
|
||||
|
||||
We can leverage the [auto](https://webpack.js.org/guides/public-path/#automatic-publicpath) option. However this means that some manifest transformation has to happen at runtime when entry scripts are loaded into the browser. More on that in the [Plugin manifest](#plugin-manifest), [CDN Plugin](#dynamic-assets-server-plugin), and [Plugin loading](#plugin-loading) sections.
|
||||
|
||||
#### Sample webpack configuration
|
||||
|
||||
```TS
|
||||
import { DynamicRemotePlugin } from '@openshift/dynamic-plugin-sdk-webpack';
|
||||
|
||||
const sharedModules = {
|
||||
/**
|
||||
* Mandatory singleton packages for sharing
|
||||
*/
|
||||
react: {
|
||||
singleton: true,
|
||||
requiredVersion: '*',
|
||||
},
|
||||
'react-dom': {
|
||||
singleton: true,
|
||||
requiredVersion: '*',
|
||||
},
|
||||
'react-router-dom': {
|
||||
singleton: true,
|
||||
requiredVersion: '*',
|
||||
},
|
||||
'react-router': {
|
||||
singleton: true,
|
||||
requiredVersion: '*',
|
||||
},
|
||||
...
|
||||
/**
|
||||
* Full list of shared modules in Janus
|
||||
* https://github.com/janus-idp/backstage-plugins/blob/87a6b045c7b0f301ebed8b8f99dc1741fa2b044b/packages/cli/src/lib/bundler/scalprumConfig.ts#L16
|
||||
*/
|
||||
type DynamicPluginConfig = {
|
||||
name: string;
|
||||
version?: string;
|
||||
};
|
||||
// { name: "@backstage/plugin-api-docs", version: "1.0.0" }
|
||||
// generates "dynamic-backstage.plugin-api-docs"
|
||||
const getName = (plugin: DynamicPluginConfig) => {
|
||||
let pluginName: string;
|
||||
if (plugin.name.includes('/')) {
|
||||
const fragments = plugin.name.split('/');
|
||||
pluginName = `${fragments[0].replace('@', '')}.${fragments[1]}`;
|
||||
} else {
|
||||
pluginName = plugin.name;
|
||||
}
|
||||
|
||||
return `dynamic-${pluginName}`;
|
||||
}
|
||||
|
||||
|
||||
// plugin = { name: "@backstage/plugin-api-docs", version: "1.0.0" } based on package.json
|
||||
const pluginName = getName(plugin);
|
||||
|
||||
const { ModuleFederationPlugin, ContainerPlugin } = require('@module-federation/enhanced');
|
||||
|
||||
const dynamicPluginPlugin = new DynamicRemotePlugin({
|
||||
extensions: [],
|
||||
sharedModules,
|
||||
entryScriptFilename: `${options.pluginMetadata.name}.[contenthash].js`,
|
||||
pluginMetadata: {
|
||||
// version cna be used from the package.json version field
|
||||
version: '1.0.0',
|
||||
/**
|
||||
* Name can be easily derived from the plugin name
|
||||
* https://github.com/janus-idp/backstage-plugins/blob/87a6b045c7b0f301ebed8b8f99dc1741fa2b044b/packages/cli/src/commands/export-dynamic-plugin/frontend.ts#L40
|
||||
*/
|
||||
name: 'backstage.plugin-github-actions',
|
||||
/**
|
||||
* Path to the plugin entry point.
|
||||
* It can default to the same entry point as in regular build.
|
||||
* Plugins can expose multiple modules. We have found that one is sufficient from backstage plugins.
|
||||
*/
|
||||
exposedModules: {
|
||||
PluginRoot: './src/index.ts'
|
||||
sharedModules, // from shared config and generated from `package.json` dependencies
|
||||
entryScriptFilename: `[name].[contenthash].js`, // using contenthash for cashing purposes
|
||||
moduleFederationSettings: {
|
||||
libraryType: 'global', // use the globalThis object rather than jsonp
|
||||
// instruct the sdk plugin to use @module-federation/enhanced tooling
|
||||
pluginOverride: {
|
||||
ModuleFederationPlugin,
|
||||
ContainerPlugin,
|
||||
}
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
The `DynamicRemotePlugin` webpack plugin takes care of the rest, including the manifest generation.
|
||||
|
||||
#### Sample plugin raw webpack configuration
|
||||
|
||||
The Scalprum config translates to a following base webpack plugin configuration:
|
||||
|
||||
```JS
|
||||
import { container } from 'webpack';
|
||||
|
||||
const dynamicPlugin = new container.ModuleFederationPlugin({
|
||||
name: 'backstage.plugin-github-actions',
|
||||
library: {
|
||||
type: 'global',
|
||||
/**
|
||||
* Some library.type has name limitation
|
||||
* for example, if "type": "var" is used, the library.name can contain the "-" character
|
||||
*/
|
||||
name: 'backstage.plugin-github-actions'
|
||||
pluginMetadata: {
|
||||
name: pluginName,
|
||||
version: plugin.version || '0.0.0',
|
||||
exposedModules: {
|
||||
// path to the default export of the frontend plugin entry point
|
||||
// the path should be sourced from the "main" attribute withing package.json
|
||||
pluginEntry: './src/index.ts',
|
||||
},
|
||||
},
|
||||
filename: 'backstage.plugin-github-actions.[contenthash].js',
|
||||
exposes: {
|
||||
PluginRoot: './src/index.ts'
|
||||
},
|
||||
// list of shared modules like "react", "react-dom", etc
|
||||
shared: sharedModules,
|
||||
});
|
||||
|
||||
|
||||
const config: Configuration = {
|
||||
context: pluginRoot,
|
||||
output: {
|
||||
chunkFilename: `${pluginName}.[contenthash].js`,
|
||||
path: path.resolve(pluginRoot, 'dist'),
|
||||
publicPath: 'auto',
|
||||
},
|
||||
entry: {},
|
||||
resolve: {
|
||||
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||
},
|
||||
// extend existing webpack plugins that are relevant for dynamic plugins
|
||||
plugins: [dynamicPluginPlugin, ...],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
// needs TS config as well
|
||||
test: /\.js$/,
|
||||
exclude: /(node_modules)/,
|
||||
use: {
|
||||
loader: 'swc-loader',
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.(png|svg|jpg|jpeg|gif)$/i,
|
||||
type: 'asset/resource',
|
||||
},
|
||||
// additional loaders for CSS if necessary, can use the same as the current backstage shell app
|
||||
],
|
||||
},
|
||||
};
|
||||
return config;
|
||||
```
|
||||
|
||||
Additional plugin would have to be written from scratch to generate the plugin manifest file.
|
||||
**Webpack plugins**
|
||||
|
||||
### Sample shell application webpack configuration
|
||||
Existing webpack plugins can be used. Subset of shared plugins should be identified from current configurations and shared between the dynamic plugins and the shell application.
|
||||
|
||||
Shell application (backstage) has very simple module federation configuration. It does not require anything special to be able to inject plugins. Main requirement is to provide core shared packages like react and react-dom.
|
||||
### Plugin manifest
|
||||
|
||||
```JS
|
||||
import { container } from 'webpack';
|
||||
Plugin manifest is a simple JSON file containing critical metadata to initialize a remote plugin.
|
||||
|
||||
const scalprumPlugin = new container.ModuleFederationPlugin({
|
||||
name: 'backstageHost',
|
||||
filename: 'backstageHost.[contenthash].js',
|
||||
// same share modules list as with plugin config
|
||||
shared: [sharedModules],
|
||||
});
|
||||
The `@openshift/dynamic-plugin-sdk-webpack` plugin will output manifest file in the following format:
|
||||
|
||||
```ts
|
||||
type PluginManifest = {
|
||||
name: string;
|
||||
version: string;
|
||||
dependencies?: Record<string, string>;
|
||||
customProperties?: AnyObject;
|
||||
baseURL: string;
|
||||
loadScripts: string[];
|
||||
registrationMethod: 'callback' | 'custom';
|
||||
buildHash?: string;
|
||||
};
|
||||
```
|
||||
|
||||
Nothing else is required.
|
||||
This manifest is directly usable in Scalprum at runtime.
|
||||
|
||||
### Plugin storage
|
||||
**baseURL**
|
||||
|
||||
Where will the dynamic plugin assets be hosted? Module federation does not strictly require the remote assets to be all hosted on the same origin.
|
||||
This attribute is populated by the `output.publicPath` configuration. In this case, it will be a value of `auto`. That is not usable by the Scalprum loader. It has to be a URL.
|
||||
|
||||
Theoretically plugins can be hosted on some "public CDN" which is detached from individual backstage instances.
|
||||
Because the origin can't be reliably "guessed" at build time, the value has to be filled by the CDN server. The attribute can be either overridden or, preferably, added to the `customProperties` attribute.
|
||||
|
||||
Assets can be also be hosted in the same way as they have always been.
|
||||
A default`DEFAULT_API_PATH` should be used. Covering majority of the use cases.
|
||||
|
||||
It's important to consider old deployments as part of this storage, to make sure that dynamic chunks are still available to users who have not yet refreshed the page to load the latest version of the app.
|
||||
```ts
|
||||
type CustomProperties = {
|
||||
assetHost?: string; // for local development should be http://localhost:PORT
|
||||
// for deployment, should match the api host https://backstage.company.org
|
||||
};
|
||||
```
|
||||
|
||||
### Plugin discovery
|
||||
Any additional metadata about plugins, can be also stored to the `customProperties`. Either at build time or runtime. That depends on the use case. The values can be read at runtime during plugin initialization.
|
||||
|
||||
How to notify/send data to browser
|
||||
```ts
|
||||
type CustomProperties = {
|
||||
backstage: Record<string, any>;
|
||||
};
|
||||
```
|
||||
|
||||
### Plugin initialization
|
||||
**Exposing singleton packages config**
|
||||
|
||||
Currently all plugins have to be initialized at UI bootstrap (page refresh). The new UI async API can be used to initialize the remote assets.
|
||||
Singleton shared packages do not follow the version matching strategy. It is a weak point in the dependency sharing strategy. Exposing the data in the manifest files provides the option to check the singleton configuration at runtime and prevent runtime crashes of plugins.
|
||||
|
||||
The `CreateAppFeatureLoader` can be leveraged to initialize the remote container.
|
||||
```ts
|
||||
type SingletonShareConfig = {
|
||||
singleton: true;
|
||||
version: string;
|
||||
packageName: string;
|
||||
};
|
||||
|
||||
```TS
|
||||
const allPluginManifests = {...} // get this from the config
|
||||
type SingletonShareObject = {
|
||||
[packageName: string]: SingletonShareConfig;
|
||||
};
|
||||
```
|
||||
|
||||
const asyncFeatureLoaders: CreateAppFeatureLoader[] = Object.values(allPluginManifests).map(({ manifest }) => {
|
||||
return {
|
||||
getLoaderName: () => manifest.name,
|
||||
load: (options) => {
|
||||
// initialize the remote container, depends on tooling
|
||||
const plugin = initDynamicPlugin(manifest)
|
||||
}
|
||||
**Backstage plugin manifest**
|
||||
|
||||
The plugin manifest for backstage with the additional attributes:
|
||||
|
||||
```ts
|
||||
type SingletonShareConfig = {
|
||||
singleton: true;
|
||||
version: string;
|
||||
packageName: string;
|
||||
};
|
||||
|
||||
type SingletonShareObject = {
|
||||
[packageName: string]: SingletonShareConfig;
|
||||
};
|
||||
|
||||
type CustomProperties = {
|
||||
assetHost?: string;
|
||||
backstage: Record<string, any>;
|
||||
singletonPackages: SingletonShareObject;
|
||||
};
|
||||
|
||||
type PluginManifest = {
|
||||
name: string;
|
||||
version: string;
|
||||
dependencies?: Record<string, string>;
|
||||
customProperties: CustomProperties;
|
||||
baseURL: 'auto';
|
||||
loadScripts: string[];
|
||||
registrationMethod: 'custom';
|
||||
buildHash?: string;
|
||||
};
|
||||
```
|
||||
|
||||
### Simplistic minimal example of module map generator
|
||||
|
||||
```js
|
||||
const path = require('path');
|
||||
const typescript = require('typescript');
|
||||
const fs = require('fs');
|
||||
|
||||
/** @type {typescript.CompilerOptions} */
|
||||
const defaultCompilerOptions = {
|
||||
targe: 'es2015',
|
||||
module: 'es2015',
|
||||
esModuleInterop: true,
|
||||
allowJs: true,
|
||||
strict: false,
|
||||
skipLibCheck: true,
|
||||
noEmit: true,
|
||||
// needs to be configured to the root directory dependency
|
||||
rootDir: path.resolve(__dirname, 'dist'),
|
||||
baseUrl: path.resolve(__dirname, 'dist'),
|
||||
};
|
||||
|
||||
// these need to be configured, usually getting metadata from the lib package.json
|
||||
const rootDit = path.resolve(__dirname, 'dist');
|
||||
const base = path.resolve(__dirname, 'dist', 'index.js');
|
||||
|
||||
function getDynamicModuleMap(libName) {
|
||||
const compiler = typescript.createCompilerHost(defaultCompilerOptions, [
|
||||
rootDit,
|
||||
]);
|
||||
const program = typescript.createProgram(
|
||||
[base],
|
||||
defaultCompilerOptions,
|
||||
compiler,
|
||||
);
|
||||
|
||||
const moduleResolutionCache = typescript.createModuleResolutionCache(
|
||||
rootDit,
|
||||
x => x,
|
||||
defaultCompilerOptions,
|
||||
);
|
||||
const errorDiagnostics = typescript
|
||||
.getPreEmitDiagnostics(program)
|
||||
.filter(d => d.category === typescript.DiagnosticCategory.Error);
|
||||
if (errorDiagnostics.length > 0) {
|
||||
const { getCanonicalFileName, getCurrentDirectory, getNewLine } = compiler;
|
||||
|
||||
console.error(
|
||||
typescript.formatDiagnostics(errorDiagnostics, {
|
||||
getCanonicalFileName,
|
||||
getCurrentDirectory,
|
||||
getNewLine,
|
||||
}),
|
||||
);
|
||||
|
||||
throw new Error(`Detected TypeScript errors while parsing modules`);
|
||||
}
|
||||
})
|
||||
const typeChecker = program.getTypeChecker();
|
||||
|
||||
const app = createApp({
|
||||
features: [
|
||||
...asyncFeatureLoaders,
|
||||
// rest of classic features
|
||||
]
|
||||
})
|
||||
/** @param {typescript.SourceFile} sourceFile */
|
||||
const getExportNames = sourceFile =>
|
||||
typeChecker
|
||||
.getExportsOfModule(typeChecker.getSymbolAtLocation(sourceFile))
|
||||
.map(symbol => symbol.getName());
|
||||
|
||||
const baseExports = getExportNames(program.getSourceFile(base));
|
||||
const compilerDir = compiler.getCurrentDirectory();
|
||||
const resolvedModules = baseExports
|
||||
.map(name => {
|
||||
const res = typescript.resolveModuleName(
|
||||
name,
|
||||
base,
|
||||
defaultCompilerOptions,
|
||||
compiler,
|
||||
moduleResolutionCache,
|
||||
);
|
||||
if (res.resolvedModule?.resolvedFileName) {
|
||||
return {
|
||||
name,
|
||||
file:
|
||||
libName +
|
||||
res.resolvedModule.resolvedFileName
|
||||
.replace(compilerDir, '')
|
||||
.replace(/\.js$/, ''),
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
})
|
||||
.filter(x => x !== undefined);
|
||||
|
||||
const moduleMapFileName = path.resolve(__dirname, 'module-map.json');
|
||||
fs.writeFileSync(moduleMapFileName, JSON.stringify(resolvedModules, null, 2));
|
||||
}
|
||||
|
||||
const libName = '@mui/foo';
|
||||
|
||||
getDynamicModuleMap(libName);
|
||||
|
||||
/**
|
||||
* [
|
||||
* {
|
||||
* "name": "foo",
|
||||
* "file": "@mui/foo/dist/foo"
|
||||
* },
|
||||
* {
|
||||
* "name": "baz",
|
||||
* "file": "@mui/foo/dist/baz"
|
||||
* }
|
||||
* ]
|
||||
*/
|
||||
```
|
||||
|
||||
### Plugin declarative configuration
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2019-09/schema",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"shareModules": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^(@[^/]+/)?[^/]+$": {
|
||||
"$ref": "#/definitions/sharedModule"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"excludeModules": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"sharedModule": {
|
||||
"type": "object",
|
||||
"required": ["requiredVersion"],
|
||||
"properties": {
|
||||
"requiredVersion": {
|
||||
"$ref": "#/definitions/semverString"
|
||||
},
|
||||
"version": {
|
||||
"$ref": "#/definitions/semverString"
|
||||
},
|
||||
"singleton": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"semverString": {
|
||||
"type": "string",
|
||||
"pattern": "^(\\^|\\~)?(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "./dependency-sharing-schema.json",
|
||||
"shareModules": {
|
||||
"foo-bar": {
|
||||
"requiredVersion": "1.0.0"
|
||||
},
|
||||
"@bax/foo-bar": {
|
||||
"requiredVersion": "1.0.0",
|
||||
"singleton": true
|
||||
},
|
||||
"@bax-baz/foo-bar2": {
|
||||
"requiredVersion": "^1.2.0",
|
||||
"version": "1.4.0"
|
||||
}
|
||||
},
|
||||
"excludeModules": ["foo-bar-baz"]
|
||||
}
|
||||
@@ -79,8 +79,25 @@ The resolvers will be tried in order, but will only be skipped if they throw a `
|
||||
|
||||
If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation.
|
||||
|
||||
## Backend Installation
|
||||
|
||||
To add the provider to the backend we will first need to install the package by running this command:
|
||||
|
||||
```bash title="from your Backstage root directory"
|
||||
yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-atlassian-provider
|
||||
```
|
||||
|
||||
Then we will need to this line:
|
||||
|
||||
```ts title="in packages/backend/src/index.ts"
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
/* highlight-add-start */
|
||||
backend.add(import('@backstage/plugin-auth-backend-module-atlassian-provider'));
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
## Adding the provider to the Backstage frontend
|
||||
|
||||
To add the provider to the frontend, add the `atlassianAuthApi` reference and
|
||||
`SignInPage` component as shown in
|
||||
[Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page).
|
||||
[Adding the provider to the sign-in page](../index.md#sign-in-configuration).
|
||||
|
||||
@@ -64,4 +64,4 @@ Auth0 requires a session, so you need to give the session a secret key.
|
||||
|
||||
To add the provider to the frontend, add the `auth0AuthApi` reference and
|
||||
`SignInPage` component as shown in
|
||||
[Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page).
|
||||
[Adding the provider to the sign-in page](../index.md#sign-in-configuration).
|
||||
|
||||
@@ -8,37 +8,6 @@ description: Adding AWS ALB as an authentication provider in Backstage
|
||||
Backstage can de deployed behind [AWS Application Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html)
|
||||
and get the user seamlessly authenticated.
|
||||
|
||||
## Installation
|
||||
|
||||
### Backend
|
||||
|
||||
:::note
|
||||
These instructions are written for the [new backend system](../../backend-system/index.md).
|
||||
:::
|
||||
|
||||
Add the `@backstage/plugin-auth-backend-module-aws-alb-provider` to your backend installation.
|
||||
|
||||
```sh
|
||||
# From your Backstage root directory
|
||||
yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-aws-alb-provider
|
||||
```
|
||||
|
||||
Then, add it to your backend's source,
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
const backend = createBackend();
|
||||
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
// highlight-add-next-line
|
||||
backend.add(import('@backstage/plugin-auth-backend-module-aws-alb-provider'));
|
||||
|
||||
await backend.start();
|
||||
```
|
||||
|
||||
### Frontend
|
||||
|
||||
See [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) for pointers on how to set up the sign-in page, and to also make it work smoothly for local development.
|
||||
|
||||
## Configuration
|
||||
|
||||
The provider configuration can be added to your `app-config.yaml` under the root
|
||||
@@ -57,4 +26,40 @@ auth:
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
```
|
||||
|
||||
### Resolvers
|
||||
|
||||
This provider includes several resolvers out of the box that you can use:
|
||||
|
||||
- `emailMatchingUserEntityProfileEmail`: Matches the email address from the auth provider with the User entity that has a matching `spec.profile.email`. If no match is found it will throw a `NotFoundError`.
|
||||
- `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`.
|
||||
|
||||
:::note Note
|
||||
|
||||
The resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`.
|
||||
|
||||
:::
|
||||
|
||||
If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation.
|
||||
|
||||
## Backend Installation
|
||||
|
||||
To add the provider to the backend we will first need to install the package by running this command:
|
||||
|
||||
```bash title="from your Backstage root directory"
|
||||
yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-aws-alb-provider
|
||||
```
|
||||
|
||||
Then we will need to add this line:
|
||||
|
||||
```ts title="in packages/backend/src/index.ts"
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
/* highlight-add-start */
|
||||
backend.add(import('@backstage/plugin-auth-backend-module-aws-alb-provider'));
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
## Adding the provider to the Backstage frontend
|
||||
|
||||
See [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) for pointers on how to set up the sign-in page, and to also make it work smoothly for local development. You'll use `awsalb` as the provider name.
|
||||
|
||||
If you [provide a custom sign in resolver](https://backstage.io/docs/auth/identity-resolver#building-custom-resolvers), you can skip the `signIn` block entirely.
|
||||
|
||||
@@ -37,6 +37,13 @@ auth:
|
||||
development:
|
||||
clientId: ${AUTH_BITBUCKET_CLIENT_ID}
|
||||
clientSecret: ${AUTH_BITBUCKET_CLIENT_SECRET}
|
||||
signIn:
|
||||
resolvers:
|
||||
# typically you would pick one of these
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
- resolver: userIdMatchingUserEntityAnnotation
|
||||
- resolver: usernameMatchingUserEntityAnnotation
|
||||
```
|
||||
|
||||
The Bitbucket provider is a structure with two configuration keys:
|
||||
@@ -45,44 +52,42 @@ The Bitbucket provider is a structure with two configuration keys:
|
||||
`b59241722e3c3b4816e2`
|
||||
- `clientSecret`: The Secret tied to the generated Key.
|
||||
|
||||
### Resolvers
|
||||
|
||||
This provider includes several resolvers out of the box that you can use:
|
||||
|
||||
- `emailMatchingUserEntityProfileEmail`: Matches the email address from the auth provider with the User entity that has a matching `spec.profile.email`. If no match is found it will throw a `NotFoundError`.
|
||||
- `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`.
|
||||
- `userIdMatchingUserEntityAnnotation`: Matches the `userId` from the auth provider with the User entity that has a matching `bitbucket.org/user-id` annotation. If no match is found it will throw a `NotFoundError`.
|
||||
- `usernameMatchingUserEntityAnnotation`: Matches the `username` from the auth provider with the User entity that has a matching `bitbucket.org/username` annotation. If no match is found it will throw a `NotFoundError`.
|
||||
|
||||
:::note Note
|
||||
|
||||
The resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`.
|
||||
|
||||
:::
|
||||
|
||||
If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation.
|
||||
|
||||
## Backend Installation
|
||||
|
||||
To add the provider to the backend we will first need to install the package by running this command:
|
||||
|
||||
```bash title="from your Backstage root directory"
|
||||
yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-bitbucket-provider
|
||||
```
|
||||
|
||||
Then we will need to add this line:
|
||||
|
||||
```ts title="in packages/backend/src/index.ts"
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
/* highlight-add-start */
|
||||
backend.add(import('@backstage/plugin-auth-backend-module-bitbucket-provider'));
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
## Adding the provider to the Backstage frontend
|
||||
|
||||
To add the provider to the frontend, add the `bitbucketAuthApi` reference and
|
||||
`SignInPage` component as shown in
|
||||
[Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page).
|
||||
|
||||
## Using Bitbucket for sign-in
|
||||
|
||||
In order to use the Bitbucket provider for sign-in, you must configure it with a
|
||||
`signIn.resolver`. See the
|
||||
[Sign-In Resolver documentation](../identity-resolver.md) for more details on
|
||||
how this is done. Note that for the Bitbucket provider, you'll want to use
|
||||
`bitbucket` as the provider ID, and `providers.bitbucket.create` for the provider
|
||||
factory.
|
||||
|
||||
The `@backstage/plugin-auth-backend` plugin also comes with two built-in
|
||||
resolvers that can be used if desired. The first one is the
|
||||
`bitbucketUsernameSignInResolver`, which identifies users by matching their
|
||||
Bitbucket username to `bitbucket.org/username` annotations of `User` entities in
|
||||
the catalog. Note that you must populate your catalog with matching entities or
|
||||
users will not be able to sign in.
|
||||
|
||||
The second resolver is the `bitbucketUserIdSignInResolver`, which works the
|
||||
same way, but uses the Bitbucket user ID instead, and matches on the
|
||||
`bitbucket.org/user-id` annotation.
|
||||
|
||||
The following is an example of how to use one of the built-in resolvers:
|
||||
|
||||
```ts
|
||||
import { providers } from '@backstage/plugin-auth-backend';
|
||||
|
||||
// ...
|
||||
providerFactories: {
|
||||
bitbucket: providers.bitbucket.create({
|
||||
signIn: {
|
||||
resolver:
|
||||
providers.bitbucket.resolvers.usernameMatchingUserEntityAnnotation(),
|
||||
},
|
||||
}),
|
||||
},
|
||||
```
|
||||
[Adding the provider to the sign-in page](../index.md#sign-in-configuration).
|
||||
|
||||
@@ -10,8 +10,8 @@ users using Bitbucket Server. This does **NOT** work with Bitbucket Cloud.
|
||||
|
||||
## Create an Application Link in Bitbucket Server
|
||||
|
||||
To add Bitbucket Server authentication, you must create an outgoing application link. Follow the steps described in
|
||||
the [Bitbucket Server documentation](https://confluence.atlassian.com/bitbucketserver/configure-an-outgoing-link-1108483656.html)
|
||||
To add Bitbucket Server authentication, you must create an incoming application link. Follow the steps described in
|
||||
the [Bitbucket Server documentation](https://confluence.atlassian.com/bitbucketserver/configure-an-incoming-link-1108483657.html)
|
||||
to create one.
|
||||
|
||||
## Configuration
|
||||
@@ -37,7 +37,7 @@ The Bitbucket Server provider is a structure with two configuration keys:
|
||||
## Adding the provider to the Backstage frontend
|
||||
|
||||
To add the provider to the frontend, add the `bitbucketServerAuthApi` reference and `SignInPage` component as shown
|
||||
in [Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page).
|
||||
in [Adding the provider to the sign-in page](../index.md#sign-in-configuration).
|
||||
|
||||
## Using Bitbucket Server for sign-in
|
||||
|
||||
|
||||
@@ -1,174 +0,0 @@
|
||||
---
|
||||
id: provider
|
||||
title: Cloudflare Access Provider
|
||||
sidebar_label: Cloudflare Access
|
||||
description: Adding Cloudflare Access as an authentication provider in Backstage
|
||||
---
|
||||
|
||||
Similar to GCP IAP Proxy Provider or AWS ALB provider, developers can offload authentication
|
||||
support to Cloudflare Access.
|
||||
|
||||
This tutorial shows how to use authentication on Cloudflare Access sitting in
|
||||
front of Backstage.
|
||||
|
||||
It is assumed a Cloudflare tunnel is already serving traffic in front of a
|
||||
Backstage instance configured to serve the frontend app from the backend and is
|
||||
already gated using Cloudflare Access.
|
||||
|
||||
## Configuration
|
||||
|
||||
Let's start by adding the following `auth` configuration in your
|
||||
`app-config.yaml` or `app-config.production.yaml` or similar:
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
providers:
|
||||
cfaccess:
|
||||
# You can find the team name in the Cloudflare Zero Trust dashboard.
|
||||
teamName: <Team Name>
|
||||
# This service tokens section is optional -- you only need it if you have
|
||||
# some Cloudflare Service Tokens that you want to be able to log in to your
|
||||
# Backstage instance.
|
||||
serviceTokens:
|
||||
- token: '1uh2fh19efvfh129f1f919u21f2f19jf2.access'
|
||||
subject: 'bot-user@your-company.com'
|
||||
# This picks what sign in resolver(s) you want to use.
|
||||
signIn:
|
||||
resolvers:
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
```
|
||||
|
||||
This config section must be in place for the provider to load at all.
|
||||
|
||||
The `signIn` section picks what sign-in resolver(s) to use for sign-in attempts.
|
||||
It is responsible for matching the upstream provider's sign-in result to a
|
||||
corresponding Backstage identity, or to throw an error if the attempt should be
|
||||
rejected for any reason. The `emailMatchingUserEntityProfileEmail` is a common
|
||||
choice: it tries to match the email of the signed-in user to a `User` kind
|
||||
entity in the catalog whose profile email matches that.
|
||||
|
||||
If the builtin sign in resolvers do not match your needs, you can skip the
|
||||
`signIn` section and instead [provide a custom resolver](#advanced-custom-sign-in-resolver).
|
||||
|
||||
## Backend Changes
|
||||
|
||||
We need to add the provider package as a dependency to our backend:
|
||||
|
||||
```bash title="from your Backstage root directory"
|
||||
yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-cloudflare-access-provider
|
||||
```
|
||||
|
||||
And to tell the backend to load it:
|
||||
|
||||
```ts title="in packages/backend/src/index.ts"
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
/* highlight-add-start */
|
||||
backend.add(
|
||||
import('@backstage/plugin-auth-backend-module-cloudflare-access-provider'),
|
||||
);
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
Now the backend is ready to serve auth requests on the
|
||||
`/api/auth/cfaccess/refresh` endpoint. All that's left is to update the frontend
|
||||
sign-in mechanism to poll that endpoint through Cloudflare Access, on the user's
|
||||
behalf.
|
||||
|
||||
## Frontend Changes
|
||||
|
||||
It is recommended to use the `ProxiedSignInPage` for this provider, which is
|
||||
installed in your app like this:
|
||||
|
||||
```tsx title="in packages/app/src/App.tsx"
|
||||
/* highlight-add-next-line */
|
||||
import { ProxiedSignInPage } from '@backstage/core-components';
|
||||
|
||||
const app = createApp({
|
||||
/* highlight-add-start */
|
||||
components: {
|
||||
SignInPage: props => <ProxiedSignInPage {...props} provider="cfaccess" />,
|
||||
},
|
||||
/* highlight-add-end */
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
See [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) for
|
||||
pointers on how to set up the sign-in page to also work smoothly for local
|
||||
development.
|
||||
|
||||
## Advanced: Custom Sign-in Resolver
|
||||
|
||||
If none of the built-in sign in resolvers fit your needs, you need to provide a
|
||||
customized version of the module. Now you should _not_
|
||||
`backend.add(import(...))`, instead you will do the following.
|
||||
|
||||
```ts title="in packages/backend/plugin/auth.ts"
|
||||
/* highlight-add-start */
|
||||
import { createCloudflareAccessAuthenticator } from '@backstage/plugin-auth-backend-module-cloudflare-access-provider';
|
||||
import {
|
||||
coreServices,
|
||||
createBackendModule,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import {
|
||||
authProvidersExtensionPoint,
|
||||
createProxyAuthProviderFactory,
|
||||
} from '@backstage/plugin-auth-node';
|
||||
|
||||
const customAuth = createBackendModule({
|
||||
// This ID must be exactly "auth" because that's the plugin it targets
|
||||
pluginId: 'auth',
|
||||
// This ID must be unique, but can be anything
|
||||
moduleId: 'custom-auth-provider',
|
||||
register(reg) {
|
||||
reg.registerInit({
|
||||
deps: {
|
||||
providers: authProvidersExtensionPoint,
|
||||
cache: coreServices.cache,
|
||||
},
|
||||
async init({ providers, cache }) {
|
||||
providers.registerProvider({
|
||||
// This ID must match the actual provider config, e.g. addressing
|
||||
// auth.providers.github means that this must be "github".
|
||||
providerId: 'cfaccess',
|
||||
// Use createProxyAuthProviderFactory instead if it's one of the proxy
|
||||
// based providers rather than an OAuth based one
|
||||
factory: createProxyAuthProviderFactory({
|
||||
authenticator: createCloudflareAccessAuthenticator({ cache }),
|
||||
async signInResolver(info, ctx) {
|
||||
// This is where the body of the sign-in resolver goes!
|
||||
const { profile } = info;
|
||||
if (!profile.email) {
|
||||
throw new Error(
|
||||
'Login failed, user profile does not contain an email',
|
||||
);
|
||||
}
|
||||
return ctx.signInWithCatalogUser({
|
||||
filter: {
|
||||
'spec.profile.email': profile.email,
|
||||
},
|
||||
});
|
||||
},
|
||||
}),
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
/* highlight-add-end */
|
||||
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
/* highlight-remove-start */
|
||||
backend.add(
|
||||
import('@backstage/plugin-auth-backend-module-cloudflare-access-provider'),
|
||||
);
|
||||
/* highlight-remove-end */
|
||||
/* highlight-add-next-line */
|
||||
backend.add(customAuth);
|
||||
```
|
||||
|
||||
The body of the sign-in resolver is up to you to write! The example code above
|
||||
is just a copy of what `emailMatchingUserEntityProfileEmail` does. The `info`
|
||||
parameter contains all of the results of the sign-in attempt so far. The `ctx`
|
||||
context [has several useful functions](https://backstage.io/docs/reference/plugin-auth-node.authresolvercontext/)
|
||||
for issuing tokens in various ways.
|
||||
@@ -0,0 +1,82 @@
|
||||
---
|
||||
id: provider
|
||||
title: Cloudflare Access Provider
|
||||
sidebar_label: Cloudflare Access
|
||||
description: Adding Cloudflare Access as an authentication provider in Backstage
|
||||
---
|
||||
|
||||
Similar to GCP IAP Proxy Provider or AWS ALB provider, developers can offload authentication
|
||||
support to Cloudflare Access.
|
||||
|
||||
This tutorial shows how to use authentication on Cloudflare Access sitting in
|
||||
front of Backstage.
|
||||
|
||||
It is assumed a Cloudflare tunnel is already serving traffic in front of a
|
||||
Backstage instance configured to serve the frontend app from the backend and is
|
||||
already gated using Cloudflare Access.
|
||||
|
||||
## Configuration
|
||||
|
||||
Let's start by adding the following `auth` configuration in your
|
||||
`app-config.yaml` or `app-config.production.yaml` or similar:
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
providers:
|
||||
cfaccess:
|
||||
# You can find the team name in the Cloudflare Zero Trust dashboard.
|
||||
teamName: <Team Name>
|
||||
# This service tokens section is optional -- you only need it if you have
|
||||
# some Cloudflare Service Tokens that you want to be able to log in to your
|
||||
# Backstage instance.
|
||||
serviceTokens:
|
||||
- token: '1uh2fh19efvfh129f1f919u21f2f19jf2.access'
|
||||
subject: 'bot-user@your-company.com'
|
||||
# This picks what sign in resolver(s) you want to use.
|
||||
signIn:
|
||||
resolvers:
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
```
|
||||
|
||||
This config section must be in place for the provider to load at all.
|
||||
|
||||
### Resolvers
|
||||
|
||||
This provider includes several resolvers out of the box that you can use:
|
||||
|
||||
- `emailMatchingUserEntityProfileEmail`: Matches the email address from the auth provider with the User entity that has a matching `spec.profile.email`. If no match is found it will throw a `NotFoundError`.
|
||||
- `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`.
|
||||
|
||||
:::note Note
|
||||
|
||||
The resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`.
|
||||
|
||||
:::
|
||||
|
||||
If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation.
|
||||
|
||||
## Backend Installation
|
||||
|
||||
To add the provider to the backend we will first need to install the package by running this command:
|
||||
|
||||
```bash title="from your Backstage root directory"
|
||||
yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-cloudflare-access-provider
|
||||
```
|
||||
|
||||
Then we will need to add this line:
|
||||
|
||||
```ts title="in packages/backend/src/index.ts"
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
/* highlight-add-start */
|
||||
backend.add(
|
||||
import('@backstage/plugin-auth-backend-module-cloudflare-access-provider'),
|
||||
);
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
## Adding the provider to the Backstage frontend
|
||||
|
||||
See [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) for pointers on how to set up the sign-in page, and to also make it work smoothly for local development. You'll use `cfaccess` as the provider name.
|
||||
|
||||
If you [provide a custom sign in resolver](https://backstage.io/docs/auth/identity-resolver#building-custom-resolvers), you can skip the `signIn` block entirely.
|
||||
@@ -26,6 +26,14 @@ Settings for local development:
|
||||
- Homepage URL: `http://localhost:3000`
|
||||
- Authorization callback URL: `http://localhost:7007/api/auth/github/handler/frame`
|
||||
|
||||
### Difference between GitHub Apps and GitHub OAuth Apps
|
||||
|
||||
GitHub Apps handle OAuth scope at the app installation level, meaning that the
|
||||
`scope` parameter for the call to `getAccessToken` in the frontend has no
|
||||
effect. When calling `getAccessToken` in open source plugins, one should still
|
||||
include the appropriate scope, but also document in the plugin README what
|
||||
scopes are required for GitHub Apps.
|
||||
|
||||
## Configuration
|
||||
|
||||
The provider configuration can then be added to your `app-config.yaml` under the
|
||||
@@ -79,16 +87,25 @@ The resolvers will be tried in order, but will only be skipped if they throw a `
|
||||
|
||||
If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation.
|
||||
|
||||
## Backend Installation
|
||||
|
||||
To add the provider to the backend we will first need to install the package by running this command:
|
||||
|
||||
```bash title="from your Backstage root directory"
|
||||
yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-github-provider
|
||||
```
|
||||
|
||||
Then we will need to add this line:
|
||||
|
||||
```ts title="in packages/backend/src/index.ts"
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
/* highlight-add-start */
|
||||
backend.add(import('@backstage/plugin-auth-backend-module-github-provider'));
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
## Adding the provider to the Backstage frontend
|
||||
|
||||
To add the provider to the frontend, add the `githubAuthApi` reference and
|
||||
`SignInPage` component as shown in
|
||||
[Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page).
|
||||
|
||||
## Difference between GitHub Apps and GitHub OAuth Apps
|
||||
|
||||
GitHub Apps handle OAuth scope at the app installation level, meaning that the
|
||||
`scope` parameter for the call to `getAccessToken` in the frontend has no
|
||||
effect. When calling `getAccessToken` in open source plugins, one should still
|
||||
include the appropriate scope, but also document in the plugin README what
|
||||
scopes are required for GitHub Apps.
|
||||
[Adding the provider to the sign-in page](../index.md#sign-in-configuration).
|
||||
|
||||
@@ -78,8 +78,25 @@ The resolvers will be tried in order, but will only be skipped if they throw a `
|
||||
|
||||
If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation.
|
||||
|
||||
## Backend Installation
|
||||
|
||||
To add the provider to the backend we will first need to install the package by running this command:
|
||||
|
||||
```bash title="from your Backstage root directory"
|
||||
yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-gitlab-provider
|
||||
```
|
||||
|
||||
Then we will need to add this line:
|
||||
|
||||
```ts title="in packages/backend/src/index.ts"
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
/* highlight-add-start */
|
||||
backend.add(import('@backstage/plugin-auth-backend-module-gitlab-provider'));
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
## Adding the provider to the Backstage frontend
|
||||
|
||||
To add the provider to the frontend, add the `gitlabAuthApi` reference and
|
||||
`SignInPage` component as shown in
|
||||
[Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page).
|
||||
[Adding the provider to the sign-in page](../index.md#sign-in-configuration).
|
||||
|
||||
@@ -58,102 +58,25 @@ The resolvers will be tried in order, but will only be skipped if they throw a `
|
||||
|
||||
If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation.
|
||||
|
||||
## Backend Changes
|
||||
## Backend Installation
|
||||
|
||||
There is a module for this provider that you will need to add to your backend.
|
||||
To add the provider to the backend we will first need to install the package by running this command:
|
||||
|
||||
First you'll want to run this command to add the module:
|
||||
|
||||
```sh
|
||||
yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-gcp-iap-provider
|
||||
```bash title="from your Backstage root directory"
|
||||
yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-gcp-iap-provider
|
||||
```
|
||||
|
||||
Then you will need to add this to your backend:
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
const backend = createBackend();
|
||||
Then we will need to add this line:
|
||||
|
||||
```ts title="in packages/backend/src/index.ts"
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
/* highlight-add-start */
|
||||
backend.add(import('@backstage/plugin-auth-backend-module-gcp-iap-provider'));
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
### Legacy Backend Changes
|
||||
## Adding the provider to the Backstage frontend
|
||||
|
||||
If you are still using the legacy backend you will need to make the changes outlined here.
|
||||
See [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) for pointers on how to set up the sign-in page, and to also make it work smoothly for local development. You'll use `gcp-iap` as the provider name.
|
||||
|
||||
This provider is not enabled by default in the auth backend code, because besides the config section above, it also needs to be given one or more callbacks in actual code as well as described below.
|
||||
|
||||
Add a `providerFactories` entry to the router in
|
||||
`packages/backend/src/plugins/auth.ts`.
|
||||
|
||||
```ts title="packages/backend/src/plugins/auth.ts"
|
||||
import { providers } from '@backstage/plugin-auth-backend';
|
||||
import { stringifyEntityRef } from '@backstage/catalog-model';
|
||||
|
||||
export default async function createPlugin(
|
||||
env: PluginEnvironment,
|
||||
): Promise<Router> {
|
||||
return await createRouter({
|
||||
logger: env.logger,
|
||||
config: env.config,
|
||||
database: env.database,
|
||||
discovery: env.discovery,
|
||||
providerFactories: {
|
||||
'gcp-iap': providers.gcpIap.create({
|
||||
// Replace the auth handler if you want to customize the returned user
|
||||
// profile info (can be left out; the default implementation is shown
|
||||
// below which only returns the email). You may want to amend this code
|
||||
// with something that loads additional user profile data out of e.g.
|
||||
// GSuite or LDAP or similar.
|
||||
async authHandler({ iapToken }) {
|
||||
return { profile: { email: iapToken.email } };
|
||||
},
|
||||
signIn: {
|
||||
// You need to supply an identity resolver, that takes the profile
|
||||
// and the IAP token and produces the Backstage token with the
|
||||
// relevant user info.
|
||||
async resolver({ profile, result: { iapToken } }, ctx) {
|
||||
// Somehow compute the Backstage token claims. Just some sample code
|
||||
// shown here, but you may want to query your LDAP server, or
|
||||
// GSuite or similar, based on the IAP token sub/email claims
|
||||
const id = iapToken.email.split('@')[0];
|
||||
const sub = stringifyEntityRef({ kind: 'User', name: id });
|
||||
const ent = [
|
||||
sub,
|
||||
stringifyEntityRef({ kind: 'Group', name: 'team-name' }),
|
||||
];
|
||||
return ctx.issueToken({ claims: { sub, ent } });
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Now the backend is ready to serve auth requests on the
|
||||
`/api/auth/gcp-iap/refresh` endpoint. All that's left is to update the frontend
|
||||
sign-in mechanism to poll that endpoint through the IAP, on the user's behalf.
|
||||
|
||||
## Frontend Changes
|
||||
|
||||
It is recommended to use the `ProxiedSignInPage` for this provider, which is
|
||||
installed in `packages/app/src/App.tsx` like this:
|
||||
|
||||
```tsx title="packages/app/src/App.tsx"
|
||||
/* highlight-add-next-line */
|
||||
import { ProxiedSignInPage } from '@backstage/core-components';
|
||||
|
||||
const app = createApp({
|
||||
/* highlight-add-start */
|
||||
components: {
|
||||
SignInPage: props => <ProxiedSignInPage {...props} provider="gcp-iap" />,
|
||||
},
|
||||
/* highlight-add-end */
|
||||
// ..
|
||||
});
|
||||
```
|
||||
|
||||
See the [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) section for more information.
|
||||
If you [provide a custom sign in resolver](https://backstage.io/docs/auth/identity-resolver#building-custom-resolvers), you can skip the `signIn` block entirely.
|
||||
|
||||
@@ -24,9 +24,9 @@ To support Google authentication, you must create OAuth credentials:
|
||||
- Add yourself as a test user, if using External user type
|
||||
6. Set **Application Type** to `Web Application` with these settings:
|
||||
- `Name`: Backstage (or your custom app name)
|
||||
- `Authorized JavaScript origins`: http://localhost:3000
|
||||
- `Authorized JavaScript origins`: <http://localhost:3000>
|
||||
- `Authorized Redirect URIs`:
|
||||
http://localhost:7007/api/auth/google/handler/frame
|
||||
<http://localhost:7007/api/auth/google/handler/frame>
|
||||
7. Click Create
|
||||
|
||||
## Configuration
|
||||
@@ -72,8 +72,25 @@ The resolvers will be tried in order, but will only be skipped if they throw a `
|
||||
|
||||
If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation.
|
||||
|
||||
## Backend Installation
|
||||
|
||||
To add the provider to the backend we will first need to install the package by running this command:
|
||||
|
||||
```bash title="from your Backstage root directory"
|
||||
yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-google-provider
|
||||
```
|
||||
|
||||
Then we will need to add this line:
|
||||
|
||||
```ts title="in packages/backend/src/index.ts"
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
/* highlight-add-start */
|
||||
backend.add(import('@backstage/plugin-auth-backend-module-google-provider'));
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
## Adding the provider to the Backstage frontend
|
||||
|
||||
To add the provider to the frontend, add the `googleAuthApi` reference and
|
||||
`SignInPage` component as shown in
|
||||
[Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page).
|
||||
[Adding the provider to the sign-in page](../index.md#sign-in-configuration).
|
||||
|
||||
@@ -25,8 +25,7 @@ This will only work with the new backend system. There is no support for this in
|
||||
|
||||
Add the `@backstage/plugin-auth-backend-module-guest-provider` to your backend installation.
|
||||
|
||||
```sh
|
||||
# From your Backstage root directory
|
||||
```sh title="From your Backstage root directory"
|
||||
yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-guest-provider
|
||||
```
|
||||
|
||||
|
||||
@@ -124,6 +124,8 @@ The list of available resolvers is different for each provider, since they often
|
||||
depend on the information model returned from the upstream provider service.
|
||||
Consult the documentation of the respective provider to find the list.
|
||||
|
||||
In the example above `emailMatchingUserEntityProfileEmail` and `emailLocalPartMatchingUserEntityName` are common to all auth providers and `usernameMatchingUserEntityName` is specific to GitHub.
|
||||
|
||||
### Building Custom Resolvers
|
||||
|
||||
If the builtins don't work for you, you can also provide a completely custom
|
||||
|
||||
+2
-2
@@ -31,7 +31,7 @@ Backstage comes with many common authentication providers in the core library:
|
||||
- [Azure Easy Auth](microsoft/azure-easyauth.md)
|
||||
- [Bitbucket](bitbucket/provider.md)
|
||||
- [Bitbucket Server](bitbucketServer/provider.md)
|
||||
- [Cloudflare Access](cloudflare/access.md)
|
||||
- [Cloudflare Access](cloudflare/provider.md)
|
||||
- [GitHub](github/provider.md)
|
||||
- [GitLab](gitlab/provider.md)
|
||||
- [Google](google/provider.md)
|
||||
@@ -158,7 +158,7 @@ Some auth providers are so-called "proxy" providers, meaning they're meant to be
|
||||
behind an authentication proxy. Examples of these are
|
||||
[Amazon Application Load Balancer](https://github.com/backstage/backstage/blob/master/contrib/docs/tutorials/aws-alb-aad-oidc-auth.md),
|
||||
[Azure EasyAuth](./microsoft/azure-easyauth.md),
|
||||
[Cloudflare Access](./cloudflare/access.md),
|
||||
[Cloudflare Access](./cloudflare/provider.md),
|
||||
[Google Identity-Aware Proxy](./google/gcp-iap-auth.md)
|
||||
and [OAuth2 Proxy](./oauth2-proxy/provider.md).
|
||||
|
||||
|
||||
@@ -7,87 +7,6 @@ description: Adding Azure's EasyAuth Proxy as an authentication provider in Back
|
||||
|
||||
The Backstage `core-plugin-api` package comes with a Microsoft authentication provider that can authenticate users using Microsoft Entra ID (formerly Azure Active Directory) for PaaS service hosted in Azure that support Easy Auth, such as Azure App Services.
|
||||
|
||||
## Backend Changes
|
||||
|
||||
Add the following into your `app-config.yaml` under the root `auth` configuration:
|
||||
|
||||
```yaml title="app-config.yaml"
|
||||
auth:
|
||||
providers:
|
||||
azureEasyAuth:
|
||||
signIn:
|
||||
resolvers:
|
||||
- resolver: idMatchingUserEntityAnnotation
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
```
|
||||
|
||||
The `idMatchingUserEntityAnnotation` is
|
||||
[a builtin sign-in resolver](../identity-resolver.md#using-builtin-resolvers) from `azureEasyAuth` provider.
|
||||
It tries to find a user entity with [a `graph.microsoft.com/user-id` annotation](../../features/software-catalog/well-known-annotations.md#graphmicrosoftcomtenant-id-graphmicrosoftcomgroup-id-graphmicrosoftcomuser-id)
|
||||
which matches the object ID of the user attempting to sign in.
|
||||
If you want to provide your own sign-in resolver,
|
||||
see [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers).
|
||||
|
||||
Add the `@backstage/plugin-auth-backend-module-azure-easyauth-provider` to your backend installation.
|
||||
|
||||
```sh
|
||||
# From your Backstage root directory
|
||||
yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-azure-easyauth-provider
|
||||
```
|
||||
|
||||
Then, add it to your backend's source,
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
const backend = createBackend();
|
||||
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
// highlight-add-next-line
|
||||
backend.add(
|
||||
import('@backstage/plugin-auth-backend-module-azure-easyauth-provider'),
|
||||
);
|
||||
|
||||
await backend.start();
|
||||
```
|
||||
|
||||
Now the backend is ready to serve auth requests on the
|
||||
`/api/auth/azureEasyAuth/refresh` endpoint. All that's left is to update the frontend
|
||||
sign-in mechanism to poll that endpoint through the Easy Auth proxy, on the user's behalf.
|
||||
|
||||
## Frontend Changes
|
||||
|
||||
To use this component, you'll need to configure the app's `SignInPage`.
|
||||
It is recommended to use the `ProxiedSignInPage` for this provider when running in Azure, However for local development (or any other scenario running outside of Azure), you'll want to set up something different.
|
||||
For the closest experience to Easy Auth, you could set up the `microsoft` provider locally, but that will requires setting up App Registrations & secrets which may be locked down by your organisation, in which case it may be easier to use guest login locally.
|
||||
See [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) for more details.
|
||||
|
||||
```tsx title="packages/app/src/App.tsx"
|
||||
/* highlight-add-next-line */
|
||||
import { ProxiedSignInPage } from '@backstage/core-components';
|
||||
|
||||
const app = createApp({
|
||||
/* highlight-add-start */
|
||||
components: {
|
||||
SignInPage: props => {
|
||||
const configApi = useApi(configApiRef);
|
||||
if (configApi.getString('auth.environment') !== 'development') {
|
||||
return <ProxiedSignInPage {...props} provider="azureEasyAuth" />;
|
||||
}
|
||||
return (
|
||||
<SignInPage
|
||||
{...props}
|
||||
providers={['guest', 'custom']}
|
||||
title="Select a sign-in method"
|
||||
align="center"
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
/* highlight-add-end */
|
||||
// ..
|
||||
});
|
||||
```
|
||||
|
||||
## Azure Configuration
|
||||
|
||||
How to configure azure depends on the Azure service you're using to host Backstage.
|
||||
@@ -136,3 +55,60 @@ resource webApp 'Microsoft.Web/sites@2022-03-01' existing = {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Add the following into your `app-config.yaml` under the root `auth` configuration:
|
||||
|
||||
```yaml title="app-config.yaml"
|
||||
auth:
|
||||
providers:
|
||||
azureEasyAuth:
|
||||
signIn:
|
||||
resolvers:
|
||||
# typically you would pick one of these
|
||||
- resolver: emailMatchingUserEntityProfileEmail
|
||||
- resolver: emailLocalPartMatchingUserEntityName
|
||||
- resolver: idMatchingUserEntityAnnotation
|
||||
```
|
||||
|
||||
### Resolvers
|
||||
|
||||
This provider includes several resolvers out of the box that you can use:
|
||||
|
||||
- `emailMatchingUserEntityProfileEmail`: Matches the email address from the auth provider with the User entity that has a matching `spec.profile.email`. If no match is found it will throw a `NotFoundError`.
|
||||
- `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`.
|
||||
- `idMatchingUserEntityAnnotation`: Matches the user Id from the auth provider with the User entity that has a matching `graph.microsoft.com/user-id` annotation. If no match is found it will throw a `NotFoundError`.
|
||||
|
||||
:::note Note
|
||||
|
||||
The resolvers will be tried in order, but will only be skipped if they throw a `NotFoundError`.
|
||||
|
||||
:::
|
||||
|
||||
If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation.
|
||||
|
||||
## Backend Installation
|
||||
|
||||
To add the provider to the backend we will first need to install the package by running this command:
|
||||
|
||||
```bash title="from your Backstage root directory"
|
||||
yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-azure-easyauth-provider
|
||||
```
|
||||
|
||||
Then we will need to this line:
|
||||
|
||||
```ts title="in packages/backend/src/index.ts"
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
/* highlight-add-start */
|
||||
backend.add(
|
||||
import('@backstage/plugin-auth-backend-module-azure-easyauth-provider'),
|
||||
);
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
## Adding the provider to the Backstage frontend
|
||||
|
||||
See [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) for pointers on how to set up the sign-in page, and to also make it work smoothly for local development. You'll use `azureEasyAuth` as the provider name.
|
||||
|
||||
If you [provide a custom sign in resolver](https://backstage.io/docs/auth/identity-resolver#building-custom-resolvers), you can skip the `signIn` block entirely.
|
||||
|
||||
@@ -40,6 +40,18 @@ If you're using an existing app registration, and backstage already has a client
|
||||
If not, go to the **Certificates & Secrets** page, then the **Client secrets** tab and create a new client secret.
|
||||
Make a note of this value as you'll need it in the next section.
|
||||
|
||||
## Outbound Network Access
|
||||
|
||||
If your environment has restrictions on outgoing access (e.g. through
|
||||
firewall rules), make sure your Backstage backend has access to the following
|
||||
hosts:
|
||||
|
||||
- `login.microsoftonline.com`, to get and exchange authorization codes and access
|
||||
tokens
|
||||
- `graph.microsoft.com`, to fetch user profile information (as seen
|
||||
in [this source code](https://github.com/seanfisher/passport-microsoft/blob/0456aa9bce05579c18e77f51330176eb26373658/lib/strategy.js#L93-L95)).
|
||||
If this host is unreachable, users may see an `Authentication failed, failed to fetch user profile` error when they attempt to log in.
|
||||
|
||||
## Configuration
|
||||
|
||||
The provider configuration can then be added to your `app-config.yaml` under the
|
||||
@@ -92,20 +104,25 @@ The resolvers will be tried in order, but will only be skipped if they throw a `
|
||||
|
||||
If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation.
|
||||
|
||||
## Backend Installation
|
||||
|
||||
To add the provider to the backend we will first need to install the package by running this command:
|
||||
|
||||
```bash title="from your Backstage root directory"
|
||||
yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-microsoft-provider
|
||||
```
|
||||
|
||||
Then we will need to this line:
|
||||
|
||||
```ts title="in packages/backend/src/index.ts"
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
/* highlight-add-start */
|
||||
backend.add(import('@backstage/plugin-auth-backend-module-microsoft-provider'));
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
## Adding the provider to the Backstage frontend
|
||||
|
||||
To add the provider to the frontend, add the `microsoftAuthApiRef` reference and
|
||||
`SignInPage` component as shown in
|
||||
[Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page).
|
||||
|
||||
## Outbound Network Access
|
||||
|
||||
If your environment has restrictions on outgoing access (e.g. through
|
||||
firewall rules), make sure your Backstage backend has access to the following
|
||||
hosts:
|
||||
|
||||
- `login.microsoftonline.com`, to get and exchange authorization codes and access
|
||||
tokens
|
||||
- `graph.microsoft.com`, to fetch user profile information (as seen
|
||||
in [this source code](https://github.com/seanfisher/passport-microsoft/blob/0456aa9bce05579c18e77f51330176eb26373658/lib/strategy.js#L93-L95)).
|
||||
If this host is unreachable, users may see an `Authentication failed, failed to fetch user profile` error when they attempt to log in.
|
||||
[Adding the provider to the sign-in page](../index.md#sign-in-configuration).
|
||||
|
||||
@@ -47,25 +47,27 @@ The resolvers will be tried in order, but will only be skipped if they throw a `
|
||||
|
||||
If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation.
|
||||
|
||||
## Adding the provider to the Backstage frontend
|
||||
## Backend Installation
|
||||
|
||||
It is recommended to use the `ProxiedSignInPage` for this provider, which is
|
||||
installed in `packages/app/src/App.tsx` like this:
|
||||
To add the provider to the backend we will first need to install the package by running this command:
|
||||
|
||||
```tsx title="packages/app/src/App.tsx"
|
||||
/* highlight-add-next-line */
|
||||
import { ProxiedSignInPage } from '@backstage/core-components';
|
||||
|
||||
const app = createApp({
|
||||
/* highlight-add-start */
|
||||
components: {
|
||||
SignInPage: props => (
|
||||
<ProxiedSignInPage {...props} provider="oauth2Proxy" />
|
||||
),
|
||||
},
|
||||
/* highlight-add-end */
|
||||
// ..
|
||||
});
|
||||
```bash title="from your Backstage root directory"
|
||||
yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-oauth2-proxy-provider
|
||||
```
|
||||
|
||||
See [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) for pointers on how to set up the sign-in page to also work smoothly for local development.
|
||||
Then we will need to this line:
|
||||
|
||||
```ts title="in packages/backend/src/index.ts"
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
/* highlight-add-start */
|
||||
backend.add(
|
||||
import('@backstage/plugin-auth-backend-module-oauth2-proxy-provider'),
|
||||
);
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
## Adding the provider to the Backstage frontend
|
||||
|
||||
See [Sign-In with Proxy Providers](../index.md#sign-in-with-proxy-providers) for pointers on how to set up the sign-in page, and to also make it work smoothly for local development. You'll use `oauth2Proxy` as the provider name.
|
||||
|
||||
If you [provide a custom sign in resolver](https://backstage.io/docs/auth/identity-resolver#building-custom-resolvers), you can skip the `signIn` block entirely.
|
||||
|
||||
@@ -83,8 +83,25 @@ The resolvers will be tried in order, but will only be skipped if they throw a `
|
||||
|
||||
If these resolvers do not fit your needs you can build a custom resolver, this is covered in the [Building Custom Resolvers](../identity-resolver.md#building-custom-resolvers) section of the Sign-in Identities and Resolvers documentation.
|
||||
|
||||
## Backend Installation
|
||||
|
||||
To add the provider to the backend we will first need to install the package by running this command:
|
||||
|
||||
```bash title="from your Backstage root directory"
|
||||
yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-okta-provider
|
||||
```
|
||||
|
||||
Then we will need to add this line:
|
||||
|
||||
```ts title="in packages/backend/src/index.ts"
|
||||
backend.add(import('@backstage/plugin-auth-backend'));
|
||||
/* highlight-add-start */
|
||||
backend.add(import('@backstage/plugin-auth-backend-module-okta-provider'));
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
## Adding the provider to the Backstage frontend
|
||||
|
||||
To add the provider to the frontend, add the `oktaAuthApi` reference and
|
||||
`SignInPage` component as shown in
|
||||
[Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page).
|
||||
[Adding the provider to the sign-in page](../index.md#sign-in-configuration).
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user