Fabian Deutsch has uploaded a new change for review. Change subject: process: Add a masking log ......................................................................
process: Add a masking log Previously there was no way to mask out parts of a command which was run. This could lead to situations where sensitive informations like passwords/usernames/addresses/etc. were exposed. To prevent this situation now a context manager is available to hide sensitive informations in command calls. Example: >>> import process >>> pw = "secret" >>> with masked([pw]): ... process.call(["app", "--user", "foo", "--password", pw]) In that example only ["app", "--user", "foo", "--password", "<masked>"] will get logged. Change-Id: I013e79b006c24e475f8f021c76a5156520145bfd Signed-off-by: Fabian Deutsch <[email protected]> --- M src/ovirt/node/utils/process.py 1 file changed, 42 insertions(+), 6 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-node refs/changes/22/22122/1 diff --git a/src/ovirt/node/utils/process.py b/src/ovirt/node/utils/process.py index 070863f..74a3c2d 100644 --- a/src/ovirt/node/utils/process.py +++ b/src/ovirt/node/utils/process.py @@ -28,13 +28,49 @@ """ -LOGGER = log.getLogger(__name__) - COMMON_POPEN_ARGS = { "close_fds": True } CalledProcessError = subprocess.CalledProcessError + + +def log_call(msg, args=[], kwargs={}, masks=[], logfunc=None): + logfunc = logfunc or log.getLogger(__name__).debug + masks = masks or log_call.masks + + # Replace masked items + if masks: + args = ["<masked>" if arg in masks else arg + for arg in args] + kwargs = dict((key, "<masked>" if v in masks else v) + for key, v in kwargs.items()) + + cmd = "%s %s" % (args, kwargs) + return logfunc("%s: %s" % (msg, cmd)) +log_call.masks = [] + + +def masked(masks): + """A context manager to hide certain args before logging + + >>> import sys + >>> with masked(["Lemmings"]): + ... log_call("Beware", ["Domminated", "By", + ... "Lemmings"], {"Save": "Lemmings"}, + ... logfunc=lambda x: x) + "Beware: ['Domminated', 'By', '<masked>'] {'Save': '<masked>'}" + """ + assert type(masks) is list + + class MaskedLog: + def __enter__(self): + self.old_masks = log_call.masks + log_call.masks = masks + def __exit__(self, exc_type, exc_value, traceback): + log_call.masks = self.old_masks + + return MaskedLog() def __update_kwargs(kwargs): @@ -71,7 +107,7 @@ """subprocess.Popen wrapper to not leak file descriptors """ kwargs = __update_kwargs(kwargs) - LOGGER.debug("Popen with: %s %s" % (args, kwargs)) + log_call("Popen with", args, kwargs) # Intentionally no check for common problems return subprocess.Popen(*args, **kwargs) @@ -89,7 +125,7 @@ 0 """ kwargs = __update_kwargs(kwargs) - LOGGER.debug("Calling with: %s %s" % (args, kwargs)) + log_call("Calling with", args, kwargs) __check_for_problems(args, kwargs) return int(subprocess.call(*args, **kwargs)) @@ -98,7 +134,7 @@ """subprocess.check_call wrapper to not leak file descriptors """ kwargs = __update_kwargs(kwargs) - LOGGER.debug("Checking call with: %s %s" % (args, kwargs)) + log_call("Checking call with", args, kwargs) __check_for_problems(args, kwargs) return int(subprocess.check_call(*args, **kwargs)) @@ -116,7 +152,7 @@ CalledProcessError: Command 'false' returned non-zero exit status 1 """ kwargs = __update_kwargs(kwargs) - LOGGER.debug("Checking output with: %s %s" % (args, kwargs)) + log_call("Checking output with", args, kwargs) __check_for_problems(args, kwargs) stdout = None try: -- To view, visit http://gerrit.ovirt.org/22122 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I013e79b006c24e475f8f021c76a5156520145bfd Gerrit-PatchSet: 1 Gerrit-Project: ovirt-node Gerrit-Branch: master Gerrit-Owner: Fabian Deutsch <[email protected]> _______________________________________________ node-patches mailing list [email protected] http://lists.ovirt.org/mailman/listinfo/node-patches
