Skip to content

Commit 57d0685

Browse files
committed
reverted to old key_setup, add handling for private keys, refactored tests
1 parent d730ce1 commit 57d0685

5 files changed

Lines changed: 106 additions & 129 deletions

File tree

stackinator/mirror.py

Lines changed: 44 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ def __init__(
4242
self._check_mirrors()
4343

4444
# Will hold a list of all the gpg keys (public and private)
45-
# self._keys: Optional[List[pathlib.Path]] = []
46-
self._keys = self._key_init()
45+
self._keys: Optional[List[pathlib.Path]] = []
4746

4847
def _load_mirrors(self, cmdline_cache: Optional[pathlib.Path]) -> Dict[str, Dict]:
4948
"""Load the mirrors file, if one exists."""
@@ -159,12 +158,14 @@ def _check_mirrors(self):
159158
f"Check the url listed in mirrors.yaml in system config. \n{err}"
160159
)
161160

162-
def key_files(self, config_root: pathlib.Path):
161+
@property
162+
def keys(self):
163163
"""Return the list of public and private key file paths."""
164+
164165
if self._keys is None:
165166
raise RuntimeError("The mirror.keys method was accessed before setup_configs() was called.")
166-
key_dir = config_root / self.KEY_STORE_DIR
167-
return [key_dir / info["path"] for info in self._keys]
167+
168+
return self._keys
168169

169170
def setup_configs(self, config_root: pathlib.Path):
170171
"""Setup all mirror configs in the given config_root."""
@@ -233,67 +234,64 @@ def _create_bootstrap_configs(self, config_root: pathlib.Path):
233234
with (config_root / "bootstrap.yaml").open("w") as file:
234235
yaml.dump(bootstrap_yaml, file, default_flow_style=False)
235236

236-
def _key_init(self):
237-
key_info = {}
238-
239-
key = self.mirrors["buildcache"].get("private_key")
237+
def _load_key(self, key: str, dest: pathlib.Path, name: str):
238+
"""Validate mirror keys, relocate to key_store, and update mirror config with new key paths."""
240239

241-
if key is None:
242-
return
240+
# key will be saved under key_store/mirror_name.[pub/priv].gpg
243241

244242
# if path, check if abs path, if not, append sys config path in front and check again
245243
path = pathlib.Path(os.path.expandvars(key))
246-
247244
if not path.is_absolute():
248245
# try prepending system config path
249246
path = self._system_config_root / path
250247

251248
if path.is_file():
252-
# use the user-provided file
253-
key_info = {"path": pathlib.Path(f"buildcache.pgp"), "source": path}
249+
with open(path, "rb") as reader:
250+
binary_key = reader.read()
251+
252+
# convert base64 key to binary
254253
else:
255-
# convert base64 key to binary
256254
try:
257-
binary_key = base64.b64decode(key, validate=True)
258-
print(binary_key)
255+
binary_key = base64.b64decode(key)
259256
except ValueError:
260257
raise MirrorError(
261-
f"Key for mirror 'buildcache' is not valid. \n"
258+
f"Key for mirror '{name}' is not valid: '{path}'. \n"
262259
f"Must be a path to a GPG public key or a base64 encoded GPG public key. \n"
263260
f"Check the key listed in mirrors.yaml in system config."
264261
)
265262

266-
file_type = magic.from_buffer(binary_key, mime=True)
267-
if file_type not in ("application/x-gnupg-keyring", "application/pgp-keys"):
268-
raise MirrorError(
269-
f"Key for mirror 'buildcache' is not a valid GPG key. \n"
270-
f"The file (or base64) was readable, but the data itself was not a PGP key.\n"
271-
f"Check the key listed in mirrors.yaml in system config."
272-
)
273-
274-
key_info = {"path": pathlib.Path("buildcache.pgp"), "source": binary_key}
263+
# private keys will evaluate as "application/octet-stream"
264+
file_type = magic.from_buffer(binary_key, mime=True)
265+
if file_type not in ("application/x-gnupg-keyring", "application/pgp-keys", "application/octet-stream"):
266+
raise MirrorError(
267+
f"Key for mirror {name} is not a valid GPG key. \n"
268+
f"The file (or base64) was readable, but the data itself was not a PGP key.\n"
269+
f"Check the key listed in mirrors.yaml in system config."
270+
)
275271

276-
return key_info
272+
# copy key to new destination in key store
273+
with open(dest, "wb") as writer:
274+
writer.write(binary_key)
277275

276+
self._keys.append(dest)
277+
278+
278279
def _key_setup(self, key_store: pathlib.Path):
279-
"""Validate mirror keys, relocate to key_store, and update mirror config with new key paths."""
280+
"""Iterate through mirror keys and load + relocate each one to key_store"""
280281

282+
self._keys = []
281283
key_store.mkdir(exist_ok=True)
282284

283-
#for key_info in self._keys:
284-
285-
#path = key_store / key_info["path"]
286-
path = key_store / self._keys["path"]
287-
#source = key_info["source"]
288-
source = self._keys["source"]
289-
290-
match source:
291-
case pathlib.Path():
292-
# copy source -> path
293-
shutil.copy2(source, path)
294-
case bytes():
295-
# open path and copy in bytes
296-
with open(path, "wb") as writer:
297-
writer.write(source)
298-
case _:
299-
raise TypeError(f"Expected Path or bytes, got {type(source).__name__}")
285+
for name, mirror in self.mirrors.items():
286+
if name == "buildcache":
287+
if mirror.get("private_key"):
288+
key = mirror["private_key"]
289+
dest = pathlib.Path(key_store / f"{name}.priv.gpg")
290+
self._load_key(key, dest, name)
291+
292+
if mirror.get("public_key") is None:
293+
continue
294+
295+
key = mirror["public_key"]
296+
dest = pathlib.Path(key_store / f"{name}.pub.gpg")
297+
self._load_key(key, dest, name)

stackinator/schema/mirror.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
"enabled": {
1111
"type": "boolean",
1212
"default": true
13-
}
13+
},
14+
"public_key": {"type": "string"}
1415
},
1516
"additionalProperties": false,
1617
"required": ["url"]
@@ -48,7 +49,8 @@
4849
"enabled": {
4950
"type": "boolean",
5051
"default": true
51-
}
52+
},
53+
"public_key": {"type": "string"}
5254
},
5355
"additionalProperties": false,
5456
"required": ["url"]

unittests/data/systems/mirror-ok-raw-key/mirrors.yaml

Lines changed: 0 additions & 59 deletions
This file was deleted.

