diff --git a/eslint.config.mjs b/eslint.config.mjs index 4f7040d7d..7ce393e02 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,10 +1,10 @@ -import path from "node:path"; -import { fileURLToPath } from "node:url"; -import js from "@eslint/js"; -import { FlatCompat } from "@eslint/eslintrc"; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import js from '@eslint/js'; +import { FlatCompat } from '@eslint/eslintrc'; import tseslint from 'typescript-eslint'; import { includeIgnoreFile } from '@eslint/compat'; - +import eslintConfigPrettier from 'eslint-config-prettier'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -12,7 +12,7 @@ const gitignorePath = path.resolve(__dirname, '.gitignore'); const compat = new FlatCompat({ baseDirectory: __dirname, recommendedConfig: js.configs.recommended, - allConfig: js.configs.all + allConfig: js.configs.all, }); export default tseslint.config( @@ -25,11 +25,14 @@ export default tseslint.config( '@typescript-eslint/no-require-imports': 'off', '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-empty-object-type': 'off', - 'camelcase': 'off', + camelcase: 'off', 'no-param-reassign': 'off', 'new-cap': 'off', - 'quotes': 'off', - '@typescript-eslint/no-unsafe-function-type':'off' - } - } + quotes: 'off', + '@typescript-eslint/no-unsafe-function-type': 'off', + }, + }, + // Must be last: turns off ESLint formatting rules that conflict with + // Prettier (indent, max-len, …) so Prettier owns formatting. + eslintConfigPrettier, ); diff --git a/lib/network/rpc/utils.ts b/lib/network/rpc/utils.ts index 2df930cd7..028df496c 100644 --- a/lib/network/rpc/utils.ts +++ b/lib/network/rpc/utils.ts @@ -1,7 +1,5 @@ import { ArsenalError, allowUnsafeErrComp } from '../../errors'; - // eslint-disable-line - /** * @brief turn all err own and prototype attributes into own attributes * @@ -31,7 +29,7 @@ export function flattenError(err: Error) { } } return flattenedErr; -}; +} /** * @brief recreate a proper Error object from its flattened @@ -58,7 +56,7 @@ export function reconstructError(err: Error) { // This restores the old behavior of errors. This should be removed as soon // as all dependent codebases have been migrated to `is` accessors (ARSN-176). reconstructedErr[err.message] = true; - if (allowUnsafeErrComp){ + if (allowUnsafeErrComp) { // @ts-expect-error reconstructedErr.is = { [err.message]: true }; } @@ -66,4 +64,4 @@ export function reconstructError(err: Error) { reconstructedErr[k] = err[k]; }); return reconstructedErr; -}; +} diff --git a/package.json b/package.json index 262c59b3b..2d301ac13 100644 --- a/package.json +++ b/package.json @@ -72,6 +72,7 @@ "@types/utf8": "^3.0.3", "@types/xml2js": "^0.4.14", "eslint": "^9.37.0", + "eslint-config-prettier": "^10.1.8", "eslint-plugin-react": "^7.37.1", "globals": "^16.4.0", "jest": "^29.7.0", diff --git a/tests/unit/models/ReplicationConfiguration.spec.ts b/tests/unit/models/ReplicationConfiguration.spec.ts index 0dafeda54..7a3506a64 100644 --- a/tests/unit/models/ReplicationConfiguration.spec.ts +++ b/tests/unit/models/ReplicationConfiguration.spec.ts @@ -5,19 +5,19 @@ const { default: ReplicationConfiguration } = require('../../../lib/models/Repli const mockS3ServerConfig = { locationConstraints: { - 'ring': { + ring: { type: 'scality', objectId: 'ring', }, - 'awsbackend': { + awsbackend: { type: 'aws_s3', objectId: 'awsbackend', }, - 'gcpbackend': { + gcpbackend: { type: 'gcp', objectId: 'gcpbackend', }, - 'azurebackend': { + azurebackend: { type: 'azure', objectId: 'azurebackend', }, @@ -27,29 +27,35 @@ const mockS3ServerConfig = { isCold: true, }, }, - replicationEndpoints: [{ - site: 'ring', - default: true, - }, { - type: 'aws_s3', - site: 'awsbackend', - }, { - type: 'gcp', - site: 'gcpbackend', - }, { - type: 'azure', - site: 'azurebackend', - }, { - type: 'dmf', - site: 'dmf-1', - }], + replicationEndpoints: [ + { + site: 'ring', + default: true, + }, + { + type: 'aws_s3', + site: 'awsbackend', + }, + { + type: 'gcp', + site: 'gcpbackend', + }, + { + type: 'azure', + site: 'azurebackend', + }, + { + type: 'dmf', + site: 'dmf-1', + }, + ], }; -const TEST_ROLE = - 'arn:aws:iam::942839175607:role/crr-trust-role,arn:aws:iam::989181102323:role/crr-trust-role'; +const TEST_ROLE = 'arn:aws:iam::942839175607:role/crr-trust-role,arn:aws:iam::989181102323:role/crr-trust-role'; function getPreferredReadXMLConfig(hasPreferredRead) { - return ` + return ( + ` arn:aws:iam::root:role/s3-replication-role @@ -64,7 +70,8 @@ function getPreferredReadXMLConfig(hasPreferredRead) { -`; +` + ); } describe('ReplicationConfiguration.parseConfiguration()', () => { @@ -73,15 +80,22 @@ describe('ReplicationConfiguration.parseConfiguration()', () => { it('should succeed for a valid configuration without a prefix', () => { const repConfig = { Role: [TEST_ROLE], - Rule: [{ - Status: ['Enabled'], - Destination: [{ - Bucket: ['arn:aws:s3:::crr-dest'], - }], - }], + Rule: [ + { + Status: ['Enabled'], + Destination: [ + { + Bucket: ['arn:aws:s3:::crr-dest'], + }, + ], + }, + ], }; - const instance = new ReplicationConfiguration({ ReplicationConfiguration: repConfig }, - null, mockS3ServerConfig); + const instance = new ReplicationConfiguration( + { ReplicationConfiguration: repConfig }, + null, + mockS3ServerConfig, + ); const result = instance.parseConfiguration(); expect(result).toBeUndefined(); expect(instance.getRole()).toEqual(TEST_ROLE); @@ -111,8 +125,11 @@ describe('ReplicationConfiguration.parseConfiguration()', () => { }, ], }; - const instance = new ReplicationConfiguration({ ReplicationConfiguration: repConfig }, - null, mockS3ServerConfig); + const instance = new ReplicationConfiguration( + { ReplicationConfiguration: repConfig }, + null, + mockS3ServerConfig, + ); const result = instance.parseConfiguration(); expect(result).toBeUndefined(); expect(instance.getRole()).toEqual(TEST_ROLE); @@ -149,8 +166,11 @@ describe('ReplicationConfiguration.parseConfiguration()', () => { }, ], }; - const instance = new ReplicationConfiguration({ ReplicationConfiguration: repConfig }, - null, mockS3ServerConfig); + const instance = new ReplicationConfiguration( + { ReplicationConfiguration: repConfig }, + null, + mockS3ServerConfig, + ); const result = instance.parseConfiguration(); expect(result).toEqual(errors.InvalidRequest); }); @@ -158,16 +178,23 @@ describe('ReplicationConfiguration.parseConfiguration()', () => { it('should return InvalidArgument if a prefix is longer than 1024 characters', () => { const repConfig = { Role: [TEST_ROLE], - Rule: [{ - Prefix: [new Array(1025).fill('X').join('')], - Status: ['Enabled'], - Destination: [{ - Bucket: ['arn:aws:s3:::crr-dest'], - }], - }], + Rule: [ + { + Prefix: [new Array(1025).fill('X').join('')], + Status: ['Enabled'], + Destination: [ + { + Bucket: ['arn:aws:s3:::crr-dest'], + }, + ], + }, + ], }; - const instance = new ReplicationConfiguration({ ReplicationConfiguration: repConfig }, - null, mockS3ServerConfig); + const instance = new ReplicationConfiguration( + { ReplicationConfiguration: repConfig }, + null, + mockS3ServerConfig, + ); const result = instance.parseConfiguration(); expect(result).toEqual(errors.InvalidArgument); }); @@ -183,8 +210,11 @@ describe('ReplicationConfiguration.parseConfiguration()', () => { }, ], }; - const instance = new ReplicationConfiguration({ ReplicationConfiguration: repConfig }, - null, mockS3ServerConfig); + const instance = new ReplicationConfiguration( + { ReplicationConfiguration: repConfig }, + null, + mockS3ServerConfig, + ); const result = instance.parseConfiguration(); expect(result).toEqual(errors.MalformedXML); }); @@ -200,8 +230,11 @@ describe('ReplicationConfiguration.parseConfiguration()', () => { }, ], }; - const instance = new ReplicationConfiguration({ ReplicationConfiguration: repConfig }, - null, mockS3ServerConfig); + const instance = new ReplicationConfiguration( + { ReplicationConfiguration: repConfig }, + null, + mockS3ServerConfig, + ); const result = instance.parseConfiguration(); expect(result).toEqual(errors.MalformedXML); }); @@ -210,16 +243,23 @@ describe('ReplicationConfiguration.parseConfiguration()', () => { it('should succeed for a minimal valid configuration without storage class', () => { const repConfig = { Role: [TEST_ROLE], - Rule: [{ - Prefix: [''], - Status: ['Enabled'], - Destination: [{ - Bucket: ['arn:aws:s3:::crr-dest'], - }], - }], + Rule: [ + { + Prefix: [''], + Status: ['Enabled'], + Destination: [ + { + Bucket: ['arn:aws:s3:::crr-dest'], + }, + ], + }, + ], }; - const instance = new ReplicationConfiguration({ ReplicationConfiguration: repConfig }, - null, mockS3ServerConfig); + const instance = new ReplicationConfiguration( + { ReplicationConfiguration: repConfig }, + null, + mockS3ServerConfig, + ); const result = instance.parseConfiguration(); expect(result).toBeUndefined(); expect(instance.getRole()).toEqual(TEST_ROLE); @@ -235,18 +275,25 @@ describe('ReplicationConfiguration.parseConfiguration()', () => { it('should succeed for a minimal valid configuration including Rule ID and destination StorageClass', () => { const repConfig = { Role: [TEST_ROLE], - Rule: [{ - ID: ['RuleID'], - Prefix: [''], - Status: ['Enabled'], - Destination: [{ - Bucket: ['arn:aws:s3:::crr-dest'], - StorageClass: ['STANDARD'], - }], - }], + Rule: [ + { + ID: ['RuleID'], + Prefix: [''], + Status: ['Enabled'], + Destination: [ + { + Bucket: ['arn:aws:s3:::crr-dest'], + StorageClass: ['STANDARD'], + }, + ], + }, + ], }; - const instance = new ReplicationConfiguration({ ReplicationConfiguration: repConfig }, - null, mockS3ServerConfig); + const instance = new ReplicationConfiguration( + { ReplicationConfiguration: repConfig }, + null, + mockS3ServerConfig, + ); const result = instance.parseConfiguration(); expect(result).toBeUndefined(); expect(instance.getRules()).toEqual([ @@ -263,16 +310,23 @@ describe('ReplicationConfiguration.parseConfiguration()', () => { it('should return MalformedXML when config is missing a Role array', () => { const repConfig = { - Rule: [{ - Prefix: [''], - Status: ['Enabled'], - Destination: [{ - Bucket: ['arn:aws:s3:::crr-dest'], - }], - }], + Rule: [ + { + Prefix: [''], + Status: ['Enabled'], + Destination: [ + { + Bucket: ['arn:aws:s3:::crr-dest'], + }, + ], + }, + ], }; - const instance = new ReplicationConfiguration({ ReplicationConfiguration: repConfig }, - null, mockS3ServerConfig); + const instance = new ReplicationConfiguration( + { ReplicationConfiguration: repConfig }, + null, + mockS3ServerConfig, + ); const result = instance.parseConfiguration(); expect(result).toEqual(errors.MalformedXML); }); @@ -280,34 +334,47 @@ describe('ReplicationConfiguration.parseConfiguration()', () => { it('should return InvalidArgument when Scality destination has a single role', () => { const repConfig = { Role: ['arn:aws:iam::942839175607:role/crr-trust-role'], - Rule: [{ - Prefix: [''], - Status: ['Enabled'], - Destination: [{ - Bucket: ['arn:aws:s3:::crr-dest'], - }], - }], + Rule: [ + { + Prefix: [''], + Status: ['Enabled'], + Destination: [ + { + Bucket: ['arn:aws:s3:::crr-dest'], + }, + ], + }, + ], }; - const instance = new ReplicationConfiguration({ ReplicationConfiguration: repConfig }, - null, mockS3ServerConfig); + const instance = new ReplicationConfiguration( + { ReplicationConfiguration: repConfig }, + null, + mockS3ServerConfig, + ); const result = instance.parseConfiguration(); expect(result).toEqual(errors.InvalidArgument); }); - // eslint-disable-next-line max-len it('should return InvalidArgument when Scality destination has two comma-separated roles but one is invalid', () => { const repConfig = { Role: [`invalidarn:${TEST_ROLE}`], - Rule: [{ - Prefix: [''], - Status: ['Enabled'], - Destination: [{ - Bucket: ['arn:aws:s3:::crr-dest'], - }], - }], + Rule: [ + { + Prefix: [''], + Status: ['Enabled'], + Destination: [ + { + Bucket: ['arn:aws:s3:::crr-dest'], + }, + ], + }, + ], }; - const instance = new ReplicationConfiguration({ ReplicationConfiguration: repConfig }, - null, mockS3ServerConfig); + const instance = new ReplicationConfiguration( + { ReplicationConfiguration: repConfig }, + null, + mockS3ServerConfig, + ); const result = instance.parseConfiguration(); expect(result).toEqual(errors.InvalidArgument); }); @@ -317,8 +384,11 @@ describe('ReplicationConfiguration.parseConfiguration()', () => { Role: [TEST_ROLE], Rule: [], }; - const instance = new ReplicationConfiguration({ ReplicationConfiguration: repConfig }, - null, mockS3ServerConfig); + const instance = new ReplicationConfiguration( + { ReplicationConfiguration: repConfig }, + null, + mockS3ServerConfig, + ); const result = instance.parseConfiguration(); expect(result).toEqual(errors.MalformedXML); }); @@ -326,17 +396,24 @@ describe('ReplicationConfiguration.parseConfiguration()', () => { it('should return InvalidArgument if a Rule ID exceeds 255 characters', () => { const repConfig = { Role: [TEST_ROLE], - Rule: [{ - ID: [new Array(256).fill('X').join('')], - Prefix: [''], - Status: ['Enabled'], - Destination: [{ - Bucket: ['arn:aws:s3:::crr-dest'], - }], - }], + Rule: [ + { + ID: [new Array(256).fill('X').join('')], + Prefix: [''], + Status: ['Enabled'], + Destination: [ + { + Bucket: ['arn:aws:s3:::crr-dest'], + }, + ], + }, + ], }; - const instance = new ReplicationConfiguration({ ReplicationConfiguration: repConfig }, - null, mockS3ServerConfig); + const instance = new ReplicationConfiguration( + { ReplicationConfiguration: repConfig }, + null, + mockS3ServerConfig, + ); const result = instance.parseConfiguration(); expect(result).toEqual(errors.InvalidArgument); }); @@ -359,8 +436,11 @@ describe('ReplicationConfiguration.parseConfiguration()', () => { }, ], }; - const instance = new ReplicationConfiguration({ ReplicationConfiguration: repConfig }, - null, mockS3ServerConfig); + const instance = new ReplicationConfiguration( + { ReplicationConfiguration: repConfig }, + null, + mockS3ServerConfig, + ); const result = instance.parseConfiguration(); expect(result).toEqual(errors.InvalidRequest); }); @@ -368,14 +448,19 @@ describe('ReplicationConfiguration.parseConfiguration()', () => { it('should return MalformedXML when config has a rule with an invalid Status value', () => { const repConfig = { Role: [TEST_ROLE], - Rule: [{ - Prefix: [''], - Status: ['Invalid'], - Destination: [{ Bucket: ['arn:aws:s3:::crr-dest'] }], - }], + Rule: [ + { + Prefix: [''], + Status: ['Invalid'], + Destination: [{ Bucket: ['arn:aws:s3:::crr-dest'] }], + }, + ], }; - const instance = new ReplicationConfiguration({ ReplicationConfiguration: repConfig }, - null, mockS3ServerConfig); + const instance = new ReplicationConfiguration( + { ReplicationConfiguration: repConfig }, + null, + mockS3ServerConfig, + ); const result = instance.parseConfiguration(); expect(result).toEqual(errors.MalformedXML); }); @@ -383,17 +468,24 @@ describe('ReplicationConfiguration.parseConfiguration()', () => { it('should return MalformedXML when the provided storage class is invalid', () => { const repConfig = { Role: [TEST_ROLE], - Rule: [{ - Prefix: [''], - Status: ['Enabled'], - Destination: [{ - Bucket: ['arn:aws:s3:::crr-dest'], - StorageClass: ['INVALID'], - }], - }], + Rule: [ + { + Prefix: [''], + Status: ['Enabled'], + Destination: [ + { + Bucket: ['arn:aws:s3:::crr-dest'], + StorageClass: ['INVALID'], + }, + ], + }, + ], }; - const instance = new ReplicationConfiguration({ ReplicationConfiguration: repConfig }, - null, mockS3ServerConfig); + const instance = new ReplicationConfiguration( + { ReplicationConfiguration: repConfig }, + null, + mockS3ServerConfig, + ); const result = instance.parseConfiguration(); expect(result).toEqual(errors.MalformedXML); }); @@ -408,50 +500,63 @@ describe('ReplicationConfiguration.parseConfiguration()', () => { ID: [`rule${i}`], Prefix: [`prefix${i}/`], Status: ['Enabled'], - Destination: [{ - Bucket: ['arn:aws:s3:::crr-dest'], - }], + Destination: [ + { + Bucket: ['arn:aws:s3:::crr-dest'], + }, + ], }); - }; - const instance = new ReplicationConfiguration({ ReplicationConfiguration: repConfig }, - null, mockS3ServerConfig); + } + const instance = new ReplicationConfiguration( + { ReplicationConfiguration: repConfig }, + null, + mockS3ServerConfig, + ); const result = instance.parseConfiguration(); expect(result).toEqual(errors.InvalidRequest); }); - // eslint-disable-next-line max-len it('should return InvalidRequest if StorageClass not provided and cloudserver config has no replication endpoint', () => { const repConfig = { Role: [TEST_ROLE], - Rule: [{ - Prefix: [''], - Status: ['Enabled'], - Destination: [{ - Bucket: ['arn:aws:s3:::crr-dest'], - }], - }], + Rule: [ + { + Prefix: [''], + Status: ['Enabled'], + Destination: [ + { + Bucket: ['arn:aws:s3:::crr-dest'], + }, + ], + }, + ], }; - const instance = new ReplicationConfiguration({ ReplicationConfiguration: repConfig }, - null, { replicationEndpoints: [] }); + const instance = new ReplicationConfiguration({ ReplicationConfiguration: repConfig }, null, { + replicationEndpoints: [], + }); const result = instance.parseConfiguration(); expect(result).toEqual(errors.InvalidRequest); }); - // eslint-disable-next-line max-len it('should return InvalidRequest if StorageClass provided and cloudserver config has no replication endpoint', () => { const repConfig = { Role: [TEST_ROLE], - Rule: [{ - Prefix: [''], - Status: ['Enabled'], - Destination: [{ - Bucket: ['arn:aws:s3:::crr-dest'], - StorageClass: ['STANDARD'], - }], - }], + Rule: [ + { + Prefix: [''], + Status: ['Enabled'], + Destination: [ + { + Bucket: ['arn:aws:s3:::crr-dest'], + StorageClass: ['STANDARD'], + }, + ], + }, + ], }; - const instance = new ReplicationConfiguration({ ReplicationConfiguration: repConfig }, - null, { replicationEndpoints: [] }); + const instance = new ReplicationConfiguration({ ReplicationConfiguration: repConfig }, null, { + replicationEndpoints: [], + }); const result = instance.parseConfiguration(); expect(result).toEqual(errors.InvalidRequest); }); @@ -460,8 +565,7 @@ describe('ReplicationConfiguration.parseConfiguration()', () => { const repConfigXML = getPreferredReadXMLConfig(false); parseString(repConfigXML, (err, parsedXml) => { expect(err).toBeNull(); - const repConf = new ReplicationConfiguration( - parsedXml, null, mockS3ServerConfig); + const repConf = new ReplicationConfiguration(parsedXml, null, mockS3ServerConfig); const repConfErr = repConf.parseConfiguration(); expect(repConfErr).toBeUndefined(); expect(repConf.getPreferredReadLocation()).toBeNull(); @@ -473,8 +577,7 @@ describe('ReplicationConfiguration.parseConfiguration()', () => { const repConfigXML = getPreferredReadXMLConfig(true); parseString(repConfigXML, (err, parsedXml) => { expect(err).toBeNull(); - const repConf = new ReplicationConfiguration( - parsedXml, null, mockS3ServerConfig); + const repConf = new ReplicationConfiguration(parsedXml, null, mockS3ServerConfig); const repConfErr = repConf.parseConfiguration(); expect(repConfErr).toBeUndefined(); expect(repConf.getPreferredReadLocation()).toEqual('gcpbackend'); @@ -500,8 +603,7 @@ describe('ReplicationConfiguration.parseConfiguration()', () => { parseString(repConfigXML, (err, parsedXml) => { expect(err).toBeNull(); - const repConf = new ReplicationConfiguration( - parsedXml, null, mockS3ServerConfig); + const repConf = new ReplicationConfiguration(parsedXml, null, mockS3ServerConfig); const repConfErr = repConf.parseConfiguration(); expect(repConfErr).toEqual(errors.MalformedXML); done(); diff --git a/yarn.lock b/yarn.lock index fe243e730..bd794b473 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4594,6 +4594,11 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== +eslint-config-prettier@^10.1.8: + version "10.1.8" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz#15734ce4af8c2778cc32f0b01b37b0b5cd1ecb97" + integrity sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w== + eslint-plugin-react@^7.37.1: version "7.37.5" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz#2975511472bdda1b272b34d779335c9b0e877065"