Ejemplo n.º 1
0
 def __init__(self, inifile):
     """
     This method does nothing in this cronjob
     """
     self.inifile = os.path.abspath(inifile)
     conf = appconfig('config:' + self.inifile)
     pylons.config = load_environment(conf.global_conf, conf.local_conf)
     self.config = pylons.config
     self.gpg = GnuPG()
Ejemplo n.º 2
0
 def __init__(self, inifile):
     """
     This method does nothing in this cronjob
     """
     self.inifile = os.path.abspath(inifile)
     conf = appconfig('config:' + self.inifile)
     pylons.config = load_environment(conf.global_conf, conf.local_conf)
     self.config = pylons.config
     self.gpg = GnuPG()
Ejemplo n.º 3
0
class GpgKey(formencode.validators.FieldStorageUploadConverter):
    """
    Validator for an uploaded GPG key. They must with the 'BEGIN PGP PUBLIC KEY BLOCK'
    text.
    """

    def __init__(self):
        self.gpg_id = None
        self.gnupg  = GnuPG()

    def _to_python(self, value, c):
        """
        Validate the GPG key.

        ``value``
            FieldStorage uploaded file.

        ``c``
        """
        if not value.value.startswith('-----BEGIN PGP PUBLIC KEY BLOCK-----'):
            log.error('GPG key does not start with BEGIN PGP PUBLIC KEY BLOCK')
            raise formencode.Invalid(_('Invalid GPG key'), value, c)

        if self.gnupg.is_unusable():
            log.error('Unable to validate GPG key because gpg is unusable.')
            raise formencode.Invalid(_('Internal error: debexpo is not ' +
                                       'properly configured to handle' +
                                       'GPG keys'), value, c)

        self.gpg_id = self.gnupg.parse_key_id(value.value)
        if self.gpg_id is None:
            log.error("Failed to parse GPG key")
            raise formencode.Invalid(_('Invalid GPG key'), value, c)

        return formencode.validators.FieldStorageUploadConverter._to_python(self, value, c)

    def key_id(self):
        return self.gpg_id
Ejemplo n.º 4
0
class UpdateKeyring(object):
    def __init__(self, inifile):
        """
        This method does nothing in this cronjob
        """
        self.inifile = os.path.abspath(inifile)
        conf = appconfig('config:' + self.inifile)
        pylons.config = load_environment(conf.global_conf, conf.local_conf)
        self.config = pylons.config
        self.gpg = GnuPG()

    def invoke(self):
        """
        Loops through the debexpo.upload.incoming directory and runs the debexpo.importer for each file
        """

        if 'debexpo.gpg_keyring' not in self.config:
            print("debexpo.gpg_keyring was not configured or is not writable")
            return

        try:
            keyring = open(self.config['debexpo.gpg_keyring'], "a+")
            keyring.close()
        except IOError as e:
            print("Can't access file: %s: %s" % (self.config['debexpo.gpg_keyring'], str(e)))
            return

        print("Regenerate keyring into %s" % (keyring.name))
        (_, keyring) = tempfile.mkstemp()
        for user in meta.session.query(User).all():
            if not user.gpg:
                continue
            temp = tempfile.NamedTemporaryFile(delete=True)
            temp.write(user.gpg)
            temp.flush()
            (out, err) = self.gpg.add_signature(temp.name, keyring)
            temp.close()
            if err != 0:
                print("gpg failed to import keyring: %s" % (out))
                continue
            print(out)

        shutil.move(keyring, self.config['debexpo.gpg_keyring'])

        meta.session.close()
