From 176f914824a3a505c034493fa6af5326ec7d7912 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Mon, 15 Dec 2025 16:20:57 +0100 Subject: [PATCH 1/3] chore: initialize `Record`s with null prototype objects --- .../src/components/change-view/bson-utils.ts | 2 +- .../src/components/table-view/document-table-view.tsx | 11 +++++++---- packages/compass-crud/src/stores/crud-store.spec.ts | 2 +- packages/compass-crud/src/stores/grid-store.ts | 2 +- .../src/application-menu.spec.tsx | 1 + packages/data-service/src/data-service.ts | 2 ++ packages/hadron-document/src/object-generator.ts | 4 ++-- packages/mongodb-query-util/src/in-value-range.ts | 1 + 8 files changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/compass-crud/src/components/change-view/bson-utils.ts b/packages/compass-crud/src/components/change-view/bson-utils.ts index dbaab06abc8..def6c4d359d 100644 --- a/packages/compass-crud/src/components/change-view/bson-utils.ts +++ b/packages/compass-crud/src/components/change-view/bson-utils.ts @@ -21,7 +21,7 @@ export function unBSON(value: any): any { if (shape === 'array') { return value.map(unBSON); } else if (shape === 'object') { - const mapped: Record = {}; + const mapped: Record = Object.create(null); for (const [k, v] of Object.entries(value)) { mapped[k] = unBSON(v); } diff --git a/packages/compass-crud/src/components/table-view/document-table-view.tsx b/packages/compass-crud/src/components/table-view/document-table-view.tsx index 798bfdd5ce3..3d2e27de0d0 100644 --- a/packages/compass-crud/src/components/table-view/document-table-view.tsx +++ b/packages/compass-crud/src/components/table-view/document-table-view.tsx @@ -224,7 +224,7 @@ export class DocumentTableView extends React.Component { onColumnResized(event: ColumnResizedEvent) { if (event.finished) { const columnState = this.columnApi?.getColumnState() || []; - const currentColumnWidths: Record = {}; + const currentColumnWidths: Record = Object.create(null); for (const column of columnState) { if (column.width) currentColumnWidths[column.colId] = column.width; } @@ -888,8 +888,11 @@ export class DocumentTableView extends React.Component { path: (string | number)[], types: TableHeaderType[] ): ColDef[] => { - const headers: Record = {}; - const headerTypes: Record> = {}; + const headers: Record = Object.create(null); + const headerTypes: Record< + string, + Record + > = Object.create(null); const isEditable = this.props.isEditable; const parentType = types.length ? types[types.length - 1] : 'Object'; @@ -944,7 +947,7 @@ export class DocumentTableView extends React.Component { the grid. This is handled here for the initial header values, and then in the GridStore for any subsequent updates. */ const columnHeaders = Object.values(headers); - const showing: Record = {}; + const showing: Record = Object.create(null); map(headerTypes, function (oids, key) { const colTypes = Object.values(oids); diff --git a/packages/compass-crud/src/stores/crud-store.spec.ts b/packages/compass-crud/src/stores/crud-store.spec.ts index fcd552b440d..786b7664f32 100644 --- a/packages/compass-crud/src/stores/crud-store.spec.ts +++ b/packages/compass-crud/src/stores/crud-store.spec.ts @@ -2719,7 +2719,7 @@ describe('store', function () { let fakeSetItem: (key: string, value: string) => void; beforeEach(function () { - const localStorageValues: Record = {}; + const localStorageValues: Record = Object.create(null); fakeGetItem = sinon.fake((key: string) => { return localStorageValues[key]; }); diff --git a/packages/compass-crud/src/stores/grid-store.ts b/packages/compass-crud/src/stores/grid-store.ts index cf2075d78f6..5e624394435 100644 --- a/packages/compass-crud/src/stores/grid-store.ts +++ b/packages/compass-crud/src/stores/grid-store.ts @@ -333,7 +333,7 @@ class GridStoreImpl * @param {Boolean} isArray - If the parent of the element is an array. */ elementRemoved(key: string, oid: string, isArray: boolean) { - const params: Record = {}; + const params: Record = Object.create(null); const newShowing: typeof this.showing = {}; /* If it's an array element, need to move subsequent elements up */ diff --git a/packages/compass-electron-menu/src/application-menu.spec.tsx b/packages/compass-electron-menu/src/application-menu.spec.tsx index 8b44c86a71a..28e0f185487 100644 --- a/packages/compass-electron-menu/src/application-menu.spec.tsx +++ b/packages/compass-electron-menu/src/application-menu.spec.tsx @@ -131,6 +131,7 @@ describe('application-menu / useApplicationMenu', function () { const handlerUndoA = () => {}; const handlerRedoA = () => {}; let roles: Record void> = { + __proto__: null, undo: handlerUndoA, redo: handlerRedoA, }; diff --git a/packages/data-service/src/data-service.ts b/packages/data-service/src/data-service.ts index 371b91bda6a..edac6012dfc 100644 --- a/packages/data-service/src/data-service.ts +++ b/packages/data-service/src/data-service.ts @@ -1194,6 +1194,7 @@ class DataServiceImpl extends WithLogContext implements DataService { // Build the aggregation pipeline dynamically based on collection type const groupStage: Record = { + __proto__: null, _id: null, capped: { $first: '$storageStats.capped' }, count: { $sum: '$storageStats.count' }, @@ -1230,6 +1231,7 @@ class DataServiceImpl extends WithLogContext implements DataService { const addFieldsStage: Record = { // `avgObjSize` is the average of per-shard `avgObjSize` weighted by `count` + __proto__: null, avgObjSize: { $cond: { if: { $ne: ['$count', 0] }, diff --git a/packages/hadron-document/src/object-generator.ts b/packages/hadron-document/src/object-generator.ts index a8f95cce351..dffd12eb21c 100644 --- a/packages/hadron-document/src/object-generator.ts +++ b/packages/hadron-document/src/object-generator.ts @@ -89,7 +89,7 @@ export class ObjectGenerator { options: ObjectGeneratorOptions = {} ): Record { if (elements) { - const object: Record = {}; + const object: Record = Object.create(null); for (const element of elements) { if (options.excludeInternalFields && element.isInternalField()) { continue; @@ -118,7 +118,7 @@ export class ObjectGenerator { options: ObjectGeneratorOptions = {} ): Record { if (elements) { - const object: Record = {}; + const object: Record = Object.create(null); for (const element of elements) { if (options.excludeInternalFields && element.isInternalField()) { continue; diff --git a/packages/mongodb-query-util/src/in-value-range.ts b/packages/mongodb-query-util/src/in-value-range.ts index 94bad3b51ce..186c9b0ce78 100644 --- a/packages/mongodb-query-util/src/in-value-range.ts +++ b/packages/mongodb-query-util/src/in-value-range.ts @@ -39,6 +39,7 @@ export const inValueRange = ( d: { value: any; dx?: number; bson?: any } ) => { const compOperators: Record boolean> = { + __proto__: null, $gte: function (a: number, b: number) { return a >= b; }, From d89b2dffba6f4f050d7863a3b94fda300f7ec942 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Mon, 15 Dec 2025 17:20:42 +0100 Subject: [PATCH 2/3] fixup: prefer readonly over `__proto__` in mongodb-query-util --- packages/mongodb-query-util/src/in-value-range.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/mongodb-query-util/src/in-value-range.ts b/packages/mongodb-query-util/src/in-value-range.ts index 186c9b0ce78..24fac0f331f 100644 --- a/packages/mongodb-query-util/src/in-value-range.ts +++ b/packages/mongodb-query-util/src/in-value-range.ts @@ -38,8 +38,9 @@ export const inValueRange = ( field: any, d: { value: any; dx?: number; bson?: any } ) => { - const compOperators: Record boolean> = { - __proto__: null, + const compOperators: Readonly< + Record boolean> + > = { $gte: function (a: number, b: number) { return a >= b; }, From b80067107558279a5cd0451f279560ee6adc6c0e Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Mon, 15 Dec 2025 17:29:51 +0100 Subject: [PATCH 3/3] fixup: readonly in compass-electron-menu as well --- packages/compass-electron-menu/src/application-menu.spec.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/compass-electron-menu/src/application-menu.spec.tsx b/packages/compass-electron-menu/src/application-menu.spec.tsx index 28e0f185487..03f0f3b8af8 100644 --- a/packages/compass-electron-menu/src/application-menu.spec.tsx +++ b/packages/compass-electron-menu/src/application-menu.spec.tsx @@ -130,8 +130,7 @@ describe('application-menu / useApplicationMenu', function () { const handlerUndoA = () => {}; const handlerRedoA = () => {}; - let roles: Record void> = { - __proto__: null, + let roles: Readonly void>> = { undo: handlerUndoA, redo: handlerRedoA, };