File size: 14,511 Bytes
5248e3b a2a5bfd 5248e3b a2a5bfd 5248e3b a2a5bfd 5248e3b a2a5bfd 5248e3b a2a5bfd 5248e3b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | """Tests for core.bootstrap β binary download and installation (all I/O mocked)."""
import io
import os
import tarfile as tarfile_mod
import zipfile as zipfile_mod
from pathlib import Path
from unittest.mock import MagicMock, patch
import pytest
import requests as req
# ββ _stream_download ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
class TestStreamDownload:
def test_writes_chunks_to_file(self, tmp_path):
dest = tmp_path / "output.bin"
mock_resp = MagicMock()
mock_resp.iter_content.return_value = iter([b"hello", b"", b"world"])
with patch("core.bootstrap.requests.get", return_value=mock_resp):
from core.bootstrap import _stream_download
_stream_download("https://github.com/owner/repo/releases/download/v1/file", dest)
assert dest.exists()
assert dest.read_bytes() == b"helloworld"
def test_skips_empty_chunks(self, tmp_path):
dest = tmp_path / "empty_chunk.bin"
mock_resp = MagicMock()
mock_resp.iter_content.return_value = iter([b"", b"", b"data"])
with patch("core.bootstrap.requests.get", return_value=mock_resp):
from core.bootstrap import _stream_download
_stream_download("https://github.com/owner/repo/releases/download/v1/file", dest)
assert dest.read_bytes() == b"data"
def test_raises_on_http_error(self, tmp_path):
dest = tmp_path / "out.bin"
mock_resp = MagicMock()
mock_resp.raise_for_status.side_effect = req.HTTPError("404 Not Found")
with patch("core.bootstrap.requests.get", return_value=mock_resp):
from core.bootstrap import _stream_download
with pytest.raises(req.HTTPError):
_stream_download("https://github.com/owner/repo/releases/download/v1/missing", dest)
def test_passes_timeout_to_get(self, tmp_path):
dest = tmp_path / "out.bin"
mock_resp = MagicMock()
mock_resp.iter_content.return_value = iter([])
with patch("core.bootstrap.requests.get", return_value=mock_resp) as mock_get:
from core.bootstrap import _stream_download
_stream_download("https://github.com/owner/repo/releases/download/v1/file", dest, timeout=42)
assert mock_get.call_args[1]["timeout"] == 42
# ββ install_gitleaks ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
class TestInstallGitleaks:
def test_already_installed_skips_download(self):
with patch("core.bootstrap.have_binary", return_value=True):
from core.bootstrap import install_gitleaks
result = install_gitleaks()
assert result == "already installed"
def test_download_failure_returns_error(self, tmp_path):
with patch("core.bootstrap.have_binary", return_value=False), \
patch("core.bootstrap.BIN_DIR", tmp_path), \
patch("core.bootstrap._stream_download",
side_effect=ConnectionError("network down")):
from core.bootstrap import install_gitleaks
result = install_gitleaks()
assert result.startswith("install failed:")
def test_windows_zip_install(self, tmp_path):
"""Windows path: download zip, extract gitleaks.exe."""
buf = io.BytesIO()
with zipfile_mod.ZipFile(buf, "w") as z:
z.writestr("gitleaks.exe", b"fake gitleaks binary")
zip_bytes = buf.getvalue()
def fake_download(url, dest_path, timeout=120):
dest_path.write_bytes(zip_bytes)
with patch("core.bootstrap.have_binary", return_value=False), \
patch("core.bootstrap.BIN_DIR", tmp_path), \
patch("core.bootstrap._IS_WINDOWS", True), \
patch("core.bootstrap._stream_download", side_effect=fake_download):
from core.bootstrap import install_gitleaks
result = install_gitleaks()
assert result == "installed"
assert (tmp_path / "gitleaks.exe").exists()
def test_windows_zip_with_lowercase_gitleaks_name(self, tmp_path):
"""Zip contains 'gitleaks' (not '.exe') β still extracted and renamed."""
buf = io.BytesIO()
with zipfile_mod.ZipFile(buf, "w") as z:
z.writestr("gitleaks", b"fake binary")
zip_bytes = buf.getvalue()
def fake_download(url, dest_path, timeout=120):
dest_path.write_bytes(zip_bytes)
with patch("core.bootstrap.have_binary", return_value=False), \
patch("core.bootstrap.BIN_DIR", tmp_path), \
patch("core.bootstrap._IS_WINDOWS", True), \
patch("core.bootstrap._stream_download", side_effect=fake_download):
from core.bootstrap import install_gitleaks
result = install_gitleaks()
assert result == "installed"
assert (tmp_path / "gitleaks.exe").exists()
def test_linux_tarball_install(self, tmp_path):
"""Linux path: download tar.gz, extract and chmod gitleaks binary."""
buf = io.BytesIO()
with tarfile_mod.open(fileobj=buf, mode="w:gz") as t:
content = b"fake gitleaks"
info = tarfile_mod.TarInfo(name="gitleaks")
info.size = len(content)
t.addfile(info, io.BytesIO(content))
tar_bytes = buf.getvalue()
def fake_download(url, dest_path, timeout=120):
dest_path.write_bytes(tar_bytes)
with patch("core.bootstrap.have_binary", return_value=False), \
patch("core.bootstrap.BIN_DIR", tmp_path), \
patch("core.bootstrap._IS_WINDOWS", False), \
patch("core.bootstrap._stream_download", side_effect=fake_download):
from core.bootstrap import install_gitleaks
result = install_gitleaks()
assert result == "installed"
assert (tmp_path / "gitleaks").exists()
def test_linux_tarball_no_matching_member(self, tmp_path):
"""Tar has no 'gitleaks' member β loop completes without extraction."""
buf = io.BytesIO()
with tarfile_mod.open(fileobj=buf, mode="w:gz") as t:
content = b"something else"
info = tarfile_mod.TarInfo(name="README.md")
info.size = len(content)
t.addfile(info, io.BytesIO(content))
tar_bytes = buf.getvalue()
def fake_download(url, dest_path, timeout=120):
dest_path.write_bytes(tar_bytes)
with patch("core.bootstrap.have_binary", return_value=False), \
patch("core.bootstrap.BIN_DIR", tmp_path), \
patch("core.bootstrap._IS_WINDOWS", False), \
patch("core.bootstrap._stream_download", side_effect=fake_download):
from core.bootstrap import install_gitleaks
result = install_gitleaks()
# Result is "installed" even without gitleaks (chmod line will fail gracefully in except)
# or succeeds if chmod doesn't raise
assert isinstance(result, str)
# ββ install_hadolint ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
class TestInstallHadolint:
def test_already_installed_skips_download(self):
with patch("core.bootstrap.have_binary", return_value=True):
from core.bootstrap import install_hadolint
result = install_hadolint()
assert result == "already installed"
def test_download_failure_returns_error(self, tmp_path):
with patch("core.bootstrap.have_binary", return_value=False), \
patch("core.bootstrap.BIN_DIR", tmp_path), \
patch("core.bootstrap._stream_download",
side_effect=OSError("disk full")):
from core.bootstrap import install_hadolint
result = install_hadolint()
assert result.startswith("install failed:")
def test_windows_download_installs_exe(self, tmp_path):
def fake_download(url, dest_path, timeout=120):
dest_path.write_bytes(b"fake hadolint")
with patch("core.bootstrap.have_binary", return_value=False), \
patch("core.bootstrap.BIN_DIR", tmp_path), \
patch("core.bootstrap._IS_WINDOWS", True), \
patch("core.bootstrap._stream_download", side_effect=fake_download):
from core.bootstrap import install_hadolint
result = install_hadolint()
assert result == "installed"
assert (tmp_path / "hadolint.exe").exists()
def test_linux_download_installs_and_chmods(self, tmp_path):
def fake_download(url, dest_path, timeout=120):
dest_path.write_bytes(b"fake hadolint")
with patch("core.bootstrap.have_binary", return_value=False), \
patch("core.bootstrap.BIN_DIR", tmp_path), \
patch("core.bootstrap._IS_WINDOWS", False), \
patch("core.bootstrap._stream_download", side_effect=fake_download):
from core.bootstrap import install_hadolint
result = install_hadolint()
assert result == "installed"
assert (tmp_path / "hadolint").exists()
def test_windows_url_contains_windows_in_path(self, tmp_path):
captured = {}
def fake_download(url, dest_path, timeout=120):
captured["url"] = url
dest_path.write_bytes(b"x")
with patch("core.bootstrap.have_binary", return_value=False), \
patch("core.bootstrap.BIN_DIR", tmp_path), \
patch("core.bootstrap._IS_WINDOWS", True), \
patch("core.bootstrap._stream_download", side_effect=fake_download):
from core.bootstrap import install_hadolint
install_hadolint()
assert "Windows" in captured["url"] or "windows" in captured["url"]
def test_linux_url_contains_linux_in_path(self, tmp_path):
captured = {}
def fake_download(url, dest_path, timeout=120):
captured["url"] = url
dest_path.write_bytes(b"x")
with patch("core.bootstrap.have_binary", return_value=False), \
patch("core.bootstrap.BIN_DIR", tmp_path), \
patch("core.bootstrap._IS_WINDOWS", False), \
patch("core.bootstrap._stream_download", side_effect=fake_download):
from core.bootstrap import install_hadolint
install_hadolint()
assert "Linux" in captured["url"] or "linux" in captured["url"]
# ββ bootstrap_binaries ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
class TestBootstrapBinaries:
def test_returns_dict_with_gitleaks_and_hadolint(self, tmp_path):
with patch("core.bootstrap.BIN_DIR", tmp_path), \
patch("core.bootstrap.install_gitleaks", return_value="already installed"), \
patch("core.bootstrap.install_hadolint", return_value="ok"), \
patch("core.bootstrap.install_trivy", return_value="ok"), \
patch("core.bootstrap.install_trufflehog", return_value="ok"), \
patch("core.bootstrap.install_syft", return_value="ok"), \
patch("core.bootstrap.install_grype", return_value="ok"):
from core.bootstrap import bootstrap_binaries
result = bootstrap_binaries()
assert "gitleaks" in result
assert "hadolint" in result
assert "trivy" in result
assert "trufflehog" in result
assert "syft" in result
assert "grype" in result
def test_adds_bin_dir_to_path_if_missing(self, tmp_path, monkeypatch):
monkeypatch.setenv("PATH", "/usr/bin")
with patch("core.bootstrap.BIN_DIR", tmp_path), \
patch("core.bootstrap.install_gitleaks", return_value="ok"), \
patch("core.bootstrap.install_hadolint", return_value="ok"), \
patch("core.bootstrap.install_trivy", return_value="ok"), \
patch("core.bootstrap.install_trufflehog", return_value="ok"), \
patch("core.bootstrap.install_syft", return_value="ok"), \
patch("core.bootstrap.install_grype", return_value="ok"):
from core.bootstrap import bootstrap_binaries
bootstrap_binaries()
assert str(tmp_path) in os.environ["PATH"]
def test_does_not_duplicate_bin_dir_in_path(self, tmp_path, monkeypatch):
monkeypatch.setenv("PATH", str(tmp_path) + os.pathsep + "/usr/bin")
with patch("core.bootstrap.BIN_DIR", tmp_path), \
patch("core.bootstrap.install_gitleaks", return_value="ok"), \
patch("core.bootstrap.install_hadolint", return_value="ok"), \
patch("core.bootstrap.install_trivy", return_value="ok"), \
patch("core.bootstrap.install_trufflehog", return_value="ok"), \
patch("core.bootstrap.install_syft", return_value="ok"), \
patch("core.bootstrap.install_grype", return_value="ok"):
from core.bootstrap import bootstrap_binaries
bootstrap_binaries()
path_parts = os.environ["PATH"].split(os.pathsep)
assert path_parts.count(str(tmp_path)) == 1
def test_creates_bin_dir_if_missing(self, tmp_path):
new_dir = tmp_path / "new_bin_dir"
with patch("core.bootstrap.BIN_DIR", new_dir), \
patch("core.bootstrap.install_gitleaks", return_value="ok"), \
patch("core.bootstrap.install_hadolint", return_value="ok"), \
patch("core.bootstrap.install_trivy", return_value="ok"), \
patch("core.bootstrap.install_trufflehog", return_value="ok"), \
patch("core.bootstrap.install_syft", return_value="ok"), \
patch("core.bootstrap.install_grype", return_value="ok"):
from core.bootstrap import bootstrap_binaries
bootstrap_binaries()
assert new_dir.exists()
|