unittests/data/systems/mirror-ok/mirrors.yaml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,55 @@ bootstrap:
44
buildcache:
55
url: https://mirror.spack.io
66
enabled: true
7+
public_key: "\
8+
mQINBGm4GvsBEACTyzQFPfRUgo1Wmb9/KgrSr/EFVobRX3LlrcAMemo4nFRdS88aCcEhRWzYQ8ML\
9+
eGvcxFbzbAoEZACpThMspYOwFsVzIUc3lYQT7g9M/KNEPHztqaTWCqESYmzDFtaLYys6AQP52KMB\
10+
2x0ya8NNd9whd2a9Vc3yD3u9qW8iqkqxDjNYtTc9Lo7T8DHlhJ79TKm8f3w0QZowTxPYh5NA8GiF\
11+
kBN6J8hmg39LekC1kAWi2BwjDzRll19zVQtYfv+b4i/ripqmMNp4zcU93Ox1ReUFOmO3eiIq3GSK\
12+
IbXw7h/NGLAImIeuMzce5cqz65iVk7+iyKeXtx5dSUGskiLR2voX8xVOGVhNtxfiolviyUAhT4kb\
13+
WcWK6ipZ9h/nEyeZ9GYtoDkKMguet2a4bJCBsQmo4FR9Pf5c7qqs79obxLXzZe9zDnj1sbxAabJh\
14+
jLUdwJqIPKvdPNy3F3nOBeKY8Jf1D+Y3szxzJX8gwqrNSyCbZUeXsaQhMZWUVoztxUXW+qfC8jlA\
15+
TfoUQuQPC9Zr+8wU/3uUlKtChQo0prgwHAEHezwNpyEhZZc884RIt55DNKllH9UeqNwUWKpZYHG3\
16+
qVxV+oi7MenLeKvfsg6nVCL0CETtB88dOen7BFfBZj9NRszRqIlVudDFf+5gqKQ0f1H241w/n4nH\
17+
KEAzm7kma4cV8QARAQABtBtUZXN0IEtleSA8bm9wZUBub3doZXJlLmNvbT6JAlEEEwEKADsWIQSe\
18+
CE84hgwq8uroW+w4Qgxu0DsXiAUCabga+wIbAwULCQgHAgIiAgYVCgkICwIEFgIDAQIeBwIXgAAK\
19+
CRA4Qgxu0DsXiBbaD/4w7MlAf5SuOxrbH3fruN7k8NPxjwsvocB3VGo5AxzIy18C78IOYm5F2EQ+\
20+
LpjsK05t1ZPsHFsBaLduo0CODcF8m1gJLI8S0uMmVUywnDGJjMKYiZNeIqXDlohVciD2KPIxWL+i\
21+
qgho1BhFKlnQkXgEaxotUXFwHiKqcBwFcq21nu3PRVqsobMTk/UgeJhoSZf7ZIj5SyVHa6YVCoMr\
22+
HB0TqRz3xIW/TDl+oxyfEdhMZ8iU6IdohfMkCP+ayZEpdx1SS37S47SRxbgNblbfJ9PfJD/dQzx1\
23+
WnGVXxinSPjTTxIwNCyiEIrxqvLnk+O8fUHeEIrSqn9P0bZrCv02gAPUIfl7l4gN4boSgWEsfS5i\
24+
/KL8ZUDGZCb9Fux64zaM17lHfwGWCAKbi1KjYRL4W7zaVmps6MfdLOcJdQSdpQufs9vRbMhiDW1x\
25+
glsvz8JzPYiF2xRqJsx2odiufx4Mrrq5yxER07sDjKzUZYF6xD8qC5BAh6/xDUE+p8EOqc0HsqTE\
26+
PhqBLdqGLf8GaXj3I9F6ZCH5dtSmehB6Q77KJ1hWTm9OzDdYm2apExbMIB9Z2H5c8FLZfIb4lnpW\
27+
lhtP97eAix9JnBzoTe8QeaV5hcvQoqypTu5rD3ne2kQHlavmSeq5KVVWrIKGsfnZNRqDg7vKg/fw\
28+
kx1f2T8qMLVfGxogJrkCDQRpuBr7ARAA08MhBUQkj4nVaLmW+Xa5e+nTnE8nYoKPYJIpbIDYP2Pe\
29+
mD9Yca9HGWHnzUgsH4KEvdETrT/Uj9i3o+6xNZJ1Xz0GQkKW+2Vttl5ZBKwipHsn2iP+e78wAhwm\
30+
HqYZi/ymgLJDEXmrgyXNr+cKaAI2cEWOb+Vomgu+WFF4ENG/UiIJH6zP5JY0TcSC1Ao47y4qL6bH\
31+
Mfzz2zi3JpbvOi1/uY2TvMgitaL45tsukuEYMFfEEnd4Vyl0LSCFYv3zQx5JRSbu5ujlRdHnopS0\
32+
UeWZMV+iEXYZ6wKVFtQ6nvxxDpjMf8k3Q5Ss+z0F9oTRwdlaJhdhXZx8PleBu0Ah1Wxd9+V6tYgF\
33+
zrjsJB9eaXKIEeioZi8xNFB6RYUuNgjIfTtgtps685LeiGCy5q55MkC2FuKVAdv+YZcuJNdy/3gx\
34+
Kg5bLz/aVQRfxakDQHI7kp9fl3bDK5jbWeY8EKvtTI8x7fxthPZP6Az2g4zp+ZojgEUdUXveuw0Y\
35+
3MVaMu0ehG81nUHNU1tu7ELuhDWM6VkigokS1zptBsPbKojfp/oZJn6DGD1LZ+QyIdSUkjyfcs9H\
36+
sfuyAbrgzVCmbcNY42x3IOZZZjIfQ66bJZpGht6kHEfO896oB2d+a7KS25ZWa5G+SsWntv5nnclr\
37+
6DYFz3ThuYVmjQDLh8jN78/f45Jd6N8AEQEAAYkCNgQYAQoAIBYhBJ4ITziGDCry6uhb7DhCDG7Q\
38+
OxeIBQJpuBr7AhsMAAoJEDhCDG7QOxeIVx8P/1wxrmmYWhIMDObXIpCM3vxq8dO+84nTuBQbomKR\
39+
NURKOiCwgndEL3N38pf0gAToSIatrTF2VdkJsksyMEIzUaNmsYiHA9xYqhmCJ2pIqWeh2ONsNdmw\
40+
Fg/M5mwZpvwl28Z2MpJP+NY6u52a3jxkxpGY1Q4+KxgMRhqXe6faXQtYwwUiYVGPSznQPudYLZ2Z\
41+
+b8rGrz0AUVvvSWt3bVbUwZIMVSK0RVIWxG/sW7dWhkhtev+04fUlaxHnQ2b8G3h6AjONmLcIlpx\
42+
7p1dVvolEqV0YQUgosl47J3tLnzacsqNzIS1Dya0ukLrXAYmeQzQWvwhLpLqjMh3cqLl5SkjatB7\
43+
xU9Qu4IXENnvWSnqCRZzz6CbU/81FopTGgJfxbYok2v78O5qTdkbeszSHN8uCuvhpPKruHZgsFc6\
44+
lw+hYhtB8YXbB8lT2f1Fp0DeEnPM+OzRgjeRYl3gmE8/1PtKGuTCOJzTxTtLWorFYtV0DXiOq4Vd\
45+
eYkR+m3vNiYVkdALN5uIL8goYrPvs/fvq1wI49iyKw6B3pE5xIQSEjgPpwJ/7hvQUhenJTtrNRs8\
46+
eKXSnjHZjhJbgIReoXSQwG44RqNtiV8dJsdPu98P27keSigBB5kguB0gCWeFVHkLfpBR3aRxSacG\
47+
gllMF++N8+7T4/ehkA/hs2udYRkSCANLQ3I3"
748
private_key: ../../test-gpg-priv.asc
849
mount_specific: false
950
cmdline: false
1051
sourcecache:
1152
mirror1:
1253
url: https://github.com
1354
enabled: true
55+
public_key: ../../test-gpg-pub.asc
1456
mirror2:
1557
url: https://github.com/spack
1658
enabled: true

