Blame org_fedora_oscap/common.py

Packit 792a06
#
Packit 792a06
# Copyright (C) 2013  Red Hat, Inc.
Packit 792a06
#
Packit 792a06
# This copyrighted material is made available to anyone wishing to use,
Packit 792a06
# modify, copy, or redistribute it subject to the terms and conditions of
Packit 792a06
# the GNU General Public License v.2, or (at your option) any later version.
Packit 792a06
# This program is distributed in the hope that it will be useful, but WITHOUT
Packit 792a06
# ANY WARRANTY expressed or implied, including the implied warranties of
Packit 792a06
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
Packit 792a06
# Public License for more details.  You should have received a copy of the
Packit 792a06
# GNU General Public License along with this program; if not, write to the
Packit 792a06
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit 792a06
# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
Packit 792a06
# source code or documentation are not subject to the GNU General Public
Packit 792a06
# License and may only be used or replicated with the express permission of
Packit 792a06
# Red Hat, Inc.
Packit 792a06
#
Packit 792a06
# Red Hat Author(s): Vratislav Podzimek <vpodzime@redhat.com>
Packit 792a06
#
Packit 792a06
Packit 792a06
"""
Packit 792a06
Module with various classes and functions needed by the OSCAP addon that are
Packit 792a06
not specific to any installation mode (tui, gui, ks).
Packit 792a06
Packit 792a06
"""
Packit 792a06
Packit 792a06
import os
Packit 792a06
import tempfile
Packit 792a06
import subprocess
Packit 792a06
import zipfile
Packit 792a06
import tarfile
Packit 792a06
Packit 792a06
import cpioarchive
Packit 792a06
import re
Packit 792a06
import logging
Packit 792a06
Packit 792a06
from collections import namedtuple
Packit 792a06
import gettext
Packit 792a06
from functools import wraps
Packit 792a06
from pyanaconda.core import constants
Packit 792a06
from pyanaconda.modules.common.constants.services import NETWORK
Packit 792a06
from pyanaconda.threading import threadMgr, AnacondaThread
Packit 792a06
from org_fedora_oscap import utils
Packit 792a06
from org_fedora_oscap.data_fetch import fetch_data
Packit 792a06
Packit 792a06
log = logging.getLogger("anaconda")
Packit 792a06
Packit 792a06
Packit 792a06
# mimick pyanaconda/core/i18n.py
Packit 792a06
def _(string):
Packit 792a06
    if string:
Packit 792a06
        return gettext.translation("oscap-anaconda-addon", fallback=True).gettext(string)
Packit 792a06
    else:
Packit 792a06
        return ""
Packit 792a06
Packit 792a06
Packit 792a06
def N_(string): return string
Packit 792a06
Packit 792a06
Packit 792a06
# everything else should be private
Packit 792a06
__all__ = ["run_oscap_remediate", "get_fix_rules_pre",
Packit 792a06
           "wait_and_fetch_net_data", "extract_data", "strip_content_dir",
Packit 792a06
           "OSCAPaddonError"]
Packit 792a06
Packit 792a06
INSTALLATION_CONTENT_DIR = "/tmp/openscap_data/"
Packit 792a06
TARGET_CONTENT_DIR = "/root/openscap_data/"
Packit 792a06
Packit 792a06
SSG_DIR = "/usr/share/xml/scap/ssg/content/"
Packit 792a06
SSG_CONTENT = "ssg-rhel7-ds.xml"
Packit 792a06
if constants.shortProductName != 'anaconda':
Packit 792a06
    if constants.shortProductName == 'fedora':
Packit 792a06
        SSG_CONTENT  = "ssg-fedora-ds.xml"
Packit 792a06
    else:
Packit 792a06
        SSG_CONTENT = "ssg-%s%s-ds.xml" % (constants.shortProductName,
Packit 792a06
                                            constants.productVersion.strip(".")[0])
Packit 792a06
Packit 792a06
RESULTS_PATH = utils.join_paths(TARGET_CONTENT_DIR,
Packit 792a06
                                "eval_remediate_results.xml")
