@eslint-sh/eslint-plugin 0.6.0 → 0.8.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.
- package/README.md +19 -8
- package/dist/command-harvest/builtins/bash.d.ts +1 -1
- package/dist/command-harvest/builtins/bash.js +1 -1
- package/dist/command-harvest/builtins/bats.d.ts +2 -0
- package/dist/command-harvest/builtins/bats.js +3 -0
- package/dist/command-harvest/wrapper-table.d.ts +3 -19
- package/dist/command-harvest/wrapper-table.js +8 -38
- package/dist/configs/bash-3-2.d.ts +7 -6
- package/dist/configs/bash-3-2.js +5 -3
- package/dist/configs/posix-portable.d.ts +1 -1
- package/dist/configs/posix-portable.js +1 -0
- package/dist/declaration-conventions/read-declared-commands.d.ts +2 -2
- package/dist/declaration-conventions/read-declared-commands.js +2 -2
- package/dist/eslint-plugin-syntax.d.ts +4 -0
- package/dist/eslint-plugin.d.ts +86 -40
- package/dist/index.d.ts +5 -2
- package/dist/index.js +4 -2
- package/dist/language/shell-language-options.d.ts +18 -15
- package/dist/language/shell-language-options.js +33 -26
- package/dist/language/shell-language.d.ts +10 -9
- package/dist/language/shell-language.js +18 -35
- package/dist/language/shell-source-code.d.ts +17 -9
- package/dist/language/shell-source-code.js +53 -12
- package/dist/rules/bash-variable-semantics.d.ts +22 -0
- package/dist/rules/bash-variable-semantics.js +41 -0
- package/dist/rules/compat/create-compat-rule.js +1 -1
- package/dist/rules/compat/declaration-options.d.ts +2 -2
- package/dist/rules/compat/declaration-options.js +5 -2
- package/dist/rules/compat/no-append-all-redirect.js +1 -1
- package/dist/rules/compat/no-associative-arrays.js +2 -2
- package/dist/rules/compat/no-brace-sequence-padding-step.d.ts +15 -0
- package/dist/rules/compat/no-brace-sequence-padding-step.js +287 -0
- package/dist/rules/compat/no-case-attributes.js +3 -3
- package/dist/rules/compat/no-case-fallthrough.js +2 -2
- package/dist/rules/compat/no-case-modification.js +2 -2
- package/dist/rules/compat/no-coproc.js +1 -1
- package/dist/rules/compat/no-declare-g.js +3 -3
- package/dist/rules/compat/no-double-bracket.js +2 -2
- package/dist/rules/compat/no-epoch-variables.js +2 -2
- package/dist/rules/compat/no-fd-variable.js +1 -1
- package/dist/rules/compat/no-globstar.js +1 -1
- package/dist/rules/compat/no-lastpipe-semantics.js +2 -2
- package/dist/rules/compat/no-let.js +2 -1
- package/dist/rules/compat/no-mapfile.js +4 -2
- package/dist/rules/compat/no-nameref.js +3 -3
- package/dist/rules/compat/no-negative-array-index.js +39 -9
- package/dist/rules/compat/no-nounset-empty-array.js +15 -4
- package/dist/rules/compat/no-parameter-transformation.js +2 -2
- package/dist/rules/compat/no-pipe-all.js +1 -1
- package/dist/rules/compat/no-printf-time-format.js +4 -2
- package/dist/rules/compat/no-source.js +2 -1
- package/dist/rules/compat/no-test-v.js +4 -2
- package/dist/rules/compat/no-unicode-escape.js +2 -2
- package/dist/rules/compat/no-wait-n.js +4 -2
- package/dist/rules/compat/nounset-array-proof.d.ts +8 -0
- package/dist/rules/compat/nounset-array-proof.js +563 -0
- package/dist/rules/compat/posix-absent-command.d.ts +7 -8
- package/dist/rules/compat/posix-absent-command.js +17 -15
- package/dist/rules/compat/shopt-options.js +3 -1
- package/dist/rules/compat/version-gates.d.ts +10 -10
- package/dist/rules/compat/version-gates.js +21 -13
- package/dist/rules/create-wrapper-rule.js +12 -7
- package/dist/rules/index.js +2 -0
- package/dist/rules/no-dynamic-invocation.d.ts +0 -8
- package/dist/rules/no-dynamic-invocation.js +7 -15
- package/dist/rules/no-eval.js +3 -1
- package/dist/rules/no-masked-exit-status.js +15 -8
- package/dist/rules/no-secret-env-reads.d.ts +4 -3
- package/dist/rules/no-secret-env-reads.js +37 -14
- package/dist/rules/no-secret-flags.d.ts +2 -1
- package/dist/rules/no-secret-flags.js +7 -8
- package/dist/rules/no-unchecked-cd.js +3 -1
- package/dist/rules/no-undeclared-commands.d.ts +1 -15
- package/dist/rules/no-undeclared-commands.js +3 -15
- package/dist/rules/no-unused-declarations.d.ts +1 -18
- package/dist/rules/no-unused-declarations.js +9 -34
- package/dist/rules/prefer-local.js +4 -3
- package/dist/rules/quote-expansions.js +3 -28
- package/dist/rules/require-network-wrapper.d.ts +2 -17
- package/dist/rules/require-network-wrapper.js +33 -4
- package/dist/rules/require-tty-guard.js +30 -1
- package/dist/rules/resolve-declaration-convention.d.ts +5 -6
- package/dist/rules/resolve-declaration-convention.js +5 -6
- package/dist/rules/resolve-network-wrapper.d.ts +19 -0
- package/dist/rules/resolve-network-wrapper.js +57 -26
- package/dist/rules/resolve-transparent-wrappers.d.ts +43 -0
- package/dist/rules/resolve-transparent-wrappers.js +98 -0
- package/dist/rules/set-options.d.ts +2 -1
- package/dist/rules/set-options.js +17 -5
- package/dist/rules/shebang-interpreter.js +4 -2
- package/dist/rules/transparent-wrappers.d.ts +4 -3
- package/dist/rules/transparent-wrappers.js +5 -4
- package/dist/rules/user-pattern.d.ts +5 -3
- package/dist/rules/user-pattern.js +6 -4
- package/dist/syntax/index.d.ts +4 -0
- package/dist/syntax/index.js +4 -0
- package/docs/compat.md +90 -34
- package/docs/custom-rule-tutorial.md +9 -3
- package/docs/examples/no-listed-commands-rule.ts +2 -2
- package/docs/rules/README.md +38 -5
- package/docs/rules/_template.md +2 -2
- package/docs/rules/compat/no-append-all-redirect.md +12 -12
- package/docs/rules/compat/no-associative-arrays.md +14 -14
- package/docs/rules/compat/no-brace-sequence-padding-step.md +90 -0
- package/docs/rules/compat/no-case-attributes.md +13 -13
- package/docs/rules/compat/no-case-fallthrough.md +12 -12
- package/docs/rules/compat/no-case-modification.md +11 -11
- package/docs/rules/compat/no-coproc.md +13 -13
- package/docs/rules/compat/no-declare-g.md +13 -13
- package/docs/rules/compat/no-double-bracket.md +2 -2
- package/docs/rules/compat/no-epoch-variables.md +13 -13
- package/docs/rules/compat/no-fd-variable.md +12 -12
- package/docs/rules/compat/no-globstar.md +13 -13
- package/docs/rules/compat/no-lastpipe-semantics.md +13 -13
- package/docs/rules/compat/no-let.md +2 -2
- package/docs/rules/compat/no-mapfile.md +16 -16
- package/docs/rules/compat/no-nameref.md +13 -13
- package/docs/rules/compat/no-negative-array-index.md +14 -14
- package/docs/rules/compat/no-nounset-empty-array.md +72 -17
- package/docs/rules/compat/no-parameter-transformation.md +19 -19
- package/docs/rules/compat/no-pipe-all.md +13 -13
- package/docs/rules/compat/no-printf-time-format.md +13 -13
- package/docs/rules/compat/no-source.md +2 -2
- package/docs/rules/compat/no-test-v.md +12 -12
- package/docs/rules/compat/no-unicode-escape.md +13 -13
- package/docs/rules/compat/no-wait-n.md +13 -13
- package/docs/rules/no-dynamic-invocation.md +17 -12
- package/docs/rules/no-eval.md +6 -1
- package/docs/rules/no-masked-exit-status.md +4 -0
- package/docs/rules/no-secret-env-reads.md +34 -3
- package/docs/rules/no-secret-flags.md +19 -2
- package/docs/rules/no-unchecked-cd.md +9 -2
- package/docs/rules/no-undeclared-commands.md +16 -15
- package/docs/rules/no-unused-declarations.md +17 -20
- package/docs/rules/prefer-local.md +20 -2
- package/docs/rules/quote-expansions.md +8 -5
- package/docs/rules/require-network-wrapper.md +22 -17
- package/docs/rules/require-shebang.md +10 -4
- package/docs/rules/require-strict-mode.md +6 -0
- package/docs/rules/require-tty-guard.md +4 -1
- package/docs/shellcheck.md +10 -5
- package/docs/transparent-wrappers.md +97 -0
- package/docs/untrusted-code.md +440 -0
- package/docs/wrapper-rules.md +9 -0
- package/package.json +2 -2
- package/dist/language/end-of-input-marker.d.ts +0 -29
- package/dist/language/end-of-input-marker.js +0 -88
|
@@ -24,19 +24,19 @@ The portable alternative is `[ -n "${name+set}" ]`. `${name+set}` expands to `se
|
|
|
24
24
|
This is a version-compat rule. Whether it reports depends only on `languageOptions`, as
|
|
25
25
|
described in [version compatibility](../../compat.md):
|
|
26
26
|
|
|
27
|
-
- `
|
|
28
|
-
- `dialect: "bash"` (the default) or `"bats"`: reports when `
|
|
29
|
-
- `dialect: "posix"`: reports `test -v` and `[ -v ]`
|
|
27
|
+
- `minBashVersion` unset: no Bash version constraint, so no report under `bash` or `bats`.
|
|
28
|
+
- `dialect: "bash"` (the default) or `"bats"`: reports when `minBashVersion` is older than `4.2`.
|
|
29
|
+
- `dialect: "posix"`: reports `test -v` and `[ -v ]` regardless of Bash releases; dash has no `-v` test.
|
|
30
30
|
- `dialect: "mksh"` or `"zsh"`: never reports.
|
|
31
31
|
|
|
32
32
|
## Options
|
|
33
33
|
|
|
34
|
-
This rule has no options. Set the
|
|
34
|
+
This rule has no options. Set the required support through `languageOptions`:
|
|
35
35
|
|
|
36
36
|
```js
|
|
37
37
|
// eslint.config.js
|
|
38
38
|
{
|
|
39
|
-
languageOptions: { dialect: 'bash',
|
|
39
|
+
languageOptions: { dialect: 'bash', minBashVersion: '3.2' },
|
|
40
40
|
rules: {
|
|
41
41
|
'sh/compat/no-test-v': 'error',
|
|
42
42
|
},
|
|
@@ -47,9 +47,9 @@ This rule has no options. Set the target through `languageOptions`:
|
|
|
47
47
|
|
|
48
48
|
### Incorrect
|
|
49
49
|
|
|
50
|
-
With `
|
|
50
|
+
With `minBashVersion: "3.2"`:
|
|
51
51
|
|
|
52
|
-
<!-- example: {"dialect": "bash", "
|
|
52
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "3.2", "findings": 3} -->
|
|
53
53
|
```sh
|
|
54
54
|
if [[ -v CI ]]; then echo ci; fi
|
|
55
55
|
if test -v HOME; then echo home; fi
|
|
@@ -58,20 +58,20 @@ if test -v HOME; then echo home; fi
|
|
|
58
58
|
|
|
59
59
|
### Correct
|
|
60
60
|
|
|
61
|
-
With `
|
|
61
|
+
With `minBashVersion: "3.2"`:
|
|
62
62
|
|
|
63
|
-
<!-- example: {"dialect": "bash", "
|
|
63
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
|
|
64
64
|
```sh
|
|
65
65
|
if [ -n "${CI+set}" ]; then echo ci; fi
|
|
66
66
|
[ "$flag" = -v ] && verbose=1
|
|
67
67
|
grep -v '^#' config
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
With `
|
|
70
|
+
With `minBashVersion: "4.2"` or newer, or with no `minBashVersion`, the `-v` test is fine.
|
|
71
71
|
|
|
72
72
|
## When not to use it
|
|
73
73
|
|
|
74
|
-
Turn the rule off when your scripts never run on Bash older than 4.2, or leave `
|
|
74
|
+
Turn the rule off when your scripts never run on Bash older than 4.2, or leave `minBashVersion`
|
|
75
75
|
unset, which makes the rule report nothing.
|
|
76
76
|
|
|
77
77
|
## Relationship to shellcheck
|
|
@@ -79,4 +79,4 @@ unset, which makes the rule report nothing.
|
|
|
79
79
|
eslint-sh is a convention and contract linter: a policy layer, where shellcheck is the gotcha
|
|
80
80
|
layer. Run shellcheck beside it.
|
|
81
81
|
|
|
82
|
-
shellcheck reports `[[` and `test -v` only for a script it treats as POSIX `sh` (its SC3xxx portability checks). It does not know which Bash release a script must run on, so it cannot report `[[ -v x ]]` for a Bash 3.2
|
|
82
|
+
shellcheck reports `[[` and `test -v` only for a script it treats as POSIX `sh` (its SC3xxx portability checks). It does not know which Bash release a script must run on, so it cannot report `[[ -v x ]]` for a script that must support Bash 3.2. This rule checks that support requirement.
|
|
@@ -27,18 +27,18 @@ Under `dialect: "posix"` the parser reads `$'…'` as a literal `$` followed by
|
|
|
27
27
|
This is a version-compat rule. Whether it reports depends only on `languageOptions`, as
|
|
28
28
|
described in [version compatibility](../../compat.md):
|
|
29
29
|
|
|
30
|
-
- `
|
|
31
|
-
- `dialect: "bash"` (the default) or `"bats"`: reports an escape when `
|
|
30
|
+
- `minBashVersion` unset: no Bash version constraint, so no report under `bash` or `bats`.
|
|
31
|
+
- `dialect: "bash"` (the default) or `"bats"`: reports an escape when `minBashVersion` is older than its release (4.2, or 4.3 for U+0080 to U+00FF).
|
|
32
32
|
- `dialect: "mksh"` or `"zsh"`: never reports.
|
|
33
33
|
|
|
34
34
|
## Options
|
|
35
35
|
|
|
36
|
-
This rule has no options. Set the
|
|
36
|
+
This rule has no options. Set the required support through `languageOptions`:
|
|
37
37
|
|
|
38
38
|
```js
|
|
39
39
|
// eslint.config.js
|
|
40
40
|
{
|
|
41
|
-
languageOptions: { dialect: 'bash',
|
|
41
|
+
languageOptions: { dialect: 'bash', minBashVersion: '3.2' },
|
|
42
42
|
rules: {
|
|
43
43
|
'sh/compat/no-unicode-escape': 'error',
|
|
44
44
|
},
|
|
@@ -49,17 +49,17 @@ This rule has no options. Set the target through `languageOptions`:
|
|
|
49
49
|
|
|
50
50
|
### Incorrect
|
|
51
51
|
|
|
52
|
-
With `
|
|
52
|
+
With `minBashVersion: "3.2"`:
|
|
53
53
|
|
|
54
|
-
<!-- example: {"dialect": "bash", "
|
|
54
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "3.2", "findings": 2} -->
|
|
55
55
|
```sh
|
|
56
56
|
ok=$'\u2713'
|
|
57
57
|
printf '%s\n' $'caf\u00e9'
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
With `
|
|
60
|
+
With `minBashVersion: "4.2"`, only the Latin-1 range reports:
|
|
61
61
|
|
|
62
|
-
<!-- example: {"dialect": "bash", "
|
|
62
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "4.2", "findings": 1} -->
|
|
63
63
|
```sh
|
|
64
64
|
ok=$'\u2713'
|
|
65
65
|
printf '%s\n' $'caf\u00e9'
|
|
@@ -67,20 +67,20 @@ printf '%s\n' $'caf\u00e9'
|
|
|
67
67
|
|
|
68
68
|
### Correct
|
|
69
69
|
|
|
70
|
-
With `
|
|
70
|
+
With `minBashVersion: "3.2"`:
|
|
71
71
|
|
|
72
|
-
<!-- example: {"dialect": "bash", "
|
|
72
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
|
|
73
73
|
```sh
|
|
74
74
|
ok=$'\342\234\223'
|
|
75
75
|
printf '%s\n' $'caf\303\251'
|
|
76
76
|
echo '\u00e9 is written literally here'
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
With `
|
|
79
|
+
With `minBashVersion: "4.3"` or newer, or with no `minBashVersion`, every escape is fine.
|
|
80
80
|
|
|
81
81
|
## When not to use it
|
|
82
82
|
|
|
83
|
-
Turn the rule off when your scripts never run on Bash older than 4.3, or leave `
|
|
83
|
+
Turn the rule off when your scripts never run on Bash older than 4.3, or leave `minBashVersion`
|
|
84
84
|
unset, which makes the rule report nothing.
|
|
85
85
|
|
|
86
86
|
## Relationship to shellcheck
|
|
@@ -88,4 +88,4 @@ unset, which makes the rule report nothing.
|
|
|
88
88
|
eslint-sh is a convention and contract linter: a policy layer, where shellcheck is the gotcha
|
|
89
89
|
layer. Run shellcheck beside it.
|
|
90
90
|
|
|
91
|
-
shellcheck reports `$'…'` only for a script it treats as POSIX `sh` (its SC3xxx portability checks). It does not know which Bash release a script must run on, so it cannot report a `\u` escape for a Bash 3.2 or 4.2
|
|
91
|
+
shellcheck reports `$'…'` only for a script it treats as POSIX `sh` (its SC3xxx portability checks). It does not know which Bash release a script must run on, so it cannot report a `\u` escape for a script that must support Bash 3.2 or 4.2. This rule checks that support requirement.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `sh/compat/no-wait-n`
|
|
2
2
|
|
|
3
|
-
Disallow `wait -n` in scripts
|
|
3
|
+
Disallow `wait -n` in scripts that must support a shell lacking it: Bash older than 4.3, including the
|
|
4
4
|
Bash 3.2 that macOS ships as `/bin/bash`, and POSIX sh.
|
|
5
5
|
|
|
6
6
|
| Configs | Fixable | Languages |
|
|
@@ -20,19 +20,19 @@ The portable alternative is to wait for one job at a time by its PID: keep each
|
|
|
20
20
|
This is a version-compat rule. Whether it reports depends only on `languageOptions`, as
|
|
21
21
|
described in [version compatibility](../../compat.md):
|
|
22
22
|
|
|
23
|
-
- `
|
|
24
|
-
- `dialect: "bash"` (the default) or `"bats"`: reports when `
|
|
25
|
-
- `dialect: "posix"`: reports
|
|
23
|
+
- `minBashVersion` unset: no Bash version constraint, so no report under `bash` or `bats`.
|
|
24
|
+
- `dialect: "bash"` (the default) or `"bats"`: reports when `minBashVersion` is older than `4.3`.
|
|
25
|
+
- `dialect: "posix"`: reports regardless of Bash releases; POSIX `wait` has no options.
|
|
26
26
|
- `dialect: "mksh"` or `"zsh"`: never reports.
|
|
27
27
|
|
|
28
28
|
## Options
|
|
29
29
|
|
|
30
|
-
This rule has no options. Set the
|
|
30
|
+
This rule has no options. Set the required support through `languageOptions`:
|
|
31
31
|
|
|
32
32
|
```js
|
|
33
33
|
// eslint.config.js
|
|
34
34
|
{
|
|
35
|
-
languageOptions: { dialect: 'bash',
|
|
35
|
+
languageOptions: { dialect: 'bash', minBashVersion: '3.2' },
|
|
36
36
|
rules: {
|
|
37
37
|
'sh/compat/no-wait-n': 'error',
|
|
38
38
|
},
|
|
@@ -43,9 +43,9 @@ This rule has no options. Set the target through `languageOptions`:
|
|
|
43
43
|
|
|
44
44
|
### Incorrect
|
|
45
45
|
|
|
46
|
-
With `
|
|
46
|
+
With `minBashVersion: "3.2"`:
|
|
47
47
|
|
|
48
|
-
<!-- example: {"dialect": "bash", "
|
|
48
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "3.2", "findings": 1} -->
|
|
49
49
|
```sh
|
|
50
50
|
for job in a b c d; do
|
|
51
51
|
run "$job" &
|
|
@@ -56,9 +56,9 @@ wait
|
|
|
56
56
|
|
|
57
57
|
### Correct
|
|
58
58
|
|
|
59
|
-
With `
|
|
59
|
+
With `minBashVersion: "3.2"`:
|
|
60
60
|
|
|
61
|
-
<!-- example: {"dialect": "bash", "
|
|
61
|
+
<!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
|
|
62
62
|
```sh
|
|
63
63
|
pids=
|
|
64
64
|
for job in a b c d; do
|
|
@@ -70,11 +70,11 @@ for pid in $pids; do
|
|
|
70
70
|
done
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
-
With `
|
|
73
|
+
With `minBashVersion: "4.3"` or newer, or with no `minBashVersion`, `wait -n` is fine.
|
|
74
74
|
|
|
75
75
|
## When not to use it
|
|
76
76
|
|
|
77
|
-
Turn the rule off when your scripts never run on Bash older than 4.3, or leave `
|
|
77
|
+
Turn the rule off when your scripts never run on Bash older than 4.3, or leave `minBashVersion`
|
|
78
78
|
unset, which makes the rule report nothing.
|
|
79
79
|
|
|
80
80
|
## Relationship to shellcheck
|
|
@@ -82,4 +82,4 @@ unset, which makes the rule report nothing.
|
|
|
82
82
|
eslint-sh is a convention and contract linter: a policy layer, where shellcheck is the gotcha
|
|
83
83
|
layer. Run shellcheck beside it.
|
|
84
84
|
|
|
85
|
-
shellcheck reports `wait` options only for a script it treats as POSIX `sh` (its SC3xxx portability checks). It does not know which Bash release a script must run on, so it cannot report `wait -n` for a Bash 4.2
|
|
85
|
+
shellcheck reports `wait` options only for a script it treats as POSIX `sh` (its SC3xxx portability checks). It does not know which Bash release a script must run on, so it cannot report `wait -n` for a script that must support Bash 4.2. This rule checks that support requirement.
|
|
@@ -30,7 +30,8 @@ wrappers_: commands that run the word after them. `time ls` runs `ls`, and
|
|
|
30
30
|
`bash ./build.sh` runs `./build.sh`. `bash -c STRING`, including a one-letter cluster such as
|
|
31
31
|
`bash -lc STRING`, runs an embedded string. `bash -s` and a bare `bash` read commands from
|
|
32
32
|
standard input, so the shell itself is the command.
|
|
33
|
-
-
|
|
33
|
+
- Project wrappers declared in `settings: { sh: { transparentWrappers: ['with-retry'] } }`,
|
|
34
|
+
and the shared network wrapper. See [shared transparent wrappers](../transparent-wrappers.md).
|
|
34
35
|
|
|
35
36
|
A command then reports in one of two ways:
|
|
36
37
|
|
|
@@ -45,8 +46,9 @@ A command then reports in one of two ways:
|
|
|
45
46
|
|
|
46
47
|
The rule is syntactic by design. It doesn't track values, so `cmd=ls; "$cmd"` reports. Aliases
|
|
47
48
|
need no handling: non-interactive shells don't expand them, so an alias name is an ordinary
|
|
48
|
-
static command word.
|
|
49
|
-
|
|
49
|
+
static command word. Utility wrappers match absolute paths by basename, so `/bin/bash -c …` runs an
|
|
50
|
+
embedded command. Configured utility wrappers also match relative paths; builtin specs
|
|
51
|
+
require exact names.
|
|
50
52
|
|
|
51
53
|
It does not depend on `languageOptions`.
|
|
52
54
|
|
|
@@ -56,18 +58,20 @@ It does not depend on `languageOptions`.
|
|
|
56
58
|
`dynamicInvocation` inside a function with one of these names, at any nesting depth, does not
|
|
57
59
|
report. The same command outside that function still reports. `embeddedCommand` still reports
|
|
58
60
|
inside these functions. Each use of the dispatcher stays visible at its call sites.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
Project wrapper facts belong in shared settings, with no rule override. The former
|
|
62
|
+
`allowWrappers` option is rejected. It added checks rather than suppressing them:
|
|
63
|
+
move its list to shared settings to preserve those checks across all wrapper-following
|
|
64
|
+
rules. Use `allowInFunctions` or a justified ESLint disable comment for an actual allowance.
|
|
65
|
+
See [migration](../transparent-wrappers.md#migration).
|
|
63
66
|
|
|
64
67
|
```js
|
|
65
68
|
// eslint.config.js
|
|
66
69
|
{
|
|
70
|
+
settings: { sh: { transparentWrappers: ['with-retry'] } },
|
|
67
71
|
rules: {
|
|
68
72
|
'sh/no-dynamic-invocation': [
|
|
69
73
|
'error',
|
|
70
|
-
{ allowInFunctions: ['dispatch']
|
|
74
|
+
{ allowInFunctions: ['dispatch'] },
|
|
71
75
|
],
|
|
72
76
|
},
|
|
73
77
|
}
|
|
@@ -91,9 +95,9 @@ bash -c "$script" # embeddedCommand: a string of shell code
|
|
|
91
95
|
sh -c 'make test' # embeddedCommand, even for a literal string
|
|
92
96
|
```
|
|
93
97
|
|
|
94
|
-
With `{
|
|
98
|
+
With `settings: { sh: { transparentWrappers: ['with-retry'] } }`:
|
|
95
99
|
|
|
96
|
-
<!-- example: {"
|
|
100
|
+
<!-- example: {"settings": {"sh": {"transparentWrappers": ["with-retry"]}}, "findings": 1, "messageIds": ["dynamicInvocation"]} -->
|
|
97
101
|
```sh
|
|
98
102
|
with-retry "$c" # the wrapped command is dynamic
|
|
99
103
|
```
|
|
@@ -110,9 +114,10 @@ alias ll='ls -l'
|
|
|
110
114
|
ll # an alias name is a static command word
|
|
111
115
|
```
|
|
112
116
|
|
|
113
|
-
With `{ allowInFunctions: ['dispatch']
|
|
117
|
+
With `{ allowInFunctions: ['dispatch'] }` and
|
|
118
|
+
`settings: { sh: { transparentWrappers: ['with-retry'] } }`:
|
|
114
119
|
|
|
115
|
-
<!-- example: {"options": {"allowInFunctions": ["dispatch"], "
|
|
120
|
+
<!-- example: {"options": {"allowInFunctions": ["dispatch"]}, "settings": {"sh": {"transparentWrappers": ["with-retry"]}}} -->
|
|
116
121
|
```sh
|
|
117
122
|
dispatch() {
|
|
118
123
|
"$@" # allowed inside the dispatcher
|
package/docs/rules/no-eval.md
CHANGED
|
@@ -7,6 +7,10 @@ of code a script runs can be reviewed before it runs.
|
|
|
7
7
|
| ------- | ------------ | --------- |
|
|
8
8
|
| `recommended`, `agent-authored` | not fixable | `sh/sh` |
|
|
9
9
|
|
|
10
|
+
Project wrapper facts are shared through
|
|
11
|
+
`settings: { sh: { transparentWrappers: ['with-retry'] } }`. This rule follows
|
|
12
|
+
those wrappers and the shared network wrapper; see [shared transparent wrappers](../transparent-wrappers.md).
|
|
13
|
+
|
|
10
14
|
## Rule details
|
|
11
15
|
|
|
12
16
|
A script you can review is a script whose code is all in front of you. Two constructs defeat
|
|
@@ -98,7 +102,8 @@ still report.
|
|
|
98
102
|
eslint-sh is a convention and contract linter: a policy layer, where shellcheck is the gotcha
|
|
99
103
|
layer. Run shellcheck beside it.
|
|
100
104
|
|
|
101
|
-
This rule is one of eslint-sh's
|
|
105
|
+
This rule is one of eslint-sh's
|
|
106
|
+
[deliberate overlaps with shellcheck](../shellcheck.md#deliberate-overlaps). shellcheck flags
|
|
102
107
|
`eval` only in specific misuse patterns, such as SC2294 (`eval` on an array negates the benefit
|
|
103
108
|
of arrays), and flags `source` of a non-constant path as SC1090 because shellcheck cannot follow
|
|
104
109
|
it. Both treat these as hazards to work around. This rule treats them as a policy: code that
|
|
@@ -6,6 +6,10 @@ Disallow `local`, `declare`, `typeset`, `export` and `readonly` with a value tak
|
|
|
6
6
|
| ---------------- | ----------------------------------------- | --------- |
|
|
7
7
|
| `agent-authored` | suggestions (split into two statements) | `sh/sh` |
|
|
8
8
|
|
|
9
|
+
Project wrapper facts are shared through
|
|
10
|
+
`settings: { sh: { transparentWrappers: ['with-retry'] } }`. This rule follows
|
|
11
|
+
those wrappers and the shared network wrapper; see [shared transparent wrappers](../transparent-wrappers.md).
|
|
12
|
+
|
|
9
13
|
## Rule details
|
|
10
14
|
|
|
11
15
|
`local x=$(cmd)` runs `cmd`, then runs `local`, and the statement's exit status is the status of
|
|
@@ -6,6 +6,10 @@ Disallow reading secret-shaped environment variables, such as `$GITHUB_TOKEN`, o
|
|
|
6
6
|
| ---------------- | ----------- | --------- |
|
|
7
7
|
| `agent-authored` (error) | not fixable | `sh/sh` |
|
|
8
8
|
|
|
9
|
+
Project wrapper facts are shared through
|
|
10
|
+
`settings: { sh: { transparentWrappers: ['with-retry'] } }`. This rule follows
|
|
11
|
+
those wrappers and the shared network wrapper; see [shared transparent wrappers](../transparent-wrappers.md).
|
|
12
|
+
|
|
9
13
|
## Rule details
|
|
10
14
|
|
|
11
15
|
Once a secret is expanded into a command's arguments, every user on the machine can read it
|
|
@@ -34,6 +38,13 @@ Four things are not reported:
|
|
|
34
38
|
command is resolved through transparent wrappers (`sudo vault …` is `vault`), and a command run
|
|
35
39
|
by path matches by basename.
|
|
36
40
|
|
|
41
|
+
Only arguments actually passed after the final resolved sink command receive this
|
|
42
|
+
exemption. Wrapper-owned options and operands are checked normally. With an approved
|
|
43
|
+
`sink` and `settings: { sh: { transparentWrappers: [{ names: ['with-retry'], argFlags: ['--log'] }] } }`,
|
|
44
|
+
`with-retry --log "$API_TOKEN" sink` reports, while
|
|
45
|
+
`with-retry --log audit.log sink "$API_TOKEN"` stays clean. Likewise, the secret in
|
|
46
|
+
`env -u "$API_TOKEN" sink` is owned by `env`, so approving `sink` does not exempt it.
|
|
47
|
+
|
|
37
48
|
Matching is a name pattern, not secret detection.
|
|
38
49
|
|
|
39
50
|
### Expected false positives
|
|
@@ -59,12 +70,16 @@ The rule matches parameter expansions only. These reads are not reported:
|
|
|
59
70
|
## Options
|
|
60
71
|
|
|
61
72
|
- `patterns` (`string[]`, at least one entry). Regular-expression sources tested against each
|
|
62
|
-
variable's name. They **replace** the default list. Sources
|
|
63
|
-
|
|
73
|
+
variable's name. They **replace** the default list. Sources use `u` (Unicode, case-sensitive):
|
|
74
|
+
`patterns: ['token']` does not catch `$GITHUB_TOKEN`, while `patterns: ['TOKEN']` does.
|
|
75
|
+
Lowercase names such as `$sort_key` do not match the uppercase default patterns.
|
|
76
|
+
See [regular-expression options](./README.md#regular-expression-options) for compilation and
|
|
77
|
+
configuration errors, which name the rule, option index and source.
|
|
64
78
|
|
|
65
79
|
Default: `["(_TOKEN|_SECRET|_PASSWORD|_KEY)$"]`.
|
|
66
80
|
|
|
67
|
-
- `allowedSinks` (`string[]`). Command names whose arguments may read a secret-shaped variable.
|
|
81
|
+
- `allowedSinks` (`string[]`). Command names whose own arguments may read a secret-shaped variable. Wrapper-owned
|
|
82
|
+
operands are not exempt.
|
|
68
83
|
|
|
69
84
|
Default: `[]`.
|
|
70
85
|
|
|
@@ -80,6 +95,22 @@ The rule matches parameter expansions only. These reads are not reported:
|
|
|
80
95
|
}
|
|
81
96
|
```
|
|
82
97
|
|
|
98
|
+
Regex syntax errors fail when this rule first runs on a file, naming the rule, option and
|
|
99
|
+
pattern. `--print-config` will not catch any regex syntax errors. See the
|
|
100
|
+
[shared compilation contract](./README.md#regular-expression-options).
|
|
101
|
+
|
|
102
|
+
### Matching examples
|
|
103
|
+
|
|
104
|
+
These examples use only this rule; `patterns` replaces the defaults. Option values below are JSON.
|
|
105
|
+
|
|
106
|
+
| Option value | Shell input | Findings |
|
|
107
|
+
| --- | --- | --- |
|
|
108
|
+
| `{"patterns":["token"]}` | `echo "$GITHUB_TOKEN"` | 0 |
|
|
109
|
+
| `{"patterns":["TOKEN"]}` | `echo "$GITHUB_TOKEN"` | 1 |
|
|
110
|
+
| `{}` | `echo "$sort_key"` | 0 |
|
|
111
|
+
| `{"patterns":["^\\p{Lu}+$"]}` | `echo "$TOKEN"` | 1 |
|
|
112
|
+
| `{"patterns":["^\\p{Lu}+$"]}` | `echo "$token"` | 0 |
|
|
113
|
+
|
|
83
114
|
### Patterns run against script-controlled text
|
|
84
115
|
|
|
85
116
|
`patterns` is tested against every variable name the linted script expands, and the script's author
|
|
@@ -60,8 +60,10 @@ positive with a disable comment that says why, or narrow the `patterns` option f
|
|
|
60
60
|
|
|
61
61
|
- `patterns` (`string[]`, at least one entry). Regular-expression sources tested against each flag's
|
|
62
62
|
name, without `=` or the value. They **replace** the default list. Each source is compiled
|
|
63
|
-
case-
|
|
64
|
-
|
|
63
|
+
with `iu` (Unicode, case-insensitive), like the default. For example, `patterns: ['token']`
|
|
64
|
+
catches `cli --TOKEN=abc`; capitals in a custom pattern also match lowercase flag names.
|
|
65
|
+
See [regular-expression options](./README.md#regular-expression-options) for compilation and
|
|
66
|
+
configuration errors, which name the rule, option index and source.
|
|
65
67
|
|
|
66
68
|
Default: `["^(?!.*-(?:stdin|file)$)--?(?:access-|auth-?)?(?:password|passwd|token|secret|api-?key|auth(?:key|orization)?)(?![a-z])"]`.
|
|
67
69
|
|
|
@@ -78,6 +80,21 @@ positive with a disable comment that says why, or narrow the `patterns` option f
|
|
|
78
80
|
}
|
|
79
81
|
```
|
|
80
82
|
|
|
83
|
+
Regex syntax errors fail when this rule first runs on a file, naming the rule, option and
|
|
84
|
+
pattern. `--print-config` will not catch any regex syntax errors. See the
|
|
85
|
+
[shared compilation contract](./README.md#regular-expression-options).
|
|
86
|
+
|
|
87
|
+
### Matching examples
|
|
88
|
+
|
|
89
|
+
These examples use only this rule; `patterns` replaces the defaults. Option values below are JSON.
|
|
90
|
+
|
|
91
|
+
| Option value | Shell input | Findings |
|
|
92
|
+
| --- | --- | --- |
|
|
93
|
+
| `{"patterns":["token"]}` | `cli --TOKEN=abc` | 1 |
|
|
94
|
+
| `{"patterns":["TOKEN"]}` | `cli --token=abc` | 1 |
|
|
95
|
+
| `{"patterns":["token"]}` | `cli --other=abc` | 0 |
|
|
96
|
+
| `{"patterns":["^--\\p{Lu}+$"]}` | `cli --TOKEN=abc` | 1 |
|
|
97
|
+
|
|
81
98
|
### Patterns run against script-controlled text
|
|
82
99
|
|
|
83
100
|
`patterns` is tested against every flag name the linted script writes, and the script's author
|
|
@@ -6,6 +6,10 @@ Require the failure of `cd`, `pushd` and `popd` to be checked, so a script never
|
|
|
6
6
|
| ------------------------------- | ---------------------------- | --------- |
|
|
7
7
|
| `recommended`, `agent-authored` | suggestions (append `\|\| exit`) | `sh/sh` |
|
|
8
8
|
|
|
9
|
+
Project wrapper facts are shared through
|
|
10
|
+
`settings: { sh: { transparentWrappers: ['with-retry'] } }`. This rule follows
|
|
11
|
+
those wrappers and the shared network wrapper; see [shared transparent wrappers](../transparent-wrappers.md).
|
|
12
|
+
|
|
9
13
|
## Rule details
|
|
10
14
|
|
|
11
15
|
When `cd` fails, the script keeps running in the directory it was already in, and every relative
|
|
@@ -31,7 +35,8 @@ read as `cd`.
|
|
|
31
35
|
by itself, so the rule is quiet there. "Prologue" is read exactly as
|
|
32
36
|
[`require-strict-mode`](./require-strict-mode.md) reads it: the first five top-level statements,
|
|
33
37
|
tracked in order, so a later `set +e` undoes an earlier `set -e`, and a `set -e` outside that
|
|
34
|
-
window does not count.
|
|
38
|
+
window does not count. Only `set` statements count; shebang flags do not. Set
|
|
39
|
+
`ignoreWhenErrexit` to `false` to report anyway.
|
|
35
40
|
|
|
36
41
|
**Files run by bats.** With `languageOptions.dialect` set to `"bats"`, a bare `cd` (or `pushd` or
|
|
37
42
|
`popd`) written directly in the body of a `@test` block, or of a top-level `setup`, `teardown`,
|
|
@@ -143,4 +148,6 @@ shellcheck overlaps with SC2164 ("Use `cd ... || exit` in case `cd` fails"), and
|
|
|
143
148
|
enforces the same practice. It exists anyway because it offers a suggestion, covers `pushd` and
|
|
144
149
|
`popd`, can be turned off per file by `set -e` detection that follows the same prologue reading as
|
|
145
150
|
`require-strict-mode`, and is part of the shipped presets, so the policy applies without running
|
|
146
|
-
shellcheck.
|
|
151
|
+
shellcheck. The checks differ when errexit comes from a shebang such as `#!/bin/bash -e`:
|
|
152
|
+
shellcheck treats it as `set -e` and suppresses SC2164, while `ignoreWhenErrexit` reads only
|
|
153
|
+
`set` statements in the prologue, so this rule still reports an unchecked `cd`.
|
|
@@ -14,7 +14,7 @@ machine it lands on. When your project states each script's dependencies, this r
|
|
|
14
14
|
statement complete: it reports each command the script uses but does not declare.
|
|
15
15
|
|
|
16
16
|
The rule needs a **declaration convention**, which says how your project declares commands. Bind
|
|
17
|
-
one with `settings
|
|
17
|
+
one with `settings: { sh: { declarationConvention: commentPragma } }`. The plugin ships one, `commentPragma`, which reads
|
|
18
18
|
`# uses: jq curl` comments from a script's header. See
|
|
19
19
|
[Declaration conventions](../declaration-conventions.md) to write your own. **With no convention
|
|
20
20
|
bound, the rule reports nothing**, so turning it on is safe until your project picks a convention.
|
|
@@ -61,16 +61,17 @@ In a file without a shebang, the message says to add the line as the first line
|
|
|
61
61
|
instead. A convention without a hint ends the message with the generic sentence
|
|
62
62
|
"Declare it with the project's declaration convention." A command run by path (`./build.sh`) is reported by that path.
|
|
63
63
|
|
|
64
|
-
##
|
|
64
|
+
## Shared settings
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
66
|
+
This rule has no options. Declare project wrapper facts once with
|
|
67
|
+
`settings: { sh: { transparentWrappers: ['with-retry'] } }`.
|
|
68
|
+
Every wrapper-following rule reads that setting, including the other declaration rule.
|
|
69
|
+
Entries accept names or flag-bearing specs, for example
|
|
70
|
+
`settings: { sh: { transparentWrappers: [{ names: ['with-retry'], argFlags: ['-n'] }] } }`.
|
|
71
|
+
Then `with-retry -n 3 curl` uses both `with-retry` and `curl`.
|
|
72
|
+
The shared network wrapper is also followed automatically. Utility wrappers invoked
|
|
73
|
+
by absolute or relative path count by basename; builtin specs require exact names.
|
|
74
|
+
See [shared transparent wrappers](../transparent-wrappers.md) for precedence and migration.
|
|
74
75
|
|
|
75
76
|
The convention is not a rule option. Bind it in `settings`, because ESLint copies rule options
|
|
76
77
|
with `structuredClone`, which cannot copy a convention's methods.
|
|
@@ -84,9 +85,9 @@ export default [
|
|
|
84
85
|
files: ['**/*.sh'],
|
|
85
86
|
plugins: { sh },
|
|
86
87
|
language: 'sh/sh',
|
|
87
|
-
settings: { sh: { declarationConvention: commentPragma } },
|
|
88
|
+
settings: { sh: { declarationConvention: commentPragma, transparentWrappers: ['with-retry'] } },
|
|
88
89
|
rules: {
|
|
89
|
-
'sh/no-undeclared-commands':
|
|
90
|
+
'sh/no-undeclared-commands': 'error',
|
|
90
91
|
},
|
|
91
92
|
},
|
|
92
93
|
];
|
|
@@ -94,11 +95,11 @@ export default [
|
|
|
94
95
|
|
|
95
96
|
## Examples
|
|
96
97
|
|
|
97
|
-
With `commentPragma` bound and `{ transparentWrappers: ['with-retry'] }`:
|
|
98
|
+
With `commentPragma` bound and `settings: { sh: { transparentWrappers: ['with-retry'] } }`:
|
|
98
99
|
|
|
99
100
|
### Incorrect
|
|
100
101
|
|
|
101
|
-
<!-- example: {"convention": "commentPragma", "
|
|
102
|
+
<!-- example: {"convention": "commentPragma", "settings": {"sh": {"transparentWrappers": ["with-retry"]}}, "findings": 6} -->
|
|
102
103
|
```sh
|
|
103
104
|
#!/usr/bin/env bash
|
|
104
105
|
# uses: jq
|
|
@@ -110,7 +111,7 @@ with-retry git pull # git, run by the wrapper, is not declared (nor is
|
|
|
110
111
|
|
|
111
112
|
### Correct
|
|
112
113
|
|
|
113
|
-
<!-- example: {"convention": "commentPragma", "
|
|
114
|
+
<!-- example: {"convention": "commentPragma", "settings": {"sh": {"transparentWrappers": ["with-retry"]}}} -->
|
|
114
115
|
```sh
|
|
115
116
|
#!/usr/bin/env bash
|
|
116
117
|
# uses: curl jq date
|
|
@@ -15,7 +15,7 @@ script's real surface. This rule reports each declared command the script never
|
|
|
15
15
|
converse of [`sh/no-undeclared-commands`](./no-undeclared-commands.md).
|
|
16
16
|
|
|
17
17
|
The rule needs a **declaration convention**, which says how your project declares commands. Bind
|
|
18
|
-
one with `settings
|
|
18
|
+
one with `settings: { sh: { declarationConvention: commentPragma } }`. The plugin ships one, `commentPragma`, which reads
|
|
19
19
|
`# uses: jq curl` comments from a script's header. See
|
|
20
20
|
[Declaration conventions](../declaration-conventions.md) to write your own. **With no convention
|
|
21
21
|
bound, the rule reports nothing**, so turning it on is safe until your project picks a convention.
|
|
@@ -135,18 +135,17 @@ the whole line goes with its `\n` or `\r\n`. When several names on one line are
|
|
|
135
135
|
edits touch, so ESLint applies one per pass. `eslint --fix` runs passes until nothing changes, so
|
|
136
136
|
a line whose every name is unused is removed entirely.
|
|
137
137
|
|
|
138
|
-
##
|
|
138
|
+
## Shared settings
|
|
139
139
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
(see [`sh/require-network-wrapper`](./require-network-wrapper.md#declaring-the-wrapper-once-settingsshnetworkwrapper)).
|
|
140
|
+
This rule has no options. Declare project wrapper facts once with
|
|
141
|
+
`settings: { sh: { transparentWrappers: ['with-retry'] } }`.
|
|
142
|
+
Every wrapper-following rule reads that setting, including the other declaration rule.
|
|
143
|
+
Entries accept names or flag-bearing specs, for example
|
|
144
|
+
`settings: { sh: { transparentWrappers: [{ names: ['with-retry'], argFlags: ['-n'] }] } }`.
|
|
145
|
+
Then `with-retry -n 3 curl` uses both `with-retry` and `curl`.
|
|
146
|
+
The shared network wrapper is also followed automatically. Utility wrappers invoked
|
|
147
|
+
by absolute or relative path count by basename; builtin specs require exact names.
|
|
148
|
+
See [shared transparent wrappers](../transparent-wrappers.md) for precedence and migration.
|
|
150
149
|
|
|
151
150
|
The convention is not a rule option. Bind it in `settings`, because ESLint copies rule options
|
|
152
151
|
with `structuredClone`, which cannot copy a convention's methods.
|
|
@@ -155,17 +154,15 @@ with `structuredClone`, which cannot copy a convention's methods.
|
|
|
155
154
|
// eslint.config.js
|
|
156
155
|
import sh, { commentPragma } from '@eslint-sh/eslint-plugin';
|
|
157
156
|
|
|
158
|
-
const wrappers = { transparentWrappers: ['with-retry'] };
|
|
159
|
-
|
|
160
157
|
export default [
|
|
161
158
|
{
|
|
162
159
|
files: ['**/*.sh'],
|
|
163
160
|
plugins: { sh },
|
|
164
161
|
language: 'sh/sh',
|
|
165
|
-
settings: { sh: { declarationConvention: commentPragma } },
|
|
162
|
+
settings: { sh: { declarationConvention: commentPragma, transparentWrappers: ['with-retry'] } },
|
|
166
163
|
rules: {
|
|
167
|
-
'sh/no-undeclared-commands':
|
|
168
|
-
'sh/no-unused-declarations':
|
|
164
|
+
'sh/no-undeclared-commands': 'error',
|
|
165
|
+
'sh/no-unused-declarations': 'error',
|
|
169
166
|
},
|
|
170
167
|
},
|
|
171
168
|
];
|
|
@@ -173,11 +170,11 @@ export default [
|
|
|
173
170
|
|
|
174
171
|
## Examples
|
|
175
172
|
|
|
176
|
-
With `commentPragma` bound and `{ transparentWrappers: ['with-retry'] }`:
|
|
173
|
+
With `commentPragma` bound and `settings: { sh: { transparentWrappers: ['with-retry'] } }`:
|
|
177
174
|
|
|
178
175
|
### Incorrect
|
|
179
176
|
|
|
180
|
-
<!-- example: {"convention": "commentPragma", "
|
|
177
|
+
<!-- example: {"convention": "commentPragma", "settings": {"sh": {"transparentWrappers": ["with-retry"]}}, "findings": 3} -->
|
|
181
178
|
```sh
|
|
182
179
|
#!/usr/bin/env bash
|
|
183
180
|
# uses: jq curl docker # docker is never run
|
|
@@ -189,7 +186,7 @@ curl -s "$URL" | jq .
|
|
|
189
186
|
|
|
190
187
|
### Correct
|
|
191
188
|
|
|
192
|
-
<!-- example: {"convention": "commentPragma", "
|
|
189
|
+
<!-- example: {"convention": "commentPragma", "settings": {"sh": {"transparentWrappers": ["with-retry"]}}} -->
|
|
193
190
|
```sh
|
|
194
191
|
#!/usr/bin/env bash
|
|
195
192
|
# uses: jq curl git sudo date with-retry
|