fix(server): scope workspace findOne in incrementMetadataVersion

https://sonarly.com/issue/42366?type=bug

Metadata mutations on

Authored by Sonarly by autonomous analysis (run 48368).
This commit is contained in:
sonarly-bot
2026-06-03 20:28:02 +00:00
parent ae7db23bdd
commit 4ac395c09c
4 changed files with 101 additions and 0 deletions
@@ -0,0 +1,65 @@
import * as Sentry from '@sentry/node';
import { ExceptionHandlerSentryDriver } from 'src/engine/core-modules/exception-handler/drivers/sentry.driver';
const setExtraMock = jest.fn();
const setTagMock = jest.fn();
const setUserMock = jest.fn();
const setContextMock = jest.fn();
const setFingerprintMock = jest.fn();
const addBreadcrumbMock = jest.fn();
const captureExceptionMock = jest.fn(() => 'event-id');
jest.mock('@sentry/node', () => ({
withScope: (callback: (scope: unknown) => void) => {
callback({
setExtra: setExtraMock,
setTag: setTagMock,
setUser: setUserMock,
setContext: setContextMock,
setFingerprint: setFingerprintMock,
addBreadcrumb: addBreadcrumbMock,
});
},
captureException: (...args: unknown[]) => captureExceptionMock(...args),
}));
describe('ExceptionHandlerSentryDriver', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should add workspace tags when workspace details are available', () => {
const driver = new ExceptionHandlerSentryDriver();
driver.captureExceptions([new Error('boom')], {
workspace: {
id: 'workspace-id',
activationStatus: 'ACTIVE',
version: '2.8',
metadataVersion: 42,
},
});
expect(setTagMock).toHaveBeenCalledWith('workspaceId', 'workspace-id');
expect(setTagMock).toHaveBeenCalledWith(
'workspaceActivationStatus',
'ACTIVE',
);
expect(setTagMock).toHaveBeenCalledWith('workspaceVersion', '2.8');
expect(setTagMock).toHaveBeenCalledWith('workspaceMetadataVersion', '42');
expect(captureExceptionMock).toHaveBeenCalledTimes(1);
});
it('should not add workspace tags when workspace details are missing', () => {
const driver = new ExceptionHandlerSentryDriver();
driver.captureExceptions([new Error('boom')]);
expect(setTagMock).not.toHaveBeenCalledWith(
'workspaceMetadataVersion',
expect.anything(),
);
expect(captureExceptionMock).toHaveBeenCalledTimes(1);
});
});
@@ -32,6 +32,28 @@ export class ExceptionHandlerSentryDriver implements ExceptionHandlerDriverInter
if (options?.workspace) {
scope.setExtra('workspace', options.workspace);
if (isDefined(options.workspace.id)) {
scope.setTag('workspaceId', options.workspace.id);
}
if (isDefined(options.workspace.activationStatus)) {
scope.setTag(
'workspaceActivationStatus',
options.workspace.activationStatus,
);
}
if (isDefined(options.workspace.version)) {
scope.setTag('workspaceVersion', options.workspace.version);
}
if (isDefined(options.workspace.metadataVersion)) {
scope.setTag(
'workspaceMetadataVersion',
`${options.workspace.metadataVersion}`,
);
}
}
if (options?.additionalData) {
@@ -3,4 +3,6 @@ export interface ExceptionHandlerWorkspace {
displayName?: string;
activationStatus?: string;
createdAt?: string;
metadataVersion?: number;
version?: string;
}
@@ -37,6 +37,7 @@ import { translateUserFriendlyMessageDescriptors } from 'src/engine/core-modules
const DEFAULT_EVENT_ID_KEY = 'exceptionEventId';
const SCHEMA_VERSION_HEADER = 'x-schema-version';
const SCHEMA_MISMATCH_ERROR = 'Schema version mismatch.';
const SCHEMA_MISMATCH_CODE = 'SCHEMA_VERSION_MISMATCH';
const APP_VERSION_HEADER = 'x-app-version';
const APP_VERSION_MISMATCH_ERROR = 'App version mismatch.';
const APP_VERSION_MISMATCH_CODE = 'APP_VERSION_MISMATCH';
@@ -76,6 +77,8 @@ export const useGraphQLErrorHandlerHook = <
displayName: req.workspace.displayName,
createdAt: req.workspace.createdAt ?? null,
activationStatus: req.workspace.activationStatus,
metadataVersion: req.workspace.metadataVersion,
version: req.workspace.version,
};
}
@@ -204,6 +207,14 @@ export const useGraphQLErrorHandlerHook = <
document,
user,
workspace: workspaceInfo,
additionalData: {
requestSchemaVersion:
args.contextValue.req.headers[SCHEMA_VERSION_HEADER],
workspaceSchemaVersion:
args.contextValue.req.workspaceMetadataVersion,
requestAppVersion:
args.contextValue.req.headers[APP_VERSION_HEADER],
},
},
);
@@ -288,6 +299,7 @@ export const useGraphQLErrorHandlerHook = <
throw new GraphQLError(SCHEMA_MISMATCH_ERROR, {
extensions: {
code: SCHEMA_MISMATCH_CODE,
userFriendlyMessage: i18n._(
msg`Your workspace has been updated with a new data model. Please refresh the page.`,
),