cli2 5.0.0rc15__tar.gz → 5.0.2__tar.gz
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.
- {cli2-5.0.0rc15/cli2.egg-info → cli2-5.0.2}/PKG-INFO +1 -1
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/__init__.py +13 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/mask.py +6 -3
- {cli2-5.0.0rc15 → cli2-5.0.2/cli2.egg-info}/PKG-INFO +1 -1
- {cli2-5.0.0rc15 → cli2-5.0.2}/setup.py +1 -1
- {cli2-5.0.0rc15 → cli2-5.0.2}/tests/test_ansible.py +64 -10
- {cli2-5.0.0rc15 → cli2-5.0.2}/tests/test_client.py +4 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/tests/test_mask.py +5 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/MANIFEST.in +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/README.rst +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/classifiers.txt +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/asyncio.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/cli.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/cli2.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/colors.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/configuration.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/decorators.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/display.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/examples/__init__.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/examples/conf.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/examples/example.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/examples/example_obj.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/examples/nesting.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/examples/obj.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/examples/obj2.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/examples/test.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/lock.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/log.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/node.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/sphinx.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/table.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2/test.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2.egg-info/SOURCES.txt +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2.egg-info/dependency_links.txt +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2.egg-info/entry_points.txt +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2.egg-info/requires.txt +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/cli2.egg-info/top_level.txt +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/setup.cfg +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/tests/test_ansible_variables.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/tests/test_asyncio.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/tests/test_cli.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/tests/test_command.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/tests/test_configuration.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/tests/test_decorators.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/tests/test_display.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/tests/test_entry_point.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/tests/test_group.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/tests/test_inject.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/tests/test_lock.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/tests/test_node.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/tests/test_restful.py +0 -0
- {cli2-5.0.0rc15 → cli2-5.0.2}/tests/test_table.py +0 -0
|
@@ -30,3 +30,16 @@ def which(cmd):
|
|
|
30
30
|
path = Path(os.getenv('HOME')) / '.local/bin' / cmd
|
|
31
31
|
if path.exists():
|
|
32
32
|
return str(path)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def mutable(obj):
|
|
36
|
+
types = (
|
|
37
|
+
int,
|
|
38
|
+
float,
|
|
39
|
+
str,
|
|
40
|
+
tuple,
|
|
41
|
+
frozenset,
|
|
42
|
+
bool,
|
|
43
|
+
bytes,
|
|
44
|
+
)
|
|
45
|
+
return not isinstance(obj, types)
|
|
@@ -32,8 +32,9 @@ class Mask:
|
|
|
32
32
|
Because:
|
|
33
33
|
|
|
34
34
|
- ``1337p4ssw0rD`` was given as a value to mask
|
|
35
|
-
- ``
|
|
36
|
-
|
|
35
|
+
- ``password``'s value because ``password`` was given as a key to match
|
|
36
|
+
- the Mask object learned the value of the ``password`` key, and masked it
|
|
37
|
+
in ``text``
|
|
37
38
|
|
|
38
39
|
.. py:attribute:: keys
|
|
39
40
|
|
|
@@ -109,8 +110,10 @@ class Mask:
|
|
|
109
110
|
data[key] = self._mask(value)
|
|
110
111
|
elif isinstance(data, list):
|
|
111
112
|
return [self._mask(item) for item in data]
|
|
113
|
+
elif isinstance(data, set):
|
|
114
|
+
return {self._mask(item) for item in data}
|
|
112
115
|
elif isinstance(data, str):
|
|
113
|
-
for value in self.values:
|
|
116
|
+
for value in sorted(self.values, key=len, reverse=True):
|
|
114
117
|
data = data.replace(str(value), '***MASKED***')
|
|
115
118
|
return data
|
|
116
119
|
|
|
@@ -9,17 +9,15 @@ import yaml
|
|
|
9
9
|
import cansible
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
class ActionModule(cansible.ActionBase):
|
|
13
|
-
mask_keys = ['a']
|
|
14
|
-
|
|
15
|
-
async def run_async(self):
|
|
16
|
-
self.result['x'] = dict(a='a', b='b', c='c', d='foo a rrr')
|
|
17
|
-
|
|
18
|
-
|
|
19
12
|
@pytest.mark.asyncio
|
|
20
13
|
async def test_mask(monkeypatch):
|
|
21
|
-
|
|
22
|
-
|
|
14
|
+
class ActionModule(cansible.ActionBase):
|
|
15
|
+
masked_keys = ['a']
|
|
16
|
+
print = mock.Mock()
|
|
17
|
+
|
|
18
|
+
async def run_async(self):
|
|
19
|
+
self.result['x'] = dict(a='a', b='b', c='c', d='foo a rrr')
|
|
20
|
+
|
|
23
21
|
module = await ActionModule.run_test_async(facts=dict(mask_keys=['b']))
|
|
24
22
|
# result is untouched
|
|
25
23
|
assert module.result == {'x':
|
|
@@ -27,7 +25,19 @@ async def test_mask(monkeypatch):
|
|
|
27
25
|
}
|
|
28
26
|
# output has proper masking
|
|
29
27
|
expected = "\x1b[94mx\x1b[39;49;00m:\x1b[37m\x1b[39;49;00m\n\x1b[37m \x1b[39;49;00m\x1b[94ma\x1b[39;49;00m:\x1b[37m \x1b[39;49;00m\x1b[33m'\x1b[39;49;00m\x1b[33m***MASKED***\x1b[39;49;00m\x1b[33m'\x1b[39;49;00m\x1b[37m\x1b[39;49;00m\n\x1b[37m \x1b[39;49;00m\x1b[94mb\x1b[39;49;00m:\x1b[37m \x1b[39;49;00m\x1b[33m'\x1b[39;49;00m\x1b[33m***MASKED***\x1b[39;49;00m\x1b[33m'\x1b[39;49;00m\x1b[37m\x1b[39;49;00m\n\x1b[37m \x1b[39;49;00m\x1b[94mc\x1b[39;49;00m:\x1b[37m \x1b[39;49;00mc\x1b[37m\x1b[39;49;00m\n\x1b[37m \x1b[39;49;00m\x1b[94md\x1b[39;49;00m:\x1b[37m \x1b[39;49;00mfoo ***MASKED*** rrr\x1b[37m\x1b[39;49;00m\n" # noqa
|
|
30
|
-
|
|
28
|
+
module.print.assert_called_once_with(expected, mask=False)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_subprocess_remote(playbook):
|
|
32
|
+
playbook.task_add(
|
|
33
|
+
'yourlabs.test.password_get',
|
|
34
|
+
no_log=True,
|
|
35
|
+
)
|
|
36
|
+
result = playbook()
|
|
37
|
+
expected = "foo:***MASKED***:bar\n\nansible_facts:\n\n mask_values:\n\n - \'***MASKED***\'\n\nsecret: \'***MASKED***\'\n\nstdout: foo:***MASKED***:bar" # noqa
|
|
38
|
+
assert expected in result['stdout']
|
|
39
|
+
|
|
40
|
+
|
|
31
41
|
|
|
32
42
|
|
|
33
43
|
@pytest.mark.asyncio
|
|
@@ -120,6 +130,41 @@ async def test_diff(monkeypatch):
|
|
|
120
130
|
_print.assert_called_once_with(expected)
|
|
121
131
|
|
|
122
132
|
|
|
133
|
+
@pytest.mark.asyncio
|
|
134
|
+
async def test_fact_set():
|
|
135
|
+
class Action(cansible.ActionBase):
|
|
136
|
+
foo = cansible.Option(fact='foo')
|
|
137
|
+
|
|
138
|
+
async def run_async(self):
|
|
139
|
+
self.foo = 'bar'
|
|
140
|
+
assert self.foo == 'bar'
|
|
141
|
+
|
|
142
|
+
action = await Action.run_test_async(facts=dict(foo='bar'))
|
|
143
|
+
assert 'ansible_facts' not in action.result
|
|
144
|
+
|
|
145
|
+
action = await Action.run_test_async()
|
|
146
|
+
assert action.result['ansible_facts'] == dict(foo='bar')
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@pytest.mark.asyncio
|
|
150
|
+
async def test_fact_set_mutable():
|
|
151
|
+
class Action(cansible.ActionBase):
|
|
152
|
+
async def run_async(self):
|
|
153
|
+
assert self.mask_values is self.mask.values
|
|
154
|
+
self.mask_values.add('foo')
|
|
155
|
+
|
|
156
|
+
action = await Action.run_test_async()
|
|
157
|
+
assert 'mask_values' in action.facts_values
|
|
158
|
+
assert action.result['ansible_facts'] == dict(mask_values=['foo'])
|
|
159
|
+
|
|
160
|
+
action = await Action.run_test_async(facts=dict(mask_values=['foo']))
|
|
161
|
+
assert 'ansible_facts' not in action.result
|
|
162
|
+
|
|
163
|
+
action = await Action.run_test_async(facts=dict(mask_values=['bar']))
|
|
164
|
+
result = action.result['ansible_facts']['mask_values']
|
|
165
|
+
assert sorted(result) == ['bar', 'foo']
|
|
166
|
+
|
|
167
|
+
|
|
123
168
|
def test_playbook_render(playbook):
|
|
124
169
|
assert playbook.name == 'test_playbook_render'
|
|
125
170
|
playbook.task_add(
|
|
@@ -166,3 +211,12 @@ def test_playbook_exec(playbook):
|
|
|
166
211
|
result = playbook()
|
|
167
212
|
assert result['changed'] == 0
|
|
168
213
|
assert result['ok'] == 2
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def test_masking_ansible_story(playbook):
|
|
217
|
+
with open('tests/test_ansible_masking.yml', 'r') as f:
|
|
218
|
+
data = yaml.safe_load(f.read())
|
|
219
|
+
playbook.tasks += data[0]['tasks']
|
|
220
|
+
result = playbook()
|
|
221
|
+
expected = "hello ***MASKED*** ***MASKED*** bye\n\nansible_facts:\n\n mask_values:\n\n - \'***MASKED***\'\n\n - \'***MASKED***\'\n\ncmd: echo hello ***MASKED*** ***MASKED*** bye\n\nstdout: hello ***MASKED*** ***MASKED*** bye" # noqa
|
|
222
|
+
assert expected in result['stdout']
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|