Пример #1
0
    def find_orig_tarball(self, changes_file):
        """
        Look to see whether there is an orig tarball present, if the dsc refers to one.
        This method returns a triple (filename, file_found, location_hint), returning the (expected)
        name of the original tarball, and whether it was found in the local repository

        ```changes_file```
            The changes file to parse for the orig.tar (note the dsc file referenced must exist)

        Returns a tuple (orig_filename, orig_filename_was_found)
        """

        orig_name = None
        if not changes_file.get_dsc() or open(changes_file.get_dsc()) == None:
            return (orig_name, constants.ORIG_TARBALL_LOCATION_NOT_FOUND)

        dscfile = open(changes_file.get_dsc())
        dsc = deb822.Dsc(dscfile)
        for file in dsc['Files']:
            if (file['name'].endswith('orig.tar.gz')
                    or file['name'].endswith('orig.tar.bz2')
                    or file['name'].endswith('orig.tar.xz')):
                # We know how the orig.tar.gz should be called - at least.
                orig_name = file['name']
                full_filename = os.path.join(
                    pylons.config['debexpo.repository'],
                    changes_file.get_pool_path(), orig_name)
                # tar.gz was found in the local directory
                if os.path.isfile(file['name']):
                    sum = md5sum(file['name'])
                    if sum == file['md5sum']:
                        return (orig_name,
                                constants.ORIG_TARBALL_LOCATION_LOCAL)
                    # tar.gz was found, but does not seem to be the same file
                # tar.gz was found in the repository
                elif os.path.isfile(full_filename):
                    return (orig_name,
                            constants.ORIG_TARBALL_LOCATION_REPOSITORY)
                # tar.gz was expected but not found at all
                else:
                    return (orig_name,
                            constants.ORIG_TARBALL_LOCATION_NOT_FOUND)

        # We should neve end up here
        return (orig_name, constants.ORIG_TARBALL_LOCATION_NOT_FOUND)
Пример #2
0
    def test_md5sum(self):
        """
        Check each file's md5sum and make sure the md5sum in the changes file is the same
        as the actual file's md5sum.
        """
        for file in self.changes['Files']:
            log.debug('Checking md5sum of %s' % file['name'])
            filename = os.path.join(config['debexpo.upload.incoming'], file['name'])
            if os.path.isfile(filename):
                sum = md5sum(filename)

                data = 'Changes file says md5sum of %s is: %s\n' % (file['name'], file['md5sum'])
                data += 'Actual md5sum of %s is: %s' % (file['name'], sum)

                if sum != file['md5sum']:
                    log.error('%s != %s' % (sum, file['md5sum']))
                    self.failed('md5sum-not-match', data, constants.PLUGIN_SEVERITY_ERROR)
                else:
                    log.debug('Test passed')
                    self.passed('md5sum-match', None, constants.PLUGIN_SEVERITY_INFO)
Пример #3
0
    def test_md5sum(self, changes_file):
        """
        Check each file's md5sum and make sure the md5sum in the changes file is the same
        as the actual file's md5sum.

        ```changes_file```
            The changes file to parse for the orig.tar (note the dsc file referenced must exist)
        """
        for file in changes_file['Files']:
            log.debug('Checking md5sum of %s' % file['name'])
            filename = os.path.join(pylons.config['debexpo.upload.incoming'], file['name'])
            if not os.path.isfile(filename):
                raise OSError("Missing file %s in incoming" % (file['name']))
            sum = md5sum(filename)

            if sum != file['md5sum']:
                log.critical('%s != %s' % (sum, file['md5sum']))
                raise OSError("MD5 sum mismatch in file %s: %s != %s" % (file['name'], sum, file['md5sum']))

        return True
