1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
import os
import pytest
from conftest import assert_bash_exec, assert_complete, bash_env_saved
@pytest.mark.bashcomp(cmd=None, temp_cwd=True)
class TestUnitQuoteCompgen:
@pytest.fixture(scope="class")
def functions(self, bash):
assert_bash_exec(
bash,
'_comp__test_quote_compgen() { local REPLY; _comp_quote_compgen "$1"; printf %s "$REPLY"; }',
)
@pytest.mark.parametrize(
"funcname", "_comp__test_quote_compgen quote_readline".split()
)
def test_exec(self, bash, functions, funcname):
assert_bash_exec(bash, "%s '' >/dev/null" % funcname)
@pytest.mark.parametrize(
"funcname", "_comp__test_quote_compgen quote_readline".split()
)
def test_env_non_pollution(self, bash, functions, funcname):
"""Test environment non-pollution, detected at teardown."""
assert_bash_exec(
bash, "foo() { %s meh >/dev/null; }; foo; unset -f foo" % funcname
)
@pytest.mark.parametrize(
"funcname", "_comp__test_quote_compgen quote_readline".split()
)
def test_1(self, bash, functions, funcname):
output = assert_bash_exec(
bash, "%s '';echo" % funcname, want_output=True
)
assert output.strip() == "''"
@pytest.mark.parametrize(
"funcname", "_comp__test_quote_compgen quote_readline".split()
)
def test_2(self, bash, functions, funcname):
output = assert_bash_exec(
bash, "%s foo;echo" % funcname, want_output=True
)
assert output.strip() == "foo"
@pytest.mark.parametrize(
"funcname", "_comp__test_quote_compgen quote_readline".split()
)
def test_3(self, bash, functions, funcname):
output = assert_bash_exec(
bash, '%s foo\\"bar;echo' % funcname, want_output=True
)
assert output.strip() == 'foo\\"bar'
@pytest.mark.parametrize(
"funcname", "_comp__test_quote_compgen quote_readline".split()
)
def test_4(self, bash, functions, funcname):
output = assert_bash_exec(
bash, "%s '$(echo x >&2)';echo" % funcname, want_output=True
)
assert output.strip() == "\\$\\(echo\\ x\\ \\>\\&2\\)"
def test_github_issue_189_1(self, bash, functions):
"""Test error messages on a certain command line
Reported at https://github.com/scop/bash-completion/issues/189
Syntax error messages should not be shown by completion on the
following line:
$ ls -- '${[TAB]
$ rm -- '${[TAB]
"""
assert_bash_exec(bash, "_comp__test_quote_compgen $'\\'${' >/dev/null")
def test_github_issue_492_1(self, bash, functions):
"""Test unintended code execution on a certain command line
Reported at https://github.com/scop/bash-completion/pull/492
Arbitrary commands could be unintendedly executed by
_comp_quote_compgen. In the following example, the command "touch
1.txt" would be unintendedly created before the fix. The file "1.txt"
should not be created by completion on the following line:
$ echo '$(touch file.txt)[TAB]
"""
assert_bash_exec(
bash, "_comp__test_quote_compgen $'\\'$(touch 1.txt)' >/dev/null"
)
assert not os.path.exists("./1.txt")
def test_github_issue_492_2(self, bash, functions):
"""Test the file clear by unintended redirection on a certain command line
Reported at https://github.com/scop/bash-completion/pull/492
The file "1.0" should not be created by completion on the following
line:
$ awk '$1 > 1.0[TAB]
"""
assert_bash_exec(
bash, "_comp__test_quote_compgen $'\\'$1 > 1.0' >/dev/null"
)
assert not os.path.exists("./1.0")
def test_github_issue_492_3(self, bash, functions):
"""Test code execution through unintended pathname expansions
When there is a file named "quote=$(COMMAND)" (for
_comp_compgen_filedir) or "REPLY=$(COMMAND)" (for _comp_quote_compgen),
the completion of the word '$* results in the execution of COMMAND.
$ echo '$*[TAB]
"""
os.mkdir("./REPLY=$(echo injected >&2)")
assert_bash_exec(bash, "_comp__test_quote_compgen $'\\'$*' >/dev/null")
def test_github_issue_492_4(self, bash, functions):
"""Test error messages through unintended pathname expansions
When "shopt -s failglob" is set by the user, the completion of the word
containing glob character and special characters (e.g. TAB) results in
the failure of pathname expansions.
$ shopt -s failglob
$ echo a\\ b*[TAB]
"""
with bash_env_saved(bash) as bash_env:
bash_env.shopt("failglob", True)
assert_bash_exec(
bash, "_comp__test_quote_compgen $'a\\\\\\tb*' >/dev/null"
)
def test_github_issue_526_1(self, bash):
r"""Regression tests for unprocessed escape sequences after quotes
Ref [1] https://github.com/scop/bash-completion/pull/492#discussion_r637213822
Ref [2] https://github.com/scop/bash-completion/pull/526
The escape sequences in the local variable of "value" in
"_comp_quote_compgen" needs to be unescaped by passing it to printf as
the format string. This causes a problem in the following case [where
the spaces after "alpha\" is a TAB character inserted in the command
string by "C-v TAB"]:
$ echo alpha\ b[TAB]
"""
os.mkdir("./alpha\tbeta")
assert (
assert_complete(
# Remark on "rendered_cmd": Bash aligns the last character 'b'
# in the rendered cmd to an "8 x n" boundary using spaces.
# Here, the command string is assumed to start from column 2
# because the width of PS1 (conftest.PS1 = '/@') is 2,
bash,
"echo alpha\\\026\tb",
rendered_cmd="echo alpha\\ b",
)
== "eta/"
)
|