Packit 792a06
REPORT_PATH = utils.join_paths(TARGET_CONTENT_DIR,
Packit 792a06
                               "eval_remediate_report.html")
Packit 792a06
Packit 792a06
PRE_INSTALL_FIX_SYSTEM_ATTR = "urn:redhat:anaconda:pre"
Packit 792a06
Packit 792a06
THREAD_FETCH_DATA = "AnaOSCAPdataFetchThread"
Packit 792a06
Packit 792a06
SUPPORTED_ARCHIVES = (".zip", ".tar", ".tar.gz", ".tar.bz2", )
Packit 792a06
Packit 792a06
# buffer size for reading and writing out data (in bytes)
Packit 792a06
IO_BUF_SIZE = 2 * 1024 * 1024
Packit 792a06
Packit 792a06
Packit 792a06
class OSCAPaddonError(Exception):
Packit 792a06
    """Exception class for OSCAP addon related errors."""
Packit 792a06
Packit 792a06
    pass
Packit 792a06
Packit 792a06
Packit 792a06
class OSCAPaddonNetworkError(OSCAPaddonError):
Packit 792a06
    """Exception class for OSCAP addon related network errors."""
Packit 792a06
Packit 792a06
    pass
Packit 792a06
Packit 792a06
Packit 792a06
class ExtractionError(OSCAPaddonError):
Packit 792a06
    """Exception class for the extraction errors."""
Packit 792a06
Packit 792a06
    pass
Packit 792a06
Packit 792a06
Packit 792a06
MESSAGE_TYPE_FATAL = 0
Packit 792a06
MESSAGE_TYPE_WARNING = 1
Packit 792a06
MESSAGE_TYPE_INFO = 2
Packit 792a06
Packit 792a06
# namedtuple for messages returned from the rules evaluation
Packit 792a06
#   origin -- class (inherited from RuleHandler) that generated the message
Packit 792a06
#   type -- one of the MESSAGE_TYPE_* constants defined above
Packit 792a06
#   text -- the actual message that should be displayed, logged, ...
Packit 792a06
RuleMessage = namedtuple("RuleMessage", ["origin", "type", "text"])
Packit 792a06
Packit 792a06
Packit 792a06
class SubprocessLauncher(object):
Packit 792a06
    def __init__(self, args):
Packit 792a06
        self.args = args
Packit 792a06
        self.stdout = ""
Packit 792a06
        self.stderr = ""
Packit 792a06
        self.messages = []
Packit 792a06
        self.returncode = None
Packit 792a06
Packit 792a06
    def execute(self, ** kwargs):
Packit 792a06
        try:
Packit 792a06
            proc = subprocess.Popen(self.args, stdout=subprocess.PIPE,
Packit 792a06
                                    stderr=subprocess.PIPE, ** kwargs)
Packit 792a06
        except OSError as oserr:
Packit 792a06
            msg = "Failed to run the oscap tool: %s" % oserr
Packit 792a06
            raise OSCAPaddonError(msg)
Packit 792a06
Packit 792a06
        (stdout, stderr) = proc.communicate()
Packit 792a06
        self.stdout = stdout.decode()
Packit Service 3794d0
        self.stderr = stderr.decode(errors="replace")
Packit 792a06
        self.messages = re.findall(r'OpenSCAP Error:.*', self.stderr)
Packit Service 3794d0
        self.messages = self.messages + re.findall(r'E: oscap:.*', self.stderr)
Packit 792a06
Packit 792a06
        self.returncode = proc.returncode
Packit 792a06
Packit 792a06
    def log_messages(self):
Packit 792a06
        for message in self.messages:
Packit 792a06
            log.warning("OSCAP addon: " + message)
Packit 792a06
Packit 792a06
Packit 792a06
def get_fix_rules_pre(profile, fpath, ds_id="", xccdf_id="", tailoring=""):
Packit 792a06
    """
Packit 792a06
    Get fix rules for the pre-installation environment for a given profile in a
Packit 792a06
    given datastream and checklist in a given file.
Packit 792a06
Packit 792a06
    :see: run_oscap_remediate
Packit 792a06
    :see: _run_oscap_gen_fix
Packit 792a06
    :return: fix rules for a given profile
Packit 792a06
    :rtype: str
Packit 792a06
Packit 792a06
    """
Packit 792a06
Packit 792a06
    return _run_oscap_gen_fix(profile, fpath, PRE_INSTALL_FIX_SYSTEM_ATTR,
Packit 792a06
                              ds_id=ds_id, xccdf_id=xccdf_id,
Packit 792a06
                              tailoring=tailoring)
Packit 792a06
Packit 792a06
Packit 792a06
def _run_oscap_gen_fix(profile, fpath, template, ds_id="", xccdf_id="",
Packit 792a06
                       tailoring=""):
Packit 792a06
    """
Packit 792a06
    Run oscap tool on a given file to get the contents of fix elements with the
Packit 792a06
    'system' attribute equal to a given template for a given datastream,
Packit 792a06
    checklist and profile.
Packit 792a06
Packit 792a06
    :see: run_oscap_remediate
Packit 792a06
    :param template: the value of the 'system' attribute of the fix elements
Packit 792a06
    :type template: str
Packit 792a06
    :return: oscap tool's stdout
Packit 792a06
    :rtype: str
Packit 792a06
Packit 792a06
    """
Packit 792a06
Packit 792a06
    if not profile:
Packit 792a06
        return ""
Packit 792a06
Packit 792a06
    args = ["oscap", "xccdf", "generate", "fix"]
Packit 792a06
    args.append("--template=%s" % template)
Packit 792a06
Packit 792a06
    # oscap uses the default profile by default
Packit 792a06
    if profile.lower() != "default":
Packit 792a06
        args.append("--profile=%s" % profile)
Packit 792a06
    if ds_id:
Packit 792a06
        args.append("--datastream-id=%s" % ds_id)
Packit 792a06
    if xccdf_id:
Packit 792a06
        args.append("--xccdf-id=%s" % xccdf_id)
Packit 792a06
    if tailoring:
Packit 792a06
        args.append("--tailoring-file=%s" % tailoring)
Packit 792a06
Packit 792a06
    args.append(fpath)
Packit 792a06
Packit 792a06
    proc = SubprocessLauncher(args)
Packit 792a06
    proc.execute()
Packit 792a06
    proc.log_messages()
Packit 792a06
    if proc.returncode != 0:
Packit 792a06
        msg = "Failed to generate fix rules with the oscap tool: %s" % proc.stderr
Packit 792a06
        raise OSCAPaddonError(msg)
Packit 792a06
Packit 792a06
    return proc.stdout
Packit 792a06
Packit 792a06
Packit 792a06
def run_oscap_remediate(profile, fpath, ds_id="", xccdf_id="", tailoring="",
Packit 792a06
                        chroot=""):
Packit 792a06
    """
Packit 792a06
    Run the evaluation and remediation with the oscap tool on a given file,
Packit 792a06
    doing the remediation as defined in a given profile defined in a given
Packit 792a06
    checklist that is a part of a given datastream. If requested, run in
Packit 792a06
    chroot.
Packit 792a06
Packit 792a06
    :param profile: id of the profile that will drive the remediation
Packit 792a06
    :type profile: str
Packit 792a06
    :param fpath: path to a file with SCAP content
Packit 792a06
    :type fpath: str
Packit 792a06
    :param ds_id: ID of the datastream that contains the checklist defining
Packit 792a06
                  the profile
Packit 792a06
    :type ds_id: str
Packit 792a06
    :param xccdf_id: ID of the checklist that defines the profile
Packit 792a06
    :type xccdf_id: str
Packit 792a06
    :param tailoring: path to a tailoring file
Packit 792a06
    :type tailoring: str
Packit 792a06
    :param chroot: path to the root the oscap tool should be run in
Packit 792a06
    :type chroot: str
Packit 792a06
    :return: oscap tool's stdout (summary of the rules, checks and fixes)
Packit 792a06
    :rtype: str
Packit 792a06
Packit 792a06
    """
