Skip to content

Commit f334546

Browse files
authored
[confcom] Make dependency fetching more resilient (#9441)
* [confcom] Make binary fetching more resilient * Fix azdev style * Bump version * Check dependency checksums for dependencies * Fix line lengths
1 parent 2a0caa4 commit f334546

File tree

8 files changed

+144
-148
lines changed

8 files changed

+144
-148
lines changed

src/confcom/HISTORY.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
Release History
44
===============
55

6+
1.4.4
7+
++++++
8+
* Improve the package building process
9+
610
1.4.3
711
++++++
812
* Fix installing OPA on Windows and in strict networking environments

src/confcom/azext_confcom/cose_proxy.py

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# Licensed under the MIT License. See License.txt in the project root for license information.
44
# --------------------------------------------------------------------------------------------
55

6+
import hashlib
67
import os
78
import platform
89
import stat
@@ -18,13 +19,30 @@
1819
POLICY_FIELD_CONTAINERS_ELEMENTS_REGO_FRAGMENTS_MINIMUM_SVN,
1920
REGO_CONTAINER_START, REGO_FRAGMENT_START)
2021
from azext_confcom.errors import eprint
22+
from azext_confcom.lib.paths import get_binaries_dir
2123
from knack.log import get_logger
2224

25+
2326
logger = get_logger(__name__)
2427
host_os = platform.system()
2528
machine = platform.machine()
2629

2730

31+
_binaries_dir = get_binaries_dir()
32+
_cosesign1_binaries = {
33+
"Linux": {
34+
"path": _binaries_dir / "sign1util",
35+
"url": "https://github.com/microsoft/cosesign1go/releases/download/v1.4.0/sign1util",
36+
"sha256": "526b54aeb6293fc160e8fa1f81be6857300aba9641d45955f402f8b082a4d4a5",
37+
},
38+
"Windows": {
39+
"path": _binaries_dir / "sign1util.exe",
40+
"url": "https://github.com/microsoft/cosesign1go/releases/download/v1.4.0/sign1util.exe",
41+
"sha256": "f33cccf2b1bb8c3a495c730984b47d0f0715678981dbfe712248a2452dd53303",
42+
},
43+
}
44+
45+
2846
def call_cose_sign_tool(args: List[str], error_message: str, check=False):
2947
item = subprocess.run(args, check=check, capture_output=True, timeout=120)
3048

@@ -38,35 +56,15 @@ class CoseSignToolProxy: # pylint: disable=too-few-public-methods
3856

3957
@staticmethod
4058
def download_binaries():
41-
dir_path = os.path.dirname(os.path.realpath(__file__))
42-
43-
bin_folder = os.path.join(dir_path, "bin")
44-
if not os.path.exists(bin_folder):
45-
os.makedirs(bin_folder)
46-
47-
# get the most recent release artifacts from github
48-
r = requests.get("https://api.github.com/repos/microsoft/cosesign1go/releases")
49-
r.raise_for_status()
50-
needed_assets = ["sign1util", "sign1util.exe"]
51-
52-
# these should be newest to oldest
53-
for release in r.json():
54-
# search for both windows and linux binaries
55-
needed_asset_info = [asset for asset in release["assets"] if asset["name"] in needed_assets]
56-
if len(needed_asset_info) == len(needed_assets):
57-
for asset in needed_asset_info:
58-
# say which version we're downloading
59-
print(f"Downloading integrity-vhd version {release['tag_name']}")
60-
# get the download url for the dmverity-vhd file
61-
exe_url = asset["browser_download_url"]
62-
# download the file
63-
r = requests.get(exe_url)
64-
r.raise_for_status()
65-
# save the file to the bin folder
66-
with open(os.path.join(bin_folder, asset["name"]), "wb") as f:
67-
f.write(r.content)
68-
# stop iterating through releases
69-
break
59+
60+
for binary_info in _cosesign1_binaries.values():
61+
cosesign1_fetch_resp = requests.get(binary_info["url"], verify=True)
62+
cosesign1_fetch_resp.raise_for_status()
63+
64+
assert hashlib.sha256(cosesign1_fetch_resp.content).hexdigest() == binary_info["sha256"]
65+
66+
with open(binary_info["path"], "wb") as f:
67+
f.write(cosesign1_fetch_resp.content)
7068

7169
def __init__(self):
7270
script_directory = os.path.dirname(os.path.realpath(__file__))

