mirror of
https://github.com/d9pouces/id_configurator.git
synced 2026-11-09 01:47:21 +01:00
feat: initial commit
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
import base64
|
||||
|
||||
from id_configurator.config import Configuration
|
||||
from id_configurator.context import Context
|
||||
from id_configurator.modules.apt import AptModule
|
||||
|
||||
SOURCE_CONTENT = {
|
||||
"uuid": "12345678-1234-5678-1234-567812345678",
|
||||
"organisation": "InterDiode",
|
||||
"configurations": {
|
||||
"apt": {
|
||||
"sources": [
|
||||
{
|
||||
"name": "interdiode",
|
||||
"uris": ["http://example.invalid/debian"],
|
||||
"suites": ["stable"],
|
||||
"signed-by": "/etc/apt/keyrings/interdiode.asc",
|
||||
}
|
||||
],
|
||||
"keys": [
|
||||
{
|
||||
"name": "interdiode",
|
||||
"content": base64.b64encode(b"fake-key-bytes").decode("ascii"),
|
||||
}
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def make_config() -> Configuration:
|
||||
return Configuration.model_validate(SOURCE_CONTENT)
|
||||
|
||||
|
||||
def test_is_relevant_false_without_src(tmp_path) -> None:
|
||||
context = Context(config=make_config(), dst=tmp_path / "dst", src=None)
|
||||
assert AptModule().is_relevant(context) is False # nosec B101
|
||||
|
||||
|
||||
def test_is_relevant_false_without_apt_dir(tmp_path) -> None:
|
||||
src = tmp_path / "src"
|
||||
src.mkdir()
|
||||
context = Context(config=make_config(), dst=tmp_path / "dst", src=src)
|
||||
assert AptModule().is_relevant(context) is False # nosec B101
|
||||
|
||||
|
||||
def test_is_relevant_true_with_apt_dir(tmp_path) -> None:
|
||||
src = tmp_path / "src"
|
||||
(src / "etc/apt").mkdir(parents=True)
|
||||
context = Context(config=make_config(), dst=tmp_path / "dst", src=src)
|
||||
assert AptModule().is_relevant(context) is True # nosec B101
|
||||
|
||||
|
||||
def test_apply_disables_existing_sources_and_adds_configured_ones(tmp_path) -> None:
|
||||
src = tmp_path / "src"
|
||||
apt_dir = src / "etc/apt"
|
||||
sources_list_d = apt_dir / "sources.list.d"
|
||||
sources_list_d.mkdir(parents=True)
|
||||
|
||||
(apt_dir / "sources.list").write_text(
|
||||
"# already disabled\ndeb http://example.invalid/legacy stable main\n\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(sources_list_d / "extra.list").write_text(
|
||||
"deb http://example.invalid/extra stable main\n", encoding="utf-8"
|
||||
)
|
||||
(sources_list_d / "docker.sources").write_text(
|
||||
"Types: deb\nURIs: http://example.invalid/docker\nSuites: stable\nEnabled: yes\n"
|
||||
"\n"
|
||||
"Types: deb\nURIs: http://example.invalid/docker2\nSuites: stable\n"
|
||||
"\n\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(sources_list_d / "ignored.txt").write_text("not a source file\n", encoding="utf-8")
|
||||
|
||||
dst = tmp_path / "dst"
|
||||
context = Context(config=make_config(), dst=dst, src=src)
|
||||
|
||||
AptModule().apply(context)
|
||||
|
||||
disabled_top_level = (dst / "etc/apt/sources.list").read_text(encoding="utf-8")
|
||||
assert (
|
||||
disabled_top_level
|
||||
== "# already disabled\n# deb http://example.invalid/legacy stable main\n\n"
|
||||
) # nosec B101
|
||||
|
||||
disabled_list = (dst / "etc/apt/sources.list.d/extra.list").read_text(
|
||||
encoding="utf-8"
|
||||
) # nosec B101
|
||||
assert disabled_list == "# deb http://example.invalid/extra stable main\n" # nosec B101
|
||||
|
||||
disabled_sources = (dst / "etc/apt/sources.list.d/docker.sources").read_text(
|
||||
encoding="utf-8"
|
||||
) # nosec B101
|
||||
assert disabled_sources == ( # nosec B101
|
||||
"Types: deb\nURIs: http://example.invalid/docker\nSuites: stable\nEnabled: no"
|
||||
"\n\n"
|
||||
"Types: deb\nURIs: http://example.invalid/docker2\nSuites: stable\nEnabled: no\n"
|
||||
)
|
||||
|
||||
assert not (dst / "etc/apt/sources.list.d/ignored.txt").exists() # nosec B101
|
||||
|
||||
keyring = (dst / "etc/apt/keyrings/interdiode.asc").read_bytes()
|
||||
assert keyring == b"fake-key-bytes" # nosec B101
|
||||
|
||||
configured_source = (dst / "etc/apt/sources.list.d/interdiode.sources").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
assert configured_source == ( # nosec B101
|
||||
"Types: deb\nURIs: http://example.invalid/debian\nSuites: stable\n"
|
||||
"Signed-By: /etc/apt/keyrings/interdiode.asc\nEnabled: yes\n"
|
||||
)
|
||||
|
||||
|
||||
def test_apply_without_existing_top_level_sources_list(tmp_path) -> None:
|
||||
src = tmp_path / "src"
|
||||
(src / "etc/apt").mkdir(parents=True)
|
||||
dst = tmp_path / "dst"
|
||||
context = Context(config=make_config(), dst=dst, src=src)
|
||||
|
||||
AptModule().apply(context)
|
||||
|
||||
assert not (dst / "etc/apt/sources.list").exists() # nosec B101
|
||||
assert (dst / "etc/apt/sources.list.d/interdiode.sources").exists() # nosec B101
|
||||
@@ -0,0 +1,119 @@
|
||||
import base64
|
||||
import subprocess
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
from id_configurator.config import Configuration
|
||||
from id_configurator.context import Context
|
||||
from id_configurator.modules.certificates import CertificatesModule
|
||||
|
||||
CERT_CONTENT = base64.b64encode(b"fake-cert-bytes").decode("ascii")
|
||||
|
||||
|
||||
def make_config(with_certificate: bool) -> Configuration:
|
||||
data = {
|
||||
"uuid": "12345678-1234-5678-1234-567812345678",
|
||||
"organisation": "InterDiode",
|
||||
}
|
||||
if with_certificate:
|
||||
data["configurations"] = {
|
||||
"certificates": [{"name": "new-root-ca", "content": CERT_CONTENT}]
|
||||
}
|
||||
return Configuration.model_validate(data)
|
||||
|
||||
|
||||
def test_is_relevant_true_when_certificates_configured(tmp_path) -> None:
|
||||
context = Context(config=make_config(True), dst=tmp_path / "dst", src=None)
|
||||
assert CertificatesModule().is_relevant(context) is True # nosec B101
|
||||
|
||||
|
||||
def test_is_relevant_false_when_no_certificates(tmp_path) -> None:
|
||||
context = Context(config=make_config(False), dst=tmp_path / "dst", src=None)
|
||||
assert CertificatesModule().is_relevant(context) is False # nosec B101
|
||||
|
||||
|
||||
def _mock_success(monkeypatch, stderr: str = "") -> MagicMock:
|
||||
mock_run = MagicMock(
|
||||
return_value=subprocess.CompletedProcess(
|
||||
args=[], returncode=0, stdout="", stderr=stderr
|
||||
)
|
||||
)
|
||||
monkeypatch.setattr("id_configurator.modules.certificates.subprocess.run", mock_run)
|
||||
return mock_run
|
||||
|
||||
|
||||
def test_apply_writes_certificate_and_calls_update_ca_certificates(
|
||||
tmp_path, monkeypatch
|
||||
) -> None:
|
||||
mock_run = _mock_success(monkeypatch)
|
||||
dst = tmp_path / "dst"
|
||||
context = Context(config=make_config(True), dst=dst, src=None)
|
||||
|
||||
CertificatesModule().apply(context)
|
||||
|
||||
written = dst / "usr/local/share/ca-certificates/new-root-ca.crt"
|
||||
assert written.read_bytes() == b"fake-cert-bytes" # nosec B101
|
||||
mock_run.assert_called_once()
|
||||
args = mock_run.call_args.args[0]
|
||||
assert args[0] == "update-ca-certificates" # nosec B101
|
||||
assert "--certsconf" not in args # nosec B101
|
||||
assert "--certsdir" not in args # nosec B101
|
||||
|
||||
|
||||
def test_apply_preserves_existing_local_certificates_from_src(
|
||||
tmp_path, monkeypatch
|
||||
) -> None:
|
||||
mock_run = _mock_success(monkeypatch, stderr="some warning")
|
||||
src = tmp_path / "src"
|
||||
local_certs_dir = src / "usr/local/share/ca-certificates"
|
||||
local_certs_dir.mkdir(parents=True)
|
||||
(local_certs_dir / "existing.crt").write_bytes(b"existing-bytes")
|
||||
(local_certs_dir / "new-root-ca.crt").write_bytes(
|
||||
b"stale-bytes-should-be-overwritten"
|
||||
)
|
||||
(src / "etc/ca-certificates.conf").parent.mkdir(parents=True)
|
||||
(src / "etc/ca-certificates.conf").write_text("existing.crt\n", encoding="utf-8")
|
||||
(src / "usr/share/ca-certificates").mkdir(parents=True)
|
||||
|
||||
dst = tmp_path / "dst"
|
||||
context = Context(config=make_config(True), dst=dst, src=src)
|
||||
|
||||
CertificatesModule().apply(context)
|
||||
|
||||
local_dst = dst / "usr/local/share/ca-certificates"
|
||||
assert (local_dst / "existing.crt").read_bytes() == b"existing-bytes" # nosec B101
|
||||
assert (local_dst / "new-root-ca.crt").read_bytes() == b"fake-cert-bytes" # nosec B101
|
||||
|
||||
args = mock_run.call_args.args[0]
|
||||
assert "--certsconf" in args # nosec B101
|
||||
assert str(src / "etc/ca-certificates.conf") in args # nosec B101
|
||||
assert "--certsdir" in args # nosec B101
|
||||
assert str(src / "usr/share/ca-certificates") in args # nosec B101
|
||||
|
||||
|
||||
def test_update_ca_certificates_raises_when_binary_missing(
|
||||
tmp_path, monkeypatch
|
||||
) -> None:
|
||||
monkeypatch.setattr(
|
||||
"id_configurator.modules.certificates.subprocess.run",
|
||||
MagicMock(side_effect=FileNotFoundError()),
|
||||
)
|
||||
context = Context(config=make_config(True), dst=tmp_path / "dst", src=None)
|
||||
|
||||
with pytest.raises(RuntimeError, match="update-ca-certificates is not available"):
|
||||
CertificatesModule().apply(context)
|
||||
|
||||
|
||||
def test_update_ca_certificates_raises_on_failure(tmp_path, monkeypatch) -> None:
|
||||
error = subprocess.CalledProcessError(
|
||||
returncode=1, cmd=["update-ca-certificates"], stderr="boom"
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"id_configurator.modules.certificates.subprocess.run",
|
||||
MagicMock(side_effect=error),
|
||||
)
|
||||
context = Context(config=make_config(True), dst=tmp_path / "dst", src=None)
|
||||
|
||||
with pytest.raises(RuntimeError, match="update-ca-certificates failed"):
|
||||
CertificatesModule().apply(context) # nosec B101
|
||||
@@ -0,0 +1,93 @@
|
||||
import base64
|
||||
import json
|
||||
import subprocess
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from typer.testing import CliRunner
|
||||
|
||||
from id_configurator import cli
|
||||
|
||||
runner = CliRunner()
|
||||
|
||||
MINIMAL_CONFIG = {
|
||||
"uuid": "12345678-1234-5678-1234-567812345678",
|
||||
"organisation": "InterDiode",
|
||||
}
|
||||
CONFIG_WITH_CERT = {
|
||||
**MINIMAL_CONFIG,
|
||||
"configurations": {
|
||||
"certificates": [
|
||||
{"name": "my-ca", "content": base64.b64encode(b"fake").decode("ascii")}
|
||||
]
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def write_config(tmp_path, data) -> str:
|
||||
path = tmp_path / "config.json"
|
||||
path.write_text(json.dumps(data), encoding="utf-8")
|
||||
return str(path)
|
||||
|
||||
|
||||
def test_validate_valid_config(tmp_path) -> None:
|
||||
config_path = write_config(tmp_path, MINIMAL_CONFIG)
|
||||
result = runner.invoke(cli.app, ["validate", "--config", config_path])
|
||||
assert result.exit_code == 0 # nosec B101
|
||||
assert "is valid" in result.stdout # nosec B101
|
||||
|
||||
|
||||
def test_validate_without_config_fails() -> None:
|
||||
result = runner.invoke(cli.app, ["validate"])
|
||||
assert result.exit_code != 0 # nosec B101
|
||||
assert "either --config or --config-env" in result.output # nosec B101
|
||||
|
||||
|
||||
def test_list_modules() -> None:
|
||||
result = runner.invoke(cli.app, ["list-modules"])
|
||||
assert result.exit_code == 0 # nosec B101
|
||||
assert set(result.stdout.splitlines()) == {"apt", "certificates"} # nosec B101
|
||||
|
||||
|
||||
def test_apply_skips_irrelevant_modules(tmp_path, caplog) -> None:
|
||||
config_path = write_config(tmp_path, MINIMAL_CONFIG)
|
||||
dst = tmp_path / "dst"
|
||||
with caplog.at_level("DEBUG", logger="id_configurator"):
|
||||
result = runner.invoke(
|
||||
cli.app, ["apply", "--config", config_path, "--dst", str(dst), "-v"]
|
||||
)
|
||||
assert result.exit_code == 0 # nosec B101
|
||||
assert "skipping module apt" in caplog.text # nosec B101
|
||||
assert "skipping module certificates" in caplog.text # nosec B101
|
||||
|
||||
|
||||
def test_apply_runs_relevant_module(tmp_path, monkeypatch) -> None:
|
||||
mock_run = MagicMock(
|
||||
return_value=subprocess.CompletedProcess(
|
||||
args=[], returncode=0, stdout="", stderr=""
|
||||
)
|
||||
)
|
||||
monkeypatch.setattr("id_configurator.modules.certificates.subprocess.run", mock_run)
|
||||
|
||||
config_path = write_config(tmp_path, CONFIG_WITH_CERT)
|
||||
dst = tmp_path / "dst"
|
||||
result = runner.invoke(
|
||||
cli.app, ["apply", "--config", config_path, "--dst", str(dst)]
|
||||
)
|
||||
|
||||
assert result.exit_code == 0 # nosec B101
|
||||
assert (dst / "usr/local/share/ca-certificates/my-ca.crt").read_bytes() == b"fake" # nosec B101
|
||||
mock_run.assert_called_once()
|
||||
|
||||
|
||||
def test_main_default_name_calls_app(monkeypatch) -> None:
|
||||
mock_app = MagicMock()
|
||||
monkeypatch.setattr(cli, "app", mock_app)
|
||||
cli.main()
|
||||
mock_app.assert_called_once()
|
||||
|
||||
|
||||
def test_main_other_name_does_not_call_app(monkeypatch) -> None:
|
||||
mock_app = MagicMock()
|
||||
monkeypatch.setattr(cli, "app", mock_app)
|
||||
cli.main("id_configurator.__main__")
|
||||
mock_app.assert_not_called()
|
||||
@@ -0,0 +1,163 @@
|
||||
import base64
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
from id_configurator.config import (
|
||||
AptSource,
|
||||
Configuration,
|
||||
load_configuration,
|
||||
parse_configuration,
|
||||
)
|
||||
|
||||
FULL_CONFIG = {
|
||||
"uuid": "12345678-1234-5678-1234-567812345678",
|
||||
"organisation": "InterDiode",
|
||||
"description": "a test configuration",
|
||||
"configurations": {
|
||||
"certificates": [{"name": "my-ca", "content": "ZmFrZQ=="}],
|
||||
"apt": {
|
||||
"sources": [
|
||||
{
|
||||
"name": "interdiode",
|
||||
"types": ["deb"],
|
||||
"uris": ["http://example.invalid/debian"],
|
||||
"suites": ["stable"],
|
||||
"components": ["main", "contrib"],
|
||||
"signed-by": "/etc/apt/keyrings/interdiode.asc",
|
||||
}
|
||||
],
|
||||
"keys": [{"name": "interdiode", "content": "ZmFrZQ=="}],
|
||||
},
|
||||
"yum": {
|
||||
"repositories": [
|
||||
{
|
||||
"name": "interdiode",
|
||||
"index-url": "http://example.invalid/yum",
|
||||
"gpg-url": "http://example.invalid/gpg",
|
||||
}
|
||||
]
|
||||
},
|
||||
"python": {
|
||||
"repositories": [
|
||||
{"name": "interdiode", "index-url": "http://example.invalid/simple"}
|
||||
]
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def test_parse_configuration_from_json() -> None:
|
||||
configuration = parse_configuration(json.dumps(FULL_CONFIG))
|
||||
assert isinstance(configuration, Configuration) # nosec B101
|
||||
assert configuration.organisation == "InterDiode" # nosec B101
|
||||
assert configuration.configurations.certificates[0].name == "my-ca" # nosec B101
|
||||
assert (
|
||||
configuration.configurations.yum.repositories[0].index_url
|
||||
== "http://example.invalid/yum"
|
||||
) # nosec B101
|
||||
assert (
|
||||
configuration.configurations.yum.repositories[0].gpg_url
|
||||
== "http://example.invalid/gpg"
|
||||
) # nosec B101
|
||||
assert (
|
||||
configuration.configurations.python.repositories[0].index_url
|
||||
== "http://example.invalid/simple"
|
||||
) # nosec B101
|
||||
assert (
|
||||
configuration.configurations.apt.sources[0].signed_by
|
||||
== "/etc/apt/keyrings/interdiode.asc"
|
||||
) # nosec B101
|
||||
assert configuration.configurations.apt.keys[0].name == "interdiode" # nosec B101
|
||||
|
||||
|
||||
def test_parse_configuration_from_yaml() -> None:
|
||||
raw = """
|
||||
uuid: 12345678-1234-5678-1234-567812345678
|
||||
organisation: InterDiode
|
||||
"""
|
||||
configuration = parse_configuration(raw)
|
||||
assert configuration.organisation == "InterDiode" # nosec B101
|
||||
assert configuration.description == "" # nosec B101
|
||||
assert configuration.configurations.certificates == [] # nosec B101
|
||||
|
||||
|
||||
def test_load_configuration_from_file(tmp_path) -> None:
|
||||
config_file = tmp_path / "config.json"
|
||||
config_file.write_text(json.dumps(FULL_CONFIG), encoding="utf-8")
|
||||
configuration = load_configuration(config_file, None)
|
||||
assert configuration.organisation == "InterDiode" # nosec B101
|
||||
|
||||
|
||||
def test_load_configuration_from_env() -> None:
|
||||
encoded = base64.b64encode(json.dumps(FULL_CONFIG).encode("utf-8")).decode("ascii")
|
||||
configuration = load_configuration(None, encoded)
|
||||
assert configuration.organisation == "InterDiode" # nosec B101
|
||||
|
||||
|
||||
def test_load_configuration_without_source_raises() -> None:
|
||||
with pytest.raises(ValueError, match="either --config or --config-env"):
|
||||
load_configuration(None, None)
|
||||
|
||||
|
||||
def test_apt_source_to_deb822_minimal() -> None:
|
||||
source = AptSource(
|
||||
name="interdiode", uris=["http://example.invalid/debian"], suites=["stable"]
|
||||
)
|
||||
assert (
|
||||
source.to_deb822()
|
||||
== "Types: deb\nURIs: http://example.invalid/debian\nSuites: stable\nEnabled: yes\n"
|
||||
) # nosec B101
|
||||
|
||||
|
||||
def test_apt_source_to_deb822_full() -> None:
|
||||
source = AptSource(
|
||||
name="interdiode",
|
||||
types=["deb", "deb-src"],
|
||||
uris=["http://example.invalid/debian"],
|
||||
suites=["stable"],
|
||||
components=["main", "contrib"],
|
||||
architectures=["amd64"],
|
||||
languages=["en"],
|
||||
targets=["deb"],
|
||||
enabled=False,
|
||||
trusted=True,
|
||||
**{
|
||||
"signed-by": "/etc/apt/keyrings/interdiode.asc",
|
||||
"by-hash": True,
|
||||
"allow-insecure": False,
|
||||
"allow-weak": False,
|
||||
"allow-downgrade-to-insecure": False,
|
||||
"check-valid-until": True,
|
||||
"valid-until-min": "10",
|
||||
"valid-until-max": "1w",
|
||||
"check-date": True,
|
||||
"date-max-future": "1d",
|
||||
},
|
||||
pdiffs=True,
|
||||
description="InterDiode APT repository",
|
||||
)
|
||||
rendered = source.to_deb822()
|
||||
assert rendered.splitlines() == [ # nosec B101
|
||||
"Types: deb deb-src",
|
||||
"URIs: http://example.invalid/debian",
|
||||
"Suites: stable",
|
||||
"Components: main contrib",
|
||||
"Architectures: amd64",
|
||||
"Languages: en",
|
||||
"Targets: deb",
|
||||
"Signed-By: /etc/apt/keyrings/interdiode.asc",
|
||||
"Trusted: yes",
|
||||
"PDiffs: yes",
|
||||
"By-Hash: yes",
|
||||
"Allow-Insecure: no",
|
||||
"Allow-Weak: no",
|
||||
"Allow-Downgrade-To-Insecure: no",
|
||||
"Check-Valid-Until: yes",
|
||||
"Valid-Until-Min: 10",
|
||||
"Valid-Until-Max: 1w",
|
||||
"Check-Date: yes",
|
||||
"Date-Max-Future: 1d",
|
||||
"Description: InterDiode APT repository",
|
||||
"Enabled: no",
|
||||
]
|
||||
@@ -0,0 +1,85 @@
|
||||
import pytest
|
||||
|
||||
from id_configurator.config import Configuration
|
||||
from id_configurator.context import Context
|
||||
|
||||
CONFIG = Configuration.model_validate(
|
||||
{"uuid": "12345678-1234-5678-1234-567812345678", "organisation": "InterDiode"}
|
||||
)
|
||||
|
||||
|
||||
def make_context(tmp_path, with_src: bool = True) -> Context:
|
||||
dst = tmp_path / "dst"
|
||||
dst.mkdir()
|
||||
src = None
|
||||
if with_src:
|
||||
src = tmp_path / "src"
|
||||
src.mkdir()
|
||||
return Context(config=CONFIG, dst=dst, src=src)
|
||||
|
||||
|
||||
def test_dst_path_within_destination(tmp_path) -> None:
|
||||
context = make_context(tmp_path)
|
||||
resolved = context.dst_path("etc/foo.conf")
|
||||
assert resolved == context.dst / "etc" / "foo.conf" # nosec B101
|
||||
|
||||
|
||||
def test_dst_path_rejects_escape(tmp_path) -> None:
|
||||
context = make_context(tmp_path)
|
||||
with pytest.raises(ValueError, match="refusing to write outside"):
|
||||
context.dst_path("../escape.conf")
|
||||
|
||||
|
||||
def test_src_path_without_src(tmp_path) -> None:
|
||||
context = make_context(tmp_path, with_src=False)
|
||||
assert context.src_path("etc/foo.conf") is None # nosec B101
|
||||
|
||||
|
||||
def test_src_path_with_src(tmp_path) -> None:
|
||||
context = make_context(tmp_path)
|
||||
resolved = context.src_path("etc/foo.conf")
|
||||
assert resolved == context.src / "etc" / "foo.conf" # nosec B101
|
||||
|
||||
|
||||
def test_write_file_creates_parents_and_content(tmp_path) -> None:
|
||||
context = make_context(tmp_path)
|
||||
path = context.write_file("etc/nested/foo.conf", b"hello")
|
||||
assert path.read_bytes() == b"hello" # nosec B101
|
||||
assert path.stat().st_mode & 0o777 == 0o644 # nosec B101
|
||||
|
||||
|
||||
def test_read_src_file_without_src(tmp_path) -> None:
|
||||
context = make_context(tmp_path, with_src=False)
|
||||
assert context.read_src_file("etc/foo.conf") is None # nosec B101
|
||||
|
||||
|
||||
def test_read_src_file_missing(tmp_path) -> None:
|
||||
context = make_context(tmp_path)
|
||||
assert context.read_src_file("etc/missing.conf") is None # nosec B101
|
||||
|
||||
|
||||
def test_read_src_file_present(tmp_path) -> None:
|
||||
context = make_context(tmp_path)
|
||||
(context.src / "foo.conf").write_bytes(b"existing")
|
||||
assert context.read_src_file("foo.conf") == b"existing" # nosec B101
|
||||
|
||||
|
||||
def test_iter_src_dir_without_src(tmp_path) -> None:
|
||||
context = make_context(tmp_path, with_src=False)
|
||||
assert context.iter_src_dir("some/dir") == [] # nosec B101
|
||||
|
||||
|
||||
def test_iter_src_dir_missing_dir(tmp_path) -> None:
|
||||
context = make_context(tmp_path)
|
||||
assert context.iter_src_dir("missing-dir") == [] # nosec B101
|
||||
|
||||
|
||||
def test_iter_src_dir_lists_only_files(tmp_path) -> None:
|
||||
context = make_context(tmp_path)
|
||||
target = context.src / "certs"
|
||||
target.mkdir()
|
||||
(target / "a.crt").write_bytes(b"a")
|
||||
(target / "b.crt").write_bytes(b"b")
|
||||
(target / "subdir").mkdir()
|
||||
result = context.iter_src_dir("certs")
|
||||
assert [entry.name for entry in result] == ["a.crt", "b.crt"] # nosec B101
|
||||
@@ -0,0 +1,19 @@
|
||||
from id_configurator.modules import base as base_module
|
||||
from id_configurator.modules.base import Module, all_modules, register
|
||||
|
||||
|
||||
def test_register_and_all_modules_are_isolated(monkeypatch) -> None:
|
||||
monkeypatch.setattr(base_module, "_REGISTRY", [])
|
||||
|
||||
class DummyModule(Module):
|
||||
name = "dummy"
|
||||
|
||||
def is_relevant(self, context) -> bool:
|
||||
return True
|
||||
|
||||
def apply(self, context) -> None:
|
||||
pass
|
||||
|
||||
register(DummyModule)
|
||||
|
||||
assert all_modules() == [DummyModule] # nosec B101
|
||||
@@ -0,0 +1,20 @@
|
||||
import importlib
|
||||
import sys
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
|
||||
def test_package_exposes_app_and_main() -> None:
|
||||
import id_configurator
|
||||
|
||||
assert id_configurator.main is id_configurator.cli.main # nosec B101
|
||||
assert id_configurator.app is id_configurator.cli.app # nosec B101
|
||||
|
||||
|
||||
def test_dunder_main_module_does_not_launch_app_when_imported(monkeypatch) -> None:
|
||||
mock_app = MagicMock()
|
||||
monkeypatch.setattr("id_configurator.cli.app", mock_app)
|
||||
sys.modules.pop("id_configurator.__main__", None)
|
||||
|
||||
importlib.import_module("id_configurator.__main__")
|
||||
|
||||
mock_app.assert_not_called()
|
||||
Reference in New Issue
Block a user