示例#1
0
文件: run.py 项目: xaleeks/tern
def get_dockerfile_packages():
    '''Given a Dockerfile return an approximate image object. This is mosty
    guess work and shouldn't be relied on for accurate information. Add
    Notice messages indicating as such:
        1. Create an image with a placeholder repotag
        2. For each RUN command, create a package list
        3. Create layer objects with incremental integers and add the package
        list to that layer with a Notice about parsing
        4. Return stub image'''
    stub_image = Image('easteregg:cookie')
    layer_count = 0
    for cmd in dhelper.docker_commands:
        if cmd['instruction'] == 'RUN':
            layer_count = layer_count + 1
            layer = ImageLayer(layer_count)
            install_commands, msg = \
                common.filter_install_commands(cmd['value'])
            if msg:
                layer.origins.add_notice_to_origins(cmd['value'],
                                                    Notice(msg, 'info'))
            pkg_names = []
            for command in install_commands:
                pkg_names.append(common.get_installed_package_names(command))
            for pkg_name in pkg_names:
                pkg = Package(pkg_name)
                # shell parser does not parse version pins yet
                # when that is enabled, Notices for no versions need to be
                # added here
                layer.add_package(pkg)
    return stub_image
示例#2
0
def execute_live(args):
    """Execute inventory at container build time
    We assume a mounted working directory is ready to inventory"""
    logger.debug('Starting analysis...')
    # create the working directory
    setup()
    # create a layer object to bundle package metadata into
    layer = ImageLayer("")
    # see if there is an os-release file at the mount point
    layer.os_guess = single_layer.find_os_release(args.live)
    # create a Prereqs object to store requirements to inventory
    prereqs = core.Prereqs()
    prereqs.host_path = os.path.abspath(args.live)
    # Find a shell that may exist in the layer
    prereqs.fs_shell = dcom.find_shell(prereqs.host_path)
    # Find the host's shell
    prereqs.host_shell = host.check_shell()
    # collect metadata into the layer object
    fill_packages(layer, prereqs)
    # resolve unique packages for this run with reports from previous runs
    if args.with_context:
        # get a list of previous layers based on plugin type
        context_layers = get_context_layers(args.with_context,
                                            args.report_format)
        # resolve the packages for each of the layers
        context_layers.append(layer)
        resolve_context_packages(context_layers)
        final_layer = context_layers.pop()
    else:
        final_layer = layer
    # report out the packages
    logger.debug("Preparing report")
    report.report_layer(final_layer, args)
示例#3
0
 def load_image(self):
     l1 = ImageLayer('123abc', 'path/to/tar')
     self.name = 'testimage'
     self.tag = 'testtag'
     l1.add_package(Package('p1'))
     l1.add_package(Package('p2'))
     self._layers.append(l1)
示例#4
0
def create_image_layer(report):
    """Given a report file, create an ImageLayer object with the metadata"""
    # expect a json input, raise an error if it is not
    content = {}
    try:
        with open(os.path.abspath(report), encoding='utf-8') as f:
            content = json.load(f)
    except OSError as err:
        logger.critical("Cannot access file %s: %s", report, err)
        raise ConsumerError(f"Error with given report file: {report}") from err
    except json.JSONDecodeError as err:
        logger.critical("Cannot parse JSON in file %s: %s", report, err)
        raise ConsumerError(f"Error with given report file: {report}") from err
    # we should have some content but it may be empty
    if not content:
        raise ConsumerError("No content consumed from given report file")
    # instantiate a layer and fill it
    layer = ImageLayer("")
    # if there are license refs, make a dictionary with license refs to
    # extracted content
    refs_license = get_license_refs_dict(
        content.get('hasExtractedLicensingInfos', []))
    try:
        # we ignore the document level information and go straight
        # to the packages
        for pkg in content['packages']:
            pkg_obj = get_package_from_dict(pkg)
            pkg_obj.pkg_license = refs_license.get(pkg['licenseDeclared'])
            layer.add_package(pkg_obj)
        return layer
    except ValueError as err:
        logger.critical("Cannot find required data in report: %s", err)
        return None