Пример #4
0
    def find_orig_tarball(self, changes_file):
        """
        Look to see whether there is an orig tarball present, if the dsc refers to one.
        This method returns a triple (filename, file_found, location_hint), returning the (expected)
        name of the original tarball, and whether it was found in the local repository

        ```changes_file```
            The changes file to parse for the orig.tar (note the dsc file referenced must exist)

        Returns a tuple (orig_filename, orig_filename_was_found)
        """

        orig_name = None
        if not changes_file.get_dsc() or open(changes_file.get_dsc()) == None:
            return (orig_name, constants.ORIG_TARBALL_LOCATION_NOT_FOUND)

        dscfile = open(changes_file.get_dsc())
        dsc = deb822.Dsc(dscfile)
        for file in dsc['Files']:
            if (file['name'].endswith('orig.tar.gz') or
                file['name'].endswith('orig.tar.bz2') or
                file['name'].endswith('orig.tar.xz')):
                    # We know how the orig.tar.gz should be called - at least.
                    orig_name = file['name']
                    full_filename = os.path.join(pylons.config['debexpo.repository'], changes_file.get_pool_path(), orig_name)
                    # tar.gz was found in the local directory
                    if os.path.isfile(file['name']):
                        sum = md5sum(file['name'])
                        if sum == file['md5sum']:
                            return (orig_name, constants.ORIG_TARBALL_LOCATION_LOCAL)
                        # tar.gz was found, but does not seem to be the same file
                    # tar.gz was found in the repository
                    elif os.path.isfile(full_filename):
                        return (orig_name, constants.ORIG_TARBALL_LOCATION_REPOSITORY)
                    # tar.gz was expected but not found at all
                    else:
                        return (orig_name, constants.ORIG_TARBALL_LOCATION_NOT_FOUND)

        # We should neve end up here
        return (orig_name, constants.ORIG_TARBALL_LOCATION_NOT_FOUND)
Пример #5
0
    def test_md5sum(self, changes_file):
        """
        Check each file's md5sum and make sure the md5sum in the changes file is the same
        as the actual file's md5sum.

        ```changes_file```
            The changes file to parse for the orig.tar (note the dsc file referenced must exist)
        """
        for file in changes_file['Files']:
            log.debug('Checking md5sum of %s' % file['name'])
            filename = os.path.join(pylons.config['debexpo.upload.incoming'],
                                    file['name'])
            if not os.path.isfile(filename):
                raise OSError("Missing file %s in incoming" % (file['name']))
            sum = md5sum(filename)

            if sum != file['md5sum']:
                log.critical('%s != %s' % (sum, file['md5sum']))
                raise OSError("MD5 sum mismatch in file %s: %s != %s" %
                              (file['name'], sum, file['md5sum']))

        return True
Пример #6
0
    def test_md5sum(self):
        """
        Check each file's md5sum and make sure the md5sum in the changes file is the same
        as the actual file's md5sum.
        """
        for file in self.changes['Files']:
            log.debug('Checking md5sum of %s' % file['name'])
            filename = os.path.join(config['debexpo.upload.incoming'],
                                    file['name'])
            if os.path.isfile(filename):
                sum = md5sum(filename)

                data = 'Changes file says md5sum of %s is: %s\n' % (
                    file['name'], file['md5sum'])
                data += 'Actual md5sum of %s is: %s' % (file['name'], sum)

                if sum != file['md5sum']:
                    log.error('%s != %s' % (sum, file['md5sum']))
                    self.failed('md5sum-not-match', data,
                                constants.PLUGIN_SEVERITY_ERROR)
                else:
                    log.debug('Test passed')
                    self.passed('md5sum-match', None,
                                constants.PLUGIN_SEVERITY_INFO)
