Merge ~peppepetra/charm-sudo-pair:blacken-20.08 into charm-sudo-pair:master

Proposed by Giuseppe Petralia
Status: Merged
Approved by: Xav Paice
Approved revision: 224d95033be074db000f82e2c66fbcede961d58c
Merged at revision: 224d95033be074db000f82e2c66fbcede961d58c
Proposed branch: ~peppepetra/charm-sudo-pair:blacken-20.08
Merge into: charm-sudo-pair:master
Prerequisite: ~peppepetra/charm-sudo-pair:makefile-20.08
Diff against target: 801 lines (+242/-151)
9 files modified
src/actions/actions.py (+1/-1)
src/lib/libsudopair.py (+92/-38)
src/reactive/sudo_pair.py (+17/-10)
src/tests/functional/conftest.py (+27/-15)
src/tests/functional/test_deploy.py (+1/-1)
src/tests/unit/conftest.py (+6/-5)
src/tests/unit/test_actions.py (+9/-8)
src/tests/unit/test_libsudopair.py (+87/-70)
src/tox.ini (+2/-3)
Reviewer Review Type Date Requested Status
Xav Paice (community) Approve
Paul Goins Approve
Review via email: mp+388998@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Paul Goins (vultaire) wrote :

LGTM.

review: Approve
Revision history for this message
Xav Paice (xavpaice) wrote :

LGTM

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/actions/actions.py b/src/actions/actions.py
2index 1cb455c..2416eb3 100755
3--- a/src/actions/actions.py
4+++ b/src/actions/actions.py
5@@ -30,7 +30,7 @@ def remove():
6 sph.deconfigure()
7 msg = "Successfully removed sudo-pair config and binaries"
8 action_set({"message": msg})
9- status_set('active', msg)
10+ status_set("active", msg)
11
12
13 # A dictionary of all the defined actions to callables (which take
14diff --git a/src/lib/libsudopair.py b/src/lib/libsudopair.py
15index 05d1f9d..cbaf467 100644
16--- a/src/lib/libsudopair.py
17+++ b/src/lib/libsudopair.py
18@@ -25,8 +25,8 @@ def group_names_to_group_ids(group_names):
19 :param group_names: i.e. "root,user1,user2"
20 :return gids: i.e. "0,1001,1002"
21 """
22- group_names = list(filter(check_valid_group, group_names.split(',')))
23- return ','.join(map(str, (map(group_id, group_names))))
24+ group_names = list(filter(check_valid_group, group_names.split(",")))
25+ return ",".join(map(str, (map(group_id, group_names))))
26
27
28 def copy_file(source, destination, owner, group, perms):
29@@ -37,8 +37,10 @@ def copy_file(source, destination, owner, group, perms):
30 # This is a terrible default directory permission, as the file
31 # or its siblings will often contain secrets.
32 host.mkdir(os.path.dirname(destination), owner, group, perms=0o755)
33- with open(source, 'rb') as source_f:
34- host.write_file(destination, source_f.read(), perms=perms, owner=owner, group=group)
35+ with open(source, "rb") as source_f:
36+ host.write_file(
37+ destination, source_f.read(), perms=perms, owner=owner, group=group
38+ )
39
40
41 class SudoPairHelper(object):
42@@ -47,17 +49,17 @@ class SudoPairHelper(object):
43 def __init__(self):
44 """Retrieve charm config and set defaults."""
45 self.charm_config = hookenv.config()
46- self.binary_path = '/usr/bin/sudo_approve'
47- self.sudo_conf_path = '/etc/sudo.conf'
48- self.sudoers_path = '/etc/sudoers'
49- self.sudo_lib_path = '/usr/lib/sudo/sudo_pair.so'
50+ self.binary_path = "/usr/bin/sudo_approve"
51+ self.sudo_conf_path = "/etc/sudo.conf"
52+ self.sudoers_path = "/etc/sudoers"
53+ self.sudo_lib_path = "/usr/lib/sudo/sudo_pair.so"
54 self.sudoers_bypass_path = "/etc/sudoers.d/91-bypass-sudopair-cmds"
55- self.user_prompt_path = '/etc/sudo_pair.prompt.user'
56- self.pair_prompt_path = '/etc/sudo_pair.prompt.pair'
57- self.socket_dir = '/var/run/sudo_pair'
58- self.tmpfiles_conf = '/usr/lib/tmpfiles.d/sudo_pair.conf'
59- self.owner = 'root'
60- self.group = 'root'
61+ self.user_prompt_path = "/etc/sudo_pair.prompt.user"
62+ self.pair_prompt_path = "/etc/sudo_pair.prompt.pair"
63+ self.socket_dir = "/var/run/sudo_pair"
64+ self.tmpfiles_conf = "/usr/lib/tmpfiles.d/sudo_pair.conf"
65+ self.owner = "root"
66+ self.group = "root"
67 self.socket_dir_perms = 0o644
68 self.sudo_pair_so_perms = 0o644
69 self.prompt_perms = 0o644
70@@ -68,12 +70,16 @@ class SudoPairHelper(object):
71 def get_config(self):
72 """Return config as a dict."""
73 config = {
74- 'binary_path': self.binary_path,
75- 'user_prompt_path': self.user_prompt_path,
76- 'pair_prompt_path': self.pair_prompt_path,
77- 'socket_dir': self.socket_dir,
78- 'gids_enforced': group_names_to_group_ids(self.charm_config['groups_enforced']),
79- 'gids_exempted': group_names_to_group_ids(self.charm_config['groups_exempted']),
80+ "binary_path": self.binary_path,
81+ "user_prompt_path": self.user_prompt_path,
82+ "pair_prompt_path": self.pair_prompt_path,
83+ "socket_dir": self.socket_dir,
84+ "gids_enforced": group_names_to_group_ids(
85+ self.charm_config["groups_enforced"]
86+ ),
87+ "gids_exempted": group_names_to_group_ids(
88+ self.charm_config["groups_exempted"]
89+ ),
90 }
91
92 config.update(self.charm_config)
93@@ -85,12 +91,23 @@ class SudoPairHelper(object):
94
95 def render_sudo_conf(self):
96 """Render sudo.conf file."""
97- return templating.render('sudo.conf.tmpl', self.sudo_conf_path, self.get_config(),
98- perms=self.sudo_conf_perms, owner=self.owner, group=self.group)
99+ return templating.render(
100+ "sudo.conf.tmpl",
101+ self.sudo_conf_path,
102+ self.get_config(),
103+ perms=self.sudo_conf_perms,
104+ owner=self.owner,
105+ group=self.group,
106+ )
107
108 def create_socket_dir(self):
109 """Create socket dir."""
110- host.mkdir(self.socket_dir, perms=self.socket_dir_perms, owner=self.owner, group=self.group)
111+ host.mkdir(
112+ self.socket_dir,
113+ perms=self.socket_dir_perms,
114+ owner=self.owner,
115+ group=self.group,
116+ )
117
118 def create_tmpfiles_conf(self):
119 """Create temporary conf file."""
120@@ -99,36 +116,71 @@ class SudoPairHelper(object):
121
122 def install_sudo_pair_so(self):
123 """Install sudo-pair lib."""
124- sudo_pair_lib = os.path.join(hookenv.charm_dir(), 'files', 'sudo_pair.so')
125- copy_file(sudo_pair_lib, self.sudo_lib_path, self.owner, self.group, self.sudo_pair_so_perms)
126+ sudo_pair_lib = os.path.join(hookenv.charm_dir(), "files", "sudo_pair.so")
127+ copy_file(
128+ sudo_pair_lib,
129+ self.sudo_lib_path,
130+ self.owner,
131+ self.group,
132+ self.sudo_pair_so_perms,
133+ )
134
135 def copy_user_prompt(self):
136 """Copy user prompt on the unit."""
137- prompt_file = os.path.join(hookenv.charm_dir(), 'files', 'sudo.prompt.user')
138- copy_file(prompt_file, self.user_prompt_path, self.owner, self.group, self.prompt_perms)
139+ prompt_file = os.path.join(hookenv.charm_dir(), "files", "sudo.prompt.user")
140+ copy_file(
141+ prompt_file,
142+ self.user_prompt_path,
143+ self.owner,
144+ self.group,
145+ self.prompt_perms,
146+ )
147
148 def copy_pair_prompt(self):
149 """Copy pair prompt on the unit."""
150- prompt_file = os.path.join(hookenv.charm_dir(), 'files', 'sudo.prompt.pair')
151- copy_file(prompt_file, self.pair_prompt_path, self.owner, self.group, self.prompt_perms)
152+ prompt_file = os.path.join(hookenv.charm_dir(), "files", "sudo.prompt.pair")
153+ copy_file(
154+ prompt_file,
155+ self.pair_prompt_path,
156+ self.owner,
157+ self.group,
158+ self.prompt_perms,
159+ )
160
161 def copy_sudoers(self):
162 """Copy sudoers file on the unit."""
163- sudoers_file = os.path.join(hookenv.charm_dir(), 'files', 'sudoers')
164- copy_file(sudoers_file, self.sudoers_path, self.owner, self.group, self.sudoers_perms)
165+ sudoers_file = os.path.join(hookenv.charm_dir(), "files", "sudoers")
166+ copy_file(
167+ sudoers_file, self.sudoers_path, self.owner, self.group, self.sudoers_perms
168+ )
169
170 def render_sudo_approve(self):
171 """Render sudo-approve file."""
172 hookenv.log("Rendering sudo_approve.tmpl to {}".format(self.binary_path))
173- return templating.render('sudo_approve.tmpl', self.binary_path, self.get_config(),
174- perms=self.sudo_approve_perms, owner=self.owner, group=self.group)
175+ return templating.render(
176+ "sudo_approve.tmpl",
177+ self.binary_path,
178+ self.get_config(),
179+ perms=self.sudo_approve_perms,
180+ owner=self.owner,
181+ group=self.group,
182+ )
183
184 def render_bypass_cmds(self):
185 """Render bypass command file."""
186- if self.get_config()['bypass_cmds'] != "" and self.get_config()['bypass_group'] != "":
187+ if (
188+ self.get_config()["bypass_cmds"] != ""
189+ and self.get_config()["bypass_group"] != ""
190+ ):
191 hookenv.log("Render bypass cmds to {}".format(self.sudoers_bypass_path))
192- return templating.render('91-bypass-sudopair-cmds.tmpl', self.sudoers_bypass_path,
193- self.get_config(), perms=0o440, owner=self.owner, group=self.group)
194+ return templating.render(
195+ "91-bypass-sudopair-cmds.tmpl",
196+ self.sudoers_bypass_path,
197+ self.get_config(),
198+ perms=0o440,
199+ owner=self.owner,
200+ group=self.group,
201+ )
202 return None
203
204 def deconfigure(self):
205@@ -140,7 +192,7 @@ class SudoPairHelper(object):
206 self.user_prompt_path,
207 self.pair_prompt_path,
208 self.sudoers_bypass_path,
209- self.tmpfiles_conf
210+ self.tmpfiles_conf,
211 ]
212 hookenv.log("Deleting: {}".format(paths))
213 for path in paths:
214@@ -148,4 +200,6 @@ class SudoPairHelper(object):
215 os.unlink(path)
216 except Exception as e:
217 # We're trying hard to delete all files, even if some might fail
218- hookenv.log("Got exception unlinking {}: {}, continuing".format(path, e))
219+ hookenv.log(
220+ "Got exception unlinking {}: {}, continuing".format(path, e)
221+ )
222diff --git a/src/reactive/sudo_pair.py b/src/reactive/sudo_pair.py
223index 974dd66..ed1d7ba 100644
224--- a/src/reactive/sudo_pair.py
225+++ b/src/reactive/sudo_pair.py
226@@ -7,10 +7,14 @@ from libsudopair import SudoPairHelper
227 sph = SudoPairHelper()
228
229
230-@when('apt.installed.socat')
231-@when_not('sudo-pair.configured')
232+@when("apt.installed.socat")
233+@when_not("sudo-pair.configured")
234 def install_sudo_pair():
235- # Install sudo_pair.so, create socket dir, copy sudo_approve to /usr/bin, copy prompts to /etc
236+ """Install sudo pair.
237+
238+ Install sudo_pair.so, create socket dir, copy sudo_approve to /usr/bin
239+ and copy prompts to /etc.
240+ """
241 sph.install_sudo_pair_so()
242
243 sph.create_socket_dir()
244@@ -32,18 +36,21 @@ def install_sudo_pair():
245 # Add Plugin sudo_pair sudo_pair.so to sudo.conf
246 sph.render_sudo_conf()
247
248- set_state('sudo-pair.installed')
249- set_state('sudo-pair.configured')
250- hookenv.status_set('active', 'sudo pairing for users groups: [{}]'.format(sph.get_config()['gids_enforced']))
251+ set_state("sudo-pair.installed")
252+ set_state("sudo-pair.configured")
253+ hookenv.status_set(
254+ "active",
255+ "sudo pairing for users groups: [{}]".format(sph.get_config()["gids_enforced"]),
256+ )
257
258
259-@hook('config-changed')
260+@hook("config-changed")
261 def reconfigure_sudo_pair_charm():
262 sph.set_charm_config(hookenv.config())
263- remove_state('sudo-pair.configured')
264+ remove_state("sudo-pair.configured")
265
266
267-@hook('stop')
268+@hook("stop")
269 def stop():
270 sph.deconfigure()
271- remove_state('sudo-pair.installed')
272+ remove_state("sudo-pair.installed")
273diff --git a/src/tests/functional/conftest.py b/src/tests/functional/conftest.py
274index 68f3ffe..7a8523e 100644
275--- a/src/tests/functional/conftest.py
276+++ b/src/tests/functional/conftest.py
277@@ -16,7 +16,7 @@ import pytest
278 STAT_FILE = "python3 -c \"import json; import os; s=os.stat('%s'); print(json.dumps({'uid': s.st_uid, 'gid': s.st_gid, 'mode': oct(s.st_mode), 'size': s.st_size}))\"" # noqa: E501
279
280
281-@pytest.yield_fixture(scope='module')
282+@pytest.yield_fixture(scope="module")
283 def event_loop(request):
284 """Override the default pytest event loop to allow for broaded scopedv fixtures."""
285 loop = asyncio.get_event_loop_policy().new_event_loop()
286@@ -27,7 +27,7 @@ def event_loop(request):
287 asyncio.set_event_loop(None)
288
289
290-@pytest.fixture(scope='module')
291+@pytest.fixture(scope="module")
292 async def controller():
293 """Connect to the current controller."""
294 controller = Controller()
295@@ -36,21 +36,21 @@ async def controller():
296 await controller.disconnect()
297
298
299-@pytest.fixture(scope='module')
300+@pytest.fixture(scope="module")
301 async def model(controller):
302 """Create a model that lives only for the duration of the test."""
303 model_name = "functest-{}".format(uuid.uuid4())
304 model = await controller.add_model(model_name)
305 yield model
306 await model.disconnect()
307- if os.getenv('PYTEST_KEEP_MODEL'):
308+ if os.getenv("PYTEST_KEEP_MODEL"):
309 return
310 await controller.destroy_model(model_name)
311 while model_name in await controller.list_models():
312 await asyncio.sleep(1)
313
314
315-@pytest.fixture(scope='module')
316+@pytest.fixture(scope="module")
317 async def current_model():
318 """Return the current model, does not create or destroy it."""
319 model = Model()
320@@ -62,29 +62,34 @@ async def current_model():
321 @pytest.fixture
322 async def get_app(model):
323 """Return the application requested."""
324+
325 async def _get_app(name):
326 try:
327 return model.applications[name]
328 except KeyError:
329 raise JujuError("Cannot find application {}".format(name))
330+
331 return _get_app
332
333
334 @pytest.fixture
335 async def get_unit(model):
336 """Return the requested <app_name>/<unit_number> unit."""
337+
338 async def _get_unit(name):
339 try:
340- (app_name, unit_number) = name.split('/')
341+ (app_name, unit_number) = name.split("/")
342 return model.applications[app_name].units[unit_number]
343 except (KeyError, ValueError):
344 raise JujuError("Cannot find unit {}".format(name))
345+
346 return _get_unit
347
348
349 @pytest.fixture
350 async def get_entity(model, get_unit, get_app):
351 """Return a unit or an application."""
352+
353 async def _get_entity(name):
354 try:
355 return await get_unit(name)
356@@ -93,6 +98,7 @@ async def get_entity(model, get_unit, get_app):
357 return await get_app(name)
358 except JujuError:
359 raise JujuError("Cannot find entity {}".format(name))
360+
361 return _get_entity
362
363
364@@ -104,14 +110,12 @@ async def run_command(get_unit):
365 :param cmd: Command to be run
366 :param target: Unit object or unit name string
367 """
368+
369 async def _run_command(cmd, target):
370- unit = (
371- target
372- if type(target) is juju.unit.Unit
373- else await get_unit(target)
374- )
375+ unit = target if type(target) is juju.unit.Unit else await get_unit(target)
376 action = await unit.run(cmd)
377 return action.results
378+
379 return _run_command
380
381
382@@ -123,10 +127,12 @@ async def file_stat(run_command):
383 :param path: File path
384 :param target: Unit object or unit name string
385 """
386+
387 async def _file_stat(path, target):
388 cmd = STAT_FILE % path
389 results = await run_command(cmd, target)
390- return json.loads(results['Stdout'])
391+ return json.loads(results["Stdout"])
392+
393 return _file_stat
394
395
396@@ -138,16 +144,19 @@ async def file_contents(run_command):
397 :param path: File path
398 :param target: Unit object or unit name string
399 """
400+
401 async def _file_contents(path, target):
402- cmd = 'cat {}'.format(path)
403+ cmd = "cat {}".format(path)
404 results = await run_command(cmd, target)
405- return results['Stdout']
406+ return results["Stdout"]
407+
408 return _file_contents
409
410
411 @pytest.fixture
412 async def reconfigure_app(get_app, model):
413 """Apply a different config to the requested app."""
414+
415 async def _reconfigure_app(cfg, target):
416 application = (
417 target
418@@ -156,14 +165,17 @@ async def reconfigure_app(get_app, model):
419 )
420 await application.set_config(cfg)
421 await application.get_config()
422- await model.block_until(lambda: application.status == 'active')
423+ await model.block_until(lambda: application.status == "active")
424+
425 return _reconfigure_app
426
427
428 @pytest.fixture
429 async def create_group(run_command):
430 """Create the UNIX group specified."""
431+
432 async def _create_group(group_name, target):
433 cmd = "sudo groupadd %s" % group_name
434 await run_command(cmd, target)
435+
436 return _create_group
437diff --git a/src/tests/functional/test_deploy.py b/src/tests/functional/test_deploy.py
438index 1d531d1..7f24224 100644
439--- a/src/tests/functional/test_deploy.py
440+++ b/src/tests/functional/test_deploy.py
441@@ -117,7 +117,7 @@ async def test_sudoers_bypass_conf(file_contents, unit):
442
443
444 async def test_reconfigure(reconfigure_app, file_contents, unit, app):
445- """Change a charm config parameter and verify that it has been propagated to the unit."""
446+ """Change a charm config parameter and verify it is applied."""
447 sudo_approve_path = "/usr/bin/sudo_approve"
448 await reconfigure_app(cfg={"auto_approve": "false"}, target=app)
449 sudo_approve_content = await file_contents(path=sudo_approve_path, target=unit)
450diff --git a/src/tests/unit/conftest.py b/src/tests/unit/conftest.py
451index c0800ea..9ca50ec 100644
452--- a/src/tests/unit/conftest.py
453+++ b/src/tests/unit/conftest.py
454@@ -14,25 +14,26 @@ def mock_hookenv_config(monkeypatch):
455
456 def mock_config():
457 cfg = {}
458- yml = yaml.load(open('./config.yaml'))
459+ yml = yaml.load(open("./config.yaml"))
460
461 # Load all defaults
462- for key, value in yml['options'].items():
463- cfg[key] = value['default']
464+ for key, value in yml["options"].items():
465+ cfg[key] = value["default"]
466
467 return cfg
468
469- monkeypatch.setattr('charmhelpers.core.hookenv.config', mock_config)
470+ monkeypatch.setattr("charmhelpers.core.hookenv.config", mock_config)
471
472
473 @pytest.fixture
474 def mock_charm_dir(monkeypatch):
475- monkeypatch.setattr('charmhelpers.core.hookenv.charm_dir', lambda: '.')
476+ monkeypatch.setattr("charmhelpers.core.hookenv.charm_dir", lambda: ".")
477
478
479 @pytest.fixture
480 def sph(mock_hookenv_config, mock_charm_dir, tmpdir):
481 from libsudopair import SudoPairHelper
482+
483 sph = SudoPairHelper()
484 sph.owner = pwd.getpwuid(os.getuid()).pw_name
485 sph.group = grp.getgrgid(os.getgid()).gr_name
486diff --git a/src/tests/unit/test_actions.py b/src/tests/unit/test_actions.py
487index c2da297..d6d86d7 100644
488--- a/src/tests/unit/test_actions.py
489+++ b/src/tests/unit/test_actions.py
490@@ -1,17 +1,18 @@
491 import os
492 import sys
493 import unittest.mock as mock
494-action_path = os.path.join(os.path.dirname(__file__), '..', '..', 'actions')
495+
496+action_path = os.path.join(os.path.dirname(__file__), "..", "..", "actions")
497 sys.path.append(action_path)
498-import actions # NOQA
499+import actions # NOQA
500
501
502-@mock.patch('libsudopair.SudoPairHelper')
503-@mock.patch('actions.action_set')
504-@mock.patch('actions.status_set')
505+@mock.patch("libsudopair.SudoPairHelper")
506+@mock.patch("actions.action_set")
507+@mock.patch("actions.status_set")
508 def test_remove_action(status_set, action_set, sudo_pair_helper):
509 actions.remove()
510- msg = 'Successfully removed sudo-pair config and binaries'
511- action_set.assert_called_with({'message': msg})
512- status_set.assert_called_with('active', msg)
513+ msg = "Successfully removed sudo-pair config and binaries"
514+ action_set.assert_called_with({"message": msg})
515+ status_set.assert_called_with("active", msg)
516 sudo_pair_helper().deconfigure.assert_called()
517diff --git a/src/tests/unit/test_libsudopair.py b/src/tests/unit/test_libsudopair.py
518index 3a598af..874f0a3 100644
519--- a/src/tests/unit/test_libsudopair.py
520+++ b/src/tests/unit/test_libsudopair.py
521@@ -2,14 +2,11 @@ import filecmp
522 import grp
523 import os
524
525-from libsudopair import (
526- check_valid_group,
527- group_id
528-)
529+from libsudopair import check_valid_group, group_id
530
531
532 def test_check_valid_group():
533- assert not check_valid_group('fake_group')
534+ assert not check_valid_group("fake_group")
535 assert check_valid_group(grp.getgrgid(os.getgid()).gr_name)
536
537
538@@ -17,7 +14,7 @@ def test_group_id():
539 assert group_id(grp.getgrgid(os.getgid()).gr_name) == os.getgid()
540
541
542-class TestSudoPairHelper():
543+class TestSudoPairHelper:
544 """Module to test SudoPairHelper lib."""
545
546 def test_pytest(self):
547@@ -31,12 +28,12 @@ class TestSudoPairHelper():
548 def test_get_config(self, sph):
549 """Check if config contains all the required entries."""
550 default_keywords = [
551- 'binary_path',
552- 'user_prompt_path',
553- 'pair_prompt_path',
554- 'socket_dir',
555- 'gids_enforced',
556- 'gids_exempted',
557+ "binary_path",
558+ "user_prompt_path",
559+ "pair_prompt_path",
560+ "socket_dir",
561+ "gids_enforced",
562+ "gids_exempted",
563 ]
564 config = sph.get_config()
565 for option in default_keywords:
566@@ -45,11 +42,11 @@ class TestSudoPairHelper():
567 def test_set_charm_config(self, sph):
568 """Set new config."""
569 charm_config = {
570- 'groups_enforced': 'root',
571- 'groups_exempted': '',
572- 'bypass_cmds': '',
573- 'bypass_group': '',
574- 'auto_approve': True
575+ "groups_enforced": "root",
576+ "groups_exempted": "",
577+ "bypass_cmds": "",
578+ "bypass_group": "",
579+ "auto_approve": True,
580 }
581
582 sph.set_charm_config(charm_config)
583@@ -62,67 +59,79 @@ class TestSudoPairHelper():
584 """Check that sudo.conf is rendered correctly."""
585 # Default config
586 content = sph.render_sudo_conf()
587- expected_content = 'Plugin sudo_pair sudo_pair.so binary_path={} ' \
588- 'user_prompt_path={} ' \
589- 'pair_prompt_path={} socket_dir={} gids_enforced={}'.format(
590- tmpdir.join('/usr/bin/sudo_approve'),
591- tmpdir.join('/etc/sudo_pair.prompt.user'),
592- tmpdir.join('/etc/sudo_pair.prompt.pair'),
593- tmpdir.join('/var/run/sudo_pair'),
594- '0')
595+ expected_content = (
596+ "Plugin sudo_pair sudo_pair.so binary_path={} "
597+ "user_prompt_path={} "
598+ "pair_prompt_path={} socket_dir={} gids_enforced={}".format(
599+ tmpdir.join("/usr/bin/sudo_approve"),
600+ tmpdir.join("/etc/sudo_pair.prompt.user"),
601+ tmpdir.join("/etc/sudo_pair.prompt.pair"),
602+ tmpdir.join("/var/run/sudo_pair"),
603+ "0",
604+ )
605+ )
606 assert expected_content in content
607
608 # Gid exempted
609 groups_exempted = grp.getgrgid(os.getgid()).gr_name
610 charm_config = {
611- 'groups_enforced': 'root',
612- 'groups_exempted': groups_exempted,
613- 'bypass_cmds': '',
614- 'bypass_group': '',
615- 'auto_approve': True
616+ "groups_enforced": "root",
617+ "groups_exempted": groups_exempted,
618+ "bypass_cmds": "",
619+ "bypass_group": "",
620+ "auto_approve": True,
621 }
622
623 sph.set_charm_config(charm_config)
624- expected_content = \
625- 'Plugin sudo_pair sudo_pair.so binary_path={} user_prompt_path={} ' \
626- 'pair_prompt_path={} socket_dir={} gids_enforced={} gids_exempted={}'.format(
627- tmpdir.join('/usr/bin/sudo_approve'),
628- tmpdir.join('/etc/sudo_pair.prompt.user'),
629- tmpdir.join('/etc/sudo_pair.prompt.pair'),
630- tmpdir.join('/var/run/sudo_pair'), '0', os.getgid())
631+ expected_content = (
632+ "Plugin sudo_pair sudo_pair.so binary_path={} user_prompt_path={} "
633+ "pair_prompt_path={} socket_dir={} gids_enforced={} "
634+ "gids_exempted={}".format(
635+ tmpdir.join("/usr/bin/sudo_approve"),
636+ tmpdir.join("/etc/sudo_pair.prompt.user"),
637+ tmpdir.join("/etc/sudo_pair.prompt.pair"),
638+ tmpdir.join("/var/run/sudo_pair"),
639+ "0",
640+ os.getgid(),
641+ )
642+ )
643
644 content = sph.render_sudo_conf()
645 assert expected_content in content
646
647 # Groups enforced
648- groups_enforced = 'root,' + grp.getgrgid(os.getgid()).gr_name
649+ groups_enforced = "root," + grp.getgrgid(os.getgid()).gr_name
650 charm_config = {
651- 'groups_enforced': groups_enforced,
652- 'groups_exempted': '',
653- 'bypass_cmds': '',
654- 'bypass_group': '',
655- 'auto_approve': True
656+ "groups_enforced": groups_enforced,
657+ "groups_exempted": "",
658+ "bypass_cmds": "",
659+ "bypass_group": "",
660+ "auto_approve": True,
661 }
662 sph.set_charm_config(charm_config)
663- expected_content = 'Plugin sudo_pair sudo_pair.so binary_path={} user_prompt_path={} ' \
664- 'pair_prompt_path={} socket_dir={} gids_enforced={}'.format(
665- tmpdir.join('/usr/bin/sudo_approve'),
666- tmpdir.join('/etc/sudo_pair.prompt.user'),
667- tmpdir.join('/etc/sudo_pair.prompt.pair'),
668- tmpdir.join('/var/run/sudo_pair'), '0,{}'.format(os.getgid()))
669+ expected_content = (
670+ "Plugin sudo_pair sudo_pair.so binary_path={} user_prompt_path={} "
671+ "pair_prompt_path={} socket_dir={} gids_enforced={}".format(
672+ tmpdir.join("/usr/bin/sudo_approve"),
673+ tmpdir.join("/etc/sudo_pair.prompt.user"),
674+ tmpdir.join("/etc/sudo_pair.prompt.pair"),
675+ tmpdir.join("/var/run/sudo_pair"),
676+ "0,{}".format(os.getgid()),
677+ )
678+ )
679 content = sph.render_sudo_conf()
680 assert expected_content in content
681
682 def test_render_bypass_cmds(self, sph):
683 """Check that sudoers file is rendered correctly."""
684 # Root bypass /bin/ls
685- expected_content = '%root ALL = (ALL) NOLOG_OUTPUT: /bin/ls'
686+ expected_content = "%root ALL = (ALL) NOLOG_OUTPUT: /bin/ls"
687 charm_config = {
688- 'groups_enforced': 'root',
689- 'groups_exempted': '',
690- 'bypass_cmds': '/bin/ls',
691- 'bypass_group': 'root',
692- 'auto_approve': True
693+ "groups_enforced": "root",
694+ "groups_exempted": "",
695+ "bypass_cmds": "/bin/ls",
696+ "bypass_group": "root",
697+ "auto_approve": True,
698 }
699 sph.set_charm_config(charm_config)
700 content = sph.render_bypass_cmds()
701@@ -131,9 +140,11 @@ class TestSudoPairHelper():
702 def test_render_sudo_approve(self, sph, tmpdir):
703 """Check that sudo_approve file is rendered correctly."""
704 # Auto Approve true
705- expected_content = 'echo ${log_line} >> /var/log/sudo_pair.log'
706- socket_dir = tmpdir.join('/var/run/sudo_pair')
707- expected_content_socket_dir = 'declare -r SUDO_SOCKET_PATH="{}"'.format(socket_dir)
708+ expected_content = "echo ${log_line} >> /var/log/sudo_pair.log"
709+ socket_dir = tmpdir.join("/var/run/sudo_pair")
710+ expected_content_socket_dir = 'declare -r SUDO_SOCKET_PATH="{}"'.format(
711+ socket_dir
712+ )
713 content = sph.render_sudo_approve()
714 assert expected_content in content
715 assert expected_content_socket_dir in content
716@@ -141,11 +152,11 @@ class TestSudoPairHelper():
717 # Auto Approve false
718 expected_content = 'echo "You can\'t approve your own session."'
719 charm_config = {
720- 'groups_enforced': 'root',
721- 'groups_exempted': '',
722- 'bypass_cmds': '/bin/ls',
723- 'bypass_group': 'root',
724- 'auto_approve': False
725+ "groups_enforced": "root",
726+ "groups_exempted": "",
727+ "bypass_cmds": "/bin/ls",
728+ "bypass_group": "root",
729+ "auto_approve": False,
730 }
731 sph.set_charm_config(charm_config)
732 content = sph.render_sudo_approve()
733@@ -154,32 +165,38 @@ class TestSudoPairHelper():
734 def test_create_socket_dir(self, sph, tmpdir):
735 """Check that sudo_pair socket dir exists."""
736 sph.create_socket_dir()
737- assert os.path.exists(tmpdir.join('/var/run/sudo_pair'))
738+ assert os.path.exists(tmpdir.join("/var/run/sudo_pair"))
739
740 def test_create_tmpfiles_conf(self, sph, tmpdir):
741 """Check that sudo pair temporary conf is rendered correctly."""
742 sph.create_tmpfiles_conf()
743- expected_content = 'd {} 0755 - - -\n'.format(sph.socket_dir)
744- with open(tmpdir.join('/usr/lib/tmpfiles.d/sudo_pair.conf')) as f:
745+ expected_content = "d {} 0755 - - -\n".format(sph.socket_dir)
746+ with open(tmpdir.join("/usr/lib/tmpfiles.d/sudo_pair.conf")) as f:
747 content = f.read()
748 assert expected_content in content
749
750 def test_install_sudo_pair_so(self, sph, tmpdir):
751 """Check that sudo system lib exists."""
752 sph.install_sudo_pair_so()
753- assert filecmp.cmp('./files/sudo_pair.so', tmpdir.join('/usr/lib/sudo/sudo_pair.so'))
754+ assert filecmp.cmp(
755+ "./files/sudo_pair.so", tmpdir.join("/usr/lib/sudo/sudo_pair.so")
756+ )
757
758 def test_copy_user_prompt(self, sph, tmpdir):
759 """Check that user prompt exists."""
760 sph.copy_user_prompt()
761- assert filecmp.cmp('./files/sudo.prompt.user', tmpdir.join('/etc/sudo_pair.prompt.user'))
762+ assert filecmp.cmp(
763+ "./files/sudo.prompt.user", tmpdir.join("/etc/sudo_pair.prompt.user")
764+ )
765
766 def test_copy_pair_prompt(self, sph, tmpdir):
767 """Check that pair prompt exists."""
768 sph.copy_pair_prompt()
769- assert filecmp.cmp('./files/sudo.prompt.pair', tmpdir.join('/etc/sudo_pair.prompt.pair'))
770+ assert filecmp.cmp(
771+ "./files/sudo.prompt.pair", tmpdir.join("/etc/sudo_pair.prompt.pair")
772+ )
773
774 def test_copy_sudoers(self, sph, tmpdir):
775 """Check that sudoers file exists."""
776 sph.copy_sudoers()
777- assert filecmp.cmp('./files/sudoers', tmpdir.join('/etc/sudoers'))
778+ assert filecmp.cmp("./files/sudoers", tmpdir.join("/etc/sudoers"))
779diff --git a/src/tox.ini b/src/tox.ini
780index d07b692..2085ea9 100644
781--- a/src/tox.ini
782+++ b/src/tox.ini
783@@ -25,7 +25,7 @@ passenv =
784 [testenv:lint]
785 commands =
786 flake8
787-#TODO black --check --exclude "/(\.eggs|\.git|\.tox|\.venv|\.build|dist|charmhelpers|mod)/" .
788+ black --check --exclude "/(\.eggs|\.git|\.tox|\.venv|\.build|dist|charmhelpers|mod)/" .
789 deps =
790 black
791 flake8
792@@ -43,8 +43,7 @@ exclude =
793 mod,
794 .build
795
796-max-line-length = 120
797-#TODO max-line-length = 88
798+max-line-length = 88
799 max-complexity = 10
800
801 [testenv:black]

Subscribers

People subscribed via source and target branches