示例#5
0
 def load_image(self):
     """Load metadata from an extracted docker image. This assumes the
     image has already been downloaded and extracted into the working
     directory"""
     try:
         self._manifest = self.get_image_manifest()
         self.__repotags = self.get_image_repotags(self._manifest)
         self._config = self.get_image_config(self._manifest)
         self.__history = self.get_image_history(self._config)
         layer_paths = self.get_image_layers(self._manifest)
         layer_diffs = self.get_diff_ids(self._config)
         checksum_type = self.get_diff_checksum_type(self._config)
         layer_count = 1
         while layer_diffs and layer_paths:
             layer = ImageLayer(layer_diffs.pop(0), layer_paths.pop(0))
             layer.set_checksum(checksum_type, layer.diff_id)
             layer.gen_fs_hash()
             layer.layer_index = layer_count
             layer_count = layer_count + 1
             self._layers.append(layer)
         self.set_layer_created_by()
     except NameError as e:
         raise NameError(e)
     except subprocess.CalledProcessError as e:
         raise subprocess.CalledProcessError(e.returncode,
                                             cmd=e.cmd,
                                             output=e.output,
                                             stderr=e.stderr)
     except IOError as e:
         raise IOError(e)
示例#6
0
def create_image_layer(report):
    """Given a report file, create an ImageLayer object with the metadata"""
    # expect a json input, raise an error if it is not
    content = {}
    try:
        with open(os.path.abspath(report), encoding='utf-8') as f:
            content = json.load(f)
    except OSError as err:
        logger.critical("Cannot access file %s: %s", report, err)
        raise ConsumerError(f"Error with given report file: {report}") from err
    except json.JSONDecodeError as err:
        logger.critical("Cannot parse JSON in file %s: %s", report, err)
        raise ConsumerError(f"Error with given report file: {report}") from err
    # we should have some content but it may be empty
    if not content:
        raise ConsumerError("No content consumed from given report file")
    # instantiate a layer and fill it
    layer = ImageLayer("")
    try:
        layer.os_guess = content['os_guess']
        for pkg in content['packages']:
            pkg_obj = Package(pkg['name'])
            pkg_obj.fill(pkg)
            layer.add_package(pkg_obj)
        for filedict in content['files']:
            file_obj = FileData(filedict['name'], filedict['path'])
            file_obj.fill(filedict)
            layer.add_file(file_obj)
        return layer
    except ValueError as err:
        logger.critical("Cannot find required data in report: %s", err)
        return None
示例#7
0
 def load_image(self):
     '''Load image metadata using docker commands'''
     try:
         container.extract_image_metadata(self.repotag)
         self._manifest = self.get_image_manifest()
         self.__repotags = self.get_image_repotags(self._manifest)
         self._config = self.get_image_config(self._manifest)
         self.__history = self.get_image_history(self._config)
         layer_paths = self.get_image_layers(self._manifest)
         layer_diffs = self.get_diff_ids(self._config)
         checksum_type = self.get_diff_checksum_type(self._config)
         layer_count = 1
         while layer_diffs and layer_paths:
             layer = ImageLayer(layer_diffs.pop(0), layer_paths.pop(0))
             layer.set_checksum(checksum_type, layer.diff_id)
             layer.gen_fs_hash()
             layer.layer_index = layer_count
             layer_count = layer_count + 1
             self._layers.append(layer)
         self.set_layer_created_by()
     except NameError as e:
         raise NameError(e)
     except subprocess.CalledProcessError as e:
         raise subprocess.CalledProcessError(
             e.returncode, cmd=e.cmd, output=e.output, stderr=e.stderr)
     except IOError as e:
         raise IOError(e)
示例#8
0
文件: run.py 项目: nishakm/tern
def execute_live(args):
    """Execute inventory at container build time
    We assume a mounted working directory is ready to inventory"""
    logger.debug('Starting analysis...')
    # create the working directory
    setup()
    # create a layer object to bundle package metadata into
    layer = ImageLayer("")
    # see if there is an os-release file at the mount point
    layer.os_guess = single_layer.find_os_release(args.live)
    # create a Prereqs object to store requirements to inventory
    prereqs = core.Prereqs()
    prereqs.host_path = os.path.abspath(args.live)
    # Find a shell that may exist in the layer
    prereqs.fs_shell = dcom.find_shell(prereqs.host_path)
    # Find the host's shell
    prereqs.host_shell = host.check_shell()
    # collect metadata into the layer object
    fill_packages(layer, prereqs)
    # report out the packages
    report.report_layer(layer, args)