Пример #7
0
    def _create_db_entries(self, qa):
        """
        Create entries in the Database for the package upload.
        """

        def _package_description(raw):
            return raw[2:].replace('      - ', ' - ')

        log.debug('Creating database entries')


        # Parse component and section from field in changes
        component, section = parse_section(self.changes['files'][0]['section'])

        # Check whether package is already in the database
        package_query = meta.session.query(Package).filter_by(name=self.changes['Source'])
        if package_query.count() == 1:
            log.debug('Package %s already exists in the database' % self.changes['Source'])
            package = package_query.one()
            # Update description to make sure it reflects the latest upload
            package.description = _package_description(self.changes['Description'])
        else:
            log.debug('Package %s is new to the system' % self.changes['Source'])
            package = Package(name=self.changes['Source'], user=self.user)
            package.description = _package_description(self.changes['Description'])
            package.needs_sponsor = 0
            meta.session.add(package)

        # No need to check whether there is the same source name and same version as an existing
        # entry in the database as the upload controller tested whether similar filenames existed
        # in the repository. The only way this would be wrong is if the filename had a different
        # version in than the Version field in changes..


        try:
            closes = self.changes['Closes']
        except KeyError:
            closes = None

        # TODO: fix these magic numbers
        if qa.stop():
            qa_status = 1
        else:
            qa_status = 0

        maintainer_matches = re.compile(r'(.*) <(.*)>').match(self.changes['Changed-By'])
        maintainer = maintainer_matches.group(2)

        package_version = PackageVersion(package=package, version=self.changes['Version'],
            section=section, distribution=self.changes['Distribution'], qa_status=qa_status,
            component=component, priority=self.changes.get_priority(), closes=closes,
            uploaded=datetime.now(), maintainer=maintainer)
        meta.session.add(package_version)

        source_package = SourcePackage(package_version=package_version)
        meta.session.add(source_package)

        binary_package = None

        # Add PackageFile objects to the database for each uploaded file
        for file in self.files:
            filename = os.path.join(self.changes.get_pool_path(), file)
            # This exception should be never caught.
            # It implies something went wrong before, as we expect a file which does not exist
            try:
                sum = md5sum(os.path.join(pylons.config['debexpo.repository'], filename))
            except AttributeError as e:
                self._fail("Could not calculate MD5 sum: %s" % (e))

            size = os.stat(os.path.join(pylons.config['debexpo.repository'], filename))[ST_SIZE]

            # Check for binary or source package file
            if file.endswith('.deb'):
                # Only create a BinaryPackage if there actually binary package files
                if binary_package is None:
                    binary_package = BinaryPackage(package_version=package_version, arch=file[:-4].split('_')[-1])
                    meta.session.add(binary_package)

                meta.session.add(PackageFile(filename=filename, binary_package=binary_package, size=size, md5sum=sum))
            else:
                meta.session.add(PackageFile(filename=filename, source_package=source_package, size=size, md5sum=sum))

        meta.session.commit()
        log.warning("Finished adding PackageFile objects.")

        # Add PackageInfo objects to the database for the package_version
        for result in qa.result:
            meta.session.add(PackageInfo(package_version=package_version, from_plugin=result.from_plugin,
                outcome=result.outcome, rich_data=result.data, severity=result.severity))

        # Commit all changes to the database
        meta.session.commit()
        log.debug('Committed package data to the database')

        subscribers = meta.session.query(PackageSubscription).filter_by(package=self.changes['Source']).filter(\
            PackageSubscription.level <= constants.SUBSCRIPTION_LEVEL_UPLOADS).all()

        if len(subscribers) > 0:
            email = Email('package_uploaded')
            self.send_email(email, [s.user.email for s in subscribers], package=self.changes['Source'],
                version=self.changes['Version'], user=self.user)

            log.debug('Sent out package subscription emails')

        # Send success email to uploader
        email = Email('successful_upload')
        dsc_url = pylons.config[
                  'debexpo.server'] + '/debian/' + self.changes.get_pool_path() + '/' + self.changes.get_dsc()
        rfs_url = pylons.config['debexpo.server'] + url('rfs', packagename=self.changes['Source'])
        self.send_email(email, [self.user.email], package=self.changes['Source'],
            dsc_url=dsc_url, rfs_url=rfs_url)
