Merge branch 'master' of https://github.com/backstage/backstage into add-additional-scaffolder-permissions

This commit is contained in:
Frank Kong
2024-05-08 13:40:12 -04:00
12 changed files with 201 additions and 1549 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-search-backend-module-elasticsearch': patch
---
Fix never resolved indexer promise.
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
The `build-workspace` command no longer manually runs `yarn postpack`, relying instead on the fact that running `yarn pack` will automatically invoke the `postpack` script. No action is necessary if you are running the latest version of yarn 1, 3, or 4.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-common': patch
---
Plugins created through the `legacyPlugin` helper are now able to authenticate requests from plugins that are fully implemented using the new backend system. This fixes the `Key for the ES256 algorithm must be one of type KeyObject or CryptoKey. Received an instance of Uint8Array` error.
@@ -37,7 +37,11 @@ export const todoListPermissions = [todoListCreatePermission];
For this tutorial, we've automatically exported all permissions from this file (see `plugins/todo-list-common/src/index.ts`).
> Note: We use a separate `todo-list-common` package since all permissions authorized by your plugin should be exported from a ["common-library" package](https://backstage.io/docs/local-dev/cli-build-system#package-roles). This allows Backstage integrators to reference them in frontend components as well as permission policies.
:::note Note
We use a separate `todo-list-common` package since all permissions authorized by your plugin should be exported from a ["common-library" package](https://backstage.io/docs/local-dev/cli-build-system#package-roles). This allows Backstage integrators to reference them in frontend components as well as permission policies.
:::
## Authorizing using the new permission
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,13 @@
---
title: Digital.ai Deploy
author: digital.ai
authorUrl: https://digital.ai/
category: CI/CD
description: The plugin offers integration with Digital.ai Deploy and backstage components and services. It provide access to deployments and reports.
documentation: https://docs.digital.ai/bundle/devops-deploy-version-v.24.1/page/deploy/concept/xl-deploy-backstage-overview.html
iconUrl: /img/digital.ai-deploy.svg
npmPackageName: '@digital.ai/plugin-dai-deploy'
tags:
- ci
- cd
addedDate: '2024-05-06'
@@ -0,0 +1,7 @@
<svg width="56" height="56" viewBox="0 0 56 56" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M28 44C36.8366 44 44 36.8366 44 28C44 19.1634 36.8366 12 28 12C19.1634 12 12 19.1634 12 28C12 36.8366 19.1634 44 28 44Z" fill="#279FEA"/>
<path d="M32.3734 26.5333L28.3268 24.1667L24.2734 26.5333V31.24L28.3268 33.5733L32.3734 31.24V26.5333Z" fill="white"/>
<path d="M20.8733 28.0001L18.9466 26.3001V34.3335L24.8199 37.6735V35.4068L20.8733 33.0801V28.0001Z" fill="white"/>
<path d="M35.7931 28V33.1667L31.9265 35.4067V37.8734L37.7065 34.3067V26.1934L35.7931 28Z" fill="white"/>
<path d="M28.3131 20.2667L33.4331 23.2267L34.8331 21.78L28.3131 18L21.7598 21.8133L23.1598 23.2667L28.3131 20.2667Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 721 B

+118
View File
@@ -0,0 +1,118 @@
/*
* Copyright 2023 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
coreServices,
createBackendPlugin,
} from '@backstage/backend-plugin-api';
import { mockServices, startTestBackend } from '@backstage/backend-test-utils';
import { EventEmitter } from 'events';
import { Router } from 'express';
import { createLegacyAuthAdapters } from './auth';
import { legacyPlugin } from './legacy';
import {
authServiceFactory,
tokenManagerServiceFactory,
} from '@backstage/backend-app-api';
describe('legacyPlugin', () => {
it('can auth across the new and old systems', async () => {
const emitter = new EventEmitter();
const done = new Promise(resolve => {
emitter.once('done', () => {
emitter.once('done', resolve);
});
});
await startTestBackend({
features: [
authServiceFactory,
tokenManagerServiceFactory,
mockServices.rootConfig.factory({
data: {
backend: {
auth: {
keys: [
{
secret: 'test',
},
],
},
},
},
}),
createBackendPlugin({
pluginId: 'new',
register(reg) {
reg.registerInit({
deps: {
auth: coreServices.auth,
discovery: coreServices.discovery,
},
async init({ auth }) {
emitter.once('legacy-token', async otherToken => {
const credentials = await auth.authenticate(otherToken);
expect(credentials.principal).toEqual({
type: 'service',
subject: 'external:backstage-plugin',
});
emitter.emit('done');
});
const { token } = await auth.getPluginRequestToken({
onBehalfOf: await auth.getOwnServiceCredentials(),
targetPluginId: 'old',
});
emitter.emit('new-token', token);
},
});
},
}),
legacyPlugin(
'old',
Promise.resolve({
async default({ tokenManager, identity, discovery }) {
const { auth } = createLegacyAuthAdapters({
tokenManager,
identity,
discovery,
auth: undefined as any as typeof coreServices.auth.T,
httpAuth: undefined as any as typeof coreServices.httpAuth.T,
});
emitter.once('new-token', async otherToken => {
const credentials = await auth.authenticate(otherToken);
expect(credentials.principal).toEqual({
type: 'service',
subject: 'external:backstage-plugin',
});
emitter.emit('done');
});
const { token } = await tokenManager.getToken();
emitter.emit('legacy-token', token);
return Router();
},
}),
),
],
});
await done;
});
});
+36 -2
View File
@@ -15,6 +15,7 @@
*/
import {
AuthService,
coreServices,
createBackendPlugin,
ServiceRef,
@@ -22,6 +23,7 @@ import {
import { RequestHandler } from 'express';
import { cacheToPluginCacheManager } from './cache';
import { loggerToWinstonLogger } from './logging';
import { TokenManager } from './tokens';
/**
* @public
@@ -38,6 +40,31 @@ type TransformedEnv<
: TEnv[key];
};
// Since the plugin will be using the new system our callers will expect us to support the
// new plugin tokens, which we'll also be signaling by supporting the JWKS endpoint through
// the http router.
// This makes sure that we accept the new plugin tokens as valid tokens, but otherwise fall
// back to whatever the token manager is doing.
function wrapTokenManager(tokenManager: TokenManager, auth: AuthService) {
return {
async getToken() {
return tokenManager.getToken();
},
async authenticate(token) {
if (token) {
// Unless it's a valid service token, we'll let the token manager do
// validation. We'll throw if we for example receive an invalid user
// token here, but that's what the token manager does too.
const credentials = await auth.authenticate(token);
if (auth.isPrincipal(credentials, 'service')) {
return;
}
}
await tokenManager.authenticate(token);
},
} satisfies TokenManager;
}
/**
* Creates a new custom plugin compatibility wrapper.
*
@@ -64,8 +91,12 @@ export function makeLegacyPlugin<
pluginId: name,
register(env) {
env.registerInit({
deps: { ...envMapping, _router: coreServices.httpRouter },
async init({ _router, ...envDeps }) {
deps: {
...envMapping,
_router: coreServices.httpRouter,
_auth: coreServices.auth,
},
async init({ _router, _auth, ...envDeps }) {
const { default: createRouter } = await createRouterImport;
const pluginEnv = Object.fromEntries(
Object.entries(envDeps).map(([key, dep]) => {
@@ -73,6 +104,9 @@ export function makeLegacyPlugin<
if (transform) {
return [key, transform(dep)];
}
if (key === 'tokenManager') {
return [key, wrapTokenManager(dep as TokenManager, _auth)];
}
return [key, dep];
}),
);
@@ -309,10 +309,6 @@ async function moveToDistWorkspace(
await run('yarn', ['pack', '--filename', archivePath], {
cwd: target.dir,
});
// TODO(Rugvip): yarn pack doesn't call postpack, once the bug is fixed this can be removed
if (target.packageJson?.scripts?.postpack) {
await run('yarn', ['postpack'], { cwd: target.dir });
}
const outputDir = relativePath(paths.targetRoot, target.dir);
const absoluteOutputPath = resolvePath(workspaceDir, outputDir);
@@ -345,6 +345,7 @@ export class ElasticSearchSearchEngine implements SearchEngine {
attempts++;
}
done();
});
if (cleanupError) {
+6 -6
View File
@@ -17075,9 +17075,9 @@ __metadata:
linkType: hard
"@types/diff@npm:^5.0.0":
version: 5.2.0
resolution: "@types/diff@npm:5.2.0"
checksum: 07e20ba25d15b997758cc248628bb1e6459e7b396c868f176dee1e6a5d1dfcdf1e186fb5bf5e67128d7f55a11e989cff2ec656de089e15ed4a44e654c5c1fda3
version: 5.2.1
resolution: "@types/diff@npm:5.2.1"
checksum: 5983a323177bd691cb2194f5d55b960cd20a9c8fec653b4b038760c5809627cc9ea3578fdf10119ccbefefef193ea925f2817136eb97b17388f66b16c8480a8a
languageName: node
linkType: hard
@@ -17444,11 +17444,11 @@ __metadata:
linkType: hard
"@types/jquery@npm:^3.3.34":
version: 3.5.29
resolution: "@types/jquery@npm:3.5.29"
version: 3.5.30
resolution: "@types/jquery@npm:3.5.30"
dependencies:
"@types/sizzle": "*"
checksum: 5e959762d6f7050b07b4387b6507a308113384566a77cfc4f8d0f54c2fb0a79f6bc8c057706c6aa4840cde56f32ad0e5814fb53c5f078c5db9e01670a1ecd535
checksum: 4594d10fa9b347062883d254a23c9259ae814ef5989ce1985f093dcc7ad4475e324ac3343aef10599c478ea4951726f0e7f79d8ed471ab04de394b7e724d6d13
languageName: node
linkType: hard