示例#9
0
 def load_image(self):
     '''Load image metadata using docker commands'''
     try:
         option = self.get_image_option()
         container.extract_image_metadata(option)
         self._manifest = self.get_image_manifest()
         self._image_id = self.get_image_id(self._manifest)
         self.__repotags = self.get_image_repotags(self._manifest)
         self._config = self.get_image_config(self._manifest)
         self.__history = self.get_image_history(self._config)
         layer_paths = self.get_image_layers(self._manifest)
         layer_diffs = self.get_diff_ids(self._config)
         checksum_type = self.get_diff_checksum_type(self._config)
         while layer_diffs and layer_paths:
             layer = ImageLayer(layer_diffs.pop(0), layer_paths.pop(0))
             layer.set_checksum(checksum_type, layer.diff_id)
             layer.gen_fs_hash()
             self._layers.append(layer)
         self.set_layer_created_by()
     except NameError:  # pylint: disable=try-except-raise
         raise
     except subprocess.CalledProcessError:  # pylint: disable=try-except-raise
         raise
     except IOError:  # pylint: disable=try-except-raise
         raise
示例#10
0
 def load_image(self, load_until_layer=0):
     """Load metadata from an extracted docker image. This assumes the
     image has already been downloaded and extracted into the working
     directory"""
     if load_until_layer > 0:
         self._load_until_layer = load_until_layer
     # else defaults to 0 - handles negative load_until_layer
     try:
         self._manifest = self.get_image_manifest()
         self.__repotags = self.get_image_repotags(self._manifest)
         self._config = self.get_image_config(self._manifest)
         self.__history = self.get_image_history(self._config)
         layer_paths = self.get_image_layers(self._manifest)
         layer_diffs = self.get_diff_ids(self._config)
         checksum_type = self.get_diff_checksum_type(self._config)
         layer_count = 1
         while layer_diffs and layer_paths:
             layer = ImageLayer(layer_diffs.pop(0), layer_paths.pop(0))
             # Only load metadata for the layers we need to report on according to the --layers command line option
             # If  --layers option is not present, load all the layers
             if self.load_until_layer >= layer_count or self.load_until_layer == 0:
                 layer.set_checksum(checksum_type, layer.diff_id)
                 layer.gen_fs_hash()
                 layer.layer_index = layer_count
                 self._layers.append(layer)
             layer_count = layer_count + 1
         self._total_layers = layer_count - 1
         if self.load_until_layer > self.total_layers:
             # if user asked to analyze more layers than image has
             # turn off the load_until_layer feature
             self._load_until_layer = 0
         self.set_layer_created_by()
     except NameError as e:
         raise NameError(e)
     except subprocess.CalledProcessError as e:
         raise subprocess.CalledProcessError(e.returncode,
                                             cmd=e.cmd,
                                             output=e.output,
                                             stderr=e.stderr)
     except IOError as e:
         raise IOError(e)
示例#11
0
 def setUp(self):
     self.layer = ImageLayer('123abc', 'path/to/tar')