unittests/test_mirrors.py

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,17 @@ def test_mirror_init(systems_path):
3535
"mirror1": {
3636
"url": "https://github.com",
3737
"enabled": True,
38+
"public_key": "../../test-gpg-pub.asc"
3839
},
3940
"mirror2": {
4041
"url": "https://github.com/spack",
4142
"enabled": True,
4243
}
4344
}
4445

45-
# with (systems_path / "../test-gpg-pub.asc").open("rb") as pub_key_file:
46-
# key = base64.b64encode(pub_key_file.read()).decode()
47-
# valid_mirrors["buildcache"]["public_key"] = key
46+
with (systems_path / "../test-gpg-pub.asc").open("rb") as pub_key_file:
47+
key = base64.b64encode(pub_key_file.read()).decode()
48+
valid_mirrors["buildcache"]["public_key"] = key
4849

4950
assert mirrors_obj.mirrors == valid_mirrors
5051

@@ -149,8 +150,7 @@ def test_create_bootstrap_configs(tmp_path, systems_path):
149150

150151
with (tmp_path / "bootstrap.yaml").open() as f:
151152
bs_data = yaml.safe_load(f)
152-
print(bs_data)
153-
print(valid_yaml)
153+
154154
assert bs_data == valid_yaml
155155

156156
with (tmp_path / "bootstrap/bootstrap-mirror/metadata.yaml").open() as f:
@@ -161,26 +161,19 @@ def test_create_bootstrap_configs(tmp_path, systems_path):
161161
def test_key_setup(systems_path, tmp_path):
162162
"""Check that public keys are set up properly."""
163163

164-
mirrors_key_file = mirror.Mirrors(systems_path / "mirror-ok")
165-
key_dir = tmp_path / "key_dir"
166-
mirrors_raw_key = mirror.Mirrors(systems_path / "mirror-ok-raw-key")
167-
raw_dir = tmp_path / "raw_dir"
168-
169-
mirrors_key_file._key_setup(key_dir)
170-
mirrors_raw_key._key_setup(raw_dir)
164+
mirrors = mirror.Mirrors(systems_path / "mirror-ok")
171165

172-
key_file, = (p for p in key_dir.iterdir() if p.is_file())
173-
assert key_file.name == "buildcache.pgp"
166+
mirrors._key_setup(tmp_path)
174167

175-
raw_key_file, = (p for p in key_dir.iterdir() if p.is_file())
176-
assert raw_key_file.name == "buildcache.pgp"
168+
pub_files = sorted(f for f in tmp_path.iterdir() if f.name.endswith(".pub.gpg"))
169+
assert {pub_file.name for pub_file in pub_files} == {"buildcache.pub.gpg", "mirror1.pub.gpg"}
177170

178171
# The two files should be identical in content
179-
with key_file.open("rb") as file:
180-
key_file_data = file.read()
181-
with raw_key_file.open("rb") as file:
182-
raw_key_file_data = file.read()
183-
assert key_file_data == raw_key_file_data
172+
pub_file_data = []
173+
for pub_file in pub_files:
174+
with pub_file.open("rb") as file:
175+
pub_file_data.append(file.read())
176+
assert pub_file_data[0] == pub_file_data[1]
184177

185178

186179
@pytest.mark.parametrize(
@@ -193,5 +186,6 @@ def test_key_setup(systems_path, tmp_path):
193186
def test_key_setup_bad_key(tmp_path, systems_path, system_name):
194187
"""Check that MirrorError is raised for bad keys"""
195188

189+
mirrors = mirror.Mirrors(systems_path / system_name)
196190
with pytest.raises(mirror.MirrorError):
197-
mirrors = mirror.Mirrors(systems_path / system_name)
191+
mirrors._key_setup(tmp_path)

0 commit comments

Comments
 (0)