Packit 792a06
Packit 792a06
    if not profile:
Packit 792a06
        return ""
Packit 792a06
Packit 792a06
    def do_chroot():
Packit 792a06
        """Helper function doing the chroot if requested."""
Packit 792a06
        if chroot and chroot != "/":
Packit 792a06
            os.chroot(chroot)
Packit 792a06
            os.chdir("/")
Packit 792a06
Packit 792a06
    # make sure the directory for the results exists
Packit 792a06
    results_dir = os.path.dirname(RESULTS_PATH)
Packit 792a06
    if chroot:
Packit 792a06
        results_dir = os.path.normpath(chroot + "/" + results_dir)
Packit 792a06
    utils.ensure_dir_exists(results_dir)
Packit 792a06
Packit 792a06
    args = ["oscap", "xccdf", "eval"]
Packit 792a06
    args.append("--remediate")
Packit 792a06
    args.append("--results=%s" % RESULTS_PATH)
Packit 792a06
    args.append("--report=%s" % REPORT_PATH)
Packit 792a06
Packit 792a06
    # oscap uses the default profile by default
Packit 792a06
    if profile.lower() != "default":
Packit 792a06
        args.append("--profile=%s" % profile)
Packit 792a06
    if ds_id:
Packit 792a06
        args.append("--datastream-id=%s" % ds_id)
Packit 792a06
    if xccdf_id:
Packit 792a06
        args.append("--xccdf-id=%s" % xccdf_id)
Packit 792a06
    if tailoring:
Packit 792a06
        args.append("--tailoring-file=%s" % tailoring)
Packit 792a06
Packit 792a06
    args.append(fpath)
Packit 792a06
Packit 792a06
    proc = SubprocessLauncher(args)
Packit 792a06
    proc.execute(preexec_fn=do_chroot)
Packit 792a06
    proc.log_messages()
Packit 792a06
Packit 792a06
    if proc.returncode not in (0, 2):
Packit 792a06
        # 0 -- success; 2 -- no error, but checks/remediation failed
Packit 792a06
        msg = "Content evaluation and remediation with the oscap tool "\
Packit 792a06
            "failed: %s" % proc.stderr
Packit 792a06
        raise OSCAPaddonError(msg)
Packit 792a06
Packit 792a06
    return proc.stdout
Packit 792a06
Packit 792a06
Packit 792a06
def wait_and_fetch_net_data(url, out_file, ca_certs=None):
Packit 792a06
    """
Packit 792a06
    Function that waits for network connection and starts a thread that fetches
Packit 792a06
    data over network.
Packit 792a06
Packit 792a06
    :see: org_fedora_oscap.data_fetch.fetch_data
Packit 792a06
    :return: the name of the thread running fetch_data
Packit 792a06
    :rtype: str
Packit 792a06
Packit 792a06
    """
Packit 792a06
Packit 792a06
    # get thread that tries to establish a network connection
Packit 792a06
    nm_conn_thread = threadMgr.get(constants.THREAD_WAIT_FOR_CONNECTING_NM)
Packit 792a06
    if nm_conn_thread:
Packit 792a06
        # NM still connecting, wait for it to finish
Packit 792a06
        nm_conn_thread.join()
Packit 792a06
Packit 792a06
    network_proxy = NETWORK.get_proxy()
Packit 792a06
    if not network_proxy.Connected:
Packit 792a06
        raise OSCAPaddonNetworkError("Network connection needed to fetch data.")
Packit 792a06
Packit 792a06
    fetch_data_thread = AnacondaThread(name=THREAD_FETCH_DATA,
Packit 792a06
                                       target=fetch_data,
Packit 792a06
                                       args=(url, out_file, ca_certs),
Packit 792a06
                                       fatal=False)