示例#12
0
class TestClassImageLayer(unittest.TestCase):
    def setUp(self):
        self.layer = ImageLayer('123abc', 'path/to/tar')

    def tearDown(self):
        del self.layer

    def testInstance(self):
        self.assertEqual(self.layer.diff_id, '123abc')
        self.assertEqual(self.layer.tar_file, 'path/to/tar')
        self.assertFalse(self.layer.packages)
        self.assertFalse(self.layer.created_by)
        self.assertRaises(AttributeError, setattr, self.layer, 'diff_id',
                          '456def')
        self.assertRaises(AttributeError, setattr, self.layer, 'tar_file',
                          'some/other/path')
        self.layer.created_by = 'some string'
        self.assertEqual(self.layer.created_by, 'some string')
        self.layer.pkg_format = 'rpm'
        self.assertEqual(self.layer.pkg_format, 'rpm')
        self.layer.os_guess = 'operating system'
        self.assertEqual(self.layer.os_guess, 'operating system')
        self.assertFalse(self.layer.files_analyzed)
        self.layer.files_analyzed = True
        self.assertTrue(self.layer.files_analyzed)
        self.assertRaises(ValueError, setattr, self.layer, 'files_analyzed',
                          'some string')
        self.assertEqual("", self.layer.analyzed_output)
        self.layer.analyzed_output = 'some string'
        self.assertEqual(self.layer.analyzed_output, 'some string')
        self.assertRaises(ValueError, setattr, self.layer, 'analyzed_output',
                          123)

    def testAddPackage(self):
        err = "Object type String, should be Package"
        p1 = Package('x')
        self.layer.add_package(p1)
        self.assertEqual(len(self.layer.packages), 1)
        with self.assertRaises(TypeError, msg=err):
            self.layer.add_package("not_a_package")

    def testRemovePackage(self):
        p1 = Package('x')
        p2 = Package('y')
        self.layer.add_package(p1)
        self.layer.add_package(p2)
        self.assertTrue(self.layer.remove_package('y'))
        self.assertFalse(self.layer.remove_package('y'))

    def testAddFile(self):
        err = "Object type String, should be FileData"
        file1 = FileData('file1', 'path/to/file1')
        self.layer.add_file(file1)
        self.assertEqual(len(self.layer.files), 1)
        with self.assertRaises(TypeError, msg=err):
            self.layer.add_file("afile")

    def testRemoveFile(self):
        file1 = FileData('file1', 'path/to/file1')
        self.layer.add_file(file1)
        self.assertFalse(self.layer.remove_file('file1'))
        self.assertTrue(self.layer.remove_file('path/to/file1'))
        self.assertFalse(self.layer.remove_file('path/to/file1'))

    def testToDict(self):
        p1 = Package('x')
        f1 = FileData('file1', 'path/to/file1')
        self.layer.add_package(p1)
        self.layer.add_file(f1)
        a_dict = self.layer.to_dict()
        self.assertEqual(a_dict['diff_id'], '123abc')
        self.assertEqual(len(a_dict['packages']), 1)
        self.assertEqual(a_dict['packages'][0]['name'], 'x')
        self.assertEqual(len(a_dict['files']), 1)
        self.assertEqual(a_dict['files'][0]['name'], 'file1')
        self.assertEqual(a_dict['files'][0]['path'], 'path/to/file1')
        self.assertEqual(a_dict['tar_file'], 'path/to/tar')

    def testToDictTemplate(self):
        template1 = TestTemplate1()
        template2 = TestTemplate2()
        p1 = Package('x')
        self.layer.add_package(p1)
        f1 = FileData('file1', 'path/to/file1')
        self.layer.add_file(f1)
        dict1 = self.layer.to_dict(template1)
        dict2 = self.layer.to_dict(template2)
        self.assertEqual(len(dict1.keys()), 4)
        self.assertEqual(dict1['layer.diff'], '123abc')
        self.assertEqual(dict1['layer.tarfile'], 'path/to/tar')
        self.assertEqual(len(dict1['layer.packages']), 1)
        self.assertEqual(len(dict1['layer.files']), 1)
        self.assertEqual(len(dict2.keys()), 5)
        self.assertFalse(dict2['notes'])
        self.assertFalse(dict2['layer.packages'][0]['notes'])
        self.assertFalse(dict2['layer.files'][0]['notes'])

    def testGetPackageNames(self):
        p1 = Package('x')
        self.layer.add_package(p1)
        pkgs = self.layer.get_package_names()
        self.assertEqual(pkgs[0], 'x')

    def testGetFilePaths(self):
        f1 = FileData('file1', 'path/to/file1')
        f2 = FileData('file2', 'path/to/file2')
        self.layer.add_file(f1)
        self.layer.add_file(f2)
        file_paths = self.layer.get_file_paths()
        self.assertEqual(file_paths, ['path/to/file1', 'path/to/file2'])
示例#13
0
class TestClassImageLayer(unittest.TestCase):
    def setUp(self):
        self.layer = ImageLayer('123abc', 'path/to/tar')

    def tearDown(self):
        del self.layer

    def testInstance(self):
        self.assertEqual(self.layer.diff_id, '123abc')
        self.assertEqual(self.layer.tar_file, 'path/to/tar')
        self.assertFalse(self.layer.packages)
        self.assertFalse(self.layer.created_by)
        self.assertRaises(AttributeError, setattr, self.layer, 'diff_id',
                          '456def')
        self.assertRaises(AttributeError, setattr, self.layer, 'tar_file',
                          'some/other/path')
        self.layer.created_by = 'some string'
        self.assertEqual(self.layer.created_by, 'some string')

    def testAddPackage(self):
        err = "Object type String, should be Package"
        p1 = Package('x')
        self.layer.add_package(p1)
        self.assertEqual(len(self.layer.packages), 1)
        with self.assertRaises(TypeError, msg=err):
            self.layer.add_package("not_a_package")

    def testRemovePackage(self):
        p1 = Package('x')
        p2 = Package('y')
        self.layer.add_package(p1)
        self.layer.add_package(p2)
        self.assertTrue(self.layer.remove_package('y'))
        self.assertFalse(self.layer.remove_package('y'))

    def testToDict(self):
        p1 = Package('x')
        self.layer.add_package(p1)
        a_dict = self.layer.to_dict()
        self.assertTrue(a_dict[''])
        self.assertEqual(len(a_dict['']['packages']), 1)
        self.assertEqual(a_dict['']['packages'][0]['name'], 'x')
        self.assertEqual(a_dict['']['tar_file'], 'path/to/tar')

    def testGetPackageNames(self):
        p1 = Package('x')
        self.layer.add_package(p1)
        pkgs = self.layer.get_package_names()
        self.assertEqual(pkgs[0], 'x')
示例#14
0
 def setUp(self):
     self.layer = ImageLayer('123abc', 'path/to/tar')
     rootfs.set_working_dir()
