Merge branch 'master' of https://github.com/backstage/backstage into add-additional-scaffolder-permissions
This commit is contained in:
@@ -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.
|
||||
@@ -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 |
@@ -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;
|
||||
});
|
||||
});
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user