src/confcom/azext_confcom/kata_proxy.py

Lines changed: 39 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# Licensed under the MIT License. See License.txt in the project root for license information.
44
# --------------------------------------------------------------------------------------------
55

6+
import hashlib
67
import os
78
import platform
89
import stat
@@ -12,72 +13,55 @@
1213
import requests
1314
from azext_confcom.config import DATA_FOLDER
1415
from azext_confcom.errors import eprint
16+
from azext_confcom.lib.paths import get_binaries_dir, get_data_dir
1517

1618
host_os = platform.system()
1719
machine = platform.machine()
1820

1921

22+
_binaries_dir = get_binaries_dir()
23+
_kata_binaries = {
24+
"Linux": {
25+
"path": _binaries_dir / "genpolicy-linux",
26+
"url": "https://github.com/microsoft/kata-containers/releases/download/3.2.0.azl3.genpolicy3/genpolicy",
27+
"sha256": "4cd497ca5e995ddacb53af4da47449c16291aea62e9f8b8ee0fe36ca8d41fe66",
28+
},
29+
"Windows": {
30+
"path": _binaries_dir / "genpolicy-windows.exe",
31+
"url": "https://github.com/microsoft/kata-containers/releases/download/3.2.0.azl1.genpolicy0/genpolicy.exe",
32+
"sha256": "caa9d8ee21b5819cc42b5c0967b14e166c715f6d4c87b574edabeaaeebf3573c",
33+
},
34+
}
35+
_data_dir = get_data_dir()
36+
_kata_data = [
37+
{
38+
"path": _data_dir / "genpolicy-settings.json",
39+
"url": "https://github.com/microsoft/kata-containers/releases/download/3.2.0.azl3.genpolicy3/genpolicy-settings.json", # pylint: disable=line-too-long
40+
"sha256": "c38be1474b133d49800a43bd30c40e7585b5f302179a307f9c6d89f195daee94",
41+
},
42+
{
43+
"path": _data_dir / "rules.rego",
44+
"url": "https://github.com/microsoft/kata-containers/releases/download/3.2.0.azl3.genpolicy3/rules.rego",
45+
"sha256": "2ca6c0e9617f97a922724112bd738fd73881d35b9ae5d31d573f0871d1ecf897",
46+
},
47+
]
48+
49+
2050
class KataPolicyGenProxy: # pylint: disable=too-few-public-methods
2151
# static variable to cache layer hashes between container groups
2252
layer_cache = {}
2353

2454
@staticmethod
2555
def download_binaries():
26-
dir_path = os.path.dirname(os.path.realpath(__file__))
27-
28-
bin_folder = os.path.join(dir_path, "bin")
29-
if not os.path.exists(bin_folder):
30-
os.makedirs(bin_folder)
31-
32-
data_folder = os.path.join(dir_path, "data")
33-
if not os.path.exists(data_folder):
34-
os.makedirs(data_folder)
35-
36-
# get the most recent release artifacts from github
37-
r = requests.get("https://api.github.com/repos/microsoft/kata-containers/releases")
38-
r.raise_for_status()
39-
bin_flag = False
40-
needed_assets = ["genpolicy", "genpolicy.exe"]
41-
# search for genpolicy in the assets from kata-container releases
42-
for release in r.json():
43-
is_target = (
44-
"genpolicy" in release.get("tag_name") and
45-
not release.get("draft") and
46-
not release.get("prerelease")
47-
)
48-
if is_target:
49-
# these should be newest to oldest
50-
for asset in release["assets"]:
51-
# download the file if it contains genpolicy
52-
if asset["name"] in needed_assets:
53-
# say which version we're downloading
54-
print(f"Downloading genpolicy version {release['tag_name']}")
55-
save_name = ""
56-
if ".exe" in asset["name"]:
57-
save_name = "genpolicy-windows.exe"
58-
else:
59-
save_name = "genpolicy-linux"
60-
bin_flag = True
61-
# get the download url for the genpolicy file
62-
exe_url = asset["browser_download_url"]
63-
# download the file
64-
r = requests.get(exe_url)
65-
r.raise_for_status()
66-
# save the file to the bin folder
67-
with open(os.path.join(bin_folder, save_name), "wb") as f:
68-
f.write(r.content)
69-
70-
# download the rules.rego and genpolicy-settings.json files
71-
if asset["name"] == "rules.rego" or asset["name"] == "genpolicy-settings.json":
72-
# download the rules.rego file
73-
exe_url = asset["browser_download_url"]
74-
# download the file
75-
r = requests.get(exe_url)
76-
# save the file to the data folder
77-
with open(os.path.join(data_folder, asset["name"]), "wb") as f:
78-
f.write(r.content)
79-
if bin_flag:
80-
break
56+
57+
for binary_info in list(_kata_binaries.values()) + _kata_data:
58+
kata_fetch_resp = requests.get(binary_info["url"], verify=True)
59+
kata_fetch_resp.raise_for_status()
60+
61+
assert hashlib.sha256(kata_fetch_resp.content).hexdigest() == binary_info["sha256"]
62+
63+
with open(binary_info["path"], "wb") as f:
64+
f.write(kata_fetch_resp.content)
8165

