@zimbra/eslint-config 2.1.1-main.96dc8a5.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -45,8 +45,15 @@ feature-branch: &feature-branch
45
45
  filters:
46
46
  branches:
47
47
  ignore:
48
+ - main
48
49
  - /(custom_)?release\/.*/
49
50
 
51
+ main-branch: &main-branch
52
+ filters:
53
+ branches:
54
+ only:
55
+ - main
56
+
50
57
  ############################################################################
51
58
  # COMMANDS
52
59
  ############################################################################
@@ -126,7 +133,7 @@ jobs:
126
133
  workflows:
127
134
  version: 2
128
135
 
129
- lint-and-publish:
136
+ commit-workflow:
130
137
  jobs:
131
138
  - lint:
132
139
  <<: *feature-branch
@@ -141,4 +148,15 @@ workflows:
141
148
  <<: *feature-branch
142
149
  <<: *env-context
143
150
  requires:
144
- - publish-approval
151
+ - publish-approval
152
+
153
+ main-branch-workflow:
154
+ jobs:
155
+ - lint:
156
+ <<: *main-branch
157
+
158
+ - publish:
159
+ <<: *main-branch
160
+ <<: *env-context
161
+ requires:
162
+ - lint
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zimbra/eslint-config",
3
- "version": "2.1.1-main.96dc8a5.0",
3
+ "version": "2.2.0",
4
4
  "type": "module",
5
5
  "description": "ESLint configuration for Zimbra javascript projects.",
6
6
  "main": "src/index.js",
@@ -1,5 +1,6 @@
1
1
  import customRules from '../rules/custom-rules/custom-rules.js';
2
2
  import noDirectMemoize from '../rules/custom-rules/no-direct-memoize.js';
3
+ import noUnsafeWindowOpen from '../rules/custom-rules/no-unsafe-window-open.js';
3
4
 
4
5
  export default {
5
6
  files: ['**/*.{js,jsx,mjs,cjs}'],
@@ -7,7 +8,8 @@ export default {
7
8
  plugins: {
8
9
  custom: {
9
10
  rules: {
10
- 'no-direct-memoize': noDirectMemoize
11
+ 'no-direct-memoize': noDirectMemoize,
12
+ 'no-unsafe-window-open': noUnsafeWindowOpen
11
13
  }
12
14
  }
13
15
  },
@@ -1,3 +1,4 @@
1
1
  export default {
2
- 'custom/no-direct-memoize': 'error'
2
+ 'custom/no-direct-memoize': 'error',
3
+ 'custom/no-unsafe-window-open': 'error'
3
4
  };
@@ -0,0 +1,70 @@
1
+ export default {
2
+ meta: {
3
+ type: 'problem',
4
+ docs: {
5
+ description: "Require 'noopener' in window.open() when target is '_blank'",
6
+ recommended: true
7
+ },
8
+ fixable: null,
9
+ messages: {
10
+ requireNoopener:
11
+ "Security risk: open() with '_blank' must include 'noopener' in the 3rd argument (e.g. 'noopener,noreferrer')."
12
+ },
13
+ schema: []
14
+ },
15
+
16
+ create(context) {
17
+ return {
18
+ CallExpression(node) {
19
+ const isWindowOpen =
20
+ node.callee.type === 'MemberExpression' &&
21
+ node.callee.object.name === 'window' &&
22
+ node.callee.property.name === 'open';
23
+
24
+ const isBareOpen = node.callee.type === 'Identifier' && node.callee.name === 'open';
25
+
26
+ if (!isWindowOpen && !isBareOpen) {
27
+ return;
28
+ }
29
+
30
+ const targetArg = node.arguments[1];
31
+ let isBlank = false;
32
+
33
+ if (!targetArg) {
34
+ isBlank = true;
35
+ } else if (targetArg.type === 'Literal' && typeof targetArg.value === 'string') {
36
+ if (targetArg.value.toLowerCase() === '_blank') {
37
+ isBlank = true;
38
+ }
39
+ } else {
40
+ // Skips genuinely dynamic values to avoid false positives
41
+ return;
42
+ }
43
+
44
+ if (!isBlank) {
45
+ return;
46
+ }
47
+
48
+ const featuresArg = node.arguments[2];
49
+
50
+ if (!featuresArg) {
51
+ context.report({
52
+ node,
53
+ messageId: 'requireNoopener'
54
+ });
55
+ return;
56
+ }
57
+
58
+ if (featuresArg.type === 'Literal' && typeof featuresArg.value === 'string') {
59
+ const features = featuresArg.value.split(',').map(s => s.trim().toLowerCase());
60
+ if (!features.includes('noopener')) {
61
+ context.report({
62
+ node,
63
+ messageId: 'requireNoopener'
64
+ });
65
+ }
66
+ }
67
+ }
68
+ };
69
+ }
70
+ };
@@ -16,6 +16,7 @@ export const reactRules = {
16
16
 
17
17
  // Security related rules
18
18
  'react/no-danger': 'error',
19
+ 'react/jsx-no-target-blank': ['error', { allowReferrer: true }],
19
20
 
20
21
  // TODO: Enable these rules once the codebase is updated to follow best practices
21
22
  'react/react-in-jsx-scope': 'off',