mirror of
https://github.com/d9pouces/id_configurator.git
synced 2026-11-09 01:47:21 +01:00
feat: new configurations for APK/Java/Python/Yum
Signed-off-by: d9pouces <github@19pouces.net>
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
import base64
|
||||
import subprocess
|
||||
from configparser import ConfigParser
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
from id_configurator.config import Configuration
|
||||
from id_configurator.context import Context
|
||||
from id_configurator.modules.yum import YumModule
|
||||
|
||||
KEY_CONTENT = base64.b64encode(b"fake-rpm-gpg-key-bytes").decode("ascii")
|
||||
|
||||
CONFIG_WITH_REPO_AND_KEY = {
|
||||
"uuid": "12345678-1234-5678-1234-567812345678",
|
||||
"organisation": "InterDiode",
|
||||
"configurations": {
|
||||
"yum": {
|
||||
"repositories": [
|
||||
{
|
||||
"name": "interdiode",
|
||||
"index-url": "https://example.invalid/yum",
|
||||
"gpg-url": "https://example.invalid/RPM-GPG-KEY-interdiode",
|
||||
}
|
||||
],
|
||||
"keys": [{"name": "interdiode", "content": KEY_CONTENT}],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
CONFIG_WITH_UNSIGNED_REPO = {
|
||||
"uuid": "12345678-1234-5678-1234-567812345678",
|
||||
"organisation": "InterDiode",
|
||||
"configurations": {
|
||||
"yum": {
|
||||
"repositories": [
|
||||
{"name": "unsigned", "index-url": "https://example.invalid/yum"}
|
||||
]
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
EMPTY_CONFIG = {
|
||||
"uuid": "12345678-1234-5678-1234-567812345678",
|
||||
"organisation": "InterDiode",
|
||||
}
|
||||
|
||||
|
||||
def make_config(data: dict) -> Configuration:
|
||||
return Configuration.model_validate(data)
|
||||
|
||||
|
||||
def test_is_relevant_false_when_empty(tmp_path) -> None:
|
||||
context = Context(config=make_config(EMPTY_CONFIG), dst=tmp_path / "dst", src=None)
|
||||
assert YumModule().is_relevant(context) is False
|
||||
|
||||
|
||||
def test_is_relevant_true_with_repository(tmp_path) -> None:
|
||||
context = Context(
|
||||
config=make_config(CONFIG_WITH_UNSIGNED_REPO), dst=tmp_path / "dst", src=None
|
||||
)
|
||||
assert YumModule().is_relevant(context) is True
|
||||
|
||||
|
||||
def test_is_relevant_true_with_existing_repo_file(tmp_path) -> None:
|
||||
src = tmp_path / "src"
|
||||
repos_dir = src / "etc/yum.repos.d"
|
||||
repos_dir.mkdir(parents=True)
|
||||
(repos_dir / "old.repo").write_text(
|
||||
"[old]\nname=old\nbaseurl=https://old.invalid\nenabled=1\n", encoding="utf-8"
|
||||
)
|
||||
context = Context(config=make_config(EMPTY_CONFIG), dst=tmp_path / "dst", src=src)
|
||||
assert YumModule().is_relevant(context) is True
|
||||
|
||||
|
||||
def test_is_relevant_false_with_only_unrelated_src_files(tmp_path) -> None:
|
||||
src = tmp_path / "src"
|
||||
repos_dir = src / "etc/yum.repos.d"
|
||||
repos_dir.mkdir(parents=True)
|
||||
(repos_dir / "README").write_text("not a repo file\n", encoding="utf-8")
|
||||
context = Context(config=make_config(EMPTY_CONFIG), dst=tmp_path / "dst", src=src)
|
||||
assert YumModule().is_relevant(context) is False
|
||||
|
||||
|
||||
def _mock_gpg_success(monkeypatch) -> MagicMock:
|
||||
mock_run = MagicMock(
|
||||
return_value=subprocess.CompletedProcess(
|
||||
args=[], returncode=0, stdout=b"", stderr=b""
|
||||
)
|
||||
)
|
||||
monkeypatch.setattr("id_configurator.modules.yum.subprocess.run", mock_run)
|
||||
return mock_run
|
||||
|
||||
|
||||
def test_apply_writes_signed_repo_and_imports_key(tmp_path, monkeypatch) -> None:
|
||||
mock_run = _mock_gpg_success(monkeypatch)
|
||||
dst = tmp_path / "dst"
|
||||
context = Context(config=make_config(CONFIG_WITH_REPO_AND_KEY), dst=dst, src=None)
|
||||
|
||||
YumModule().apply(context)
|
||||
|
||||
repo_content = (dst / "etc/yum.repos.d/interdiode.repo").read_text(encoding="utf-8")
|
||||
assert repo_content == (
|
||||
"[interdiode]\n"
|
||||
"name=interdiode\n"
|
||||
"baseurl=https://example.invalid/yum\n"
|
||||
"enabled=1\n"
|
||||
"gpgcheck=1\n"
|
||||
"gpgkey=https://example.invalid/RPM-GPG-KEY-interdiode\n"
|
||||
)
|
||||
|
||||
key_content = (dst / "etc/pki/rpm-gpg/RPM-GPG-KEY-interdiode").read_bytes()
|
||||
assert key_content == b"fake-rpm-gpg-key-bytes"
|
||||
mock_run.assert_called_once()
|
||||
assert mock_run.call_args.kwargs["input"] == b"fake-rpm-gpg-key-bytes"
|
||||
|
||||
|
||||
def test_apply_unsigned_repo_disables_gpgcheck(tmp_path) -> None:
|
||||
dst = tmp_path / "dst"
|
||||
context = Context(config=make_config(CONFIG_WITH_UNSIGNED_REPO), dst=dst, src=None)
|
||||
|
||||
YumModule().apply(context)
|
||||
|
||||
repo_content = (dst / "etc/yum.repos.d/unsigned.repo").read_text(encoding="utf-8")
|
||||
assert repo_content == (
|
||||
"[unsigned]\nname=unsigned\nbaseurl=https://example.invalid/yum\nenabled=1\ngpgcheck=0\n"
|
||||
)
|
||||
|
||||
|
||||
def test_apply_disables_existing_repos_before_adding_configured_ones(tmp_path) -> None:
|
||||
src = tmp_path / "src"
|
||||
repos_dir = src / "etc/yum.repos.d"
|
||||
repos_dir.mkdir(parents=True)
|
||||
(repos_dir / "multi.repo").write_text(
|
||||
"[old-one]\nname=old-one\nbaseurl=https://old-one.invalid\nenabled=1\ngpgcheck=1\n"
|
||||
"\n"
|
||||
"[old-two]\nname=old-two\nbaseurl=https://old-two.invalid\nenabled=1\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(repos_dir / "ignored.txt").write_text("not a repo file\n", encoding="utf-8")
|
||||
# A same-named existing file must end up enabled again once the configured repo overwrites it.
|
||||
(repos_dir / "unsigned.repo").write_text(
|
||||
"[unsigned]\nname=unsigned\nbaseurl=https://stale.invalid\nenabled=1\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
dst = tmp_path / "dst"
|
||||
context = Context(config=make_config(CONFIG_WITH_UNSIGNED_REPO), dst=dst, src=src)
|
||||
|
||||
YumModule().apply(context)
|
||||
|
||||
disabled_multi = (dst / "etc/yum.repos.d/multi.repo").read_text(encoding="utf-8")
|
||||
assert "[old-one]" in disabled_multi
|
||||
assert "[old-two]" in disabled_multi
|
||||
parser = ConfigParser(interpolation=None)
|
||||
parser.read_string(disabled_multi)
|
||||
assert parser["old-one"]["enabled"] == "0"
|
||||
assert parser["old-two"]["enabled"] == "0"
|
||||
|
||||
assert not (dst / "etc/yum.repos.d/ignored.txt").exists()
|
||||
|
||||
overridden = (dst / "etc/yum.repos.d/unsigned.repo").read_text(encoding="utf-8")
|
||||
assert (
|
||||
overridden
|
||||
== "[unsigned]\nname=unsigned\nbaseurl=https://example.invalid/yum\nenabled=1\ngpgcheck=0\n"
|
||||
)
|
||||
|
||||
|
||||
def test_import_key_raises_when_gpg_binary_missing(tmp_path, monkeypatch) -> None:
|
||||
monkeypatch.setattr(
|
||||
"id_configurator.modules.yum.subprocess.run",
|
||||
MagicMock(side_effect=FileNotFoundError()),
|
||||
)
|
||||
context = Context(
|
||||
config=make_config(CONFIG_WITH_REPO_AND_KEY), dst=tmp_path / "dst", src=None
|
||||
)
|
||||
|
||||
with pytest.raises(RuntimeError, match="gpg is not available"):
|
||||
YumModule().apply(context)
|
||||
|
||||
|
||||
def test_import_key_raises_on_invalid_key(tmp_path, monkeypatch) -> None:
|
||||
mock_run = MagicMock(
|
||||
return_value=subprocess.CompletedProcess(
|
||||
args=[], returncode=2, stdout=b"", stderr=b"gpg: no valid data found"
|
||||
)
|
||||
)
|
||||
monkeypatch.setattr("id_configurator.modules.yum.subprocess.run", mock_run)
|
||||
context = Context(
|
||||
config=make_config(CONFIG_WITH_REPO_AND_KEY), dst=tmp_path / "dst", src=None
|
||||
)
|
||||
|
||||
with pytest.raises(RuntimeError, match="invalid GPG key interdiode"):
|
||||
YumModule().apply(context)
|
||||
Reference in New Issue
Block a user