Merge branch 'master' into camilaibs/nbs10-deprecate-legacy-system-commons

Signed-off-by: Camila Belo <camilaibs@gmail.com>
This commit is contained in:
Camila Belo
2024-05-21 15:12:02 +02:00
committed by GitHub
238 changed files with 7330 additions and 1383 deletions
+14 -14
View File
@@ -65,7 +65,7 @@ export interface Backend {
stop(): Promise<void>;
}
// @public (undocumented)
// @public @deprecated (undocumented)
export const cacheServiceFactory: () => ServiceFactory<CacheClient, 'plugin'>;
// @public (undocumented)
@@ -100,7 +100,7 @@ export interface CreateSpecializedBackendOptions {
defaultServiceFactories: ServiceFactoryOrFunction[];
}
// @public (undocumented)
// @public @deprecated (undocumented)
export const databaseServiceFactory: () => ServiceFactory<
PluginDatabaseManager,
'plugin'
@@ -121,7 +121,7 @@ export interface DefaultRootHttpRouterOptions {
indexPath?: string | false;
}
// @public (undocumented)
// @public @deprecated (undocumented)
export const discoveryServiceFactory: () => ServiceFactory<
DiscoveryService,
'plugin'
@@ -137,7 +137,7 @@ export interface ExtendedHttpServer extends http.Server {
stop(): Promise<void>;
}
// @public
// @public @deprecated
export class HostDiscovery implements DiscoveryService {
static fromConfig(
config: Config,
@@ -190,13 +190,13 @@ export type HttpServerOptions = {
};
};
// @public
// @public @deprecated
export type IdentityFactoryOptions = {
issuer?: string;
algorithms?: string[];
};
// @public (undocumented)
// @public @deprecated (undocumented)
export const identityServiceFactory: (
options?: IdentityFactoryOptions | undefined,
) => ServiceFactory<IdentityService, 'plugin'>;
@@ -208,7 +208,7 @@ export interface LifecycleMiddlewareOptions {
startupRequestPauseTimeout?: HumanDuration;
}
// @public
// @public @deprecated
export const lifecycleServiceFactory: () => ServiceFactory<
LifecycleService,
'plugin'
@@ -255,7 +255,7 @@ export interface MiddlewareFactoryOptions {
logger: LoggerService;
}
// @public (undocumented)
// @public @deprecated (undocumented)
export const permissionsServiceFactory: () => ServiceFactory<
PermissionsService,
'plugin'
@@ -270,7 +270,7 @@ export function readHelmetOptions(config?: Config): HelmetOptions;
// @public
export function readHttpServerOptions(config?: Config): HttpServerOptions;
// @public (undocumented)
// @public @deprecated (undocumented)
export interface RootConfigFactoryOptions {
argv?: string[];
remote?: Pick<RemoteConfigSourceOptions, 'reloadInterval'>;
@@ -278,7 +278,7 @@ export interface RootConfigFactoryOptions {
watch?: boolean;
}
// @public (undocumented)
// @public @deprecated (undocumented)
export const rootConfigServiceFactory: (
options?: RootConfigFactoryOptions | undefined,
) => ServiceFactory<RootConfigService, 'root'>;
@@ -314,7 +314,7 @@ export const rootHttpRouterServiceFactory: (
options?: RootHttpRouterFactoryOptions | undefined,
) => ServiceFactory<RootHttpRouterService, 'root'>;
// @public
// @public @deprecated
export const rootLifecycleServiceFactory: () => ServiceFactory<
RootLifecycleService,
'root'
@@ -326,19 +326,19 @@ export const rootLoggerServiceFactory: () => ServiceFactory<
'root'
>;
// @public (undocumented)
// @public @deprecated (undocumented)
export const schedulerServiceFactory: () => ServiceFactory<
SchedulerService,
'plugin'
>;
// @public (undocumented)
// @public @deprecated (undocumented)
export const tokenManagerServiceFactory: () => ServiceFactory<
TokenManagerService,
'plugin'
>;
// @public (undocumented)
// @public @deprecated (undocumented)
export const urlReaderServiceFactory: () => ServiceFactory<UrlReader, 'plugin'>;
// @public (undocumented)
+1
View File
@@ -83,6 +83,7 @@
"path-to-regexp": "^6.2.1",
"selfsigned": "^2.0.0",
"stoppable": "^1.1.0",
"triple-beam": "^1.4.1",
"uuid": "^9.0.0",
"winston": "^3.2.1",
"winston-transport": "^4.5.0"
@@ -14,12 +14,10 @@
* limitations under the License.
*/
import { TransformableInfo } from 'logform';
import { format } from 'logform';
import { WinstonLogger } from './WinstonLogger';
function msg(info: TransformableInfo): TransformableInfo {
return { message: info.message, level: info.level, stack: info.stack };
}
import Transport from 'winston-transport';
import { MESSAGE } from 'triple-beam';
describe('WinstonLogger', () => {
it('creates a winston logger instance with default options', () => {
@@ -33,57 +31,66 @@ describe('WinstonLogger', () => {
expect(childLogger).toBeInstanceOf(WinstonLogger);
});
it('redacter should redact and escape regex', () => {
const redacter = WinstonLogger.redacter();
const log = {
level: 'error',
message: 'hello (world)',
stack: 'hello (world) from this file',
};
expect(redacter.format.transform(msg(log))).toEqual(msg(log));
redacter.add(['hello\n']);
expect(redacter.format.transform(msg(log))).toEqual(
msg({
...log,
message: '[REDACTED] (world)',
stack: '[REDACTED] (world) from this file',
}),
);
redacter.add(['(world']);
expect(redacter.format.transform(msg(log))).toEqual(
msg({
...log,
message: '[REDACTED] [REDACTED])',
stack: '[REDACTED] [REDACTED]) from this file',
it('should redact and escape regex', () => {
const mockTransport = new Transport({
log: jest.fn(),
logv: jest.fn(),
});
const logger = WinstonLogger.create({
format: format.json(),
transports: [mockTransport],
});
logger.addRedactions(['hello (world']);
logger.error('hello (world) from this file');
expect(mockTransport.log).toHaveBeenCalledWith(
expect.objectContaining({
[MESSAGE]: JSON.stringify({
level: 'error',
message: '***) from this file',
}),
}),
expect.any(Function),
);
});
it('redacter should redact nested object', () => {
const redacter = WinstonLogger.redacter();
const log = {
level: 'error',
message: {
nested: 'hello (world) from nested object',
null: null,
nullProto: Object.create(null, {
foo: { value: 'hello foo', enumerable: true },
}),
},
};
it('should redact nested object', () => {
const mockTransport = new Transport({
log: jest.fn(),
logv: jest.fn(),
});
redacter.add(['hello']);
expect(redacter.format.transform(msg(log))).toEqual(
msg({
...log,
message: {
nested: '[REDACTED] (world) from nested object',
const logger = WinstonLogger.create({
format: format.json(),
transports: [mockTransport],
});
logger.addRedactions(['hello']);
logger.error('something went wrong', {
null: null,
nested: 'hello (world) from nested object',
nullProto: Object.create(null, {
foo: { value: 'hello foo', enumerable: true },
}),
});
expect(mockTransport.log).toHaveBeenCalledWith(
expect.objectContaining({
[MESSAGE]: JSON.stringify({
level: 'error',
message: 'something went wrong',
nested: '*** (world) from nested object',
null: null,
nullProto: {
foo: 'hello foo', // read only prop is not redacted
foo: '*** foo',
},
},
}),
}),
expect.any(Function),
);
});
});
@@ -27,6 +27,7 @@ import {
transports,
transport as Transport,
} from 'winston';
import { MESSAGE } from 'triple-beam';
import { escapeRegExp } from '../lib/escapeRegExp';
/**
@@ -61,8 +62,8 @@ export class WinstonLogger implements RootLoggerService {
let logger = createLogger({
level: process.env.LOG_LEVEL || options.level || 'info',
format: format.combine(
redacter.format,
options.format ?? defaultFormatter,
redacter.format,
),
transports: options.transports ?? new transports.Console(),
});
@@ -85,24 +86,16 @@ export class WinstonLogger implements RootLoggerService {
let redactionPattern: RegExp | undefined = undefined;
const replace = (obj: TransformableInfo) => {
for (const key in obj) {
if (Object.hasOwn(obj, key)) {
if (typeof obj[key] === 'object') {
obj[key] = replace(obj[key] as TransformableInfo);
} else if (typeof obj[key] === 'string') {
try {
obj[key] = obj[key]?.replace(redactionPattern, '[REDACTED]');
} catch {
/* ignore read only properties */
}
}
}
}
return obj;
};
return {
format: format(replace)(),
format: format((obj: TransformableInfo) => {
if (!redactionPattern || !obj) {
return obj;
}
obj[MESSAGE] = obj[MESSAGE]?.replace?.(redactionPattern, '***');
return obj;
})(),
add(newRedactions) {
let added = 0;
for (const redactionToTrim of newRedactions) {
@@ -20,7 +20,10 @@ import {
createServiceFactory,
} from '@backstage/backend-plugin-api';
/** @public */
/**
* @public
* @deprecated Please import from `@backstage/backend-defaults/cache` instead.
*/
export const cacheServiceFactory = createServiceFactory({
service: coreServices.cache,
deps: {
@@ -23,7 +23,10 @@ import {
RemoteConfigSourceOptions,
} from '@backstage/config-loader';
/** @public */
/**
* @public
* @deprecated Please import from `@backstage/backend-defaults/rootConfig` instead.
*/
export interface RootConfigFactoryOptions {
/**
* Process arguments to use instead of the default `process.argv()`.
@@ -37,7 +40,10 @@ export interface RootConfigFactoryOptions {
watch?: boolean;
}
/** @public */
/**
* @public
* @deprecated Please import from `@backstage/backend-defaults/rootConfig` instead.
*/
export const rootConfigServiceFactory = createServiceFactory(
(options?: RootConfigFactoryOptions) => ({
service: coreServices.rootConfig,
@@ -21,7 +21,10 @@ import {
} from '@backstage/backend-plugin-api';
import { ConfigReader } from '@backstage/config';
/** @public */
/**
* @public
* @deprecated Please import from `@backstage/backend-defaults/database` instead.
*/
export const databaseServiceFactory = createServiceFactory({
service: coreServices.database,
deps: {
@@ -0,0 +1,17 @@
/*
* Copyright 2024 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.
*/
export * from './scheduler';
@@ -29,6 +29,7 @@ type Target = string | { internal: string; external: string };
* resolved to the same host, so there won't be any balancing of internal traffic.
*
* @public
* @deprecated Please import from `@backstage/backend-defaults/discovery` instead.
*/
export class HostDiscovery implements DiscoveryService {
/**
@@ -20,7 +20,10 @@ import {
} from '@backstage/backend-plugin-api';
import { HostDiscovery } from './HostDiscovery';
/** @public */
/**
* @public
* @deprecated Please import from `@backstage/backend-defaults/discovery` instead.
*/
export const discoveryServiceFactory = createServiceFactory({
service: coreServices.discovery,
deps: {
@@ -24,16 +24,22 @@ import { DefaultIdentityClient } from '@backstage/plugin-auth-node';
* An identity client options object which allows extra configurations
*
* @public
* @deprecated Please migrate to the new `coreServices.auth`, `coreServices.httpAuth`, and `coreServices.userInfo` services as needed instead
*/
export type IdentityFactoryOptions = {
issuer?: string;
/** JWS "alg" (Algorithm) Header Parameter values. Defaults to an array containing just ES256.
* More info on supported algorithms: https://github.com/panva/jose */
/**
* JWS "alg" (Algorithm) Header Parameter values. Defaults to an array containing just ES256.
* More info on supported algorithms: https://github.com/panva/jose
*/
algorithms?: string[];
};
/** @public */
/**
* @public
* @deprecated Please migrate to the new `coreServices.auth`, `coreServices.httpAuth`, and `coreServices.userInfo` services as needed instead
*/
export const identityServiceFactory = createServiceFactory(
(options?: IdentityFactoryOptions) => ({
service: coreServices.identity,
@@ -28,7 +28,8 @@ export * from './permissions';
export * from './rootHttpRouter';
export * from './rootLifecycle';
export * from './rootLogger';
export * from './scheduler';
export * from './tokenManager';
export * from './urlReader';
export * from './userInfo';
export * from './deprecated';
@@ -26,7 +26,10 @@ import {
createServiceFactory,
} from '@backstage/backend-plugin-api';
/** @internal */
/**
* @internal
* @deprecated
*/
export class BackendPluginLifecycleImpl implements LifecycleService {
constructor(
private readonly logger: LoggerService,
@@ -85,7 +88,9 @@ export class BackendPluginLifecycleImpl implements LifecycleService {
/**
* Allows plugins to register shutdown hooks that are run when the process is about to exit.
*
* @public
* @deprecated Please import from `@backstage/backend-defaults/lifecycle` instead.
*/
export const lifecycleServiceFactory = createServiceFactory({
service: coreServices.lifecycle,
@@ -20,7 +20,10 @@ import {
} from '@backstage/backend-plugin-api';
import { ServerPermissionClient } from '@backstage/plugin-permission-node';
/** @public */
/**
* @public
* @deprecated Please import from `@backstage/backend-defaults/permissions` instead.
*/
export const permissionsServiceFactory = createServiceFactory({
service: coreServices.permissions,
deps: {
@@ -25,7 +25,10 @@ import {
LoggerService,
} from '@backstage/backend-plugin-api';
/** @internal */
/**
* @internal
* @deprecated
*/
export class BackendLifecycleImpl implements RootLifecycleService {
constructor(private readonly logger: LoggerService) {}
@@ -108,6 +111,7 @@ export class BackendLifecycleImpl implements RootLifecycleService {
* Allows plugins to register shutdown hooks that are run when the process is about to exit.
*
* @public
* @deprecated Please import from `@backstage/backend-defaults/rootLifecycle` instead.
*/
export const rootLifecycleServiceFactory = createServiceFactory({
service: coreServices.rootLifecycle,
@@ -20,7 +20,10 @@ import {
} from '@backstage/backend-plugin-api';
import { TaskScheduler } from '@backstage/backend-tasks';
/** @public */
/**
* @public
* @deprecated Please import from `@backstage/backend-defaults/scheduler` instead.
*/
export const schedulerServiceFactory = createServiceFactory({
service: coreServices.scheduler,
deps: {
@@ -20,7 +20,10 @@ import {
} from '@backstage/backend-plugin-api';
import { ServerTokenManager } from '@backstage/backend-common';
/** @public */
/**
* @public
* @deprecated Please migrate to the new `coreServices.auth`, `coreServices.httpAuth`, and `coreServices.userInfo` services as needed instead
*/
export const tokenManagerServiceFactory = createServiceFactory({
service: coreServices.tokenManager,
deps: {
@@ -20,7 +20,10 @@ import {
createServiceFactory,
} from '@backstage/backend-plugin-api';
/** @public */
/**
* @public
* @deprecated Please import from `@backstage/backend-defaults/urlReader` instead.
*/
export const urlReaderServiceFactory = createServiceFactory({
service: coreServices.urlReader,
deps: {
@@ -20,9 +20,9 @@ import {
coreServices,
ServiceRef,
ServiceFactory,
LifecycleService,
RootLifecycleService,
} from '@backstage/backend-plugin-api';
import { BackendLifecycleImpl } from '../services/implementations/rootLifecycle/rootLifecycleServiceFactory';
import { BackendPluginLifecycleImpl } from '../services/implementations/lifecycle/lifecycleServiceFactory';
import { ServiceOrExtensionPoint } from './types';
// Direct internal import to avoid duplication
// eslint-disable-next-line @backstage/no-forbidden-package-imports
@@ -345,27 +345,42 @@ export class BackendInitializer {
}
// Bit of a hacky way to grab the lifecycle services, potentially find a nicer way to do this
async #getRootLifecycleImpl(): Promise<BackendLifecycleImpl> {
async #getRootLifecycleImpl(): Promise<
RootLifecycleService & {
startup(): Promise<void>;
shutdown(): Promise<void>;
}
> {
const lifecycleService = await this.#serviceRegistry.get(
coreServices.rootLifecycle,
'root',
);
if (lifecycleService instanceof BackendLifecycleImpl) {
return lifecycleService;
const service = lifecycleService as any;
if (
service &&
typeof service.startup === 'function' &&
typeof service.shutdown === 'function'
) {
return service;
}
throw new Error('Unexpected root lifecycle service implementation');
}
async #getPluginLifecycleImpl(
pluginId: string,
): Promise<BackendPluginLifecycleImpl> {
): Promise<LifecycleService & { startup(): Promise<void> }> {
const lifecycleService = await this.#serviceRegistry.get(
coreServices.lifecycle,
pluginId,
);
if (lifecycleService instanceof BackendPluginLifecycleImpl) {
return lifecycleService;
const service = lifecycleService as any;
if (service && typeof service.startup === 'function') {
return service;
}
throw new Error('Unexpected plugin lifecycle service implementation');
}
}