8266
def __init__(self):
8367
script_directory = os.path.dirname(os.path.realpath(__file__))

src/confcom/azext_confcom/lib/opa.py

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,49 +3,50 @@
33
# Licensed under the MIT License. See License.txt in the project root for license information.
44
# --------------------------------------------------------------------------------------------
55

6+
import platform
7+
import requests
68
import hashlib
79
import json
810
import os
9-
from pathlib import Path
10-
import platform
1111
import subprocess
12-
from typing import Iterable
13-
14-
import requests
15-
16-
from azext_confcom.lib.binaries import get_binaries_dir
1712

18-
_opa_path = os.path.abspath(os.path.join(get_binaries_dir(), "opa"))
19-
_opa_url = {
20-
"Linux": "https://github.com/open-policy-agent/opa/releases/download/v1.10.1/opa_linux_amd64",
21-
"Windows": "https://github.com/open-policy-agent/opa/releases/download/v1.10.1/opa_windows_amd64.exe",
22-
}
23-
_expected_sha256 = {
24-
"Linux": "fe8e191d44fec33db2a3d0ca788b9f83f866d980c5371063620c3c6822792877",
25-
"Windows": "4c932053350eabca47681208924046fbf3ad9de922d6853fb12cddf59aef15ce",
13+
from typing import Iterable
14+
from pathlib import Path
15+
from azext_confcom.lib.paths import get_binaries_dir
16+
17+
18+
_binaries_dir = get_binaries_dir()
19+
_opa_binaries = {
20+
"Linux": {
21+
"path": _binaries_dir / "opa",
22+
"url": "https://github.com/open-policy-agent/opa/releases/download/v1.10.1/opa_linux_amd64",
23+
"sha256": "fe8e191d44fec33db2a3d0ca788b9f83f866d980c5371063620c3c6822792877",
24+
},
25+
"Windows": {
26+
"path": _binaries_dir / "opa.exe",
27+
"url": "https://github.com/open-policy-agent/opa/releases/download/v1.10.1/opa_windows_amd64.exe",
28+
"sha256": "4c932053350eabca47681208924046fbf3ad9de922d6853fb12cddf59aef15ce",
29+
},
2630
}
2731

2832

2933
def opa_get():
3034

31-
if not all(platform.system() in mapping for mapping in [_opa_url, _expected_sha256]):
32-
raise RuntimeError(f"OPA is not supported on platform: {platform.system()}")
33-
34-
opa_fetch_resp = requests.get(_opa_url[platform.system()], verify=True)
35-
opa_fetch_resp.raise_for_status()
35+
for binary_info in _opa_binaries.values():
36+
opa_fetch_resp = requests.get(binary_info["url"], verify=True)
37+
opa_fetch_resp.raise_for_status()
3638

37-
assert hashlib.sha256(opa_fetch_resp.content).hexdigest() == _expected_sha256[platform.system()]
39+
assert hashlib.sha256(opa_fetch_resp.content).hexdigest() == binary_info["sha256"]
3840

39-
with open(_opa_path, "wb") as f:
40-
f.write(opa_fetch_resp.content)
41+
with open(binary_info["path"], "wb") as f:
42+
f.write(opa_fetch_resp.content)
4143

42-
os.chmod(_opa_path, 0o755)
43-
return _opa_path
44+
os.chmod(binary_info["path"], 0o755)
4445

4546

4647
def opa_run(args: Iterable[str]) -> subprocess.CompletedProcess:
4748
return subprocess.run(
48-
[_opa_path, *args],
49+
[_opa_binaries[platform.system()]["path"], *args],
4950
check=True,
5051
stdout=subprocess.PIPE,
5152
text=True,

src/confcom/azext_confcom/lib/binaries.py renamed to src/confcom/azext_confcom/lib/paths.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@
33
# Licensed under the MIT License. See License.txt in the project root for license information.
44
# --------------------------------------------------------------------------------------------
55

6-
import os
6+
from pathlib import Path
77

88

99
def get_binaries_dir():
10-
binaries_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", "bin")
11-
if not os.path.exists(binaries_dir):
12-
os.makedirs(binaries_dir)
10+
binaries_dir = Path(__file__).parent.parent / "bin"
11+
binaries_dir.mkdir(parents=True, exist_ok=True)
1312
return binaries_dir
13+
14+
15+
def get_data_dir():
16+
data_dir = Path(__file__).parent.parent / "data"
17+
data_dir.mkdir(parents=True, exist_ok=True)
18+
return data_dir

src/confcom/azext_confcom/rootfs_proxy.py

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# --------------------------------------------------------------------------------------------
55

66

7+
import hashlib
78
import os
89
import platform
910
import stat
@@ -13,47 +14,45 @@
1314

1415
import requests
1516
from azext_confcom.errors import eprint
17+
from azext_confcom.lib.paths import get_binaries_dir
1618
from knack.log import get_logger
1719

20+
1821
host_os = platform.system()
1922
machine = platform.machine()
2023
logger = get_logger(__name__)
2124

2225

26+
_binaries_dir = get_binaries_dir()
27+
_dmverity_vhd_binaries = {
28+
"Linux": {
29+
"path": _binaries_dir / "dmverity-vhd",
30+
"url": "https://github.com/microsoft/integrity-vhd/releases/download/v1.6/dmverity-vhd",
31+
"sha256": "b8cf3fa3594e48070a31aa538d5b4b40d5b33b8ac18bc25a1816245159648fb0",
32+
},
33+
"Windows": {
34+
"path": _binaries_dir / "dmverity-vhd.exe",
35+
"url": "https://github.com/microsoft/integrity-vhd/releases/download/v1.6/dmverity-vhd.exe",
36+
"sha256": "ca0f95d798323f3ef26feb036112be9019f5ceaa6233ee2a65218d5a143ae474",
37+
},
38+
}
39+
40+
2341
class SecurityPolicyProxy: # pylint: disable=too-few-public-methods
2442
# static variable to cache layer hashes between container groups
2543
layer_cache = {}
2644

2745
@staticmethod
2846
def download_binaries():
29-
dir_path = os.path.dirname(os.path.realpath(__file__))
30-
31-
bin_folder = os.path.join(dir_path, "bin")
32-
if not os.path.exists(bin_folder):
33-
os.makedirs(bin_folder)
34-
35-
# get the most recent release artifacts from github
36-
r = requests.get("https://api.github.com/repos/microsoft/integrity-vhd/releases")
37-
r.raise_for_status()
38-
needed_assets = ["dmverity-vhd", "dmverity-vhd.exe"]
39-
# these should be newest to oldest
40-
for release in r.json():
41-
# search for both windows and linux binaries
42-
needed_asset_info = [asset for asset in release["assets"] if asset["name"] in needed_assets]
43-
if len(needed_asset_info) == len(needed_assets):
44-
for asset in needed_asset_info:
45-
# say which version we're downloading
46-
print(f"Downloading integrity-vhd version {release['tag_name']}")
47-
# get the download url for the dmverity-vhd file
48-
exe_url = asset["browser_download_url"]
49-
# download the file
50-
r = requests.get(exe_url)
51-
r.raise_for_status()
52-
# save the file to the bin folder
53-
with open(os.path.join(bin_folder, asset["name"]), "wb") as f:
54-
f.write(r.content)
55-
# stop iterating through releases
56-
break
47+
48+
for binary_info in _dmverity_vhd_binaries.values():
49+
dmverity_vhd_fetch_resp = requests.get(binary_info["url"], verify=True)
50+
dmverity_vhd_fetch_resp.raise_for_status()
51+
52+
assert hashlib.sha256(dmverity_vhd_fetch_resp.content).hexdigest() == binary_info["sha256"]
53+
54+
with open(binary_info["path"], "wb") as f:
55+
f.write(dmverity_vhd_fetch_resp.content)
5756

5857
def __init__(self):
5958
script_directory = os.path.dirname(os.path.realpath(__file__))

0 commit comments

Comments
 (0)