From: Michael Casadevall Date: Fri, 2 Jan 2009 21:58:37 +0000 (-0500) Subject: Merge commit 'origin/master' into dm_upload_allowed X-Git-Url: https://git.decadent.org.uk/gitweb/?a=commitdiff_plain;h=203e76d0f6eddac1ad270d68df5e96357d0d0011;hp=076955c92fab7438ca1076e17ed07a997e9bd4de;p=dak.git Merge commit 'origin/master' into dm_upload_allowed Conflicts: ChangeLog.old Signed-off-by: Michael Casadevall --- diff --git a/config/debian/dak.conf b/config/debian/dak.conf index 332a6170..345565b3 100644 --- a/config/debian/dak.conf +++ b/config/debian/dak.conf @@ -126,6 +126,14 @@ Import-Archive ExportDir "/srv/ftp.debian.org/dak/import-archive-files/"; }; +Import-Keyring +{ + /srv/ftp.debian.org/keyrings/debian-maintainers.gpg + { + Debian-Maintainer "true"; + }; +}; + Reject-Proposed-Updates { StableRejector "the Stable Release Team"; diff --git a/dak/dak.py b/dak/dak.py index 9dfd026b..e8a7df03 100755 --- a/dak/dak.py +++ b/dak/dak.py @@ -144,6 +144,8 @@ def init(): "Sync PostgreSQL users with passwd file"), ("init-db", "Update the database to match the conf file"), + ("update-db", + "Updates databae schema to latest revision"), ("init-dirs", "Initial setup of the archive"), ("make-maintainers", diff --git a/dak/dakdb/__init__.py b/dak/dakdb/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/dak/dakdb/update1.py b/dak/dakdb/update1.py new file mode 100644 index 00000000..3f0aa801 --- /dev/null +++ b/dak/dakdb/update1.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python + +# Debian Archive Kit Database Update Script +# Copyright (C) 2008 Michael Casadevall + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +################################################################################ + +# really, if we want to screw ourselves, let's find a better way. +# rm -rf /srv/ftp.debian.org + +################################################################################ + +import psycopg2, time + +################################################################################ + +def do_update(self): + print "Adding DM fields to database" + + try: + c = self.db.cursor() + c.execute("ALTER TABLE source ADD COLUMN dm_upload_allowed BOOLEAN DEFAULT 'no' NOT NULL;") + c.execute("ALTER TABLE keyrings ADD COLUMN debian_maintainer BOOLEAN DEFAULT 'false' NOT NULL;") + + print "Migrating DM data to source table. This might take some time ..." + + c.execute("UPDATE source SET dm_upload_allowed = 't' WHERE id IN (SELECT source FROM src_uploaders);") + c.execute("UPDATE config SET value = '1' WHERE name = 'db_revision'") + + print "Migrating DM uids to normal uids" + c.execute("SELECT uid FROM uid WHERE uid LIKE 'dm:%'") + rows = c.fetchall() + for r in rows: + uid = r[0] + c.execute("UPDATE uid SET uid = '%s' WHERE uid = '%s'" % (uid[3:], uid)) + + self.db.commit() + + print "IMPORTANT: Set the debian_maintainer flag in the config file for keyrings that are DMs!" + print " Failure to do so will result in DM's having full upload abilities!" + print "REMINDER: Remember to run the updated byhand-dm crontab to update Debian Maintainer information" + print "" + print "Pausing for five seconds ..." + time.sleep (5) + + except psycopg2.ProgrammingError, msg: + self.db.rollback() + print "FATAL: Unable to apply DM table update 1!" + print "Error Message: " + str(msg) + print "Database changes have been rolled back." diff --git a/dak/import_keyring.py b/dak/import_keyring.py index a70a2e78..602eb374 100755 --- a/dak/import_keyring.py +++ b/dak/import_keyring.py @@ -222,6 +222,11 @@ def main(): keyringname = keyring_names[0] keyring = Keyring(keyringname) + is_dm = "false" + if Cnf.has_key("Import-Keyring::"+keyringname+"::Debian-Maintainer"): + projectB.query("UPDATE keyrings SET debian_maintainer = '%s' WHERE name = '%s'" % (Cnf["Import-Keyring::"+keyringname+"::Debian-Maintainer"], keyringname.split("/")[-1])) + is_dm = Cnf["Import-Keyring::"+keyringname+"::Debian-Maintainer"] + keyring_id = database.get_or_set_keyring_id( keyringname.split("/")[-1]) @@ -291,7 +296,12 @@ def main(): projectB.query("UPDATE fingerprint SET uid = %d WHERE id = %d" % (newuid, oldfid)) if oldkid != keyring_id: - projectB.query("UPDATE fingerprint SET keyring = %d WHERE id = %d" % (keyring_id, oldfid)) + # Only change the keyring if it won't result in a loss of permissions + q = projectB.query("SELECT debian_maintainer FROM keyrings WHERE id = '%d'" % (keyring_id)) + if is_dm == "false" and q.getresult()[0][0] == 'f': + projectB.query("UPDATE fingerprint SET keyring = %d WHERE id = %d" % (keyring_id, oldfid)) + else: + print "Key %s exists in both DM and DD keyrings. Not demoting." % (f) # All done! diff --git a/dak/import_ldap_fingerprints.py b/dak/import_ldap_fingerprints.py index b5682853..4cc8aa01 100755 --- a/dak/import_ldap_fingerprints.py +++ b/dak/import_ldap_fingerprints.py @@ -151,7 +151,7 @@ SELECT f.fingerprint, f.id, u.uid FROM fingerprint f, uid u WHERE f.uid = u.id print "Assigning %s to 0x%s." % (uid, fingerprint) elif existing_uid == uid: pass - elif existing_uid[:3] == "dm:": + elif '@' not in existing_ui: q = projectB.query("UPDATE fingerprint SET uid = %s WHERE id = %s" % (uid_id, fingerprint_id)) print "Promoting DM %s to DD %s with keyid 0x%s." % (existing_uid, uid, fingerprint) else: diff --git a/dak/process_accepted.py b/dak/process_accepted.py index 0d5a5387..ea238ef7 100755 --- a/dak/process_accepted.py +++ b/dak/process_accepted.py @@ -298,10 +298,14 @@ def install (): filename = files[file]["pool name"] + file dsc_component = files[file]["component"] dsc_location_id = files[file]["location id"] + if dsc.has_key("dm-upload-allowed") and dsc["dm-upload-allowed"] == "yes": + dm_upload_allowed = "true" + else: + dm_upload_allowed = "false" if not files[file].has_key("files id") or not files[file]["files id"]: files[file]["files id"] = database.set_files_id (filename, files[file]["size"], files[file]["md5sum"], files[file]["sha1sum"], files[file]["sha256sum"], dsc_location_id) - projectB.query("INSERT INTO source (source, version, maintainer, changedby, file, install_date, sig_fpr) VALUES ('%s', '%s', %d, %d, %d, '%s', %s)" - % (package, version, maintainer_id, changedby_id, files[file]["files id"], install_date, fingerprint_id)) + projectB.query("INSERT INTO source (source, version, maintainer, changedby, file, install_date, sig_fpr, dm_upload_allowed) VALUES ('%s', '%s', %d, %d, %d, '%s', %s, %s)" + % (package, version, maintainer_id, changedby_id, files[file]["files id"], install_date, fingerprint_id, dm_upload_allowed)) for suite in changes["distribution"].keys(): suite_id = database.get_suite_id(suite) @@ -322,21 +326,20 @@ def install (): projectB.query("INSERT INTO dsc_files (source, file) VALUES (currval('source_id_seq'), %d)" % (files_id)) # Add the src_uploaders to the DB - if dsc.get("dm-upload-allowed", "no") == "yes": - uploader_ids = [maintainer_id] - if dsc.has_key("uploaders"): - for u in dsc["uploaders"].split(","): - u = u.replace("'", "\\'") - u = u.strip() - uploader_ids.append( - database.get_or_set_maintainer_id(u)) - added_ids = {} - for u in uploader_ids: - if added_ids.has_key(u): - utils.warn("Already saw uploader %s for source %s" % (u, package)) - continue - added_ids[u]=1 - projectB.query("INSERT INTO src_uploaders (source, maintainer) VALUES (currval('source_id_seq'), %d)" % (u)) + uploader_ids = [maintainer_id] + if dsc.has_key("uploaders"): + for u in dsc["uploaders"].split(","): + u = u.replace("'", "\\'") + u = u.strip() + uploader_ids.append( + database.get_or_set_maintainer_id(u)) + added_ids = {} + for u in uploader_ids: + if added_ids.has_key(u): + utils.warn("Already saw uploader %s for source %s" % (u, package)) + continue + added_ids[u]=1 + projectB.query("INSERT INTO src_uploaders (source, maintainer) VALUES (currval('source_id_seq'), %d)" % (u)) # Add the .deb files to the DB diff --git a/dak/process_unchecked.py b/dak/process_unchecked.py index 690c1c11..fd0afc4e 100755 --- a/dak/process_unchecked.py +++ b/dak/process_unchecked.py @@ -997,7 +997,7 @@ def check_timestamps(): ################################################################################ def lookup_uid_from_fingerprint(fpr): - q = Upload.projectB.query("SELECT u.uid, u.name FROM fingerprint f, uid u WHERE f.uid = u.id AND f.fingerprint = '%s'" % (fpr)) + q = Upload.projectB.query("SELECT u.uid, u.name, k.debian_maintainer FROM fingerprint f JOIN keyrings k ON (f.keyring=k.id), uid u WHERE f.uid = u.id AND f.fingerprint = '%s'" % (fpr)) qs = q.getresult() if len(qs) == 0: return (None, None) @@ -1007,7 +1007,7 @@ def lookup_uid_from_fingerprint(fpr): def check_signed_by_key(): """Ensure the .changes is signed by an authorized uploader.""" - (uid, uid_name) = lookup_uid_from_fingerprint(changes["fingerprint"]) + (uid, uid_name, is_dm) = lookup_uid_from_fingerprint(changes["fingerprint"]) if uid_name == None: uid_name = "" @@ -1017,8 +1017,8 @@ def check_signed_by_key(): may_nmu, may_sponsor = 1, 1 # XXX by default new dds don't have a fingerprint/uid in the db atm, # and can't get one in there if we don't allow nmu/sponsorship - elif uid[:3] == "dm:": - uid_email = uid[3:] + elif is_dm is "t": + uid_email = uid may_nmu, may_sponsor = 0, 0 else: uid_email = "%s@debian.org" % (uid) @@ -1043,25 +1043,28 @@ def check_signed_by_key(): if not sponsored and not may_nmu: source_ids = [] - check_suites = changes["distribution"].keys() - if "unstable" not in check_suites: check_suites.append("unstable") - for suite in check_suites: - suite_id = database.get_suite_id(suite) - q = Upload.projectB.query("SELECT s.id FROM source s JOIN src_associations sa ON (s.id = sa.source) WHERE s.source = '%s' AND sa.suite = %d" % (changes["source"], suite_id)) - for si in q.getresult(): - if si[0] not in source_ids: source_ids.append(si[0]) - - is_nmu = 1 - for si in source_ids: - is_nmu = 1 - q = Upload.projectB.query("SELECT m.name FROM maintainer m WHERE m.id IN (SELECT maintainer FROM src_uploaders WHERE src_uploaders.source = %s)" % (si)) + q = Upload.projectB.query("SELECT s.id, s.version FROM source s JOIN src_associations sa ON (s.id = sa.source) WHERE s.source = '%s' AND s.dm_upload_allowed = 'yes'" % (changes["source"])) + + highest_sid, highest_version = None, None + + should_reject = True + for si in q.getresult(): + if highest_version == None or apt_pkg.VersionCompare(si[1], highest_version) == 1: + highest_sid = si[0] + highest_version = si[1] + + if highest_sid == None: + reject("Source package %s does not have 'DM-Upload-Allowed: yes' in its most recent version" % changes["source"]) + else: + q = Upload.projectB.query("SELECT m.name FROM maintainer m WHERE m.id IN (SELECT su.maintainer FROM src_uploaders su JOIN source s ON (s.id = su.source) WHERE su.source = %s)" % (highest_sid)) for m in q.getresult(): (rfc822, rfc2047, name, email) = utils.fix_maintainer(m[0]) if email == uid_email or name == uid_name: - is_nmu=0 + should_reject=True break - if is_nmu: - reject("%s may not upload/NMU source package %s" % (uid, changes["source"])) + + if should_reject == True: + reject("%s is not in Maintainer or Uploaders of source package %s" % (uid, changes["source"])) for b in changes["binary"].keys(): for suite in changes["distribution"].keys(): diff --git a/dak/update_db.py b/dak/update_db.py new file mode 100755 index 00000000..dc943503 --- /dev/null +++ b/dak/update_db.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python + +# Debian Archive Kit Database Update Script +# Copyright (C) 2008 Michael Casadevall + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +################################################################################ + +# when do you have it written? +# Ganneff, after you make my debian account +# blackmail wont work +# damn it + +################################################################################ + +import psycopg2, sys, fcntl, os +import apt_pkg +import time +from daklib import database +from daklib import utils + +################################################################################ + +Cnf = None +projectB = None +required_database_schema = 1 + +################################################################################ + +class UpdateDB: + def usage (self, exit_code=0): + print """Usage: dak update-db +Updates dak's database schema to the lastest version. You should disable crontabs while this is running + + -h, --help show this help and exit.""" + sys.exit(exit_code) + + +################################################################################ + + def update_db_to_zero(self): + # This function will attempt to update a pre-zero database schema to zero + + # First, do the sure thing, and create the configuration table + try: + print "Creating configuration table ..." + c = self.db.cursor() + c.execute("""CREATE TABLE config ( + id SERIAL PRIMARY KEY NOT NULL, + name TEXT UNIQUE NOT NULL, + value TEXT + );""") + c.execute("INSERT INTO config VALUES ( nextval('config_id_seq'), 'db_revision', '0')"); + self.db.commit() + + except psycopg2.ProgrammingError: + self.db.rollback() + print "Failed to create configuration table." + print "Can the projectB user CREATE TABLE?" + print "" + print "Aborting update." + sys.exit(-255) + +################################################################################ + + def get_db_rev(self): + global projectB + + # We keep database revision info the config table + # Try and access it + + try: + c = self.db.cursor() + q = c.execute("SELECT value FROM config WHERE name = 'db_revision';"); + return c.fetchone()[0] + + except psycopg2.ProgrammingError: + # Whoops .. no config table ... + self.db.rollback() + print "No configuration table found, assuming dak database revision to be pre-zero" + return -1 + +################################################################################ + + def update_db(self): + # Ok, try and find the configuration table + print "Determining dak database revision ..." + + try: + self.db = psycopg2.connect("dbname='" + Cnf["DB::Name"] + "' host='" + Cnf["DB::Host"] + "' port='" + str(Cnf["DB::Port"]) + "'") + + except: + print "FATAL: Failed connect to database" + pass + + database_revision = int(self.get_db_rev()) + + if database_revision == -1: + print "dak database schema predates update-db." + print "" + print "This script will attempt to upgrade it to the lastest, but may fail." + print "Please make sure you have a database backup handy. If you don't, press Ctrl-C now!" + print "" + print "Continuing in five seconds ..." + time.sleep(5) + print "" + print "Attempting to upgrade pre-zero database to zero" + + self.update_db_to_zero() + database_revision = 0 + + print "dak database schema at " + str(database_revision) + print "dak version requires schema " + str(required_database_schema) + + if database_revision == required_database_schema: + print "no updates required" + sys.exit(0) + + for i in range (database_revision, required_database_schema): + print "updating databse schema from " + str(database_revision) + " to " + str(i+1) + dakdb = __import__("dakdb", globals(), locals(), ['update'+str(i+1)]) + update_module = getattr(dakdb, "update"+str(i+1)) + update_module.do_update(self) + database_revision += 1 + +################################################################################ + + def init (self): + global Cnf, projectB + + Cnf = utils.get_conf() + arguments = [('h', "help", "Update-DB::Options::Help")] + for i in [ "help" ]: + if not Cnf.has_key("Update-DB::Options::%s" % (i)): + Cnf["Update-DB::Options::%s" % (i)] = "" + + arguments = apt_pkg.ParseCommandLine(Cnf, arguments, sys.argv) + + options = Cnf.SubTree("Update-DB::Options") + if options["Help"]: + usage() + elif arguments: + utils.warn("dak update-db takes no arguments.") + usage(exit_code=1) + + + self.update_db() + + try: + lock_fd = os.open(Cnf["Dinstall::LockFile"], os.O_RDWR | os.O_CREAT) + fcntl.lockf(lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB) + except IOError, e: + if errno.errorcode[e.errno] == 'EACCES' or errno.errorcode[e.errno] == 'EAGAIN': + utils.fubar("Couldn't obtain lock; assuming another 'dak process-unchecked' is already running.") + + +################################################################################ + +if __name__ == '__main__': + app = UpdateDB() + app.init() + +def main(): + app = UpdateDB() + app.init() diff --git a/scripts/debian/byhand-dm b/scripts/debian/byhand-dm index a410f703..37438805 100755 --- a/scripts/debian/byhand-dm +++ b/scripts/debian/byhand-dm @@ -41,7 +41,7 @@ echo "Authorised upload by $ID, copying into place" OUT=$(mktemp) cp "$BYHAND" "$DESTKR" -dak import-keyring --generate-users "dm:%s" "$DESTKR" >$OUT +dak import-keyring -D --generate-users "%s" "$DESTKR" >$OUT if [ -s "$OUT" ]; then /usr/sbin/sendmail -odq -oi -t <