Packit 792a06
Packit 792a06
    # register and run the thread
Packit 792a06
    threadMgr.add(fetch_data_thread)
Packit 792a06
Packit 792a06
    return THREAD_FETCH_DATA
Packit 792a06
Packit 792a06
Packit 792a06
def extract_data(archive, out_dir, ensure_has_files=None):
Packit 792a06
    """
Packit 792a06
    Fuction that extracts the given archive to the given output directory. It
Packit 792a06
    tries to find out the archive type by the file name.
Packit 792a06
Packit 792a06
    :param archive: path to the archive file that should be extracted
Packit 792a06
    :type archive: str
Packit 792a06
    :param out_dir: output directory the archive should be extracted to
Packit 792a06
    :type out_dir: str
Packit 792a06
    :param ensure_has_files: relative paths to the files that must exist in the
Packit 792a06
                             archive
Packit 792a06
    :type ensure_has_files: iterable of strings or None
Packit 792a06
    :return: a list of files and directories extracted from the archive
Packit 792a06
    :rtype: [str]
Packit 792a06
Packit 792a06
    """
Packit 792a06
Packit 792a06
    # get rid of empty file paths
Packit 792a06
    ensure_has_files = [fpath for fpath in ensure_has_files if fpath]
Packit 792a06
Packit 792a06
    if archive.endswith(".zip"):
Packit 792a06
        # ZIP file
Packit 792a06
        try:
Packit 792a06
            zfile = zipfile.ZipFile(archive, "r")
Packit 792a06
        except zipfile.BadZipfile as err:
Packit 792a06
            raise ExtractionError(str(err))
Packit 792a06
Packit 792a06
        # generator for the paths of the files found in the archive (dirs end
Packit 792a06
        # with "/")
Packit 792a06
        files = set(info.filename for info in zfile.filelist
Packit 792a06
                    if not info.filename.endswith("/"))
Packit 792a06
        for fpath in ensure_has_files or ():
Packit 792a06
            if fpath not in files:
Packit 792a06
                msg = "File '%s' not found in the archive '%s'" % (fpath,
Packit 792a06
                                                                   archive)
Packit 792a06
                raise ExtractionError(msg)
Packit 792a06
Packit 792a06
        utils.ensure_dir_exists(out_dir)
Packit 792a06
        zfile.extractall(path=out_dir)
Packit 792a06
        result = [utils.join_paths(out_dir, info.filename) for info in zfile.filelist]
Packit 792a06
        zfile.close()
Packit 792a06
        return result
Packit 792a06
    elif archive.endswith(".tar"):
Packit 792a06
        # plain tarball
Packit 792a06
        return _extract_tarball(archive, out_dir, ensure_has_files, None)
Packit 792a06
    elif archive.endswith(".tar.gz"):
Packit 792a06
        # gzipped tarball
Packit 792a06
        return _extract_tarball(archive, out_dir, ensure_has_files, "gz")
Packit 792a06
    elif archive.endswith(".tar.bz2"):
Packit 792a06
        # bzipped tarball
Packit 792a06
        return _extract_tarball(archive, out_dir, ensure_has_files, "bz2")
Packit 792a06
    elif archive.endswith(".rpm"):
Packit 792a06
        # RPM
Packit 792a06
        return _extract_rpm(archive, out_dir, ensure_has_files)
Packit 792a06
    # elif other types of archives
Packit 792a06
    else:
Packit 792a06
        raise ExtractionError("Unsuported archive type")
Packit 792a06
Packit 792a06
Packit 792a06
def _extract_tarball(archive, out_dir, ensure_has_files, alg):
Packit 792a06
    """
Packit 792a06
    Extract the given TAR archive to the given output directory and make sure
Packit 792a06
    the given file exists in the archive.
Packit 792a06
Packit 792a06
    :see: extract_data
Packit 792a06
    :param alg: compression algorithm used for the tarball
Packit 792a06
    :type alg: str (one of "gz", "bz2") or None
Packit 792a06
    :return: a list of files and directories extracted from the archive
Packit 792a06
    :rtype: [str]
Packit 792a06
Packit 792a06
    """
