mirror of
https://github.com/d9pouces/id_configurator.git
synced 2026-11-09 01:47:21 +01:00
0f019ac6ea
Signed-off-by: d9pouces <github@19pouces.net>
298 lines
9.4 KiB
Python
298 lines
9.4 KiB
Python
import tomllib
|
|
|
|
from id_configurator.config import Configuration
|
|
from id_configurator.context import Context
|
|
from id_configurator.modules.python import PythonModule
|
|
|
|
ONE_REPO_CONFIG = {
|
|
"uuid": "12345678-1234-5678-1234-567812345678",
|
|
"organisation": "InterDiode",
|
|
"configurations": {
|
|
"python": {
|
|
"repositories": [
|
|
{"name": "interdiode", "index-url": "https://example.invalid/simple"}
|
|
]
|
|
}
|
|
},
|
|
}
|
|
|
|
TWO_REPOS_CONFIG = {
|
|
"uuid": "12345678-1234-5678-1234-567812345678",
|
|
"organisation": "InterDiode",
|
|
"configurations": {
|
|
"python": {
|
|
"repositories": [
|
|
{"name": "interdiode", "index-url": "https://example.invalid/simple"},
|
|
{
|
|
"name": "interdiode-extra",
|
|
"index-url": "https://example2.invalid/simple",
|
|
},
|
|
]
|
|
}
|
|
},
|
|
}
|
|
|
|
|
|
def test_is_relevant_false_without_repositories(tmp_path) -> None:
|
|
config = Configuration.model_validate(
|
|
{"uuid": "12345678-1234-5678-1234-567812345678", "organisation": "InterDiode"}
|
|
)
|
|
context = Context(config=config, dst=tmp_path / "dst", src=None)
|
|
assert PythonModule().is_relevant(context) is False
|
|
|
|
|
|
def test_is_relevant_true_with_repositories(tmp_path) -> None:
|
|
config = Configuration.model_validate(ONE_REPO_CONFIG)
|
|
context = Context(config=config, dst=tmp_path / "dst", src=None)
|
|
assert PythonModule().is_relevant(context) is True
|
|
|
|
|
|
def test_apply_single_repository(tmp_path) -> None:
|
|
config = Configuration.model_validate(ONE_REPO_CONFIG)
|
|
dst = tmp_path / "dst"
|
|
context = Context(config=config, dst=dst, src=None)
|
|
|
|
PythonModule().apply(context)
|
|
|
|
pip_conf = (dst / "etc/pip.conf").read_text(encoding="utf-8")
|
|
assert pip_conf == (
|
|
"[global]\nindex-url = https://example.invalid/simple\ncert = /etc/ssl/certs/ca-certificates.crt\n"
|
|
)
|
|
|
|
uv_toml = (dst / "etc/uv/uv.toml").read_text(encoding="utf-8")
|
|
assert uv_toml == (
|
|
'native-tls = true\n\n[[index]]\nname = "interdiode"\nurl = "https://example.invalid/simple"\ndefault = true\n'
|
|
)
|
|
|
|
poetry_config = (dst / "root/.config/pypoetry/config.toml").read_text(
|
|
encoding="utf-8"
|
|
)
|
|
assert poetry_config == (
|
|
"[repositories.interdiode]\n"
|
|
'url = "https://example.invalid/simple"\n'
|
|
"\n"
|
|
"[certificates.interdiode]\n"
|
|
'cert = "/etc/ssl/certs/ca-certificates.crt"\n'
|
|
)
|
|
|
|
assert not (dst / "usr/lib").exists()
|
|
|
|
|
|
def test_apply_sanitizes_uv_index_name_with_non_bmp_characters(tmp_path) -> None:
|
|
data = {
|
|
"uuid": "12345678-1234-5678-1234-567812345678",
|
|
"organisation": "InterDiode",
|
|
"configurations": {
|
|
"python": {
|
|
"repositories": [
|
|
{"name": "demo 😀", "index-url": "https://example.invalid/simple"}
|
|
]
|
|
}
|
|
},
|
|
}
|
|
config = Configuration.model_validate(data)
|
|
dst = tmp_path / "dst"
|
|
context = Context(config=config, dst=dst, src=None)
|
|
|
|
PythonModule().apply(context)
|
|
|
|
uv_toml = (dst / "etc/uv/uv.toml").read_text(encoding="utf-8")
|
|
# The emoji isn't a plain identifier character, so sanitize_repository_name
|
|
# replaces it (and the space before it) with "_", same as every other
|
|
# non-ASCII or syntax-breaking character.
|
|
assert '"demo__"' in uv_toml
|
|
parsed = tomllib.loads(uv_toml)
|
|
assert parsed["index"][0]["name"] == "demo__"
|
|
|
|
|
|
def test_apply_adds_trusted_host_for_non_https_repository(tmp_path) -> None:
|
|
data = {
|
|
"uuid": "12345678-1234-5678-1234-567812345678",
|
|
"organisation": "InterDiode",
|
|
"configurations": {
|
|
"python": {
|
|
"repositories": [
|
|
{"name": "interdiode", "index-url": "http://example.invalid/simple"}
|
|
]
|
|
}
|
|
},
|
|
}
|
|
config = Configuration.model_validate(data)
|
|
dst = tmp_path / "dst"
|
|
context = Context(config=config, dst=dst, src=None)
|
|
|
|
PythonModule().apply(context)
|
|
|
|
pip_conf = (dst / "etc/pip.conf").read_text(encoding="utf-8")
|
|
assert pip_conf == (
|
|
"[global]\n"
|
|
"index-url = http://example.invalid/simple\n"
|
|
"trusted-host =\n"
|
|
" example.invalid\n"
|
|
"cert = /etc/ssl/certs/ca-certificates.crt\n"
|
|
)
|
|
|
|
|
|
def test_apply_adds_trusted_host_only_for_non_https_among_mixed_repositories(
|
|
tmp_path,
|
|
) -> None:
|
|
data = {
|
|
"uuid": "12345678-1234-5678-1234-567812345678",
|
|
"organisation": "InterDiode",
|
|
"configurations": {
|
|
"python": {
|
|
"repositories": [
|
|
{
|
|
"name": "interdiode",
|
|
"index-url": "https://example.invalid/simple",
|
|
},
|
|
{
|
|
"name": "insecure",
|
|
"index-url": "http://insecure.invalid/simple",
|
|
},
|
|
]
|
|
}
|
|
},
|
|
}
|
|
config = Configuration.model_validate(data)
|
|
dst = tmp_path / "dst"
|
|
context = Context(config=config, dst=dst, src=None)
|
|
|
|
PythonModule().apply(context)
|
|
|
|
pip_conf = (dst / "etc/pip.conf").read_text(encoding="utf-8")
|
|
assert pip_conf == (
|
|
"[global]\n"
|
|
"index-url = https://example.invalid/simple\n"
|
|
"extra-index-url =\n"
|
|
" http://insecure.invalid/simple\n"
|
|
"trusted-host =\n"
|
|
" insecure.invalid\n"
|
|
"cert = /etc/ssl/certs/ca-certificates.crt\n"
|
|
)
|
|
|
|
|
|
def test_apply_does_not_add_trusted_host_when_all_repositories_https(tmp_path) -> None:
|
|
config = Configuration.model_validate(ONE_REPO_CONFIG)
|
|
dst = tmp_path / "dst"
|
|
context = Context(config=config, dst=dst, src=None)
|
|
|
|
PythonModule().apply(context)
|
|
|
|
pip_conf = (dst / "etc/pip.conf").read_text(encoding="utf-8")
|
|
assert "trusted-host" not in pip_conf
|
|
|
|
|
|
def test_apply_multiple_repositories(tmp_path) -> None:
|
|
config = Configuration.model_validate(TWO_REPOS_CONFIG)
|
|
dst = tmp_path / "dst"
|
|
context = Context(config=config, dst=dst, src=None)
|
|
|
|
PythonModule().apply(context)
|
|
|
|
pip_conf = (dst / "etc/pip.conf").read_text(encoding="utf-8")
|
|
assert pip_conf == (
|
|
"[global]\n"
|
|
"index-url = https://example.invalid/simple\n"
|
|
"extra-index-url =\n"
|
|
" https://example2.invalid/simple\n"
|
|
"cert = /etc/ssl/certs/ca-certificates.crt\n"
|
|
)
|
|
|
|
uv_toml = (dst / "etc/uv/uv.toml").read_text(encoding="utf-8")
|
|
assert uv_toml == (
|
|
"native-tls = true\n\n"
|
|
"[[index]]\n"
|
|
'name = "interdiode"\n'
|
|
'url = "https://example.invalid/simple"\n'
|
|
"default = true\n\n"
|
|
"[[index]]\n"
|
|
'name = "interdiode-extra"\n'
|
|
'url = "https://example2.invalid/simple"\n'
|
|
)
|
|
|
|
|
|
def test_apply_sanitizes_poetry_repository_name_with_special_characters(
|
|
tmp_path,
|
|
) -> None:
|
|
data = {
|
|
"uuid": "12345678-1234-5678-1234-567812345678",
|
|
"organisation": "InterDiode",
|
|
"configurations": {
|
|
"python": {
|
|
"repositories": [
|
|
{
|
|
"name": "weird.name]here[bad",
|
|
"index-url": "https://example.invalid/simple",
|
|
}
|
|
]
|
|
}
|
|
},
|
|
}
|
|
config = Configuration.model_validate(data)
|
|
dst = tmp_path / "dst"
|
|
context = Context(config=config, dst=dst, src=None)
|
|
|
|
PythonModule().apply(context)
|
|
|
|
poetry_config = (dst / "root/.config/pypoetry/config.toml").read_text(
|
|
encoding="utf-8"
|
|
)
|
|
assert poetry_config == (
|
|
"[repositories.weird_name_here_bad]\n"
|
|
'url = "https://example.invalid/simple"\n'
|
|
"\n"
|
|
"[certificates.weird_name_here_bad]\n"
|
|
'cert = "/etc/ssl/certs/ca-certificates.crt"\n'
|
|
)
|
|
|
|
|
|
def test_apply_writes_poetry_config_for_each_configured_user(tmp_path) -> None:
|
|
config = Configuration.model_validate(ONE_REPO_CONFIG)
|
|
dst = tmp_path / "dst"
|
|
context = Context(config=config, dst=dst, src=None, users=["alice"])
|
|
|
|
PythonModule().apply(context)
|
|
|
|
root_content = (dst / "root/.config/pypoetry/config.toml").read_text(
|
|
encoding="utf-8"
|
|
)
|
|
alice_content = (dst / "home/alice/.config/pypoetry/config.toml").read_text(
|
|
encoding="utf-8"
|
|
)
|
|
assert alice_content == root_content
|
|
|
|
|
|
def test_apply_writes_distutils_cfg_for_detected_python_prefixes(tmp_path) -> None:
|
|
config = Configuration.model_validate(ONE_REPO_CONFIG)
|
|
src = tmp_path / "src"
|
|
(src / "usr/lib/python3.11").mkdir(parents=True)
|
|
(src / "usr/local/lib/python3.12").mkdir(parents=True)
|
|
(src / "usr/lib/not-python").mkdir(parents=True)
|
|
dst = tmp_path / "dst"
|
|
context = Context(config=config, dst=dst, src=src)
|
|
|
|
PythonModule().apply(context)
|
|
|
|
content_311 = (dst / "usr/lib/python3.11/distutils/distutils.cfg").read_text(
|
|
encoding="utf-8"
|
|
)
|
|
assert content_311 == "[easy_install]\nindex_url = https://example.invalid/simple\n"
|
|
|
|
content_312 = (dst / "usr/local/lib/python3.12/distutils/distutils.cfg").read_text(
|
|
encoding="utf-8"
|
|
)
|
|
assert content_312 == "[easy_install]\nindex_url = https://example.invalid/simple\n"
|
|
|
|
assert not (dst / "usr/lib/not-python").exists()
|
|
|
|
|
|
def test_apply_without_src_skips_distutils_cfg(tmp_path) -> None:
|
|
config = Configuration.model_validate(ONE_REPO_CONFIG)
|
|
dst = tmp_path / "dst"
|
|
context = Context(config=config, dst=dst, src=None)
|
|
|
|
PythonModule().apply(context)
|
|
|
|
assert not (dst / "usr").exists()
|