Пример #8
0
    def test_orig_tarball(self):
        """
        Check whether there is an original tarball referenced by the dsc file, but not
        actually in the package upload.

        This procedure is skipped to avoid denial of service attacks when a package is
        larger than the configured size
        """

        # Set download of files, when the expected file size of the orig.tar.gz is larger
        # than the configured threshold.
        # XXX TODO: This size should be the 75% quartile, that is the value where 75% of all
        #           packages are smaller than that. For now, blindly assume this as 15M
        size = 15728640
        log.debug(
            'Checking whether an orig tarball mentioned in the dsc is missing')
        dsc = deb822.Dsc(file(self.changes.get_dsc()))
        filecheck = CheckFiles()

        if filecheck.is_native_package(self.changes):
            log.debug('No orig.tar.gz file found; native package?')
            return

        # An orig.tar.gz was found in the dsc, and also in the upload.
        (orig, orig_file_found) = filecheck.find_orig_tarball(self.changes)
        if orig_file_found > constants.ORIG_TARBALL_LOCATION_NOT_FOUND:
            log.debug('%s found successfully', orig)
            return

        if not orig:
            log.debug("Couldn't determine name of the orig.tar.gz?")
            return

        for dscfile in dsc['Files']:
            dscfile['size'] = int(dscfile['size'])
            if orig == dscfile['name']:
                if dscfile['size'] > size:
                    log.warning(
                        "Skipping eventual download of orig.tar.gz %s: size %d > %d"
                        % (dscfile['name'], dscfile['size'], size))
                    return
                orig = dscfile
                break
        else:
            log.debug(
                "dsc does not reference our expected orig.tar.gz name '%s'" %
                (orig))
            return

        log.debug('Could not find %s; looking in Debian for it', orig['name'])

        url = os.path.join(pylons.config['debexpo.debian_mirror'],
                           self.changes.get_pool_path(), orig['name'])
        log.debug('Trying to fetch %s' % url)
        out = urllib.urlopen(url)
        contents = out.read()

        f = open(orig['name'], "wb")
        f.write(contents)
        f.close()

        if md5sum(orig['name']) == orig['md5sum']:
            log.debug('Tarball %s taken from Debian' % orig['name'])
            self.info('tarball-taken-from-debian', None)
        else:
            log.error('Tarball %s not found in Debian' % orig['name'])
            os.unlink(orig['name'])
Пример #9
0
    def test_orig_tarball(self):
        """
        Check whether there is an original tarball referenced by the dsc file, but not
        actually in the package upload.

        This procedure is skipped to avoid denial of service attacks when a package is
        larger than the configured size
        """

        # Set download of files, when the expected file size of the orig.tar.gz is larger
        # than the configured threshold.
        # XXX TODO: This size should be the 75% quartile, that is the value where 75% of all
        #           packages are smaller than that. For now, blindly assume this as 15M
        size = 15728640
        log.debug('Checking whether an orig tarball mentioned in the dsc is missing')
        dsc = deb822.Dsc(file(self.changes.get_dsc()))
        filecheck = CheckFiles()

        if filecheck.is_native_package(self.changes):
            log.debug('No orig.tar.gz file found; native package?')
            return

        # An orig.tar.gz was found in the dsc, and also in the upload.
        (orig, orig_file_found) = filecheck.find_orig_tarball(self.changes)
        if orig_file_found > constants.ORIG_TARBALL_LOCATION_NOT_FOUND:
            log.debug('%s found successfully', orig)
            return

        if not orig:
            log.debug("Couldn't determine name of the orig.tar.gz?")
            return

        for dscfile in dsc['Files']:
            dscfile['size'] = int(dscfile['size'])
            if orig == dscfile['name']:
                if dscfile['size'] > size:
                        log.warning("Skipping eventual download of orig.tar.gz %s: size %d > %d" % (dscfile['name'], dscfile['size'], size))
                        return
                orig = dscfile
                break
        else:
            log.debug("dsc does not reference our expected orig.tar.gz name '%s'" % (orig))
            return

        log.debug('Could not find %s; looking in Debian for it', orig['name'])

        url = os.path.join(pylons.config['debexpo.debian_mirror'], self.changes.get_pool_path(), orig['name'])
        log.debug('Trying to fetch %s' % url)
        out = urllib.urlopen(url)
        contents = out.read()

        f = open(orig['name'], "wb")
        f.write(contents)
        f.close()

        if md5sum(orig['name']) == orig['md5sum']:
            log.debug('Tarball %s taken from Debian' % orig['name'])
            self.info('tarball-taken-from-debian', None)
        else:
            log.error('Tarball %s not found in Debian' % orig['name'])
            os.unlink(orig['name'])