Ejemplo n.º 5
0
class UpdateKeyring(object):
    def __init__(self, inifile):
        """
        This method does nothing in this cronjob
        """
        self.inifile = os.path.abspath(inifile)
        conf = appconfig('config:' + self.inifile)
        pylons.config = load_environment(conf.global_conf, conf.local_conf)
        self.config = pylons.config
        self.gpg = GnuPG()

    def invoke(self):
        """
        Loops through the debexpo.upload.incoming directory and runs the debexpo.importer for each file
        """

        if 'debexpo.gpg_keyring' not in self.config:
            print("debexpo.gpg_keyring was not configured or is not writable")
            return

        try:
            keyring = open(self.config['debexpo.gpg_keyring'], "a+")
            keyring.close()
        except IOError as e:
            print("Can't access file: %s: %s" % (self.config['debexpo.gpg_keyring'], str(e)))
            return

        print("Regenerate keyring into %s" % (keyring.name))
        (_, keyring) = tempfile.mkstemp()
        for user in meta.session.query(User).all():
            if not user.gpg:
                continue
            temp = tempfile.NamedTemporaryFile(delete=True)
            temp.write(user.gpg)
            temp.flush()
            (out, err) = self.gpg.add_signature(temp.name, keyring)
            temp.close()
            if err != 0:
                print("gpg failed to import keyring: %s" % (out))
                continue
            print(out)

        shutil.move(keyring, self.config['debexpo.gpg_keyring'])

        meta.session.close()