Packit 792a06
Packit 792a06
    if alg and alg not in ("gz", "bz2",):
Packit 792a06
        raise ExtractionError("Unsupported compression algorithm")
Packit 792a06
Packit 792a06
    mode = "r"
Packit 792a06
    if alg:
Packit 792a06
        mode += ":%s" % alg
Packit 792a06
Packit 792a06
    try:
Packit 792a06
        tfile = tarfile.TarFile.open(archive, mode)
Packit 792a06
    except tarfile.TarError as err:
Packit 792a06
        raise ExtractionError(str(err))
Packit 792a06
Packit 792a06
    # generator for the paths of the files found in the archive
Packit 792a06
    files = set(member.path for member in tfile.getmembers()
Packit 792a06
                if member.isfile())
Packit 792a06
Packit 792a06
    for fpath in ensure_has_files or ():
Packit 792a06
        if fpath not in files:
Packit 792a06
            msg = "File '%s' not found in the archive '%s'" % (fpath, archive)
Packit 792a06
            raise ExtractionError(msg)
Packit 792a06
Packit 792a06
    utils.ensure_dir_exists(out_dir)
Packit 792a06
    tfile.extractall(path=out_dir)
Packit 792a06
    result = [utils.join_paths(out_dir, member.path) for member in tfile.getmembers()]
Packit 792a06
    tfile.close()
Packit 792a06
Packit 792a06
    return result
Packit 792a06
Packit 792a06
Packit 792a06
def _extract_rpm(rpm_path, root="/", ensure_has_files=None):
Packit 792a06
    """
Packit 792a06
    Extract the given RPM into the directory tree given by the root argument
Packit 792a06
    and make sure the given file exists in the archive.
Packit 792a06
Packit 792a06
    :param rpm_path: path to the RPM file that should be extracted
Packit 792a06
    :type rpm_path: str
Packit 792a06
    :param root: root of the directory tree the RPM should be extracted into
Packit 792a06
    :type root: str
Packit 792a06
    :param ensure_has_files: relative paths to the files that must exist in the
Packit 792a06
                             RPM
Packit 792a06
    :type ensure_has_files: iterable of strings or None
Packit 792a06
    :return: a list of files and directories extracted from the archive
Packit 792a06
    :rtype: [str]
Packit 792a06
Packit 792a06
    """
Packit 792a06
Packit 792a06
    # run rpm2cpio and process the output with the cpioarchive module
Packit 792a06
    temp_fd, temp_path = tempfile.mkstemp(prefix="oscap_rpm")
Packit 792a06
    proc = subprocess.Popen(["rpm2cpio", rpm_path], stdout=temp_fd)
Packit 792a06
    proc.wait()
Packit 792a06
    if proc.returncode != 0:
Packit 792a06
        msg = "Failed to convert RPM '%s' to cpio archive" % rpm_path
Packit 792a06
        raise ExtractionError(msg)
Packit 792a06
Packit 792a06
    os.close(temp_fd)
Packit 792a06
Packit 792a06
    try:
Packit 792a06
        archive = cpioarchive.CpioArchive(temp_path)
Packit 792a06
    except cpioarchive.CpioError as err:
Packit 792a06
        raise ExtractionError(str(err))
Packit 792a06
Packit 792a06
    # get entries from the archive (supports only iteration over entries)
Packit 792a06
    entries = set(entry for entry in archive)
Packit 792a06
Packit 792a06
    # cpio entry names (paths) start with the dot
Packit 792a06
    entry_names = [entry.name.lstrip(".") for entry in entries]
Packit 792a06
Packit 792a06
    for fpath in ensure_has_files or ():
Packit 792a06
        # RPM->cpio entries have absolute paths
Packit 792a06
        if fpath not in entry_names and \
Packit 792a06
           os.path.join("/", fpath) not in entry_names:
Packit 792a06
            msg = "File '%s' not found in the archive '%s'" % (fpath, rpm_path)
Packit 792a06
            raise ExtractionError(msg)
Packit 792a06
Packit 792a06
    try:
Packit 792a06
        for entry in entries:
Packit 792a06
            if entry.size == 0:
Packit 792a06
                continue
Packit 792a06
            dirname = os.path.dirname(entry.name.lstrip("."))
Packit 792a06
            out_dir = os.path.normpath(root + dirname)
Packit 792a06
            utils.ensure_dir_exists(out_dir)
Packit 792a06
Packit 792a06
            out_fpath = os.path.normpath(root + entry.name.lstrip("."))
Packit 792a06
            if os.path.exists(out_fpath):
Packit 792a06
                continue
Packit 792a06
            with open(out_fpath, "wb") as out_file:
Packit 792a06
                buf = entry.read(IO_BUF_SIZE)
Packit 792a06
                while buf:
Packit 792a06
                    out_file.write(buf)
Packit 792a06
                    buf = entry.read(IO_BUF_SIZE)
Packit 792a06
    except (IOError, cpioarchive.CpioError) as e:
Packit 792a06
        raise ExtractionError(e)
Packit 792a06
Packit 792a06
    # cleanup
Packit 792a06
    archive.close()
Packit 792a06
    os.unlink(temp_path)
Packit 792a06
Packit 792a06
    return [os.path.normpath(root + name) for name in entry_names]
Packit 792a06
Packit 792a06
Packit 792a06
def strip_content_dir(fpaths, phase="preinst"):
Packit 792a06
    """
Packit 792a06
    Strip content directory prefix from the file paths for either
Packit 792a06
    pre-installation or post-installation phase.
Packit 792a06
Packit 792a06
    :param fpaths: iterable of file paths to strip content directory prefix
Packit 792a06
                   from
Packit 792a06
    :type fpaths: iterable of strings
Packit 792a06
    :param phase: specifies pre-installation or post-installation phase
Packit 792a06
    :type phase: "preinst" or "postinst"
Packit 792a06
    :return: the same iterable of file paths as given with the content
Packit 792a06
             directory prefix stripped
Packit 792a06
    :rtype: same type as fpaths
Packit 792a06
Packit 792a06
    """
Packit 792a06
Packit 792a06
    if phase == "preinst":
Packit 792a06
        remove_prefix = lambda x: x[len(INSTALLATION_CONTENT_DIR):]
Packit 792a06
    else:
Packit 792a06
        remove_prefix = lambda x: x[len(TARGET_CONTENT_DIR):]
Packit 792a06
Packit 792a06
    return utils.keep_type_map(remove_prefix, fpaths)
Packit 792a06
Packit 792a06
Packit 792a06
def ssg_available(root="/"):
Packit 792a06
    """
Packit 792a06
    Tries to find the SCAP Security Guide under the given root.
Packit 792a06
Packit 792a06
    :return: True if SSG was found under the given root, False otherwise
Packit 792a06
Packit 792a06
    """
Packit 792a06
Packit 792a06
    return os.path.exists(utils.join_paths(root, SSG_DIR + SSG_CONTENT))
Packit 792a06
Packit 792a06
Packit 792a06
def dry_run_skip(func):
Packit 792a06
    """
Packit 792a06
    Decorator that makes sure the decorated function is noop in the dry-run
Packit 792a06
    mode.
Packit 792a06
Packit 792a06
    :param func: a decorated function that needs to have the first parameter an
Packit 792a06
                 object with the _addon_data attribute referencing the OSCAP
Packit 792a06
                 addon's ksdata
Packit 792a06
    """
Packit 792a06
Packit 792a06
    @wraps(func)
Packit 792a06
    def decorated(self, *args, **kwargs):
Packit 792a06
        if self._addon_data.dry_run:
Packit 792a06
            return
Packit 792a06
        else:
Packit 792a06
            return func(self, *args, **kwargs)
Packit 792a06
Packit 792a06
    return decorated