← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~xnox/launchpad:only-sha256 into launchpad:master

 

Dimitri John Ledkov has proposed merging ~xnox/launchpad:only-sha256 into launchpad:master.

Commit message:
archivepublisher: consistently use only sha256 for apt archives

Unused hashes are redundant, and are now cauing interop problems with
overly strict programs and humans.

Summary of changes:

 * Remove md5, sha1 from Release, Packages, Sources metadata in
   primary & ppa publisher.

 * Change i18n Index from SHA1 to SHA256. Uncertain if actually used
   by clients.

 * Remove sha512 from Packages & Sources in primary publisher only, do
   not exist anywhere else. (Also see LP: #1536602). Also it is
   noticably slow even on most modern hardware for rudimentary
   repository sizes.

 * Ensure and enforce consistent publishing by both primary & ppa
   publisher, irrespective of host release.

Note that overall security is provided by rsa-pkcs1-v1_5 + sha512
signatures in current primary and ppa publishers, independent of the
hash changes in this commit.

Minimum required apt for Launchpad host deployment is 1.1 (Xenial) due
to `--no-sha512` option usage.

Minimum required apt for clients is 0.7.7 (Hardy), subject to
compatible signing.

This implementation is intentionally global for all suites in both
primary and ppa publishers.

Fixes LP: #1883271

Requested reviews:
  Canonical Security Team (canonical-security)
  Julian Andres Klode (juliank)
  Canonical Foundations Team (canonical-foundations)
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #1536602 in Launchpad itself: "lp should generate 512sums in apt release files"
  https://bugs.launchpad.net/launchpad/+bug/1536602
  Bug #1883271 in Launchpad itself: "Please remove md5sum and sha1 from the archive metadata"
  https://bugs.launchpad.net/launchpad/+bug/1883271

For more details, see:
https://code.launchpad.net/~xnox/launchpad/+git/launchpad/+merge/452749
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~xnox/launchpad:only-sha256 into launchpad:master.
diff --git a/lib/lp/archivepublisher/indices.py b/lib/lp/archivepublisher/indices.py
index 05fa6ec..2af2be4 100644
--- a/lib/lp/archivepublisher/indices.py
+++ b/lib/lp/archivepublisher/indices.py
@@ -98,13 +98,9 @@ def build_source_stanza_fields(spr, component, section):
     """Build a map of fields to be included in a Sources file."""
     # Special fields preparation.
     pool_path = makePoolPath(spr.name, component.name)
-    files_list = []
-    sha1_list = []
     sha256_list = []
     for spf in spr.files:
         common = (spf.libraryfile.content.filesize, spf.libraryfile.filename)
-        files_list.append((spf.libraryfile.content.md5, common))
-        sha1_list.append((spf.libraryfile.content.sha1, common))
         sha256_list.append((spf.libraryfile.content.sha256, common))
     user_defined_fields = OrderedDict(
         [(key.lower(), (key, value)) for key, value in spr.user_defined_fields]
@@ -134,8 +130,6 @@ def build_source_stanza_fields(spr, component, section):
     fields.append("Standards-Version", spr.dsc_standards_version)
     fields.append("Format", spr.dsc_format)
     fields.append("Directory", pool_path)
-    fields.append("Files", format_file_list(files_list))
-    fields.append("Checksums-Sha1", format_file_list(sha1_list))
     fields.append("Checksums-Sha256", format_file_list(sha256_list))
     fields.append("Homepage", spr.homepage)
     fields.extend(user_defined_fields.values())
@@ -162,8 +156,6 @@ def build_binary_stanza_fields(
     bin_file = bpr.files[0]
     bin_filename = bin_file.libraryfile.filename
     bin_size = bin_file.libraryfile.content.filesize
-    bin_md5 = bin_file.libraryfile.content.md5
-    bin_sha1 = bin_file.libraryfile.content.sha1
     bin_sha256 = bin_file.libraryfile.content.sha256
     bin_filepath = os.path.join(
         makePoolPath(spr.name, component.name), bin_filename
@@ -220,8 +212,6 @@ def build_binary_stanza_fields(
     fields.append("Essential", essential)
     fields.append("Filename", bin_filepath)
     fields.append("Size", bin_size)
-    fields.append("MD5sum", bin_md5)
-    fields.append("SHA1", bin_sha1)
     fields.append("SHA256", bin_sha256)
     fields.append("Phased-Update-Percentage", phased_update_percentage)
     fields.append("Description", bin_description)
diff --git a/lib/lp/archivepublisher/model/ftparchive.py b/lib/lp/archivepublisher/model/ftparchive.py
index 529118e..009aa83 100644
--- a/lib/lp/archivepublisher/model/ftparchive.py
+++ b/lib/lp/archivepublisher/model/ftparchive.py
@@ -179,7 +179,11 @@ class FTPArchiveHandler:
 
         stdout_handler = OutputLineHandler(self.log.debug, "a-f: ")
         stderr_handler = OutputLineHandler(self.log.info, "a-f: ")
-        base_command = ["apt-ftparchive"] + list(args) + [apt_config_filename]
+        base_command = (
+            ["apt-ftparchive", "--no-md5", "--no-sha1", "--no-sha512"]
+            + list(args)
+            + [apt_config_filename]
+        )
         spawner = CommandSpawner()
 
         returncodes = {}
diff --git a/lib/lp/archivepublisher/publishing.py b/lib/lp/archivepublisher/publishing.py
index 0bb7985..094367f 100644
--- a/lib/lp/archivepublisher/publishing.py
+++ b/lib/lp/archivepublisher/publishing.py
@@ -183,7 +183,7 @@ class I18nIndex(_multivalued):
     """Represents an i18n/Index file."""
 
     _multivalued_fields = {
-        "sha1": ["sha1", "size", "name"],
+        "sha256": ["sha256", "size", "name"],
     }
 
     @property
@@ -224,28 +224,6 @@ class IArchiveHash(Interface):
 
 
 @implementer(IArchiveHash)
-class MD5ArchiveHash:
-    hash_factory = hashlib.md5
-    deb822_name = "md5sum"
-    apt_name = "MD5Sum"
-    lfc_name = "md5"
-    dh_name = "MD5SUMS"
-    write_by_hash = False
-    write_directory_hash = False
-
-
-@implementer(IArchiveHash)
-class SHA1ArchiveHash:
-    hash_factory = hashlib.sha1
-    deb822_name = "sha1"
-    apt_name = "SHA1"
-    lfc_name = "sha1"
-    dh_name = "SHA1SUMS"
-    write_by_hash = False
-    write_directory_hash = False
-
-
-@implementer(IArchiveHash)
 class SHA256ArchiveHash:
     hash_factory = hashlib.sha256
     deb822_name = "sha256"
@@ -257,8 +235,6 @@ class SHA256ArchiveHash:
 
 
 archive_hashes = [
-    MD5ArchiveHash(),
-    SHA1ArchiveHash(),
     SHA256ArchiveHash(),
 ]
 
@@ -1678,7 +1654,7 @@ class Publisher:
             )
             if hashes is None:
                 continue
-            i18n_index.setdefault("SHA1", []).append(hashes["sha1"])
+            i18n_index.setdefault("SHA256", []).append(hashes["sha256"])
             # Schedule i18n files for inclusion in the Release file.
             all_series_files.add(os.path.join(i18n_subpath, i18n_file))
 
diff --git a/lib/lp/archivepublisher/tests/apt-data/Packages b/lib/lp/archivepublisher/tests/apt-data/Packages
index d1b1f59..7ffafe9 100644
--- a/lib/lp/archivepublisher/tests/apt-data/Packages
+++ b/lib/lp/archivepublisher/tests/apt-data/Packages
@@ -7,10 +7,7 @@ Architecture: i386
 Version: 0.1
 Filename: pool/main/t/tiny/tiny_0.1_i386.deb
 Size: 932
-MD5sum: 390074949d9533c4cf6774b9891306d0
-SHA1: 1beb6c7f6be8d5b9d86335a0a939b1b49aec9aa9
 SHA256: d652be5856066b3f5bb8df43e43199ee480aa65a1ccf8e78be4178a824c493ce
-SHA512: 51a3a466a70bb447b1dd2cecd35ff9184ce89f8785d6783dae286d7e03ce8cd4bb72af0a61c294469e683e003ecb4c833ab45ed98102ad8020d9f9dc7ac82909
 Description: A tiny test package.
  Doesn't really do anything at all.
 Bugs: https://bugs.launchpad.net/ubuntu/+filebug
diff --git a/lib/lp/archivepublisher/tests/apt-data/Sources b/lib/lp/archivepublisher/tests/apt-data/Sources
index 7f7b059..86aedda 100644
--- a/lib/lp/archivepublisher/tests/apt-data/Sources
+++ b/lib/lp/archivepublisher/tests/apt-data/Sources
@@ -9,18 +9,8 @@ Architecture: any
 Standards-Version: 3.9.4.0
 Format: 1.0
 Directory: pool/main/t/tiny
-Files:
- 4699a6dda30a4a32c6264c931a601da5 444 tiny_0.1.dsc
- 63a97b775d908be8426e8891e582f1c2 485 tiny_0.1.tar.gz
 Package-List: 
  tiny deb devel extra
-Checksums-Sha1:
- 0528aa847dfd802bc788320f906f846b4931b840 444 tiny_0.1.dsc
- d19603504f4c5c347dd6871d03bf232c7d54516a 485 tiny_0.1.tar.gz
 Checksums-Sha256:
  4b21ba373193932f1e72359d765fe26f2c991f25a0ec3ad72d209a5fe81823f3 444 tiny_0.1.dsc
  8a4a42063805dc1f9ee52b201b58da7c4aa594d6ad916673827320458bf0d9b2 485 tiny_0.1.tar.gz
-Checksums-Sha512:
- 9ec0fb83923f67e7a55fde5b1bc323e950cdf710e676d5b69486e8c3b1afe63b137e7f7bdcdd2e10f080d75de40cff162857dfafb455e23ccfd52c4b1a1c7f5e 444 tiny_0.1.dsc
- 7c1502d6709c2dbed18fa7ab6cf485321c46f44467745101ef1230413840378dadfb8f361d72a1df12d927308a77938914b166921e77258c3d3471c4650aa9b1 485 tiny_0.1.tar.gz
-
diff --git a/lib/lp/archivepublisher/tests/test_generate_contents_files.py b/lib/lp/archivepublisher/tests/test_generate_contents_files.py
index 838f59f..1544ac9 100644
--- a/lib/lp/archivepublisher/tests/test_generate_contents_files.py
+++ b/lib/lp/archivepublisher/tests/test_generate_contents_files.py
@@ -326,7 +326,7 @@ class TestGenerateContentsFiles(TestCaseWithFactory):
         self.assertIn(
             " %s %16s Contents-%s.gz\n"
             % (
-                hashlib.md5(contents_bytes).hexdigest(),
+                hashlib.sha256(contents_bytes).hexdigest(),
                 len(contents_bytes),
                 das.architecturetag,
             ),
diff --git a/lib/lp/archivepublisher/tests/test_indices.py b/lib/lp/archivepublisher/tests/test_indices.py
index 1397ffd..aaf410b 100644
--- a/lib/lp/archivepublisher/tests/test_indices.py
+++ b/lib/lp/archivepublisher/tests/test_indices.py
@@ -39,13 +39,9 @@ def get_field(stanza_fields, name):
 
 
 class TestNativeArchiveIndexes(TestNativePublishingBase):
-    deb_md5 = "008409e7feb1c24a6ccab9f6a62d24c5"
-    deb_sha1 = "30b7b4e583fa380772c5a40e428434628faef8cf"
     deb_sha256 = (
         "006ca0f356f54b1916c24c282e6fd19961f4356441401f4b0966f2a00bb3e945"
     )
-    dsc_md5 = "5913c3ad52c14a62e6ae7eef51f9ef42"
-    dsc_sha1 = "e35e29b2ea94bbaa831882e11d1f456690f04e69"
     dsc_sha256 = (
         "ac512102db9724bee18f26945efeeb82fdab89819e64e120fbfda755ca50c2c6"
     )
@@ -95,10 +91,6 @@ class TestNativeArchiveIndexes(TestNativePublishingBase):
                 "Standards-Version: 3.6.2",
                 "Format: 1.0",
                 "Directory: pool/main/f/foo",
-                "Files:",
-                " %s 28 foo_666.dsc" % self.dsc_md5,
-                "Checksums-Sha1:",
-                " %s 28 foo_666.dsc" % self.dsc_sha1,
                 "Checksums-Sha256:",
                 " %s 28 foo_666.dsc" % self.dsc_sha256,
             ],
@@ -111,7 +103,7 @@ class TestNativeArchiveIndexes(TestNativePublishingBase):
 
         A field is excluded if its key case-insensitively matches one that's
         already there. This mostly affects sources that were uploaded before
-        Homepage, Checksums-Sha1 or Checksums-Sha256 were excluded.
+        Homepage or Checksums-Sha256 were excluded.
         """
         pub_source = self.getPubSource(
             builddepends="fooish",
@@ -120,7 +112,7 @@ class TestNativeArchiveIndexes(TestNativePublishingBase):
             build_conflicts_indep="pybar",
             user_defined_fields=[
                 ("Python-Version", "< 1.5"),
-                ("CHECKSUMS-SHA1", "BLAH"),
+                ("CHECKSUMS-SHA256", "BLAH"),
                 ("Build-Depends-Arch", "libfoo-dev"),
                 ("Build-Conflicts-Arch", "libbar-dev"),
             ],
@@ -143,10 +135,6 @@ class TestNativeArchiveIndexes(TestNativePublishingBase):
                 "Standards-Version: 3.6.2",
                 "Format: 1.0",
                 "Directory: pool/main/f/foo",
-                "Files:",
-                " %s 28 foo_666.dsc" % self.dsc_md5,
-                "Checksums-Sha1:",
-                " %s 28 foo_666.dsc" % self.dsc_sha1,
                 "Checksums-Sha256:",
                 " %s 28 foo_666.dsc" % self.dsc_sha256,
                 "Python-Version: < 1.5",
@@ -194,8 +182,6 @@ class TestNativeArchiveIndexes(TestNativePublishingBase):
                 "Breaks: old-foo",
                 "Filename: pool/main/f/foo/foo-bin_666_all.deb",
                 "Size: 18",
-                "MD5sum: " + self.deb_md5,
-                "SHA1: " + self.deb_sha1,
                 "SHA256: " + self.deb_sha256,
                 "Phased-Update-Percentage: 50",
                 "Description: Foo app is great",
@@ -244,8 +230,6 @@ class TestNativeArchiveIndexes(TestNativePublishingBase):
                 "Breaks: old-foo",
                 "Filename: pool/main/f/foo/foo-bin_666_all.deb",
                 "Size: 18",
-                "MD5sum: " + self.deb_md5,
-                "SHA1: " + self.deb_sha1,
                 "SHA256: " + self.deb_sha256,
                 "Description: Foo app is great",
                 " Well ...",
@@ -290,8 +274,6 @@ class TestNativeArchiveIndexes(TestNativePublishingBase):
                 "Version: 666",
                 "Filename: pool/main/f/foo/foo-bin_666_all.deb",
                 "Size: 18",
-                "MD5sum: " + self.deb_md5,
-                "SHA1: " + self.deb_sha1,
                 "SHA256: " + self.deb_sha256,
                 "Description: Foo app is great",
                 " Normal",
@@ -328,8 +310,6 @@ class TestNativeArchiveIndexes(TestNativePublishingBase):
                 "Version: 666",
                 "Filename: pool/main/f/foo/foo-bin_666_all.deb",
                 "Size: 18",
-                "MD5sum: " + self.deb_md5,
-                "SHA1: " + self.deb_sha1,
                 "SHA256: " + self.deb_sha256,
                 "Description: Foo app is great",
                 " Using non-ascii as: \xe7\xe3\xe9\xf3",
diff --git a/lib/lp/archivepublisher/tests/test_publish_ftpmaster.py b/lib/lp/archivepublisher/tests/test_publish_ftpmaster.py
index f210112..f629c89 100644
--- a/lib/lp/archivepublisher/tests/test_publish_ftpmaster.py
+++ b/lib/lp/archivepublisher/tests/test_publish_ftpmaster.py
@@ -338,9 +338,10 @@ class TestPublishFTPMasterScript(
         self.assertEqual("", release["Architectures"])
         self.assertIn("Date", release)
         self.assertIn("Description", release)
-        self.assertNotEqual("", release["MD5Sum"])
-        self.assertNotEqual("", release["SHA1"])
+        self.assertNotIn("MD5Sum", release)
+        self.assertNotIn("SHA1", release)
         self.assertNotEqual("", release["SHA256"])
+        self.assertNotIn("SHA512", release)
 
         main_release = self.readReleaseFile(
             os.path.join(distcopyseries, "main", "source", "Release")
diff --git a/lib/lp/archivepublisher/tests/test_publisher.py b/lib/lp/archivepublisher/tests/test_publisher.py
index be57298..f073ef5 100644
--- a/lib/lp/archivepublisher/tests/test_publisher.py
+++ b/lib/lp/archivepublisher/tests/test_publisher.py
@@ -676,7 +676,15 @@ class TestByHash(TestCaseWithFactory):
         by_hash.prune()
         self.assertThat(by_hash_path, Not(PathExists()))
 
+    # with removal of md5 and sha1 from Sources, this test case
+    # now fails to clean up md5/sha1 by-hash links, as it is now
+    # impractical to calculate them. Hopefully it has been very
+    # short time when md5/sha1 by-hash links exists, and most
+    # should have been republished or retired by now. Keep this
+    # test around for when we add a new hash, and will want to
+    # clean up SHA256 symlinks.
     def test_prune_old_hashes(self):
+        self.skipTest("No prunable old-hashes known right now")
         # The initial implementation of by-hash included MD5Sum and SHA1,
         # but we since decided that this was unnecessary cruft.  If they
         # exist on disk, they are pruned in their entirety.
@@ -797,12 +805,14 @@ class TestPublisher(TestPublisherBase):
     """Testing `Publisher` behaviour."""
 
     def assertReleaseContentsMatch(self, release, filename, contents):
-        for hash_name, hash_func in (
-            ("md5sum", hashlib.md5),
-            ("sha1", hashlib.sha1),
-            ("sha256", hashlib.sha256),
+        for unused_hash in (
+            ("md5sum"),
+            ("sha1"),
+            ("sha512"),
         ):
-            self.assertTrue(hash_name in release)
+            self.assertNotIn(unused_hash, release)
+        for hash_name, hash_func in (("sha256", hashlib.sha256),):
+            self.assertIn(hash_name, release)
             entries = [
                 entry
                 for entry in release[hash_name]
@@ -1631,10 +1641,6 @@ class TestPublisher(TestPublisherBase):
             b"Standards-Version: 3.6.2",
             b"Format: 1.0",
             b"Directory: pool/main/f/foo",
-            b"Files:",
-            b" 3e25960a79dbc69b674cd4ec67a72c62 11 foo_1.dsc",
-            b"Checksums-Sha1:",
-            b" 7b502c3a1f48c8609ae212cdfb639dee39673f5e 11 foo_1.dsc",
             b"Checksums-Sha256:",
             b" 64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f"
             b"3c 11 foo_1.dsc",
@@ -1660,8 +1666,6 @@ class TestPublisher(TestPublisherBase):
             b"Version: 666",
             b"Filename: pool/main/f/foo/foo-bin_666_all.deb",
             b"Size: 18",
-            b"MD5sum: 008409e7feb1c24a6ccab9f6a62d24c5",
-            b"SHA1: 30b7b4e583fa380772c5a40e428434628faef8cf",
             b"SHA256: 006ca0f356f54b1916c24c282e6fd19961f4356441401f4b0966f2a"
             b"00bb3e945",
             b"Description: Foo app is great",
@@ -1691,8 +1695,6 @@ class TestPublisher(TestPublisherBase):
             b"Version: 666",
             b"Filename: pool/main/f/foo/bingo_666_all.udeb",
             b"Size: 18",
-            b"MD5sum: 008409e7feb1c24a6ccab9f6a62d24c5",
-            b"SHA1: 30b7b4e583fa380772c5a40e428434628faef8cf",
             b"SHA256: 006ca0f356f54b1916c24c282e6fd19961f4356441401f4b0966f2a"
             b"00bb3e945",
             b"Description: Foo app is great",
@@ -1718,8 +1720,6 @@ class TestPublisher(TestPublisherBase):
             b"Version: 666",
             b"Filename: pool/main/f/foo/foo-bin-dbgsym_666_all.ddeb",
             b"Size: 18",
-            b"MD5sum: 008409e7feb1c24a6ccab9f6a62d24c5",
-            b"SHA1: 30b7b4e583fa380772c5a40e428434628faef8cf",
             b"SHA256: 006ca0f356f54b1916c24c282e6fd19961f4356441401f4b0966f2a"
             b"00bb3e945",
             b"Description: Foo app is great",
@@ -1782,10 +1782,6 @@ class TestPublisher(TestPublisherBase):
             b"Standards-Version: 3.6.2",
             b"Format: 1.0",
             b"Directory: pool/main/f/foo",
-            b"Files:",
-            b" 3e25960a79dbc69b674cd4ec67a72c62 11 foo_1.dsc",
-            b"Checksums-Sha1:",
-            b" 7b502c3a1f48c8609ae212cdfb639dee39673f5e 11 foo_1.dsc",
             b"Checksums-Sha256:",
             b" 64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f"
             b"3c 11 foo_1.dsc",
@@ -1811,8 +1807,6 @@ class TestPublisher(TestPublisherBase):
             b"Version: 666",
             b"Filename: pool/main/f/foo/foo-bin_666_all.deb",
             b"Size: 18",
-            b"MD5sum: 008409e7feb1c24a6ccab9f6a62d24c5",
-            b"SHA1: 30b7b4e583fa380772c5a40e428434628faef8cf",
             b"SHA256: 006ca0f356f54b1916c24c282e6fd19961f4356441401f4b0966f2a"
             b"00bb3e945",
             b"Description: Foo app is great",
@@ -1840,8 +1834,6 @@ class TestPublisher(TestPublisherBase):
             b"Version: 666",
             b"Filename: pool/main/f/foo/bingo_666_all.udeb",
             b"Size: 18",
-            b"MD5sum: 008409e7feb1c24a6ccab9f6a62d24c5",
-            b"SHA1: 30b7b4e583fa380772c5a40e428434628faef8cf",
             b"SHA256: 006ca0f356f54b1916c24c282e6fd19961f4356441401f4b0966f2a"
             b"00bb3e945",
             b"Description: Foo app is great",
@@ -1867,8 +1859,6 @@ class TestPublisher(TestPublisherBase):
             b"Version: 666",
             b"Filename: pool/main/f/foo/foo-bin-dbgsym_666_all.ddeb",
             b"Size: 18",
-            b"MD5sum: 008409e7feb1c24a6ccab9f6a62d24c5",
-            b"SHA1: 30b7b4e583fa380772c5a40e428434628faef8cf",
             b"SHA256: 006ca0f356f54b1916c24c282e6fd19961f4356441401f4b0966f2a"
             b"00bb3e945",
             b"Description: Foo app is great",
@@ -2093,8 +2083,9 @@ class TestPublisher(TestPublisherBase):
     def testReleaseFile(self):
         """Test release file writing.
 
-        The release file should contain the MD5, SHA1 and SHA256 for each
-        index created for a given distroseries.
+        The release file should contain the SHA256 for each index
+        created for a given distroseries.
+
         """
         publisher = Publisher(
             self.logger,
@@ -2143,8 +2134,8 @@ class TestPublisher(TestPublisherBase):
     def testReleaseFileForPPA(self):
         """Test release file writing for PPA
 
-        The release file should contain the MD5, SHA1 and SHA256 for each
-        index created for a given distroseries.
+        The release file should contain the SHA256 for each index
+        created for a given distroseries.
 
         Note that the individuals indexes have exactly the same content
         as the ones generated by apt-ftparchive (see previous test), however
@@ -2157,6 +2148,7 @@ class TestPublisher(TestPublisherBase):
         distinct 'Origin:' value.  The origin is specific to each PPA, using
         the pattern 'LP-PPA-%(owner_name)s'.  This allows proper pinning of
         the PPA packages.
+
         """
         allowed_suites = []
         cprov = getUtility(IPersonSet).getByName("cprov")
@@ -2283,32 +2275,32 @@ class TestPublisher(TestPublisherBase):
 
         # The Release file must contain lines ending in "Packages",
         # "Packages.gz", "Sources" and "Sources.gz".
-        self.assertTrue("md5sum" in release)
+        self.assertTrue("sha256" in release)
         self.assertTrue(
             [
                 entry
-                for entry in release["md5sum"]
+                for entry in release["sha256"]
                 if entry["name"].endswith("Packages.gz")
             ]
         )
         self.assertTrue(
             [
                 entry
-                for entry in release["md5sum"]
+                for entry in release["sha256"]
                 if entry["name"].endswith("Packages")
             ]
         )
         self.assertTrue(
             [
                 entry
-                for entry in release["md5sum"]
+                for entry in release["sha256"]
                 if entry["name"].endswith("Sources.gz")
             ]
         )
         self.assertTrue(
             [
                 entry
-                for entry in release["md5sum"]
+                for entry in release["sha256"]
                 if entry["name"].endswith("Sources")
             ]
         )
@@ -2646,7 +2638,7 @@ class TestPublisher(TestPublisherBase):
         publisher.D_writeReleaseFiles(False)
 
         release = self.parseRelease(suite_path("Release"))
-        paths = ["Release"] + [entry["name"] for entry in release["md5sum"]]
+        paths = ["Release"] + [entry["name"] for entry in release["sha256"]]
         timestamps = {
             os.stat(suite_path(path)).st_mtime
             for path in paths
@@ -2775,18 +2767,18 @@ class TestPublisher(TestPublisherBase):
         with open(translation_en, "rb") as translation_en_file:
             translation_en_contents = translation_en_file.read()
         i18n_index = self.parseI18nIndex(os.path.join(i18n_root, "Index"))
-        self.assertTrue("sha1" in i18n_index)
-        self.assertEqual(3, len(i18n_index["sha1"]))
+        self.assertTrue("sha256" in i18n_index)
+        self.assertEqual(3, len(i18n_index["sha256"]))
         self.assertEqual(
-            hashlib.sha1(translation_en_contents).hexdigest(),
-            i18n_index["sha1"][1]["sha1"],
+            hashlib.sha256(translation_en_contents).hexdigest(),
+            i18n_index["sha256"][1]["sha256"],
         )
         self.assertEqual(
-            str(len(translation_en_contents)), i18n_index["sha1"][1]["size"]
+            str(len(translation_en_contents)), i18n_index["sha256"][1]["size"]
         )
         self.assertContentEqual(
             ["Translation-en", "Translation-en.gz", "Translation-en.bz2"],
-            [hash["name"] for hash in i18n_index["sha1"]],
+            [hash["name"] for hash in i18n_index["sha256"]],
         )
 
         # i18n/Index and i18n/Translation-en.bz2 are scheduled for inclusion
@@ -2870,16 +2862,6 @@ class TestPublisher(TestPublisherBase):
                 f.write(contents)
             self.assertEqual(
                 {
-                    "md5sum": {
-                        "md5sum": hashlib.md5(contents).hexdigest(),
-                        "name": "Test",
-                        "size": len(contents),
-                    },
-                    "sha1": {
-                        "sha1": hashlib.sha1(contents).hexdigest(),
-                        "name": "Test",
-                        "size": len(contents),
-                    },
                     "sha256": {
                         "sha256": hashlib.sha256(contents).hexdigest(),
                         "name": "Test",