Пример #10
0
    def _create_db_entries(self, qa):
        """
        Create entries in the Database for the package upload.
        """
        def _package_description(raw):
            return raw[2:].replace('      - ', ' - ')

        log.debug('Creating database entries')

        # Parse component and section from field in changes
        component, section = parse_section(self.changes['files'][0]['section'])

        # Check whether package is already in the database
        package_query = meta.session.query(Package).filter_by(
            name=self.changes['Source'])
        if package_query.count() == 1:
            log.debug('Package %s already exists in the database' %
                      self.changes['Source'])
            package = package_query.one()
            # Update description to make sure it reflects the latest upload
            package.description = _package_description(
                self.changes['Description'])
        else:
            log.debug('Package %s is new to the system' %
                      self.changes['Source'])
            package = Package(name=self.changes['Source'], user=self.user)
            package.description = _package_description(
                self.changes['Description'])
            package.needs_sponsor = 0
            meta.session.add(package)

        # No need to check whether there is the same source name and same version as an existing
        # entry in the database as the upload controller tested whether similar filenames existed
        # in the repository. The only way this would be wrong is if the filename had a different
        # version in than the Version field in changes..

        try:
            closes = self.changes['Closes']
        except KeyError:
            closes = None

        # TODO: fix these magic numbers
        if qa.stop():
            qa_status = 1
        else:
            qa_status = 0

        maintainer_matches = re.compile(r'(.*) <(.*)>').match(
            self.changes['Changed-By'])
        maintainer = maintainer_matches.group(2)

        package_version = PackageVersion(
            package=package,
            version=self.changes['Version'],
            section=section,
            distribution=self.changes['Distribution'],
            qa_status=qa_status,
            component=component,
            priority=self.changes.get_priority(),
            closes=closes,
            uploaded=datetime.now(),
            maintainer=maintainer)
        meta.session.add(package_version)

        source_package = SourcePackage(package_version=package_version)
        meta.session.add(source_package)

        binary_package = None

        # Add PackageFile objects to the database for each uploaded file
        for file in self.files:
            filename = os.path.join(self.changes.get_pool_path(), file)
            # This exception should be never caught.
            # It implies something went wrong before, as we expect a file which does not exist
            try:
                sum = md5sum(
                    os.path.join(pylons.config['debexpo.repository'],
                                 filename))
            except AttributeError as e:
                self._fail("Could not calculate MD5 sum: %s" % (e))

            size = os.stat(
                os.path.join(pylons.config['debexpo.repository'],
                             filename))[ST_SIZE]

            # Check for binary or source package file
            if file.endswith('.deb'):
                # Only create a BinaryPackage if there actually binary package files
                if binary_package is None:
                    binary_package = BinaryPackage(
                        package_version=package_version,
                        arch=file[:-4].split('_')[-1])
                    meta.session.add(binary_package)

                meta.session.add(
                    PackageFile(filename=filename,
                                binary_package=binary_package,
                                size=size,
                                md5sum=sum))
            else:
                meta.session.add(
                    PackageFile(filename=filename,
                                source_package=source_package,
                                size=size,
                                md5sum=sum))

        meta.session.commit()
        log.warning("Finished adding PackageFile objects.")

        # Add PackageInfo objects to the database for the package_version
        for result in qa.result:
            meta.session.add(
                PackageInfo(package_version=package_version,
                            from_plugin=result.from_plugin,
                            outcome=result.outcome,
                            rich_data=result.data,
                            severity=result.severity))

        # Commit all changes to the database
        meta.session.commit()
        log.debug('Committed package data to the database')

        subscribers = meta.session.query(PackageSubscription).filter_by(package=self.changes['Source']).filter(\
            PackageSubscription.level <= constants.SUBSCRIPTION_LEVEL_UPLOADS).all()

        if len(subscribers) > 0:
            email = Email('package_uploaded')
            self.send_email(email, [s.user.email for s in subscribers],
                            package=self.changes['Source'],
                            version=self.changes['Version'],
                            user=self.user)

            log.debug('Sent out package subscription emails')

        # Send success email to uploader
        email = Email('successful_upload')
        dsc_url = pylons.config[
            'debexpo.server'] + '/debian/' + self.changes.get_pool_path(
            ) + '/' + self.changes.get_dsc()
        rfs_url = pylons.config['debexpo.server'] + url(
            'rfs', packagename=self.changes['Source'])
        self.send_email(email, [self.user.email],
                        package=self.changes['Source'],
                        dsc_url=dsc_url,
                        rfs_url=rfs_url)