Ejemplo n.º 6
0
    def main(self):
        """
        Actually start the import of the package.

        Do several environment sanity checks, move files into the right place, and then
        create the database entries for the imported package.
        """
        # Set up importer
        self._setup()

        log.debug('Importer started with arguments: %s' % sys.argv[1:])
        filecheck = CheckFiles()
        signature = GnuPG()

        # Try parsing the changes file, but fail if there's an error.
        try:
            self.changes = Changes(filename=self.changes_file)
            filecheck.test_files_present(self.changes)
            filecheck.test_md5sum(self.changes)
        except Exception as e:
            # XXX: The user won't ever see this message. The changes file was
            # invalid, we don't know whom send it to
            self._reject("Your changes file appears invalid. Refusing your upload\n%s" % (e.message))



        # Determine user from changed-by field
        # This might be temporary, the GPG check should replace the user later
        # At this stage it is only helpful to get an email address to send blame mails to
        self._determine_uploader()

        # Next, find out whether the changes file was signed with a valid signature, if not reject immediately
        if not self.skip_gpg:
            if not signature.is_signed(self.changes_file):
                self._reject('Your upload does not appear to be signed')
            (gpg_out, gpg_status) = signature.verify_sig_full(self.changes_file)
            if gpg_status != 0:
                self._reject('Your upload does not contain a valid signature. Output was:\n%s' % (gpg_out))
            log.debug("GPG signature matches user %s" % (self.user.email))

        # XXX: Replace self.user by something which was verified by GPG!

        if self.user_id == -1:
            self._reject('Couldn\'t find user %s. Exiting.' % self.user.email)
        log.debug("User found in database. Has id: %s", self.user.id)

        self.files = self.changes.get_files()
        self.files_to_remove = []

        distribution = self.changes['Distribution'].lower()
        allowed_distributions = ('oldstable', 'stable', 'unstable', 'experimental', 'stable-backports', 'oldstable-backports',
            'oldstable-backports-sloppy', 'oldstable-security', 'stable-security', 'testing-security', 'stable-proposed-updates',
            'testing-proposed-updates', 'sid', 'wheezy', 'squeeze', 'lenny', 'squeeze-backports', 'lenny-backports',
            'lenny-security', 'lenny-backports-sloppy', 'lenny-volatile', 'squeeze-security', 'squeeze-updates', 'wheezy-security',
            'unreleased')
        if distribution not in allowed_distributions:
            self._reject("You are not uploading to one of those Debian distributions: %s" %
                (reduce(lambda x,xs: x + " " + xs, allowed_distributions)))

        # Look whether the orig tarball is present, and if not, try and get it from
        # the repository.
        (orig, orig_file_found) = filecheck.find_orig_tarball(self.changes)
        if orig_file_found != constants.ORIG_TARBALL_LOCATION_LOCAL:
            log.debug("Upload does not contain orig.tar.gz - trying to find it elsewhere")
        if orig and orig_file_found == constants.ORIG_TARBALL_LOCATION_REPOSITORY:
            filename = os.path.join(pylons.config['debexpo.repository'],
                self.changes.get_pool_path(), orig)
            if os.path.isfile(filename):
                log.debug("Found tar.gz in repository as %s" % (filename))
                shutil.copy(filename, pylons.config['debexpo.upload.incoming'])
                # We need the orig.tar.gz for the import run, plugins need to extract the source package
                # also Lintian needs it. However the orig.tar.gz is in the repository already, so we can
                # remove it later
                self.files_to_remove.append(orig)

        destdir = pylons.config['debexpo.repository']


        # Check whether the files are already present
        log.debug("Checking whether files are already in the repository")
        toinstall = []
        pool_dir = os.path.join(destdir, self.changes.get_pool_path())
        log.debug("Pool directory: %s", pool_dir)
        for file in self.files:
            if os.path.isfile(file) and os.path.isfile(os.path.join(pool_dir, file)):
                log.warning('%s is being installed even though it already exists' % file)
                toinstall.append(file)
            elif os.path.isfile(file):
                log.debug('File %s is safe to install' % os.path.join(pool_dir, file))
                toinstall.append(file)
            # skip another corner case, where the dsc contains a orig.tar.gz but wasn't uploaded
            # by doing nothing here for that case

        # Run post-upload plugins.
        post_upload = Plugins('post-upload', self.changes, self.changes_file,
            user_id=self.user_id)
        if post_upload.stop():
            log.critical('post-upload plugins failed')
            self._remove_changes()
            sys.exit(1)

        # Check whether a post-upload plugin has got the orig tarball from somewhere.
        if not orig_file_found and not filecheck.is_native_package(self.changes):
            (orig, orig_file_found) = filecheck.find_orig_tarball(self.changes)
            if orig_file_found == constants.ORIG_TARBALL_LOCATION_NOT_FOUND:
                # When coming here it means:
                # a) The uploader did not include a orig.tar.gz in his upload
                # b) We couldn't find a orig.tar.gz in our repository
                # c) No plugin could get the orig.tar.gz
                # ... time to give up
                if orig == None:
                    orig = "any original tarball (orig.tar.gz)"
                self._reject("Rejecting incomplete upload. "
                    "You did not upload %s and we didn't find it on any of our alternative resources.\n" \
                    "If you tried to upload a package which only increased the Debian revision part, make sure you include the full source (pass -sa to dpkg-buildpackage)" %
                    ( orig ))
            else:
                toinstall.append(orig)

        # Check whether the debexpo.repository variable is set
        if 'debexpo.repository' not in pylons.config:
            self._fail('debexpo.repository not set')

        # Check whether debexpo.repository is a directory
        if not os.path.isdir(pylons.config['debexpo.repository']):
            self._fail('debexpo.repository is not a directory')

        # Check whether debexpo.repository is writeable
        if not os.access(pylons.config['debexpo.repository'], os.W_OK):
            self._fail('debexpo.repository is not writeable')

        qa = Plugins('qa', self.changes, self.changes_file, user_id=self.user_id)
        if qa.stop():
            self._reject('QA plugins failed the package')

        # Loop through parent directories in the target installation directory to make sure they
        # all exist. If not, create them.
        for dir in self.changes.get_pool_path().split('/'):
            destdir = os.path.join(destdir, dir)

            if not os.path.isdir(destdir):
                log.debug('Creating directory: %s' % destdir)
                os.mkdir(destdir)

        # Install files in repository
        for file in toinstall:
            log.debug("Installing new file %s" % (file))
            shutil.move(file, os.path.join(destdir, file))

        self._remove_temporary_files()
        # Create the database rows
        self._create_db_entries(qa)

        # Execute post-successful-upload plugins
        f = open(self.changes_file)
        changes_contents = f.read()
        f.close()
        Plugins('post-successful-upload', self.changes, self.changes_file,
            changes_contents=changes_contents)

        # Remove the changes file
        self._remove_changes()

        # Refresh the Sources/Packages files.
        log.debug('Updating Sources and Packages files')
        r = Repository(pylons.config['debexpo.repository'])
        r.update()

        log.debug('Done')
Ejemplo n.º 7
0
 def _get_gnupg(self, gpg_path='/usr/bin/gpg'):
     keyring_path = self._get_data_file('pubring_with_355304E4.gpg')
     gnupg = GnuPG(gpg_path, keyring_path)
     return gnupg
Ejemplo n.º 8
0
 def __init__(self):
     self.gpg_id = None
     self.gnupg  = GnuPG()