diff options
Diffstat (limited to 'devel')
-rw-r--r-- | devel/management/commands/import_signatures.py | 104 | ||||
-rw-r--r-- | devel/management/commands/reporead.py | 11 | ||||
-rw-r--r-- | devel/migrations/0003_auto__add_pgpsignature.py | 81 | ||||
-rw-r--r-- | devel/models.py | 13 | ||||
-rw-r--r-- | devel/views.py | 2 |
5 files changed, 204 insertions, 7 deletions
diff --git a/devel/management/commands/import_signatures.py b/devel/management/commands/import_signatures.py new file mode 100644 index 00000000..8a4ce873 --- /dev/null +++ b/devel/management/commands/import_signatures.py @@ -0,0 +1,104 @@ +# -*- coding: utf-8 -*- +""" +import_signatures command + +Import signatures from a given GPG keyring. + +Usage: ./manage.py generate_keyring <keyring_path> +""" + +from datetime import datetime +import logging +import subprocess +import sys + +from django.core.management.base import BaseCommand, CommandError +from django.db import transaction + +from devel.models import PGPSignature + +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s -> %(levelname)s: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S', + stream=sys.stderr) +logger = logging.getLogger() + +class Command(BaseCommand): + args = "<keyring_path>" + help = "Import signatures from a given GPG keyring." + + def handle(self, *args, **options): + v = int(options.get('verbosity', None)) + if v == 0: + logger.level = logging.ERROR + elif v == 1: + logger.level = logging.INFO + elif v == 2: + logger.level = logging.DEBUG + + if len(args) < 1: + raise CommandError("keyring_path must be provided") + + import_signatures(args[0]) + +def parse_sigdata(data): + nodes = {} + edges = [] + current_pubkey = None + + # parse all of the output from our successful GPG command + logger.info("parsing command output") + for line in data.split('\n'): + parts = line.split(':') + if parts[0] == 'pub': + current_pubkey = parts[4] + nodes[current_pubkey] = None + if parts[0] == 'uid': + uid = parts[9] + # only set uid if this is the first one encountered + if nodes[current_pubkey] is None: + nodes[current_pubkey] = uid + if parts[0] == 'sig': + created = datetime.utcfromtimestamp(int(parts[5])) + expires = None + if parts[6]: + expires = datetime.utcfromtimestamp(int(parts[6])) + valid = parts[1] != '-' + edge = (parts[4], current_pubkey, created, expires, valid) + edges.append(edge) + + return nodes, edges + + +def import_signatures(keyring): + gpg_cmd = ["gpg", "--no-default-keyring", "--keyring", keyring, + "--list-sigs", "--with-colons", "--fixed-list-mode"] + logger.info("running command: %r", gpg_cmd) + proc = subprocess.Popen(gpg_cmd, stdout=subprocess.PIPE) + outdata, errdata = proc.communicate() + if proc.returncode != 0: + logger.error(errdata) + raise subprocess.CalledProcessError(proc.returncode, gpg_cmd) + + nodes, edges = parse_sigdata(outdata) + + # now prune the data down to what we actually want. + # prune edges not in nodes, remove duplicates, and self-sigs + pruned_edges = set(edge for edge in edges + if edge[0] in nodes and edge[0] != edge[1]) + + logger.info("creating or finding %d signatures", len(pruned_edges)) + created_ct = 0 + with transaction.commit_on_success(): + for edge in pruned_edges: + _, created = PGPSignature.objects.get_or_create( + signer=edge[0], signee=edge[1], + created=edge[2], expires=edge[3], + defaults={ 'valid': edge[4] }) + if created: + created_ct += 1 + + logger.info("created %d signatures", created_ct) + +# vim: set ts=4 sw=4 et: diff --git a/devel/management/commands/reporead.py b/devel/management/commands/reporead.py index 66df7b97..4dd26091 100644 --- a/devel/management/commands/reporead.py +++ b/devel/management/commands/reporead.py @@ -376,10 +376,9 @@ def db_update(archname, reponame, pkgs, force=False): timestamp = None # for a force, we don't want to update the timestamp. # for a non-force, we don't want to do anything at all. - if pkg_same_version(pkg, dbpkg): - if not force: - continue - else: + if not force and pkg_same_version(pkg, dbpkg): + continue + elif not force: timestamp = datetime.utcnow() # The odd select_for_update song and dance here are to ensure @@ -388,7 +387,7 @@ def db_update(archname, reponame, pkgs, force=False): with transaction.commit_on_success(): # TODO Django 1.4 select_for_update() will work once released dbpkg = select_pkg_for_update(dbpkg) - if pkg_same_version(pkg, dbpkg): + if not force and pkg_same_version(pkg, dbpkg): logger.debug("Package %s was already updated", pkg.name) continue logger.info("Updating package %s", pkg.name) @@ -415,7 +414,7 @@ def filesonly_update(archname, reponame, pkgs, force=False): with transaction.commit_on_success(): if not dbpkg.files_last_update or not dbpkg.last_update: pass - elif dbpkg.files_last_update > dbpkg.last_update: + elif not force and dbpkg.files_last_update > dbpkg.last_update: logger.debug("Files for %s are up to date", pkg.name) continue # TODO Django 1.4 select_for_update() will work once released diff --git a/devel/migrations/0003_auto__add_pgpsignature.py b/devel/migrations/0003_auto__add_pgpsignature.py new file mode 100644 index 00000000..f9ac5021 --- /dev/null +++ b/devel/migrations/0003_auto__add_pgpsignature.py @@ -0,0 +1,81 @@ +# encoding: utf-8 +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + db.create_table('devel_pgpsignature', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('signer', self.gf('main.fields.PGPKeyField')(max_length=40)), + ('signee', self.gf('main.fields.PGPKeyField')(max_length=40)), + ('created', self.gf('django.db.models.fields.DateField')()), + ('expires', self.gf('django.db.models.fields.DateField')(null=True)), + ('valid', self.gf('django.db.models.fields.BooleanField')(default=True)), + )) + db.send_create_signal('devel', ['PGPSignature']) + + + def backwards(self, orm): + db.delete_table('devel_pgpsignature') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'devel.masterkey': { + 'Meta': {'ordering': "('created',)", 'object_name': 'MasterKey'}, + 'created': ('django.db.models.fields.DateTimeField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'masterkey_owner'", 'to': "orm['auth.User']"}), + 'pgp_key': ('main.fields.PGPKeyField', [], {'max_length': '40'}), + 'revoked': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'revoker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'masterkey_revoker'", 'to': "orm['auth.User']"}) + }, + 'devel.pgpsignature': { + 'Meta': {'object_name': 'PGPSignature'}, + 'created': ('django.db.models.fields.DateField', [], {}), + 'expires': ('django.db.models.fields.DateField', [], {'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'signee': ('main.fields.PGPKeyField', [], {'max_length': '40'}), + 'signer': ('main.fields.PGPKeyField', [], {'max_length': '40'}), + 'valid': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + } + } + + complete_apps = ['devel'] diff --git a/devel/models.py b/devel/models.py index f31b8fbb..6c97375c 100644 --- a/devel/models.py +++ b/devel/models.py @@ -17,4 +17,17 @@ class MasterKey(models.Model): class Meta: ordering = ('created',) + +class PGPSignature(models.Model): + signer = PGPKeyField(max_length=40, verbose_name="PGP key fingerprint", + help_text="consists of 40 hex digits; use `gpg --fingerprint`") + signee = PGPKeyField(max_length=40, verbose_name="PGP key fingerprint", + help_text="consists of 40 hex digits; use `gpg --fingerprint`") + created = models.DateField() + expires = models.DateField(null=True) + valid = models.BooleanField(default=True) + + class Meta: + verbose_name = 'PGP signature' + # vim: set ts=4 sw=4 et: diff --git a/devel/views.py b/devel/views.py index b9bd7cce..c888871d 100644 --- a/devel/views.py +++ b/devel/views.py @@ -123,7 +123,7 @@ class UserProfileForm(forms.ModelForm): class Meta: model = UserProfile - exclude = ['allowed_repos', 'user'] + exclude = ('allowed_repos', 'user', 'latin_name') @login_required @never_cache |