diff --git a/packages/server/modules/auth/graph/resolvers/apps.ts b/packages/server/modules/auth/graph/resolvers/apps.ts index e0065f7b9..0b03faa72 100644 --- a/packages/server/modules/auth/graph/resolvers/apps.ts +++ b/packages/server/modules/auth/graph/resolvers/apps.ts @@ -12,6 +12,7 @@ import { } from '@/modules/auth/repositories/apps' import { db } from '@/db/knex' import { Resolvers } from '@/modules/core/graph/generated/graphql' +import { withOperationLogging } from '@/observability/domain/businessLogging' const getApp = getAppFactory({ db }) const getAllPublicApps = getAllPublicAppsFactory({ db }) @@ -65,12 +66,20 @@ export = { }, Mutation: { async appCreate(_parent, args, context) { - const { id } = await createApp({ - ...args.app, - authorId: context.userId!, - public: isNullOrUndefined(args.app.public) ? undefined : args.app.public, - scopes: args.app.scopes.filter(isScope) - }) + const { id } = await withOperationLogging( + async () => + await createApp({ + ...args.app, + authorId: context.userId!, + public: isNullOrUndefined(args.app.public) ? undefined : args.app.public, + scopes: args.app.scopes.filter(isScope) + }), + { + operationName: 'appCreate', + operationDescription: 'Create a new app', + logger: context.log + } + ) return id }, @@ -88,13 +97,21 @@ export = { if (app?.author?.id !== context.userId && context.role !== Roles.Server.Admin) throw new ForbiddenError('You are not authorized to edit this app.') - await updateApp({ - app: { - ...args.app, - public: isNullOrUndefined(args.app.public) ? undefined : args.app.public, - scopes: args.app.scopes.filter(isScope) + await withOperationLogging( + async () => + await updateApp({ + app: { + ...args.app, + public: isNullOrUndefined(args.app.public) ? undefined : args.app.public, + scopes: args.app.scopes.filter(isScope) + } + }), + { + operationName: 'appUpdate', + operationDescription: 'Update an existing app', + logger: context.log } - }) + ) return true }, @@ -112,14 +129,29 @@ export = { if (app.author?.id !== context.userId && context.role !== Roles.Server.Admin) throw new ForbiddenError('You are not authorized to edit this app.') - return (await deleteApp({ id: args.appId })) === 1 + return await withOperationLogging( + async () => (await deleteApp({ id: args.appId })) === 1, + { + operationName: 'appDelete', + operationDescription: 'Delete an existing app', + logger: context.log + } + ) }, async appRevokeAccess(_parent, args, context) { - return !!(await revokeExistingAppCredentialsForUser({ - appId: args.appId, - userId: context.userId! - })) + return await withOperationLogging( + async () => + !!(await revokeExistingAppCredentialsForUser({ + appId: args.appId, + userId: context.userId! + })), + { + operationName: 'appRevokeAccess', + operationDescription: 'Revoke access to an app', + logger: context.log + } + ) } } } as Resolvers diff --git a/packages/server/modules/auth/rest/index.ts b/packages/server/modules/auth/rest/index.ts index 926e5707e..a46cf4033 100644 --- a/packages/server/modules/auth/rest/index.ts +++ b/packages/server/modules/auth/rest/index.ts @@ -37,6 +37,7 @@ import { } from '@/modules/core/repositories/tokens' import { getUserRoleFactory } from '@/modules/core/repositories/users' import { corsMiddlewareFactory } from '@/modules/core/configs/cors' +import { withOperationLogging } from '@/observability/domain/businessLogging' // TODO: Secure these endpoints! export default function (app: Express) { @@ -146,11 +147,19 @@ export default function (app: Express) { if (!req.body.appId || !req.body.appSecret) throw new BadRequestError('Invalid request - App Id and Secret are required.') - const authResponse = await refreshAppToken({ - refreshToken: req.body.refreshToken, - appId: req.body.appId, - appSecret: req.body.appSecret - }) + const authResponse = await withOperationLogging( + async () => + await refreshAppToken({ + refreshToken: req.body.refreshToken, + appId: req.body.appId, + appSecret: req.body.appSecret + }), + { + operationName: 'refreshAppToken', + operationDescription: 'Refresh an app token', + logger: req.log + } + ) return res.send(authResponse) } @@ -165,12 +174,20 @@ export default function (app: Express) { `Invalid request, insufficient information provided in the request. App Id, Secret, Access Code, and Challenge are required.` ) - const authResponse = await createAppTokenFromAccessCode({ - appId: req.body.appId, - appSecret: req.body.appSecret, - accessCode: req.body.accessCode, - challenge: req.body.challenge - }) + const authResponse = await withOperationLogging( + async () => + await createAppTokenFromAccessCode({ + appId: req.body.appId, + appSecret: req.body.appSecret, + accessCode: req.body.accessCode, + challenge: req.body.challenge + }), + { + operationName: 'createAppTokenFromAccessCode', + operationDescription: 'Create an app token from an access code', + logger: req.log + } + ) return res.send(authResponse) } catch (err) { req.log.info({ err }, 'Error while trying to generate a new token.') diff --git a/packages/server/modules/gatekeeper/rest/billing.ts b/packages/server/modules/gatekeeper/rest/billing.ts index 6754fa96e..f048386ad 100644 --- a/packages/server/modules/gatekeeper/rest/billing.ts +++ b/packages/server/modules/gatekeeper/rest/billing.ts @@ -153,7 +153,7 @@ export const getBillingRouter = (): Router => { operationName: 'completeCheckoutSession', operationDescription: 'Payment succeeded or Stripe session completed, and payment was paid', - errorHandler: (err, logger) => { + errorHandler: async (err, logger) => { if (err instanceof WorkspaceAlreadyPaidError) { // ignore the request, this is prob a replay from stripe logger.info('Workspace is already paid, ignoring') diff --git a/packages/server/observability/domain/businessLogging.ts b/packages/server/observability/domain/businessLogging.ts index 145f1f52a..1e545bc84 100644 --- a/packages/server/observability/domain/businessLogging.ts +++ b/packages/server/observability/domain/businessLogging.ts @@ -18,9 +18,9 @@ export const withOperationLogging = async ( logger: Logger operationName: string operationDescription?: string - errorHandler?: (err: unknown, logger: Logger) => MaybeAsync + errorHandler?: (err: unknown, logger: Logger) => MaybeAsync } -): Promise => { +): Promise => { const { operationName, operationDescription } = params const errorHandler = params.errorHandler || logErrorThenThrow const logger = params.logger.child(OperationName(operationName)) @@ -36,6 +36,6 @@ export const withOperationLogging = async ( logger.info(OperationStatus.success, OperationLogLinePrefix) return results } catch (err) { - await errorHandler(err, logger) + return await errorHandler(err, logger) } }