示例#15
0
class TestClassImageLayer(unittest.TestCase):
    def setUp(self):
        self.layer = ImageLayer('123abc', 'path/to/tar')
        rootfs.set_working_dir()

    def tearDown(self):
        del self.layer

    def testInstance(self):
        self.assertEqual(self.layer.diff_id, '123abc')
        self.assertEqual(self.layer.tar_file, 'path/to/tar')
        self.assertFalse(self.layer.packages)
        self.assertFalse(self.layer.created_by)
        self.assertRaises(AttributeError, setattr, self.layer, 'diff_id',
                          '456def')
        self.assertRaises(AttributeError, setattr, self.layer, 'tar_file',
                          'some/other/path')
        self.layer.created_by = 'some string'
        self.assertEqual(self.layer.created_by, 'some string')
        self.layer.pkg_format = 'rpm'
        self.assertEqual(self.layer.pkg_format, 'rpm')
        self.layer.os_guess = 'operating system'
        self.assertEqual(self.layer.os_guess, 'operating system')
        self.assertFalse(self.layer.files_analyzed)
        self.layer.files_analyzed = True
        self.assertTrue(self.layer.files_analyzed)
        self.assertRaises(ValueError, setattr, self.layer, 'files_analyzed',
                          'some string')
        self.assertEqual("", self.layer.analyzed_output)
        self.layer.analyzed_output = 'some string'
        self.assertEqual(self.layer.analyzed_output, 'some string')
        self.assertRaises(ValueError, setattr, self.layer, 'analyzed_output',
                          123)

    def testAddPackage(self):
        err = "Object type String, should be Package"
        p1 = Package('x')
        self.layer.add_package(p1)
        self.assertEqual(len(self.layer.packages), 1)
        with self.assertRaises(TypeError, msg=err):
            self.layer.add_package("not_a_package")

    def testRemovePackage(self):
        p1 = Package('x')
        p2 = Package('y')
        self.layer.add_package(p1)
        self.layer.add_package(p2)
        self.assertTrue(self.layer.remove_package('y'))
        self.assertFalse(self.layer.remove_package('y'))

    def testAddFile(self):
        err = "Object type String, should be FileData"
        file1 = FileData('file1', 'path/to/file1')
        self.layer.add_file(file1)
        self.assertEqual(len(self.layer.files), 1)
        with self.assertRaises(TypeError, msg=err):
            self.layer.add_file("afile")

    def testRemoveFile(self):
        file1 = FileData('file1', 'path/to/file1')
        self.layer.add_file(file1)
        self.assertFalse(self.layer.remove_file('file1'))
        self.assertTrue(self.layer.remove_file('path/to/file1'))
        self.assertFalse(self.layer.remove_file('path/to/file1'))

    def testToDict(self):
        p1 = Package('x')
        f1 = FileData('file1', 'path/to/file1')
        self.layer.add_package(p1)
        self.layer.add_file(f1)
        a_dict = self.layer.to_dict()
        self.assertEqual(a_dict['diff_id'], '123abc')
        self.assertEqual(len(a_dict['packages']), 1)
        self.assertEqual(a_dict['packages'][0]['name'], 'x')
        self.assertEqual(len(a_dict['files']), 1)
        self.assertEqual(a_dict['files'][0]['name'], 'file1')
        self.assertEqual(a_dict['files'][0]['path'], 'path/to/file1')
        self.assertEqual(a_dict['tar_file'], 'path/to/tar')

    def testToDictTemplate(self):
        template1 = TestTemplate1()
        template2 = TestTemplate2()
        p1 = Package('x')
        self.layer.add_package(p1)
        f1 = FileData('file1', 'path/to/file1')
        self.layer.add_file(f1)
        dict1 = self.layer.to_dict(template1)
        dict2 = self.layer.to_dict(template2)
        self.assertEqual(len(dict1.keys()), 4)
        self.assertEqual(dict1['layer.diff'], '123abc')
        self.assertEqual(dict1['layer.tarfile'], 'path/to/tar')
        self.assertEqual(len(dict1['layer.packages']), 1)
        self.assertEqual(len(dict1['layer.files']), 1)
        self.assertEqual(len(dict2.keys()), 5)
        self.assertFalse(dict2['notes'])
        self.assertFalse(dict2['layer.packages'][0]['notes'])
        self.assertFalse(dict2['layer.files'][0]['notes'])

    def testGetPackageNames(self):
        p1 = Package('x')
        self.layer.add_package(p1)
        pkgs = self.layer.get_package_names()
        self.assertEqual(pkgs[0], 'x')

    def testGetFilePaths(self):
        f1 = FileData('file1', 'path/to/file1')
        f2 = FileData('file2', 'path/to/file2')
        self.layer.add_file(f1)
        self.layer.add_file(f2)
        file_paths = self.layer.get_file_paths()
        self.assertEqual(file_paths, ['path/to/file1', 'path/to/file2'])

    def testSetChecksum(self):
        self.layer.set_checksum('sha256', '12345abcde')
        self.assertEqual(self.layer.checksum_type, 'sha256')
        self.assertEqual(self.layer.checksum, '12345abcde')

    def testAddChecksums(self):
        self.layer.add_checksums({
            'SHA1': '12345abcde',
            'MD5': '1ff38cc592c4c5d0c8e3ca38be8f1eb1'
        })
        self.assertEqual(self.layer.checksums, {
            'sha1': '12345abcde',
            'md5': '1ff38cc592c4c5d0c8e3ca38be8f1eb1'
        })

    def testSetExtensionInfo(self):
        self.layer.extension_info = {"header": set({"Test Header"})}
        self.assertIsInstance(self.layer.extension_info, dict)
        self.assertIsNotNone(self.layer.extension_info.get("header", None),
                             None)
        self.assertIsInstance(self.layer.extension_info.get("header", None),
                              set)
        header = self.layer.extension_info.get("header").pop()
        self.assertEqual(header, "Test Header")

    def testGetUntarDir(self):
        self.layer.image_layout = "oci"
        self.assertEqual(self.layer.image_layout, "oci")
        self.layer.image_layout = "docker"
        self.assertEqual(self.layer.image_layout, "docker")
        self.layer.image_layout = ""
        self.assertEqual(self.layer.image_layout, "oci")
        self.layer.layer_index = 1
        self.assertEqual(self.layer.layer_index, "1")
        expected_path = os.path.join(rootfs.get_working_dir(), '1/contents')
        self.assertEqual(self.layer.get_untar_dir(), expected_path)
        self.layer.image_layout = "docker"
        expected_path = os.path.join(rootfs.get_working_dir(),
                                     'path/to/contents')
        self.assertEqual(self.layer.get_untar_dir(), expected_path)
示例#16
0
 def load_image(self):
     l1 = ImageLayer('123abc', 'path/to/tar')
     l1.add_package(Package('p1'))
     l1.add_package(Package('p2'))
     self._layers.append(l1)