################################################################################
-re_valid_version = re.compile(r"^([0-9]+:)?[0-9A-Za-z\.\-\+:]+$")
+re_valid_version = re.compile(r"^([0-9]+:)?[0-9A-Za-z\.\-\+:~]+$")
re_valid_pkg_name = re.compile(r"^[\dA-Za-z][\dA-Za-z\+\-\.]+$")
re_changelog_versions = re.compile(r"^\w[-+0-9a-z.]+ \([^\(\) \t]+\)")
re_strip_revision = re.compile(r"-([^-]+)$")
+re_strip_srcver = re.compile(r"\s+\(\S+\)$")
################################################################################
reject("%s: Missing mandatory field `%s'." % (filename, i))
return 0 # Avoid <undef> errors during later tests
+ # Strip a source version in brackets from the source field
+ if re_strip_srcver.search(changes["source"]):
+ changes["source"] = re_strip_srcver.sub('', changes["source"])
+
+ # Ensure the source field is a valid package name.
+ if not re_valid_pkg_name.match(changes["source"]):
+ reject("%s: invalid source name '%s'." % (filename, changes["source"]))
+
# Split multi-value fields into a lower-level dictionary
for i in ("architecture", "distribution", "binary", "closes"):
o = changes.get(i, "")
except:
reject("%s: deb contents timestamp check failed [%s: %s]" % (filename, sys.exc_type, sys.exc_value))
+################################################################################
+
+def check_signed_by_key():
+ """Ensure the .changes is signed by an authorized uploader."""
+
+ # We only check binary-only uploads right now
+ if changes["architecture"].has_key("source"):
+ return
+
+ if not Cnf.Exists("Binary-Upload-Restrictions"):
+ return
+
+ restrictions = Cnf.SubTree("Binary-Upload-Restrictions")
+
+ # If the restrictions only apply to certain components make sure
+ # that the upload is actual targeted there.
+ if restrictions.Exists("Components"):
+ restricted_components = restrictions.SubTree("Components").ValueList()
+ is_restricted = False
+ for file in files:
+ if files[file]["component"] in restricted_components:
+ is_restricted = True
+ break
+ if not is_restricted:
+ return
+
+ # Assuming binary only upload restrictions are in place we then
+ # iterate over suite and architecture checking the key is in the
+ # allowed list. If no allowed list exists for a given suite or
+ # architecture it's assumed to be open to anyone.
+ for suite in changes["distribution"].keys():
+ if not restrictions.Exists(suite):
+ continue
+ for arch in changes["architecture"].keys():
+ if not restrictions.SubTree(suite).Exists(arch):
+ continue
+ allowed_keys = restrictions.SubTree("%s::%s" % (suite, arch)).ValueList()
+ if changes["fingerprint"] not in allowed_keys:
+ base_filename = os.path.basename(pkg.changes_file)
+ reject("%s: not signed by authorised uploader for %s/%s"
+ % (base_filename, suite, arch))
+
################################################################################
################################################################################
################################################################################
def is_stableupdate ():
- if changes["distribution"].has_key("proposed-updates"):
- return 1
- return 0
+ if not changes["distribution"].has_key("proposed-updates"):
+ return 0
+
+ if not changes["architecture"].has_key("source"):
+ pusuite = database.get_suite_id("proposed-updates")
+ q = Upload.projectB.query(
+ "SELECT S.source FROM source s JOIN src_associations sa ON (s.id = sa.source) WHERE s.source = '%s' AND s.version = '%s' AND sa.suite = %d" %
+ (changes["source"], changes["version"], pusuite))
+ ql = q.getresult()
+ if ql:
+ # source is already in proposed-updates
+ return 0
+
+ return 1
def do_stableupdate (summary):
print "Moving to PROPOSED-UPDATES holding area."
check_md5sums()
check_urgency()
check_timestamps()
+ check_signed_by_key()
Upload.update_subst(reject_message)
action()
except SystemExit: