Skip to content

Commit 8499bab

Browse files
authored
Merge pull request #4697 from cloud-gov/chore-reenable-sonarjs-lint-rules-4652
chore: Reenable sonarjs linting rules #4652
2 parents a0ce9e7 + 7fbea52 commit 8499bab

File tree

19 files changed

+194
-677
lines changed

19 files changed

+194
-677
lines changed

api/controllers/build-task.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,14 @@ module.exports = wrapHandlers({
6060
update: async (req, res) => {
6161
const { params, body } = req;
6262
const { build_task_id: buildTaskId, token } = params;
63-
const { Error, Success } = BuildTask.Statuses;
63+
const { Error: ErrorStatus, Success } = BuildTask.Statuses;
6464

6565
const task = await BuildTask.findByPk(buildTaskId);
6666

6767
if (!task) {
6868
return res.notFound();
6969
}
70-
if (task.token !== token || [Error, Success].includes(task.status)) {
70+
if (task.token !== token || [ErrorStatus, Success].includes(task.status)) {
7171
return res.forbidden();
7272
}
7373

api/controllers/site.js

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
const _ = require('underscore');
21
const authorizer = require('../authorizers/site');
32
const SiteCreator = require('../services/SiteCreator');
43
const SiteDestroyer = require('../services/SiteDestroyer');

api/models/build.js

+1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ const beforeValidate = (build) => {
9292
};
9393

9494
const sanitizeCompleteJobErrorMessage = (message) =>
95+
// eslint-disable-next-line sonarjs/slow-regex
9596
message.replace(/\/\/(.*)@github/g, '//[token_redacted]@github');
9697

9798
async function beforeCreate(build) {

api/services/SiteBuildQueue.js

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const siteConfig = (build, siteBranchConfigs = []) => {
2727
const baseURLForBuild = (build) => {
2828
const link = buildUrl(build, build.Site);
2929
const urlObject = new URL(link);
30+
// eslint-disable-next-line sonarjs/slow-regex
3031
return urlObject.pathname.replace(/(\/)+$/, '');
3132
};
3233

@@ -85,6 +86,7 @@ const buildContainerEnvironment = async (build) => {
8586

8687
const SiteBuildQueue = {};
8788

89+
// eslint-disable-next-line sonarjs/no-invariant-returns
8890
SiteBuildQueue.setupBucket = async (build, buildCount) => {
8991
if (buildCount > 1) return true;
9092

api/utils/build.js

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ function buildUrl(build, site) {
3636

3737
const domainName = domain.names.split(',')[0];
3838

39+
// eslint-disable-next-line sonarjs/slow-regex
3940
return `https://${domainName.replace(/\/+$/, '')}/`;
4041
}
4142

api/utils/index.js

+4
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ function generateS3ServiceName(owner, repository) {
5555
const characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
5656
const charactersLength = characters.length;
5757
for (let i = 0; i < 6; i += 1) {
58+
// eslint-disable-next-line sonarjs/pseudo-random
5859
result += characters.charAt(Math.floor(Math.random() * charactersLength));
5960
}
6061
return result;
@@ -69,8 +70,10 @@ function toSubdomainPart(str) {
6970
// replace all invalid chars with '-'
7071
.replace(/[^a-zA-Z0-9-]+/g, '-')
7172
// remove leading and trailing '-'
73+
// eslint-disable-next-line
7274
.replace(/(^[-]+|[-]+$)/g, '')
7375
// replace multiple sequential '-' with a single '-'
76+
// eslint-disable-next-line sonarjs/single-char-in-character-classes
7477
.replace(/[-]{2,}/g, '-')
7578
.substring(0, 62)
7679
.toLowerCase();
@@ -79,6 +82,7 @@ function toSubdomainPart(str) {
7982
if (subdomain.length < 2) {
8083
// If we generate parts, make it longer
8184
while (subdomain.length < 5) {
85+
// eslint-disable-next-line sonarjs/pseudo-random
8286
subdomain += characters[Math.floor(Math.random() * Math.floor(characters.length))];
8387
}
8488
}

api/utils/site.js

+2
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,15 @@ function siteViewLink(site, deployment = 'site') {
2323
} else {
2424
link = `${siteViewDomain(site)}${path(site, deployment)}`;
2525
}
26+
// eslint-disable-next-line sonarjs/slow-regex
2627
return `${link.replace(/\/+$/, '')}/`;
2728
}
2829

2930
const hideBasicAuthPassword = ({ username, password }) => {
3031
if (password && password.length) {
3132
return {
3233
username,
34+
// eslint-disable-next-line sonarjs/no-hardcoded-passwords
3335
password: '**********',
3436
};
3537
}

api/utils/validators.js

+1-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const yaml = require('js-yaml');
22
const validator = require('validator');
33

4+
// eslint-disable-next-line sonarjs/slow-regex
45
const branchRegex = /^[\w.]+(?:[/-]*[\w.])*$/;
56
const githubUsernameRegex = /^[^-][a-zA-Z-]+$/;
67
const shaRegex = /^[a-f0-9]{40}$/;
@@ -126,10 +127,6 @@ function isValidSubdomain(value) {
126127
}
127128
}
128129

129-
const validBasicAuthUsername = (s) => /^(?!.*[:])(?=.*[a-zA-Z0-9]).{4,255}$/.test(s);
130-
131-
const validBasicAuthPassword = (s) => /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,255}$/.test(s);
132-
133130
const isDelimitedFQDN = (str) => {
134131
const msg = 'must be a comma-separated list of valid fully qualified domain names';
135132
const isValid = str.split(',').every((s) => validator.isFQDN(s));
@@ -150,8 +147,6 @@ module.exports = {
150147
isEmptyOrBranch,
151148
isEmptyOrUrl,
152149
ValidationError,
153-
validBasicAuthUsername,
154-
validBasicAuthPassword,
155150
isValidSubdomain,
156151
isDelimitedFQDN,
157152
};

eslint.config.mjs

+10-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import eslintConfigPrettier from 'eslint-config-prettier';
77
import testingLibrary from 'eslint-plugin-testing-library';
88
import jsxA11y from 'eslint-plugin-jsx-a11y';
99
import importPlugin from 'eslint-plugin-import';
10-
// import sonarjsPlugin from 'eslint-plugin-sonarjs';
10+
import sonarjs from 'eslint-plugin-sonarjs';
1111

1212
export default [
1313
{
@@ -87,12 +87,19 @@ export default [
8787
ecmaVersion: 'latest',
8888
},
8989
},
90+
{
91+
ignores: ['**/*.test.*', 'test/**/*', 'scripts/**/*', 'e2e/**/*', 'config/**/*'],
92+
...sonarjs.configs.recommended,
93+
rules: {
94+
...sonarjs.configs.recommended.rules,
95+
'sonarjs/cognitive-complexity': ['error', 16],
96+
'sonarjs/todo-tag': 'off',
97+
},
98+
},
9099
pluginReact.configs.flat['jsx-runtime'],
91100
pluginReact.configs.flat.recommended,
92101
jsxA11y.flatConfigs.recommended,
93102
pluginJs.configs.recommended,
94-
// ignore for a future PR to minimize noise
95-
// sonarjsPlugin.configs.recommended,
96103
eslintConfigPrettier,
97104
{
98105
settings: {

frontend/pages/Error.jsx frontend/pages/ErrorMessage.jsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from 'react';
22

3-
const Error = () => (
3+
const ErrorMessage = () => (
44
<div className="grid-container padding-y-6">
55
<h1>An Unexpected Error Occurred</h1>
66
<p>
@@ -11,4 +11,4 @@ const Error = () => (
1111
</div>
1212
);
1313

14-
export default Error;
14+
export default ErrorMessage;

frontend/pages/sites/$siteId/settings/ReportConfigs.jsx

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ function ReportConfigs({ siteId: id }) {
5151
function addNewRule(index) {
5252
// start with pseudo-random ids to avoid key collisions
5353
// default to the first type
54+
// eslint-disable-next-line sonarjs/pseudo-random
5455
const ruleUid = `temp-${Math.random().toString(36).slice(2)}`;
5556
const newRule = {
5657
id: ruleUid,

frontend/reducers/builds.js

+7-8
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,12 @@ const initialState = {
66
};
77

88
export default function builds(state = initialState, action) {
9-
switch (action.type) {
10-
case buildRestartedType:
11-
return {
12-
isLoading: false,
13-
data: [action.build, ...state.data],
14-
};
15-
default:
16-
return state;
9+
if (action.type === buildRestartedType) {
10+
return {
11+
isLoading: false,
12+
data: [action.build, ...state.data],
13+
};
1714
}
15+
16+
return state;
1817
}

frontend/routes.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import EditCustomDomain from '@pages/sites/$siteId/custom-domains/$domainId/edit
1919
import Reports from '@pages/sites/$siteId/reports';
2020
import Settings from '@pages/settings';
2121
import NotFound from '@pages/NotFound';
22-
import Error from '@pages/Error';
22+
import ErrorMessage from '@pages/ErrorMessage';
2323

2424
import siteActions from './actions/siteActions';
2525
import userActions from './actions/userActions';
@@ -28,7 +28,7 @@ import organizationActions from './actions/organizationActions';
2828
const { NODE_ENV } = process.env;
2929
let ErrorElement = null;
3030
if (NODE_ENV !== 'development') {
31-
ErrorElement = <Error />;
31+
ErrorElement = <ErrorMessage />;
3232
}
3333

3434
const fetchInitialData = () => {

frontend/util/index.js

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
export function getSafeRepoName(name) {
2-
return name
3-
.replace(/[^\w.]+/g, '-') // replace non-alphabetic and periods with hyphens
4-
.replace(/^-+/g, '') // remove starting hyphens
5-
.replace(/-+$/g, ''); // remove ending hyphens
2+
return (
3+
name
4+
.replace(/[^\w.]+/g, '-') // replace non-alphabetic and periods with hyphens
5+
.replace(/^-+/g, '') // remove starting hyphens
6+
// eslint-disable-next-line sonarjs/slow-regex
7+
.replace(/-+$/g, '')
8+
); // remove ending hyphens
69
}
710

811
export function groupLogs(logs) {

frontend/util/validators.js

+3-19
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,13 @@ const validAddRepoSiteForm = ({ repoOrganizationId, repoUrl }, { organizations }
1515
return errors;
1616
};
1717

18+
// eslint-disable-next-line
1819
const validBranchName = (s) => /^[\w._]+(?:[/-]*[\w._])*$/.test(s);
1920

20-
const validBasicAuthUsername = (s) =>
21-
/^(?!.*[:])(?=.*[a-zA-Z0-9]).{4,255}$/.test(s)
22-
? undefined
23-
: 'Value is required and must be at least 4 characters. Semicolons are not allowed.';
24-
25-
const validBasicAuthPassword = (s) =>
26-
/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,255}$/.test(s)
27-
? undefined
28-
: // eslint-disable-next-line max-len
29-
'Value is required and must be at least 4 characters. At least 1 uppercase, 1 lowercase and 1 number is required';
30-
3121
function isValidYaml(yamlString) {
3222
try {
3323
load(yamlString);
34-
} catch (_) {
24+
} catch {
3525
// for Sequelize validators, we need to throw an error
3626
// on invalid values
3727
throw new Error('input is not valid YAML');
@@ -40,10 +30,4 @@ function isValidYaml(yamlString) {
4030
return true;
4131
}
4232

43-
export {
44-
isValidYaml,
45-
validAddRepoSiteForm,
46-
validBranchName,
47-
validBasicAuthUsername,
48-
validBasicAuthPassword,
49-
};
33+
export { isValidYaml, validAddRepoSiteForm, validBranchName };

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@
162162
"eslint-plugin-jsx-a11y": "^6.8.0",
163163
"eslint-plugin-mocha": "^10.5.0",
164164
"eslint-plugin-react": "^7.37.2",
165-
"eslint-plugin-sonarjs": "^2.0.4",
165+
"eslint-plugin-sonarjs": "^3.0.1",
166166
"eslint-plugin-svelte": "^2.46.0",
167167
"eslint-plugin-testing-library": "^6.4.0",
168168
"fetch-mock": "^12.1.0",

test/api/unit/utils/validators.test.js

-50
Original file line numberDiff line numberDiff line change
@@ -80,54 +80,4 @@ describe('validators', () => {
8080
);
8181
});
8282
});
83-
84-
describe('.validBasicAuthUsername', () => {
85-
it('accepts valid username', () => {
86-
expect(validators.validBasicAuthUsername('username1')).to.be.true;
87-
});
88-
89-
it('accepts valid username with symbols that arenot semicolons', () => {
90-
expect(validators.validBasicAuthUsername('username1!@#$%^&*()-_+=<>?,./~`{}[]|\\'))
91-
.to.be.true;
92-
});
93-
94-
it('must contain at least 1 alphanumeric char', () => {
95-
expect(validators.validBasicAuthUsername('****')).to.be.false;
96-
});
97-
98-
it('must be 4 characters', () => {
99-
expect(validators.validBasicAuthUsername('use')).to.be.false;
100-
});
101-
102-
it('colons are not allowed in username', () => {
103-
expect(validators.validBasicAuthUsername('user:name1')).to.be.false;
104-
});
105-
});
106-
107-
describe('.validBasicAuthPassword', () => {
108-
it('at least 1 uppercase, 1 lowercase and one number required', () => {
109-
expect(validators.validBasicAuthPassword('paSsw0rd')).to.be.true;
110-
});
111-
112-
it('at least 1 uppercase, 1 lowercase and one number required w/ symbols', () => {
113-
expect(validators.validBasicAuthPassword('paSsw0rd!@#$%^&*()-_+=<>?,./~`{}[]|\\'))
114-
.to.be.true;
115-
});
116-
117-
it('at least 1 uppercase char required', () => {
118-
expect(validators.validBasicAuthPassword('passw0rd')).to.be.false;
119-
});
120-
121-
it('at leaset 1 lowercase char required', () => {
122-
expect(validators.validBasicAuthPassword('PASSW0RD')).to.be.false;
123-
});
124-
125-
it('at least one number required', () => {
126-
expect(validators.validBasicAuthPassword('paSsword')).to.be.false;
127-
});
128-
129-
it('must be 4 characters', () => {
130-
expect(validators.validBasicAuthPassword('Pa5')).to.be.false;
131-
});
132-
});
13383
});

test/frontend/util/validators.test.js

-50
Original file line numberDiff line numberDiff line change
@@ -65,53 +65,3 @@ describe('validAddRepoSiteForm', () => {
6565
expect(expected.repoOrganizationId).to.equal('Please select an organization');
6666
});
6767
});
68-
69-
describe('validBasicAuthUsername', () => {
70-
it('accepts valid username', () => {
71-
expect(validators.validBasicAuthUsername('username1')).to.be.undefined;
72-
});
73-
74-
it('accepts valid username with symbols that arenot semicolons', () => {
75-
expect(validators.validBasicAuthUsername('username1!@#$%^&*()-_+=<>?,./~`{}[]|\\')).to
76-
.be.undefined;
77-
});
78-
79-
it('must contain at least 1 alphanumeric char', () => {
80-
expect(validators.validBasicAuthUsername('****')).to.not.be.undefined;
81-
});
82-
83-
it('must be 4 characters', () => {
84-
expect(validators.validBasicAuthUsername('use')).to.not.be.undefined;
85-
});
86-
87-
it('colons are not allowed in username', () => {
88-
expect(validators.validBasicAuthUsername('user:name1')).to.not.be.undefined;
89-
});
90-
});
91-
92-
describe('validBasicAuthPassword', () => {
93-
it('at least 1 uppercase, 1 lowercase and one number required', () => {
94-
expect(validators.validBasicAuthPassword('paSsw0rd')).to.be.undefined;
95-
});
96-
97-
it('at least 1 uppercase, 1 lowercase and one number required w/ symbols', () => {
98-
expect(validators.validBasicAuthPassword('paSsw0rd!@#$%^&*()-_+=<>?,./~`{}[]|\\')).to
99-
.be.undefined;
100-
});
101-
102-
it('at least 1 uppercase char required', () => {
103-
expect(validators.validBasicAuthPassword('passw0rd')).to.not.be.undefined;
104-
});
105-
106-
it('at leaset 1 lowercase char required', () => {
107-
expect(validators.validBasicAuthPassword('PASSW0RD')).to.not.be.undefined;
108-
});
109-
110-
it('at least one number required', () => {
111-
expect(validators.validBasicAuthPassword('paSsword')).to.not.be.undefined;
112-
});
113-
114-
it('must be 4 characters', () => {
115-
expect(validators.validBasicAuthPassword('Pa5')).to.not.be.undefined;
116-
});
117-
});

0 commit comments

Comments
 (0)