apply requested changes
Signed-off-by: Paul Schultz <pschultz@pobox.com>
This commit is contained in:
@@ -30,10 +30,9 @@ The `auditorServiceFactory` creates an `Auditor` instance for the root context a
|
||||
|
||||
The Auditor Service is designed for recording security-relevant events that require special attention or are subject to compliance regulations. These events often involve actions like:
|
||||
|
||||
- User authentication and authorization
|
||||
- User session management
|
||||
- Data access and modification
|
||||
- System configuration changes
|
||||
- Security policy enforcement
|
||||
|
||||
For general application logging that is not security-critical, you should use the standard `LoggerService` provided by Backstage. This helps to keep your audit logs focused and relevant.
|
||||
|
||||
@@ -63,10 +62,11 @@ export async function createRouter(
|
||||
// ... process the request
|
||||
|
||||
await auditorEvent.success();
|
||||
res.status(200).send('Success!');
|
||||
res.status(200).json({ message: 'Succeeded!' });
|
||||
} catch (error) {
|
||||
await auditorEvent.fail({ error });
|
||||
res.status(500).send('Error!');
|
||||
res.status(500).json({ message: 'Failed!' });
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -102,30 +102,3 @@ backend:
|
||||
```
|
||||
|
||||
By default, console logging is enabled. You can disable it by setting the `enabled` flag to `false`.
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Customizing the Auditor Service Factory
|
||||
|
||||
The `auditorServiceFactoryWithOptions` function allows you to create an auditor service factory with custom transports and formats. This is useful if you need to integrate with a different logging system or modify the default logging behavior.
|
||||
|
||||
Here's an example of how to create a custom auditor service factory:
|
||||
|
||||
```typescript
|
||||
import { auditorServiceFactoryWithOptions } from '@backstage/backend-defaults/auditor';
|
||||
import winston from 'winston';
|
||||
|
||||
const myAuditorServiceFactory = auditorServiceFactoryWithOptions({
|
||||
transports: () => {
|
||||
return [new winston.transports.File({ filename: 'my-audit.log' })];
|
||||
},
|
||||
format: () => {
|
||||
return winston.format.combine(
|
||||
winston.format.timestamp(),
|
||||
winston.format.json(),
|
||||
);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
This example creates a factory that logs to a file named `my-audit.log` and uses a JSON format for the log messages. You can then use this factory in your plugin to create an auditor service with the desired configuration.
|
||||
|
||||
@@ -18,66 +18,24 @@ import { mockServices } from '@backstage/backend-test-utils';
|
||||
import { format } from 'logform';
|
||||
import { MESSAGE } from 'triple-beam';
|
||||
import Transport from 'winston-transport';
|
||||
import { Auditor } from './Auditor';
|
||||
import { DefaultAuditorService, DefaultRootAuditorService } from './Auditor';
|
||||
|
||||
describe('Auditor', () => {
|
||||
it('creates a auditor instance with default options', () => {
|
||||
const auditor = Auditor.create();
|
||||
expect(auditor).toBeInstanceOf(Auditor);
|
||||
const auditor = DefaultRootAuditorService.create();
|
||||
expect(auditor).toBeInstanceOf(DefaultRootAuditorService);
|
||||
});
|
||||
|
||||
it('creates a child logger', () => {
|
||||
const auditor = Auditor.create();
|
||||
const childLogger = auditor.child({ plugin: 'test-plugin' });
|
||||
expect(childLogger).toBeInstanceOf(Auditor);
|
||||
});
|
||||
|
||||
it('should error without plugin service', async () => {
|
||||
const auditor = Auditor.create();
|
||||
await expect(
|
||||
auditor.createEvent({
|
||||
eventId: 'test-event',
|
||||
}),
|
||||
).rejects.toThrow(
|
||||
`The core service 'plugin' was not provided during the auditor's instantiation`,
|
||||
);
|
||||
});
|
||||
|
||||
it('should error without auth service', async () => {
|
||||
const pluginId = 'test-plugin';
|
||||
|
||||
const auditor = Auditor.create({
|
||||
plugin: {
|
||||
getId: () => pluginId,
|
||||
},
|
||||
});
|
||||
|
||||
await expect(
|
||||
auditor.createEvent({
|
||||
eventId: 'test-event',
|
||||
}),
|
||||
).rejects.toThrow(
|
||||
`The core service 'auth' was not provided during the auditor's instantiation`,
|
||||
);
|
||||
});
|
||||
|
||||
it('should error without httpAuth service', async () => {
|
||||
const pluginId = 'test-plugin';
|
||||
|
||||
const auditor = Auditor.create({
|
||||
plugin: {
|
||||
getId: () => pluginId,
|
||||
},
|
||||
const auditor = DefaultRootAuditorService.create();
|
||||
const childLogger = auditor.forPlugin({
|
||||
auth: mockServices.auth.mock(),
|
||||
httpAuth: mockServices.httpAuth.mock(),
|
||||
plugin: {
|
||||
getId: () => 'test-plugin',
|
||||
},
|
||||
});
|
||||
|
||||
await expect(
|
||||
auditor.createEvent({
|
||||
eventId: 'test-event',
|
||||
}),
|
||||
).rejects.toThrow(
|
||||
`The core service 'httpAuth' was not provided during the auditor's instantiation`,
|
||||
);
|
||||
expect(childLogger).toBeInstanceOf(DefaultAuditorService);
|
||||
});
|
||||
|
||||
it('should log', async () => {
|
||||
@@ -88,14 +46,15 @@ describe('Auditor', () => {
|
||||
|
||||
const pluginId = 'test-plugin';
|
||||
|
||||
const auditor = Auditor.create({
|
||||
const auditor = DefaultRootAuditorService.create({
|
||||
format: format.json(),
|
||||
transports: [mockTransport],
|
||||
}).forPlugin({
|
||||
auth: mockServices.auth.mock(),
|
||||
httpAuth: mockServices.httpAuth.mock(),
|
||||
plugin: {
|
||||
getId: () => pluginId,
|
||||
},
|
||||
format: format.json(),
|
||||
transports: [mockTransport],
|
||||
});
|
||||
|
||||
await auditor.createEvent({
|
||||
@@ -117,63 +76,10 @@ describe('Auditor', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should redact nested object', async () => {
|
||||
const mockTransport = new Transport({
|
||||
log: jest.fn(),
|
||||
logv: jest.fn(),
|
||||
});
|
||||
|
||||
const pluginId = 'test-plugin';
|
||||
|
||||
const auditor = Auditor.create({
|
||||
auth: mockServices.auth.mock(),
|
||||
httpAuth: mockServices.httpAuth.mock(),
|
||||
plugin: {
|
||||
getId: () => pluginId,
|
||||
},
|
||||
format: format.json(),
|
||||
transports: [mockTransport],
|
||||
});
|
||||
|
||||
auditor.addRedactions(['hello']);
|
||||
|
||||
await auditor.createEvent({
|
||||
eventId: 'test-event',
|
||||
meta: {
|
||||
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({
|
||||
actor: {},
|
||||
isAuditorEvent: true,
|
||||
level: 'info',
|
||||
message: 'test-plugin.test-event',
|
||||
meta: {
|
||||
nested: '*** (world) from nested object',
|
||||
null: null,
|
||||
nullProto: {
|
||||
foo: '*** foo',
|
||||
},
|
||||
},
|
||||
severityLevel: 'low',
|
||||
status: 'initiated',
|
||||
}),
|
||||
}),
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
|
||||
it('should log a status "initiated" using createEvent', async () => {
|
||||
const pluginId = 'test-plugin';
|
||||
|
||||
const auditor = Auditor.create({
|
||||
const auditor = DefaultRootAuditorService.create().forPlugin({
|
||||
auth: mockServices.auth.mock(),
|
||||
httpAuth: mockServices.httpAuth.mock(),
|
||||
plugin: {
|
||||
@@ -196,7 +102,7 @@ describe('Auditor', () => {
|
||||
it('should log a status "succeeded" using createEvent', async () => {
|
||||
const pluginId = 'test-plugin';
|
||||
|
||||
const auditor = Auditor.create({
|
||||
const auditor = DefaultRootAuditorService.create().forPlugin({
|
||||
auth: mockServices.auth.mock(),
|
||||
httpAuth: mockServices.httpAuth.mock(),
|
||||
plugin: {
|
||||
@@ -222,7 +128,7 @@ describe('Auditor', () => {
|
||||
it('should log a status "failed"', async () => {
|
||||
const pluginId = 'test-plugin';
|
||||
|
||||
const auditor = Auditor.create({
|
||||
const auditor = DefaultRootAuditorService.create().forPlugin({
|
||||
auth: mockServices.auth.mock(),
|
||||
httpAuth: mockServices.httpAuth.mock(),
|
||||
plugin: {
|
||||
@@ -250,7 +156,7 @@ describe('Auditor', () => {
|
||||
it('should use root meta', async () => {
|
||||
const pluginId = 'test-plugin';
|
||||
|
||||
const auditor = Auditor.create({
|
||||
const auditor = DefaultRootAuditorService.create().forPlugin({
|
||||
auth: mockServices.auth.mock(),
|
||||
httpAuth: mockServices.httpAuth.mock(),
|
||||
plugin: {
|
||||
|
||||
@@ -23,14 +23,13 @@ import type {
|
||||
HttpAuthService,
|
||||
PluginMetadataService,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { ForwardedError, ServiceUnavailableError } from '@backstage/errors';
|
||||
import { ForwardedError } from '@backstage/errors';
|
||||
import type { JsonObject } from '@backstage/types';
|
||||
import type { Request } from 'express';
|
||||
import type { Format } from 'logform';
|
||||
import * as winston from 'winston';
|
||||
import { colorFormat } from '../../lib/colorFormat';
|
||||
import { defaultConsoleTransport } from '../../lib/defaultConsoleTransport';
|
||||
import { redacterFormat } from '../../lib/redacterFormat';
|
||||
|
||||
/** @public */
|
||||
export type AuditorEventActorDetails = {
|
||||
@@ -99,7 +98,6 @@ export const defaultProdFormat = winston.format.combine(
|
||||
winston.format.errors({ stack: true }),
|
||||
winston.format.splat(),
|
||||
winston.format.json(),
|
||||
redacterFormat().format,
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -112,10 +110,7 @@ export const auditorFieldFormat = winston.format(info => {
|
||||
})();
|
||||
|
||||
/** @public */
|
||||
export interface AuditorOptions {
|
||||
auth?: AuthService;
|
||||
httpAuth?: HttpAuthService;
|
||||
plugin?: PluginMetadataService;
|
||||
export interface RootAuditorOptions {
|
||||
meta?: JsonObject;
|
||||
format?: Format;
|
||||
transports?: winston.transport[];
|
||||
@@ -126,85 +121,45 @@ export interface AuditorOptions {
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class Auditor implements AuditorService {
|
||||
readonly #winstonLogger: winston.Logger;
|
||||
readonly #auth?: AuthService;
|
||||
readonly #httpAuth?: HttpAuthService;
|
||||
readonly #plugin?: PluginMetadataService;
|
||||
readonly #addRedactions?: (redactions: Iterable<string>) => void;
|
||||
|
||||
/**
|
||||
* Creates a {@link Auditor} instance.
|
||||
*/
|
||||
static create(options?: AuditorOptions): Auditor {
|
||||
const redacter = Auditor.redacter();
|
||||
const defaultFormatter =
|
||||
process.env.NODE_ENV === 'production'
|
||||
? defaultProdFormat
|
||||
: Auditor.colorFormat();
|
||||
|
||||
let auditor = winston.createLogger({
|
||||
level: 'info',
|
||||
format: winston.format.combine(
|
||||
auditorFieldFormat,
|
||||
options?.format ?? defaultFormatter,
|
||||
redacter.format,
|
||||
),
|
||||
transports: options?.transports ?? defaultConsoleTransport,
|
||||
});
|
||||
|
||||
if (options?.meta) {
|
||||
auditor = auditor.child(options.meta);
|
||||
}
|
||||
return new Auditor(
|
||||
auditor,
|
||||
{
|
||||
auth: options?.auth,
|
||||
httpAuth: options?.httpAuth,
|
||||
plugin: options?.plugin,
|
||||
},
|
||||
redacter.add,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a winston log formatter for redacting secrets.
|
||||
*/
|
||||
static redacter(): {
|
||||
format: Format;
|
||||
add: (redactions: Iterable<string>) => void;
|
||||
} {
|
||||
return redacterFormat();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a pretty printed winston log formatter.
|
||||
*/
|
||||
static colorFormat(): Format {
|
||||
return colorFormat();
|
||||
}
|
||||
export class DefaultAuditorService implements AuditorService {
|
||||
private readonly impl: DefaultRootAuditorService;
|
||||
private readonly auth: AuthService;
|
||||
private readonly httpAuth: HttpAuthService;
|
||||
private readonly plugin: PluginMetadataService;
|
||||
|
||||
private constructor(
|
||||
winstonLogger: winston.Logger,
|
||||
deps?: {
|
||||
auth?: AuthService;
|
||||
httpAuth?: HttpAuthService;
|
||||
plugin?: PluginMetadataService;
|
||||
impl: DefaultRootAuditorService,
|
||||
deps: {
|
||||
auth: AuthService;
|
||||
httpAuth: HttpAuthService;
|
||||
plugin: PluginMetadataService;
|
||||
},
|
||||
addRedactions?: (redactions: Iterable<string>) => void,
|
||||
) {
|
||||
this.#winstonLogger = winstonLogger;
|
||||
this.#auth = deps?.auth;
|
||||
this.#httpAuth = deps?.httpAuth;
|
||||
this.#plugin = deps?.plugin;
|
||||
this.#addRedactions = addRedactions;
|
||||
this.impl = impl;
|
||||
this.auth = deps.auth;
|
||||
this.httpAuth = deps.httpAuth;
|
||||
this.plugin = deps.plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link DefaultAuditorService} instance.
|
||||
*/
|
||||
static create(
|
||||
impl: DefaultRootAuditorService,
|
||||
deps: {
|
||||
auth: AuthService;
|
||||
httpAuth: HttpAuthService;
|
||||
plugin: PluginMetadataService;
|
||||
},
|
||||
): DefaultAuditorService {
|
||||
return new DefaultAuditorService(impl, deps);
|
||||
}
|
||||
|
||||
private async log<TMeta extends JsonObject>(
|
||||
options: AuditorEventOptions<TMeta>,
|
||||
): Promise<void> {
|
||||
const auditEvent = await this.reshapeAuditorEvent(options);
|
||||
this.#winstonLogger.info(...auditEvent);
|
||||
this.impl.log(auditEvent);
|
||||
}
|
||||
|
||||
async createEvent<TMeta extends JsonObject>(
|
||||
@@ -247,56 +202,25 @@ export class Auditor implements AuditorService {
|
||||
};
|
||||
}
|
||||
|
||||
child(
|
||||
meta: JsonObject,
|
||||
deps?: {
|
||||
auth?: AuthService;
|
||||
httpAuth?: HttpAuthService;
|
||||
plugin?: PluginMetadataService;
|
||||
},
|
||||
): AuditorService {
|
||||
return new Auditor(this.#winstonLogger.child(meta), {
|
||||
auth: deps?.auth ?? this.#auth,
|
||||
httpAuth: deps?.httpAuth ?? this.#httpAuth,
|
||||
plugin: deps?.plugin ?? this.#plugin,
|
||||
});
|
||||
}
|
||||
|
||||
addRedactions(redactions: Iterable<string>) {
|
||||
this.#addRedactions?.(redactions);
|
||||
}
|
||||
|
||||
private async getActorId(
|
||||
request?: Request<any, any, any, any, any>,
|
||||
): Promise<string | undefined> {
|
||||
if (!this.#auth) {
|
||||
throw new ServiceUnavailableError(
|
||||
`The core service 'auth' was not provided during the auditor's instantiation`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!this.#httpAuth) {
|
||||
throw new ServiceUnavailableError(
|
||||
`The core service 'httpAuth' was not provided during the auditor's instantiation`,
|
||||
);
|
||||
}
|
||||
|
||||
let credentials: BackstageCredentials =
|
||||
await this.#auth.getOwnServiceCredentials();
|
||||
await this.auth.getOwnServiceCredentials();
|
||||
|
||||
if (request) {
|
||||
try {
|
||||
credentials = await this.#httpAuth.credentials(request);
|
||||
credentials = await this.httpAuth.credentials(request);
|
||||
} catch (error) {
|
||||
throw new ForwardedError('Could not resolve credentials', error);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.#auth.isPrincipal(credentials, 'user')) {
|
||||
if (this.auth.isPrincipal(credentials, 'user')) {
|
||||
return credentials.principal.userEntityRef;
|
||||
}
|
||||
|
||||
if (this.#auth.isPrincipal(credentials, 'service')) {
|
||||
if (this.auth.isPrincipal(credentials, 'service')) {
|
||||
return credentials.principal.subject;
|
||||
}
|
||||
|
||||
@@ -308,14 +232,8 @@ export class Auditor implements AuditorService {
|
||||
): Promise<AuditorEvent> {
|
||||
const { eventId, severityLevel = 'low', request, ...rest } = options;
|
||||
|
||||
if (!this.#plugin) {
|
||||
throw new ServiceUnavailableError(
|
||||
`The core service 'plugin' was not provided during the auditor's instantiation`,
|
||||
);
|
||||
}
|
||||
|
||||
const auditEvent: AuditorEvent = [
|
||||
`${this.#plugin.getId()}.${eventId}`,
|
||||
`${this.plugin.getId()}.${eventId}`,
|
||||
{
|
||||
severityLevel,
|
||||
actor: {
|
||||
@@ -337,3 +255,56 @@ export class Auditor implements AuditorService {
|
||||
return auditEvent;
|
||||
}
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export class DefaultRootAuditorService {
|
||||
private readonly impl: winston.Logger;
|
||||
|
||||
private constructor(impl: winston.Logger) {
|
||||
this.impl = impl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link DefaultRootAuditorService} instance.
|
||||
*/
|
||||
static create(options?: RootAuditorOptions): DefaultRootAuditorService {
|
||||
const defaultFormatter =
|
||||
process.env.NODE_ENV === 'production'
|
||||
? defaultProdFormat
|
||||
: DefaultRootAuditorService.colorFormat();
|
||||
|
||||
let auditor = winston.createLogger({
|
||||
level: 'info',
|
||||
format: winston.format.combine(
|
||||
auditorFieldFormat,
|
||||
options?.format ?? defaultFormatter,
|
||||
),
|
||||
transports: options?.transports ?? defaultConsoleTransport,
|
||||
});
|
||||
|
||||
if (options?.meta) {
|
||||
auditor = auditor.child(options.meta);
|
||||
}
|
||||
return new DefaultRootAuditorService(auditor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a pretty printed winston log formatter.
|
||||
*/
|
||||
static colorFormat(): Format {
|
||||
return colorFormat();
|
||||
}
|
||||
|
||||
async log(auditEvent: AuditorEvent): Promise<void> {
|
||||
this.impl.info(...auditEvent);
|
||||
}
|
||||
|
||||
forPlugin(deps: {
|
||||
auth: AuthService;
|
||||
httpAuth: HttpAuthService;
|
||||
plugin: PluginMetadataService;
|
||||
}): AuditorService {
|
||||
const impl = new DefaultRootAuditorService(this.impl.child({}));
|
||||
return DefaultAuditorService.create(impl, deps);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,11 @@ import {
|
||||
import type { Config } from '@backstage/config';
|
||||
import * as winston from 'winston';
|
||||
import { defaultConsoleTransport } from '../../lib/defaultConsoleTransport';
|
||||
import { Auditor, auditorFieldFormat, defaultProdFormat } from './Auditor';
|
||||
import {
|
||||
DefaultRootAuditorService,
|
||||
auditorFieldFormat,
|
||||
defaultProdFormat,
|
||||
} from './Auditor';
|
||||
|
||||
const transports = {
|
||||
auditorConsole: (config?: Config) => {
|
||||
@@ -32,20 +36,6 @@ const transports = {
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Access to static configuration.
|
||||
*
|
||||
* See {@link @backstage/code-plugin-api#AuditorService}
|
||||
* and {@link https://backstage.io/docs/backend-system/core-services/auditor | the service docs}
|
||||
* for more information.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface AuditorFactoryOptions {
|
||||
transports: (config?: Config) => winston.transport[];
|
||||
format: (config?: Config) => winston.Logform.Format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin-level auditing.
|
||||
*
|
||||
@@ -55,52 +45,33 @@ export interface AuditorFactoryOptions {
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const auditorServiceFactoryWithOptions = (
|
||||
options?: AuditorFactoryOptions,
|
||||
) =>
|
||||
createServiceFactory({
|
||||
service: coreServices.auditor,
|
||||
deps: {
|
||||
config: coreServices.rootConfig,
|
||||
auth: coreServices.auth,
|
||||
httpAuth: coreServices.httpAuth,
|
||||
plugin: coreServices.pluginMetadata,
|
||||
},
|
||||
async createRootContext({ config }) {
|
||||
const auditorConfig = config.getOptionalConfig('backend.auditor');
|
||||
export const auditorServiceFactory = createServiceFactory({
|
||||
service: coreServices.auditor,
|
||||
deps: {
|
||||
config: coreServices.rootConfig,
|
||||
auth: coreServices.auth,
|
||||
httpAuth: coreServices.httpAuth,
|
||||
plugin: coreServices.pluginMetadata,
|
||||
},
|
||||
async createRootContext({ config }) {
|
||||
const auditorConfig = config.getOptionalConfig('backend.auditor');
|
||||
|
||||
const auditor = Auditor.create({
|
||||
meta: {
|
||||
service: 'backstage',
|
||||
},
|
||||
format:
|
||||
options?.format(auditorConfig) ??
|
||||
winston.format.combine(
|
||||
auditorFieldFormat,
|
||||
process.env.NODE_ENV === 'production'
|
||||
? defaultProdFormat
|
||||
: Auditor.colorFormat(),
|
||||
),
|
||||
transports: [
|
||||
...transports.auditorConsole(auditorConfig),
|
||||
...(options?.transports?.(auditorConfig) ?? []),
|
||||
],
|
||||
});
|
||||
const auditor = DefaultRootAuditorService.create({
|
||||
meta: {
|
||||
service: 'backstage',
|
||||
},
|
||||
format: winston.format.combine(
|
||||
auditorFieldFormat,
|
||||
process.env.NODE_ENV === 'production'
|
||||
? defaultProdFormat
|
||||
: DefaultRootAuditorService.colorFormat(),
|
||||
),
|
||||
transports: [...transports.auditorConsole(auditorConfig)],
|
||||
});
|
||||
|
||||
return auditor;
|
||||
},
|
||||
factory({ plugin, auth, httpAuth }, rootAuditor) {
|
||||
return rootAuditor.child(
|
||||
{ plugin: plugin.getId() },
|
||||
{ auth, httpAuth, plugin },
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export const auditorServiceFactory = Object.assign(
|
||||
auditorServiceFactoryWithOptions,
|
||||
auditorServiceFactoryWithOptions(),
|
||||
);
|
||||
return auditor;
|
||||
},
|
||||
factory({ plugin, auth, httpAuth }, rootAuditor) {
|
||||
return rootAuditor.forPlugin({ auth, httpAuth, plugin });
|
||||
},
|
||||
});
|
||||
|
||||
@@ -15,8 +15,4 @@
|
||||
*/
|
||||
|
||||
export * from './Auditor';
|
||||
export {
|
||||
auditorServiceFactory,
|
||||
auditorServiceFactoryWithOptions,
|
||||
type AuditorFactoryOptions,
|
||||
} from './auditorServiceFactory';
|
||||
export { auditorServiceFactory } from './auditorServiceFactory';
|
||||
|
||||
@@ -29,7 +29,6 @@ import type { Response as Response_2 } from 'express';
|
||||
// @public (undocumented)
|
||||
export type AuditorCreateEvent<TRootMeta extends JsonObject> = (options: {
|
||||
eventId: string;
|
||||
subEventId?: string;
|
||||
severityLevel?: AuditorEventSeverityLevel;
|
||||
request?: Request_2<any, any, any, any, any>;
|
||||
meta?: TRootMeta;
|
||||
|
||||
@@ -35,20 +35,17 @@ export type AuditorCreateEvent<TRootMeta extends JsonObject> = (options: {
|
||||
*/
|
||||
eventId: string;
|
||||
|
||||
/**
|
||||
* Use kebab-case to name sub-events (e.g., "by-id", "by-user").
|
||||
*
|
||||
* (Optional) The ID for a sub-event or related action within the main event. This allows further categorization of events within a logical group. For example, if the `eventId` is "fetch", the `subEventId` could be "by-id" or "by-location" to specify the method used for fetching.
|
||||
*/
|
||||
subEventId?: string;
|
||||
|
||||
/** (Optional) The severity level for the audit event. */
|
||||
severityLevel?: AuditorEventSeverityLevel;
|
||||
|
||||
/** (Optional) The associated HTTP request, if applicable. */
|
||||
request?: Request<any, any, any, any, any>;
|
||||
|
||||
/** (Optional) Additional metadata relevant to the event, structured as a JSON object. */
|
||||
/**
|
||||
* (Optional) Additional metadata relevant to the event, structured as a JSON object.
|
||||
* This could include a `queryType` field, using kebab-case, for variations within the main event (e.g., "by-id", "by-user").
|
||||
* For example, if the `eventId` is "fetch", the `queryType` in `meta` could be "by-id" or "by-location".
|
||||
*/
|
||||
meta?: TRootMeta;
|
||||
|
||||
/** (Optional) Suppresses the automatic initial event. */
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
import type { ErrorLike } from '@backstage/errors';
|
||||
import { MockAuditorService } from './MockAuditorService';
|
||||
import { MockAuthService } from './MockAuthService';
|
||||
import { mockCredentials } from './mockCredentials';
|
||||
import { MockHttpAuthService } from './MockHttpAuthService';
|
||||
import { mockCredentials } from './mockCredentials';
|
||||
|
||||
describe('MockAuditorService', () => {
|
||||
afterEach(() => {
|
||||
@@ -39,11 +39,14 @@ describe('MockAuditorService', () => {
|
||||
it('should error without auth service', async () => {
|
||||
const pluginId = 'test-plugin';
|
||||
|
||||
const auditor = MockAuditorService.create({
|
||||
plugin: {
|
||||
getId: () => pluginId,
|
||||
const auditor = MockAuditorService.create().child(
|
||||
{},
|
||||
{
|
||||
plugin: {
|
||||
getId: () => pluginId,
|
||||
},
|
||||
},
|
||||
});
|
||||
);
|
||||
|
||||
await expect(
|
||||
auditor.createEvent({
|
||||
@@ -57,15 +60,18 @@ describe('MockAuditorService', () => {
|
||||
it('should error without httpAuth service', async () => {
|
||||
const pluginId = 'test-plugin';
|
||||
|
||||
const auditor = MockAuditorService.create({
|
||||
plugin: {
|
||||
getId: () => pluginId,
|
||||
const auditor = MockAuditorService.create().child(
|
||||
{},
|
||||
{
|
||||
plugin: {
|
||||
getId: () => pluginId,
|
||||
},
|
||||
auth: new MockAuthService({
|
||||
pluginId,
|
||||
disableDefaultAuthPolicy: false,
|
||||
}),
|
||||
},
|
||||
auth: new MockAuthService({
|
||||
pluginId,
|
||||
disableDefaultAuthPolicy: false,
|
||||
}),
|
||||
});
|
||||
);
|
||||
|
||||
await expect(
|
||||
auditor.createEvent({
|
||||
@@ -81,16 +87,19 @@ describe('MockAuditorService', () => {
|
||||
|
||||
const pluginId = 'test-plugin';
|
||||
|
||||
const auditor = MockAuditorService.create({
|
||||
plugin: {
|
||||
getId: () => pluginId,
|
||||
const auditor = MockAuditorService.create().child(
|
||||
{},
|
||||
{
|
||||
plugin: {
|
||||
getId: () => pluginId,
|
||||
},
|
||||
auth: new MockAuthService({
|
||||
pluginId,
|
||||
disableDefaultAuthPolicy: false,
|
||||
}),
|
||||
httpAuth: new MockHttpAuthService(pluginId, mockCredentials.user()),
|
||||
},
|
||||
auth: new MockAuthService({
|
||||
pluginId,
|
||||
disableDefaultAuthPolicy: false,
|
||||
}),
|
||||
httpAuth: new MockHttpAuthService(pluginId, mockCredentials.user()),
|
||||
});
|
||||
);
|
||||
|
||||
await auditor.createEvent({
|
||||
eventId: 'test-event',
|
||||
@@ -104,16 +113,19 @@ describe('MockAuditorService', () => {
|
||||
|
||||
const pluginId = 'test-plugin';
|
||||
|
||||
const auditor = MockAuditorService.create({
|
||||
plugin: {
|
||||
getId: () => pluginId,
|
||||
const auditor = MockAuditorService.create().child(
|
||||
{},
|
||||
{
|
||||
plugin: {
|
||||
getId: () => pluginId,
|
||||
},
|
||||
auth: new MockAuthService({
|
||||
pluginId,
|
||||
disableDefaultAuthPolicy: false,
|
||||
}),
|
||||
httpAuth: new MockHttpAuthService(pluginId, mockCredentials.user()),
|
||||
},
|
||||
auth: new MockAuthService({
|
||||
pluginId,
|
||||
disableDefaultAuthPolicy: false,
|
||||
}),
|
||||
httpAuth: new MockHttpAuthService(pluginId, mockCredentials.user()),
|
||||
});
|
||||
);
|
||||
|
||||
await auditor.createEvent({
|
||||
eventId: 'test-event',
|
||||
@@ -127,16 +139,19 @@ describe('MockAuditorService', () => {
|
||||
|
||||
const pluginId = 'test-plugin';
|
||||
|
||||
const auditor = MockAuditorService.create({
|
||||
plugin: {
|
||||
getId: () => pluginId,
|
||||
const auditor = MockAuditorService.create().child(
|
||||
{},
|
||||
{
|
||||
plugin: {
|
||||
getId: () => pluginId,
|
||||
},
|
||||
auth: new MockAuthService({
|
||||
pluginId,
|
||||
disableDefaultAuthPolicy: false,
|
||||
}),
|
||||
httpAuth: new MockHttpAuthService(pluginId, mockCredentials.user()),
|
||||
},
|
||||
auth: new MockAuthService({
|
||||
pluginId,
|
||||
disableDefaultAuthPolicy: false,
|
||||
}),
|
||||
httpAuth: new MockHttpAuthService(pluginId, mockCredentials.user()),
|
||||
});
|
||||
);
|
||||
|
||||
const auditorEvent = await auditor.createEvent({
|
||||
eventId: 'test-event',
|
||||
@@ -152,16 +167,19 @@ describe('MockAuditorService', () => {
|
||||
|
||||
const pluginId = 'test-plugin';
|
||||
|
||||
const auditor = MockAuditorService.create({
|
||||
plugin: {
|
||||
getId: () => pluginId,
|
||||
const auditor = MockAuditorService.create().child(
|
||||
{},
|
||||
{
|
||||
plugin: {
|
||||
getId: () => pluginId,
|
||||
},
|
||||
auth: new MockAuthService({
|
||||
pluginId,
|
||||
disableDefaultAuthPolicy: false,
|
||||
}),
|
||||
httpAuth: new MockHttpAuthService(pluginId, mockCredentials.user()),
|
||||
},
|
||||
auth: new MockAuthService({
|
||||
pluginId,
|
||||
disableDefaultAuthPolicy: false,
|
||||
}),
|
||||
httpAuth: new MockHttpAuthService(pluginId, mockCredentials.user()),
|
||||
});
|
||||
);
|
||||
|
||||
const auditorEvent = await auditor.createEvent({
|
||||
eventId: 'test-event',
|
||||
|
||||
@@ -32,7 +32,11 @@ import type { Request } from 'express';
|
||||
import type { mockServices } from './mockServices';
|
||||
|
||||
export class MockAuditorService implements AuditorService {
|
||||
readonly #options: mockServices.auditor.Options;
|
||||
readonly #options: mockServices.auditor.Options & {
|
||||
auth?: AuthService;
|
||||
httpAuth?: HttpAuthService;
|
||||
plugin?: PluginMetadataService;
|
||||
};
|
||||
|
||||
static create(options?: mockServices.auditor.Options): MockAuditorService {
|
||||
return new MockAuditorService(options ?? {});
|
||||
@@ -54,17 +58,31 @@ export class MockAuditorService implements AuditorService {
|
||||
|
||||
return {
|
||||
success: async params => {
|
||||
// return undefined if both objects are empty; otherwise, merge the objects
|
||||
const meta =
|
||||
Object.keys(options.meta ?? {}).length === 0 &&
|
||||
Object.keys(params?.meta ?? {}).length === 0
|
||||
? undefined
|
||||
: { ...options.meta, ...params?.meta };
|
||||
|
||||
await this.log({
|
||||
...options,
|
||||
meta: { ...options.meta, ...params?.meta },
|
||||
meta,
|
||||
status: 'succeeded',
|
||||
});
|
||||
},
|
||||
fail: async params => {
|
||||
// return undefined if both objects are empty; otherwise, merge the objects
|
||||
const meta =
|
||||
Object.keys(options.meta ?? {}).length === 0 &&
|
||||
Object.keys(params.meta ?? {}).length === 0
|
||||
? undefined
|
||||
: { ...options.meta, ...params.meta };
|
||||
|
||||
await this.log({
|
||||
...options,
|
||||
...params,
|
||||
meta: { ...options.meta, ...params.meta },
|
||||
meta,
|
||||
status: 'failed',
|
||||
});
|
||||
},
|
||||
@@ -76,14 +94,14 @@ export class MockAuditorService implements AuditorService {
|
||||
deps?: {
|
||||
auth?: AuthService;
|
||||
httpAuth?: HttpAuthService;
|
||||
plugin: PluginMetadataService;
|
||||
plugin?: PluginMetadataService;
|
||||
},
|
||||
): AuditorService {
|
||||
return new MockAuditorService({
|
||||
...this.#options,
|
||||
auth: deps?.auth ?? this.#options.auth,
|
||||
httpAuth: deps?.httpAuth ?? this.#options.httpAuth,
|
||||
plugin: deps?.plugin ?? this.#options.plugin,
|
||||
auth: deps?.auth,
|
||||
httpAuth: deps?.httpAuth,
|
||||
plugin: deps?.plugin,
|
||||
meta: {
|
||||
...this.#options.meta,
|
||||
...meta,
|
||||
@@ -162,7 +180,13 @@ export class MockAuditorService implements AuditorService {
|
||||
return auditEvent;
|
||||
}
|
||||
|
||||
private constructor(options: mockServices.auditor.Options) {
|
||||
private constructor(
|
||||
options: mockServices.auditor.Options & {
|
||||
auth?: AuthService;
|
||||
httpAuth?: HttpAuthService;
|
||||
plugin?: PluginMetadataService;
|
||||
},
|
||||
) {
|
||||
this.#options = options;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { AuditorOptions } from '@backstage/backend-defaults/auditor';
|
||||
import type { RootAuditorOptions } from '@backstage/backend-defaults/auditor';
|
||||
import { cacheServiceFactory } from '@backstage/backend-defaults/cache';
|
||||
import { databaseServiceFactory } from '@backstage/backend-defaults/database';
|
||||
import { HostDiscovery } from '@backstage/backend-defaults/discovery';
|
||||
@@ -234,15 +234,14 @@ export namespace mockServices {
|
||||
): AuditorService {
|
||||
const service = 'backstage';
|
||||
const pluginId = options?.pluginId ?? 'test';
|
||||
const mockAuth =
|
||||
options?.auth ??
|
||||
new MockAuthService({
|
||||
pluginId,
|
||||
disableDefaultAuthPolicy: false,
|
||||
});
|
||||
const mockHttpAuth =
|
||||
options?.httpAuth ??
|
||||
new MockHttpAuthService(pluginId, mockCredentials.user());
|
||||
const mockAuth = new MockAuthService({
|
||||
pluginId,
|
||||
disableDefaultAuthPolicy: false,
|
||||
});
|
||||
const mockHttpAuth = new MockHttpAuthService(
|
||||
pluginId,
|
||||
mockCredentials.user(),
|
||||
);
|
||||
|
||||
const mockPlugin = {
|
||||
getId: () => pluginId,
|
||||
@@ -259,7 +258,7 @@ export namespace mockServices {
|
||||
}
|
||||
|
||||
export namespace auditor {
|
||||
export type Options = Omit<AuditorOptions, 'format' | 'transports'>;
|
||||
export type Options = Omit<RootAuditorOptions, 'format' | 'transports'>;
|
||||
|
||||
export const factory = (options?: auditor.Options) =>
|
||||
createServiceFactory({
|
||||
|
||||
@@ -95,6 +95,8 @@ The Catalog backend emits audit events for various operations. Events are groupe
|
||||
|
||||
- **`entity-fetch`**: Retrieves entities.
|
||||
|
||||
Filter on `queryType`.
|
||||
|
||||
- **`all`**: Fetching all entities. (GET `/entities`)
|
||||
- **`by-id`**: Fetching a single entity using its UID. (GET `/entities/by-uid/:uid`)
|
||||
- **`by-name`**: Fetching a single entity using its kind, namespace, and name. (GET `/entities/by-name/:kind/:namespace/:name`)
|
||||
@@ -104,6 +106,8 @@ The Catalog backend emits audit events for various operations. Events are groupe
|
||||
|
||||
- **`entity-mutate`**: Modifies entities.
|
||||
|
||||
Filter on `actionType`.
|
||||
|
||||
- **`delete`**: Deleting a single entity. Note: this will not be a permanent deletion and the entity will be restored if the parent location is still present in the catalog. (DELETE `/entities/by-uid/:uid`)
|
||||
- **`refresh`**: Scheduling an entity refresh. (POST `/entities/refresh`)
|
||||
|
||||
@@ -115,6 +119,8 @@ The Catalog backend emits audit events for various operations. Events are groupe
|
||||
|
||||
- **`location-fetch`**: Retrieves locations.
|
||||
|
||||
Filter on `actionType`.
|
||||
|
||||
- **`all`**: Fetching all locations. (GET `/locations`)
|
||||
- **`by-id`**: Fetching a single location by ID. (GET `/locations/:id`)
|
||||
- **`by-entity`**: Fetching locations associated with an entity ref. (GET `/locations/by-entity`)
|
||||
|
||||
@@ -35,7 +35,7 @@ import { LocationAnalyzer } from '@backstage/plugin-catalog-node';
|
||||
import express from 'express';
|
||||
import yn from 'yn';
|
||||
import { z } from 'zod';
|
||||
import { Cursor, EntitiesCatalog } from '../catalog/types';
|
||||
import { EntitiesCatalog } from '../catalog/types';
|
||||
import { CatalogProcessingOrchestrator } from '../processing/types';
|
||||
import { validateEntityEnvelope } from '../processing/util';
|
||||
import { createOpenApiRouter } from '../schema/openapi';
|
||||
@@ -50,11 +50,7 @@ import {
|
||||
import { parseEntityFacetParams } from './request/parseEntityFacetParams';
|
||||
import { parseEntityOrderParams } from './request/parseEntityOrderParams';
|
||||
import { parseEntityPaginationParams } from './request/parseEntityPaginationParams';
|
||||
import {
|
||||
createEntityArrayJsonStream,
|
||||
writeEntitiesResponse,
|
||||
writeSingleEntityResponse,
|
||||
} from './response';
|
||||
import { writeEntitiesResponse, writeSingleEntityResponse } from './response';
|
||||
import { LocationService, RefreshService } from './types';
|
||||
import {
|
||||
disallowReadonlyMode,
|
||||
@@ -129,9 +125,9 @@ export async function createRouter(
|
||||
|
||||
const auditorEvent = await auditor?.createEvent({
|
||||
eventId: 'entity-mutate',
|
||||
subEventId: 'refresh',
|
||||
severityLevel: 'medium',
|
||||
meta: {
|
||||
queryType: 'refresh',
|
||||
entityRef: restBody.entityRef,
|
||||
},
|
||||
request: req,
|
||||
@@ -165,8 +161,11 @@ export async function createRouter(
|
||||
.get('/entities', async (req, res) => {
|
||||
const auditorEvent = await auditor?.createEvent({
|
||||
eventId: 'entity-fetch',
|
||||
subEventId: 'all',
|
||||
request: req,
|
||||
meta: {
|
||||
queryType: 'all',
|
||||
query: req.query,
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
@@ -260,8 +259,10 @@ export async function createRouter(
|
||||
.get('/entities/by-query', async (req, res) => {
|
||||
const auditorEvent = await auditor?.createEvent({
|
||||
eventId: 'entity-fetch',
|
||||
subEventId: 'by-query',
|
||||
request: req,
|
||||
meta: {
|
||||
queryType: 'by-query',
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
@@ -311,9 +312,9 @@ export async function createRouter(
|
||||
|
||||
const auditorEvent = await auditor?.createEvent({
|
||||
eventId: 'entity-fetch',
|
||||
subEventId: 'by-uid',
|
||||
request: req,
|
||||
meta: {
|
||||
queryType: 'by-uid',
|
||||
uid: uid,
|
||||
},
|
||||
});
|
||||
@@ -343,10 +344,10 @@ export async function createRouter(
|
||||
|
||||
const auditorEvent = await auditor?.createEvent({
|
||||
eventId: 'entity-mutate',
|
||||
subEventId: 'delete',
|
||||
severityLevel: 'medium',
|
||||
request: req,
|
||||
meta: {
|
||||
actionType: 'delete',
|
||||
uid: uid,
|
||||
},
|
||||
});
|
||||
@@ -372,9 +373,9 @@ export async function createRouter(
|
||||
|
||||
const auditorEvent = await auditor?.createEvent({
|
||||
eventId: 'entity-fetch',
|
||||
subEventId: 'by-name',
|
||||
request: req,
|
||||
meta: {
|
||||
queryType: 'by-name',
|
||||
entityRef: entityRef,
|
||||
},
|
||||
});
|
||||
@@ -407,9 +408,9 @@ export async function createRouter(
|
||||
|
||||
const auditorEvent = await auditor?.createEvent({
|
||||
eventId: 'entity-fetch',
|
||||
subEventId: 'ancestry',
|
||||
request: req,
|
||||
meta: {
|
||||
actionType: 'ancestry',
|
||||
entityRef: entityRef,
|
||||
},
|
||||
});
|
||||
@@ -443,8 +444,10 @@ export async function createRouter(
|
||||
.post('/entities/by-refs', async (req, res) => {
|
||||
const auditorEvent = await auditor?.createEvent({
|
||||
eventId: 'entity-fetch',
|
||||
subEventId: 'by-refs',
|
||||
request: req,
|
||||
meta: {
|
||||
queryType: 'by-refs',
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
@@ -510,10 +513,10 @@ export async function createRouter(
|
||||
|
||||
const auditorEvent = await auditor?.createEvent({
|
||||
eventId: 'location-mutate',
|
||||
subEventId: 'create',
|
||||
severityLevel: dryRun ? 'low' : 'medium',
|
||||
request: req,
|
||||
meta: {
|
||||
actionType: 'create',
|
||||
location: location,
|
||||
isDryRun: dryRun,
|
||||
},
|
||||
@@ -555,8 +558,10 @@ export async function createRouter(
|
||||
.get('/locations', async (req, res) => {
|
||||
const auditorEvent = await auditor?.createEvent({
|
||||
eventId: 'location-fetch',
|
||||
subEventId: 'all',
|
||||
request: req,
|
||||
meta: {
|
||||
queryType: 'all',
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
@@ -580,9 +585,9 @@ export async function createRouter(
|
||||
|
||||
const auditorEvent = await auditor?.createEvent({
|
||||
eventId: 'location-fetch',
|
||||
subEventId: 'by-id',
|
||||
request: req,
|
||||
meta: {
|
||||
queryType: 'by-id',
|
||||
id: id,
|
||||
},
|
||||
});
|
||||
@@ -611,10 +616,10 @@ export async function createRouter(
|
||||
|
||||
const auditorEvent = await auditor?.createEvent({
|
||||
eventId: 'location-mutate',
|
||||
subEventId: 'delete',
|
||||
severityLevel: 'medium',
|
||||
request: req,
|
||||
meta: {
|
||||
actionType: 'delete',
|
||||
id: id,
|
||||
},
|
||||
});
|
||||
@@ -642,9 +647,9 @@ export async function createRouter(
|
||||
|
||||
const auditorEvent = await auditor?.createEvent({
|
||||
eventId: 'location-fetch',
|
||||
subEventId: 'by-entity',
|
||||
request: req,
|
||||
meta: {
|
||||
queryType: 'by-entity',
|
||||
locationRef: locationRef,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -79,6 +79,9 @@ The Scaffolder backend emits audit events for various operations. Events are gro
|
||||
**Task Events:**
|
||||
|
||||
- **`task`**: Operations related to Scaffolder tasks.
|
||||
|
||||
Filter on `actionType`.
|
||||
|
||||
- **`create`**: Creates a new task. (POST `/v2/tasks`)
|
||||
- **`list`**: Fetches details of all tasks. (GET `/v2/tasks`)
|
||||
- **`get`**: Fetches details of a specific task. (GET `/v2/tasks/:taskId`)
|
||||
|
||||
@@ -207,9 +207,9 @@ export class TaskManager implements TaskContext {
|
||||
|
||||
const auditorEvent = await this.auditor?.createEvent({
|
||||
eventId: 'task',
|
||||
subEventId: 'execution',
|
||||
severityLevel: 'medium',
|
||||
meta: {
|
||||
actionType: 'execution',
|
||||
taskId: this.task.taskId,
|
||||
taskParameters: this.task.spec.parameters,
|
||||
},
|
||||
@@ -474,9 +474,9 @@ export class StorageTaskBroker implements TaskBroker {
|
||||
tasks.map(async task => {
|
||||
const auditorEvent = await this.auditor?.createEvent({
|
||||
eventId: 'task',
|
||||
subEventId: 'stale-cancel',
|
||||
severityLevel: 'medium',
|
||||
meta: {
|
||||
actionType: 'stale-cancel',
|
||||
taskId: task.taskId,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -176,9 +176,9 @@ export class TaskWorker {
|
||||
async runOneTask(task: TaskContext) {
|
||||
await this.auditor?.createEvent({
|
||||
eventId: 'task',
|
||||
subEventId: 'execution',
|
||||
severityLevel: 'medium',
|
||||
meta: {
|
||||
actionType: 'execution',
|
||||
taskId: task.taskId,
|
||||
taskParameters: task.spec.parameters,
|
||||
templateRef: task.spec.templateInfo?.entityRef,
|
||||
|
||||
@@ -542,10 +542,10 @@ export async function createRouter(
|
||||
|
||||
const auditorEvent = await auditor?.createEvent({
|
||||
eventId: 'task',
|
||||
subEventId: 'create',
|
||||
severityLevel: 'medium',
|
||||
request: req,
|
||||
meta: {
|
||||
actionType: 'create',
|
||||
templateRef: templateRef,
|
||||
},
|
||||
});
|
||||
@@ -648,8 +648,10 @@ export async function createRouter(
|
||||
.get('/v2/tasks', async (req, res) => {
|
||||
const auditorEvent = await auditor?.createEvent({
|
||||
eventId: 'task',
|
||||
subEventId: 'list',
|
||||
request: req,
|
||||
meta: {
|
||||
actionType: 'list',
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
@@ -711,9 +713,9 @@ export async function createRouter(
|
||||
|
||||
const auditorEvent = await auditor?.createEvent({
|
||||
eventId: 'task',
|
||||
subEventId: 'get',
|
||||
request: req,
|
||||
meta: {
|
||||
actionType: 'get',
|
||||
taskId: taskId,
|
||||
},
|
||||
});
|
||||
@@ -746,10 +748,12 @@ export async function createRouter(
|
||||
|
||||
const auditorEvent = await auditor?.createEvent({
|
||||
eventId: 'task',
|
||||
subEventId: 'cancel',
|
||||
severityLevel: 'medium',
|
||||
request: req,
|
||||
meta: { taskId: taskId },
|
||||
meta: {
|
||||
actionType: 'cancel',
|
||||
taskId: taskId,
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
@@ -776,10 +780,12 @@ export async function createRouter(
|
||||
|
||||
const auditorEvent = await auditor?.createEvent({
|
||||
eventId: 'task',
|
||||
subEventId: 'retry',
|
||||
severityLevel: 'medium',
|
||||
request: req,
|
||||
meta: { taskId: taskId },
|
||||
meta: {
|
||||
actionType: 'retry',
|
||||
taskId: taskId,
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
@@ -805,9 +811,11 @@ export async function createRouter(
|
||||
|
||||
const auditorEvent = await auditor?.createEvent({
|
||||
eventId: 'task',
|
||||
subEventId: 'stream',
|
||||
request: req,
|
||||
meta: { taskId: taskId },
|
||||
meta: {
|
||||
actionType: 'stream',
|
||||
taskId: taskId,
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
@@ -875,9 +883,9 @@ export async function createRouter(
|
||||
|
||||
const auditorEvent = await auditor?.createEvent({
|
||||
eventId: 'task',
|
||||
subEventId: 'events',
|
||||
request: req,
|
||||
meta: {
|
||||
actionType: 'events',
|
||||
taskId: taskId,
|
||||
},
|
||||
});
|
||||
@@ -927,8 +935,10 @@ export async function createRouter(
|
||||
.post('/v2/dry-run', async (req, res) => {
|
||||
const auditorEvent = await auditor?.createEvent({
|
||||
eventId: 'task',
|
||||
subEventId: 'dry-run',
|
||||
request: req,
|
||||
meta: {
|
||||
actionType: 'dry-run',
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user