Merge ~pappacena/launchpad:copy-signing-key-overwrite into launchpad:master

Proposed by Thiago F. Pappacena
Status: Merged
Approved by: Thiago F. Pappacena
Approved revision: 96b1c12c4def2771e8a8445c7d6cdd6032dc3364
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~pappacena/launchpad:copy-signing-key-overwrite
Merge into: launchpad:master
Diff against target: 141 lines (+60/-6)
4 files modified
lib/lp/archivepublisher/scripts/copy_signingkeys.py (+16/-4)
lib/lp/archivepublisher/tests/test_copy_signingkeys.py (+36/-0)
lib/lp/services/signing/interfaces/signingkey.py (+4/-1)
lib/lp/services/signing/model/signingkey.py (+4/-1)
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Review via email: mp+400277@code.launchpad.net

Commit message

Adding --overwrite option to copy-signingkeys script

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) :
review: Approve
96b1c12... by Thiago F. Pappacena

Omitting short version of override option

Revision history for this message
Thiago F. Pappacena (pappacena) wrote :

Pushed requested change.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/archivepublisher/scripts/copy_signingkeys.py b/lib/lp/archivepublisher/scripts/copy_signingkeys.py
2index e4a46bd..322b7d9 100644
3--- a/lib/lp/archivepublisher/scripts/copy_signingkeys.py
4+++ b/lib/lp/archivepublisher/scripts/copy_signingkeys.py
5@@ -42,6 +42,10 @@ class CopySigningKeysScript(LaunchpadScript):
6 "-n", "--dry-run", action="store_true", default=False,
7 help="Report what would be done, but don't actually copy keys.")
8
9+ self.parser.add_option(
10+ "--overwrite", action="store_true", default=False,
11+ help="Overwrite existing keys when executing the copy.")
12+
13 def getArchive(self, reference):
14 archive = getUtility(IArchiveSet).getByReference(reference)
15 if archive is None:
16@@ -78,7 +82,8 @@ class CopySigningKeysScript(LaunchpadScript):
17 self.key_types = self.getKeyTypes(self.options.key_type)
18 self.series = self.getSeries(self.options.series)
19
20- def copy(self, from_archive, to_archive, key_type, series=None):
21+ def copy(self, from_archive, to_archive, key_type, series=None,
22+ overwrite=False):
23 series_name = series.name if series else None
24 from_archive_signing_key = getUtility(IArchiveSigningKeySet).get(
25 key_type, from_archive, series, exact_match=True)
26@@ -90,10 +95,17 @@ class CopySigningKeysScript(LaunchpadScript):
27 to_archive_signing_key = getUtility(IArchiveSigningKeySet).get(
28 key_type, to_archive, series, exact_match=True)
29 if to_archive_signing_key is not None:
30+ if not overwrite:
31+ # If it already exists and we do not force overwrite,
32+ # abort this signing key copy.
33+ self.logger.warning(
34+ "%s signing key for %s / %s already exists",
35+ key_type, to_archive.reference, series_name)
36+ return
37 self.logger.warning(
38- "%s signing key for %s / %s already exists",
39+ "%s signing key for %s / %s being overwritten",
40 key_type, to_archive.reference, series_name)
41- return
42+ to_archive_signing_key.destroySelf()
43 self.logger.info(
44 "Copying %s signing key %s from %s / %s to %s / %s",
45 key_type, from_archive_signing_key.signing_key.fingerprint,
46@@ -107,7 +119,7 @@ class CopySigningKeysScript(LaunchpadScript):
47 for key_type in self.key_types:
48 self.copy(
49 self.from_archive, self.to_archive, key_type,
50- series=self.series)
51+ series=self.series, overwrite=self.options.overwrite)
52 if self.options.dry_run:
53 self.logger.info("Dry run requested. Not committing changes.")
54 transaction.abort()
55diff --git a/lib/lp/archivepublisher/tests/test_copy_signingkeys.py b/lib/lp/archivepublisher/tests/test_copy_signingkeys.py
56index 56862a7..f993c19 100644
57--- a/lib/lp/archivepublisher/tests/test_copy_signingkeys.py
58+++ b/lib/lp/archivepublisher/tests/test_copy_signingkeys.py
59@@ -306,6 +306,42 @@ class TestCopySigningKeysScript(TestCaseWithFactory):
60 MatchesStructure.byEquality(
61 archive=archives[1], earliest_distro_series=None,
62 key_type=SigningKeyType.UEFI, signing_key=signing_keys[1]),
63+ ))
64+
65+ def test_copy_forced_overwrite(self):
66+ archives = [self.factory.makeArchive() for _ in range(2)]
67+ signing_keys = [
68+ self.factory.makeSigningKey(key_type=SigningKeyType.UEFI)
69+ for _ in range(2)]
70+ for archive, signing_key in zip(archives, signing_keys):
71+ self.factory.makeArchiveSigningKey(
72+ archive=archive, signing_key=signing_key)
73+ script = self.makeScript(
74+ test_args=["--key-type", "UEFI", "--overwrite"],
75+ archives=archives[:2])
76+ script.main()
77+
78+ expected_log = [
79+ "WARNING UEFI signing key for %s / None being overwritten" % (
80+ archives[1].reference),
81+ "INFO Copying UEFI signing key %s from %s / %s to %s / %s" % (
82+ signing_keys[0].fingerprint,
83+ archives[0].reference, None,
84+ archives[1].reference, None),
85+ ]
86+ self.assertEqual(
87+ expected_log, script.logger.content.as_text().splitlines())
88+ self.assertThat(
89+ self.findKeys(archives),
90+ MatchesSetwise(
91+ # First archive keeps its signing keys.
92+ MatchesStructure.byEquality(
93+ archive=archives[0], earliest_distro_series=None,
94+ key_type=SigningKeyType.UEFI, signing_key=signing_keys[0]),
95+ # Second archive uses the same signing_key from first archive.
96+ MatchesStructure.byEquality(
97+ archive=archives[1], earliest_distro_series=None,
98+ key_type=SigningKeyType.UEFI, signing_key=signing_keys[0]),
99 ))
100
101 def runScript(self, args=None):
102diff --git a/lib/lp/services/signing/interfaces/signingkey.py b/lib/lp/services/signing/interfaces/signingkey.py
103index 8548fa8..b714d42 100644
104--- a/lib/lp/services/signing/interfaces/signingkey.py
105+++ b/lib/lp/services/signing/interfaces/signingkey.py
106@@ -1,4 +1,4 @@
107-# Copyright 2020 Canonical Ltd. This software is licensed under the
108+# Copyright 2020-2021 Canonical Ltd. This software is licensed under the
109 # GNU Affero General Public License version 3 (see the file LICENSE).
110
111 """Interfaces for signing keys stored at the signing service."""
112@@ -126,6 +126,9 @@ class IArchiveSigningKey(Interface):
113 ISigningKey, title=_("Signing key"), required=True, readonly=True,
114 description=_("Which signing key should be used by this archive"))
115
116+ def destroySelf():
117+ """Removes the ArchiveSigningKey from the database."""
118+
119
120 class IArchiveSigningKeySet(Interface):
121 """Management class to deal with ArchiveSigningKey objects
122diff --git a/lib/lp/services/signing/model/signingkey.py b/lib/lp/services/signing/model/signingkey.py
123index ee77613..fdbc199 100644
124--- a/lib/lp/services/signing/model/signingkey.py
125+++ b/lib/lp/services/signing/model/signingkey.py
126@@ -1,4 +1,4 @@
127-# Copyright 2020 Canonical Ltd. This software is licensed under the
128+# Copyright 2020-2021 Canonical Ltd. This software is licensed under the
129 # GNU Affero General Public License version 3 (see the file LICENSE).
130
131 """Database classes to manage signing keys stored at the signing service."""
132@@ -177,6 +177,9 @@ class ArchiveSigningKey(StormBase):
133 self.key_type = signing_key.key_type
134 self.earliest_distro_series = earliest_distro_series
135
136+ def destroySelf(self):
137+ IStore(self).remove(self)
138+
139
140 @implementer(IArchiveSigningKeySet)
141 class ArchiveSigningKeySet: