Migrate codebase to use Object.hasOwn instead of Object.hasOwnProperty (#186829)

## Summary

This PR has breadth, but not depth. This adds 3 new `eslint` rules. The
first two protect against the use of code generated from strings (`eval`
and friends), which will not work client-side due to our CSP, and is not
something we wish to support server-side. The last rule aims to prevent
a subtle class of bugs, and to defend against a subset of prototype
pollution exploits:

- `no-new-func` to be compliant with our CSP, and to prevent code
execution from strings server-side:
https://eslint.org/docs/latest/rules/no-new-func
- `no-implied-eval` to be compliant with our CSP, and to prevent code
execution from strings server-side:
https://eslint.org/docs/latest/rules/no-implied-eval. Note that this
function implies that it prevents no-new-func, but I don't see [test
cases](https://github.com/eslint/eslint/blob/main/tests/lib/rules/no-implied-eval.js)
covering this behavior, so I think we should play it safe and enable
both rules.
- `no-prototype-builtins` to prevent accessing shadowed properties:
https://eslint.org/docs/latest/rules/no-prototype-builtins


In order to be compliant with `no-prototype-builtins`, I've migrated all
usages and variants of `Object.hasOwnProperty` to use the newer
[`Object.hasOwn`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn).
This commit is contained in:
Larry Gregory 2024-08-13 11:30:19 -04:00 committed by GitHub
parent 386d290ea4
commit 74d88580a5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
230 changed files with 458 additions and 437 deletions

View file

@ -409,9 +409,9 @@ export class DataVisualizer {
};
let cardinalityField: AggCardinality;
if (datafeedConfig?.script_fields?.hasOwnProperty(field)) {
if (Object.hasOwn(datafeedConfig?.script_fields ?? {}, field)) {
cardinalityField = aggs[`${safeFieldName}_cardinality`] = {
cardinality: { script: datafeedConfig?.script_fields[field].script },
cardinality: { script: datafeedConfig?.script_fields![field].script },
};
} else {
cardinalityField = {
@ -475,8 +475,8 @@ export class DataVisualizer {
});
} else {
if (
datafeedConfig?.script_fields?.hasOwnProperty(field) ||
datafeedConfig?.runtime_mappings?.hasOwnProperty(field)
Object.hasOwn(datafeedConfig?.script_fields ?? {}, field) ||
Object.hasOwn(datafeedConfig?.runtime_mappings ?? {}, field)
) {
const cardinality = get(
aggregations,

View file

@ -59,13 +59,13 @@ export function fieldsServiceProvider({ asCurrentUser }: IScopedClusterClient) {
fieldNames.forEach((fieldName) => {
if (
typeof datafeedConfig?.script_fields === 'object' &&
datafeedConfig.script_fields.hasOwnProperty(fieldName)
Object.hasOwn(datafeedConfig.script_fields, fieldName)
) {
aggregatableFields.push(fieldName);
}
if (
typeof datafeedConfig?.runtime_mappings === 'object' &&
datafeedConfig.runtime_mappings.hasOwnProperty(fieldName)
Object.hasOwn(datafeedConfig.runtime_mappings, fieldName)
) {
aggregatableFields.push(fieldName);
}
@ -122,7 +122,7 @@ export function fieldsServiceProvider({ asCurrentUser }: IScopedClusterClient) {
) ?? {};
// No need to perform aggregation over the cached fields
const fieldsToAgg = aggregatableFields.filter((field) => !cachedValues.hasOwnProperty(field));
const fieldsToAgg = aggregatableFields.filter((field) => !Object.hasOwn(cachedValues, field));
if (fieldsToAgg.length === 0) {
return cachedValues;
@ -151,12 +151,12 @@ export function fieldsServiceProvider({ asCurrentUser }: IScopedClusterClient) {
(obj, field) => {
if (
typeof datafeedConfig?.script_fields === 'object' &&
datafeedConfig.script_fields.hasOwnProperty(field)
Object.hasOwn(datafeedConfig.script_fields, field)
) {
obj[field] = { cardinality: { script: datafeedConfig.script_fields[field].script } };
} else if (
typeof datafeedConfig?.runtime_mappings === 'object' &&
datafeedConfig.runtime_mappings.hasOwnProperty(field)
Object.hasOwn(datafeedConfig.runtime_mappings, field)
) {
obj[field] = { cardinality: { field } };
runtimeMappings.runtime_mappings = datafeedConfig.runtime_mappings;
@ -350,7 +350,7 @@ export function fieldsServiceProvider({ asCurrentUser }: IScopedClusterClient) {
) ?? {};
// No need to perform aggregation over the cached fields
const fieldsToAgg = aggregatableFields.filter((field) => !cachedValues.hasOwnProperty(field));
const fieldsToAgg = aggregatableFields.filter((field) => !Object.hasOwn(cachedValues, field));
if (fieldsToAgg.length === 0) {
return cachedValues;

View file

@ -454,7 +454,7 @@ export function jobsProvider(
// de-duplicate calendars
for (const cal in calendarsByJobId) {
if (calendarsByJobId.hasOwnProperty(cal)) {
if (Object.hasOwn(calendarsByJobId, cal)) {
calendarsByJobId[cal] = uniq(calendarsByJobId[cal]);
}
}

View file

@ -98,13 +98,13 @@ const validateFactory = (client: IScopedClusterClient, job: CombinedJob): Valida
aggregatableFieldNames = uniqueFieldNames.filter((field) => {
if (
typeof datafeedConfig?.script_fields === 'object' &&
datafeedConfig?.script_fields.hasOwnProperty(field)
Object.hasOwn(datafeedConfig?.script_fields ?? {}, field)
) {
return true;
}
if (
typeof datafeedConfig?.runtime_mappings === 'object' &&
datafeedConfig?.runtime_mappings.hasOwnProperty(field)
Object.hasOwn(datafeedConfig?.runtime_mappings ?? {}, field)
) {
return true;
}

View file

@ -273,7 +273,7 @@ export class NotificationsService {
return res.reduce((acc, curr) => {
for (const levelKey in curr) {
if (curr.hasOwnProperty(levelKey)) {
if (Object.hasOwn(curr, levelKey)) {
acc[levelKey as MlNotificationMessageLevel] +=
curr[levelKey as MlNotificationMessageLevel];
}