diff options
author | Jake Hunsaker <jhunsake@redhat.com> | 2020-05-20 16:51:08 -0400 |
---|---|---|
committer | Jake Hunsaker <jhunsake@redhat.com> | 2020-06-17 12:11:29 -0400 |
commit | 582eacb8d92b741959ad556ffcacd748fa3bbf14 (patch) | |
tree | ff2c30fc9ffefd1c760417c83e98d51f77241caf | |
parent | dc3b2014bc0a991dd587851f33f522f00f53fa35 (diff) | |
download | sos-582eacb8d92b741959ad556ffcacd748fa3bbf14.tar.gz |
[report] Add hook into SoSCleaner
Adds a new option, `--clean` or `--mask`, to hook a report into
`SoSCleaner`.
This is done after collection is complete, and before the archive is
built and compressed. Data is substituted in place for the report, which
means there will not be an obfuscated copy on disk. There will however
still be a mapping file produced and located in the same directory as
the final archive.
If it desired to have both an obfuscated and unobfuscated copy, it is
recommended to run `sos report` followed by a separate `sos clean`.
Related: #1987
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
-rw-r--r-- | sos/cleaner/__init__.py | 30 | ||||
-rw-r--r-- | sos/policies/__init__.py | 12 | ||||
-rw-r--r-- | sos/report/__init__.py | 29 |
3 files changed, 55 insertions, 16 deletions
diff --git a/sos/cleaner/__init__.py b/sos/cleaner/__init__.py index 2545e581..ec2d6ce2 100644 --- a/sos/cleaner/__init__.py +++ b/sos/cleaner/__init__.py @@ -42,17 +42,26 @@ class SoSCleaner(SoSComponent): 'target': '' } - def __init__(self, parser=None, args=None, cmdline=None, in_place=False): - if parser is not None and args is not None and cmdline is not None: + def __init__(self, parser=None, args=None, cmdline=None, in_place=False, + hook_commons=None): + if not in_place: # we are running `sos clean` directly super(SoSCleaner, self).__init__(parser, args, cmdline) self.from_cmdline = True else: # we are being hooked by either SoSReport or SoSCollector, don't - # re-init everything + # re-init everything as that will cause issues, but instead load + # the needed bits from the calling component + self.opts = hook_commons['options'] + self.tmpdir = hook_commons['tmpdir'] + self.sys_tmp = hook_commons['sys_tmp'] + self.policy = hook_commons['policy'] + self.from_cmdline = False + self.opts.map_file = '/etc/sos/cleaner/default_mapping' + self.opts.jobs = 4 + self.opts.no_update = False self.soslog = logging.getLogger('sos') self.ui_log = logging.getLogger('sos_ui') - self.from_cmdline = False self.validate_map_file() os.umask(0o77) @@ -92,16 +101,14 @@ class SoSCleaner(SoSComponent): a warning and continue on with cleaning building a fresh map """ default_map = '/etc/sos/cleaner/default_mapping' + if os.path.isdir(self.opts.map_file): + raise Exception("Requested map file %s is a directory" + % self.opts.map_file) if not os.path.exists(self.opts.map_file): if self.opts.map_file != default_map: self.log_error( - "Map file %s does not exist, will not load any obfuscation" - " matches" % self.opts.map_file) - if os.path.isdir(self.opts.map_file): - self.log_error( - "Requested map file %s is a directory. Ignoring `--map` option" - " and using %s" % default_map) - self.opts.map_file = default_map + "ERROR: map file %s does not exist, will not load any " + "obfuscation matches" % self.opts.map_file) def print_disclaimer(self): """When we are directly running `sos clean`, rather than hooking into @@ -234,6 +241,7 @@ third party. % self.opts.target) self._exit(1) if os.path.isdir(self.opts.target): + self.arc_name = self.opts.target.split('/')[-1] for _file in os.listdir(self.opts.target): if _file == 'sos_logs': self.report_paths.append(self.opts.target) diff --git a/sos/policies/__init__.py b/sos/policies/__init__.py index 7936590b..6fd08adf 100644 --- a/sos/policies/__init__.py +++ b/sos/policies/__init__.py @@ -30,6 +30,7 @@ try: except ImportError: REQUESTS_LOADED = False + def import_policy(name): policy_fqname = "sos.policies.%s" % name try: @@ -800,7 +801,8 @@ any third party. to use""" return "md5" - def display_results(self, archive, directory, checksum, archivestat=None): + def display_results(self, archive, directory, checksum, archivestat=None, + map_file=None): # Display results is called from the tail of SoSReport.final_work() # # Logging is already shutdown and all terminal output must use the @@ -812,16 +814,20 @@ any third party. self._print() + if map_file: + self._print(_("A mapping of obfuscated elements is available at" + "\n\t%s\n" % map_file)) + if archive: self._print(_("Your sosreport has been generated and saved " - "in:\n %s\n") % archive, always=True) + "in:\n\t%s\n") % archive, always=True) self._print(_(" Size\t%s") % get_human_readable(archivestat.st_size)) self._print(_(" Owner\t%s") % getpwuid(archivestat.st_uid).pw_name) else: self._print(_("Your sosreport build tree has been generated " - "in:\n %s\n") % directory, always=True) + "in:\n\t%s\n") % directory, always=True) if checksum: self._print(" " + self.get_preferred_hash_name() + "\t" + checksum) self._print() diff --git a/sos/report/__init__.py b/sos/report/__init__.py index fa0c4573..c0c2eb1b 100644 --- a/sos/report/__init__.py +++ b/sos/report/__init__.py @@ -30,6 +30,7 @@ import sos.policies from sos.report.reporting import (Report, Section, Command, CopiedFile, CreatedFile, Alert, Note, PlainTextReport, JSONReport, HTMLReport) +from sos.cleaner import SoSCleaner # file system errors that should terminate a run fatal_fs_errors = (errno.ENOSPC, errno.EROFS) @@ -78,6 +79,7 @@ class SoSReport(SoSComponent): 'build': False, 'case_id': '', 'chroot': 'auto', + 'clean': False, 'desc': '', 'dry_run': False, 'experimental': False, @@ -174,6 +176,9 @@ class SoSReport(SoSComponent): dest="all_logs", default=False, help="collect all available logs regardless " "of size") + parser.add_argument('--clean', '--mask', dest='clean', default=False, + action='store_true', + help='Obfuscate sensistive network information') parser.add_argument("--since", action="store", dest="since", default=None, type=_format_since, @@ -1098,6 +1103,21 @@ class SoSReport(SoSComponent): archive = None # archive path directory = None # report directory path (--build) + map_file = None # path of the map file generated for the report + + if self.opts.clean: + try: + hook_commons = { + 'policy': self.policy, + 'tmpdir': self.tmpdir, + 'sys_tmp': self.sys_tmp, + 'options': self.opts + } + cleaner = SoSCleaner(in_place=True, hook_commons=hook_commons) + cleaner.set_target_path(self.archive.get_archive_path()) + map_file = cleaner.execute() + except Exception as err: + print(_("ERROR: Unable to obfuscate report: %s" % err)) # package up and compress the results if not self.opts.build: @@ -1154,6 +1174,10 @@ class SoSReport(SoSComponent): # containing directory. final_name = os.path.join(self.sys_tmp, os.path.basename(archive)) + if self.opts.clean: + final_name = cleaner.obfuscate_string( + final_name.replace('.tar', '-obfuscated.tar') + ) # Get stat on the archive archivestat = os.stat(archive) @@ -1187,9 +1211,10 @@ class SoSReport(SoSComponent): if not self.opts.build: self.policy.display_results(archive, directory, checksum, - archivestat) + archivestat, map_file=map_file) else: - self.policy.display_results(archive, directory, checksum) + self.policy.display_results(archive, directory, checksum, + map_file=map_file) if self.opts.upload or self.opts.upload_url: if not self.opts.build: |