diff --git a/packages/server/api/src/app/benchmark/benchmark-feature-guard.ts b/packages/server/api/src/app/benchmark/benchmark-feature-guard.ts index c5a1adaaf..d3b7c59dd 100644 --- a/packages/server/api/src/app/benchmark/benchmark-feature-guard.ts +++ b/packages/server/api/src/app/benchmark/benchmark-feature-guard.ts @@ -1,15 +1,15 @@ import { AppSystemProp, logger, system } from '@openops/server-shared'; +import { preHandlerAsyncHookHandler } from 'fastify'; import { throwFeatureDisabledError } from './errors'; -export async function assertBenchmarkFeatureEnabled( - projectId: string, - provider?: string, -): Promise { +export const assertBenchmarkFeatureEnabled: preHandlerAsyncHookHandler = async ( + request, +) => { if (system.getBoolean(AppSystemProp.FINOPS_BENCHMARK_ENABLED) !== true) { logger.info( 'Benchmark access denied: FINOPS_BENCHMARK_ENABLED flag is not enabled', - { provider, projectId }, + { projectId: request.principal.projectId }, ); throwFeatureDisabledError('Benchmark feature is not enabled'); } -} +}; diff --git a/packages/server/api/src/app/benchmark/benchmark.controller.ts b/packages/server/api/src/app/benchmark/benchmark.controller.ts index 81571fd34..dddaaee2b 100644 --- a/packages/server/api/src/app/benchmark/benchmark.controller.ts +++ b/packages/server/api/src/app/benchmark/benchmark.controller.ts @@ -19,15 +19,12 @@ import { createBenchmark } from './create-benchmark.service'; import { resolveWizardNavigation } from './wizard.service'; export const benchmarkController: FastifyPluginAsyncTypebox = async (app) => { + app.addHook('preHandler', assertBenchmarkFeatureEnabled); + app.post( '/:provider/wizard', WizardStepRequestOptions, async (request, reply) => { - await assertBenchmarkFeatureEnabled( - request.principal.projectId, - request.params.provider, - ); - const step = await resolveWizardNavigation( request.params.provider, { @@ -44,11 +41,6 @@ export const benchmarkController: FastifyPluginAsyncTypebox = async (app) => { '/:provider', CreateBenchmarkRequestOptions, async (request, reply) => { - await assertBenchmarkFeatureEnabled( - request.principal.projectId, - request.params.provider, - ); - const result = await createBenchmark({ provider: request.params.provider, projectId: request.principal.projectId, @@ -59,10 +51,6 @@ export const benchmarkController: FastifyPluginAsyncTypebox = async (app) => { }, ); app.get('/', ListBenchmarksRequestOptions, async (request, reply) => { - await assertBenchmarkFeatureEnabled( - request.principal.projectId, - request.query.provider, - ); const items = await listBenchmarks({ projectId: request.principal.projectId, provider: request.query.provider, @@ -74,7 +62,6 @@ export const benchmarkController: FastifyPluginAsyncTypebox = async (app) => { '/:benchmarkId/status', BenchmarkStatusRequestOptions, async (request, reply) => { - await assertBenchmarkFeatureEnabled(request.principal.projectId); const status = await getBenchmarkStatus({ benchmarkId: request.params.benchmarkId, projectId: request.principal.projectId, diff --git a/packages/server/api/test/unit/benchmark/benchmark-feature-guard.test.ts b/packages/server/api/test/unit/benchmark/benchmark-feature-guard.test.ts new file mode 100644 index 000000000..702b784d3 --- /dev/null +++ b/packages/server/api/test/unit/benchmark/benchmark-feature-guard.test.ts @@ -0,0 +1,61 @@ +jest.mock('@openops/server-shared', () => ({ + system: { + getBoolean: jest.fn(), + }, + AppSystemProp: { + FINOPS_BENCHMARK_ENABLED: 'FINOPS_BENCHMARK_ENABLED', + }, + logger: { + info: jest.fn(), + }, +})); + +import { logger, system } from '@openops/server-shared'; +import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'; + +const mockSystem = system as jest.Mocked; + +import { assertBenchmarkFeatureEnabled } from '../../../src/app/benchmark/benchmark-feature-guard'; + +const mockFastifyInstance = {} as FastifyInstance; + +const mockRequest = (projectId: string) => + ({ principal: { projectId } } as unknown as FastifyRequest); + +const mockReply = {} as FastifyReply; + +const callHook = (projectId: string) => + assertBenchmarkFeatureEnabled.call( + mockFastifyInstance, + mockRequest(projectId), + mockReply, + ); + +describe('assertBenchmarkFeatureEnabled', () => { + const projectId = 'project-id'; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should throw error if FINOPS_BENCHMARK_ENABLED is not enabled', async () => { + mockSystem.getBoolean.mockReturnValue(false); + + await expect(callHook(projectId)).rejects.toThrow( + expect.objectContaining({ + message: 'FEATURE_DISABLED: Benchmark feature is not enabled', + }), + ); + + expect(logger.info).toHaveBeenCalledWith( + 'Benchmark access denied: FINOPS_BENCHMARK_ENABLED flag is not enabled', + { projectId }, + ); + }); + + it('should pass when FINOPS_BENCHMARK_ENABLED is true', async () => { + mockSystem.getBoolean.mockReturnValue(true); + + await expect(callHook(projectId)).resolves.toBeUndefined(); + }); +});