File: test_runner_softhsm2.py

package info (click to toggle)
python-pkcs11 0.7.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 804 kB
  • sloc: python: 3,844; ansic: 1,981; sh: 33; makefile: 24
file content (122 lines) | stat: -rw-r--r-- 3,463 bytes parent folder | download
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
#!/usr/bin/env python3
"""Test runner for python-pkcs11.

This program sets up a test environment for python-pkcs11, utilizing SoftHSM 2
with a custom config and state file in a temporary directory, executes the test
suite, and then cleans up after itself.

It reuses the logic from the project's Travis configuration.

Copyright (c) 2023 Faidon Liambotis <paravoid@debian.org>
License: MIT
"""

import contextlib
import os
import pathlib
import subprocess
import sys
import tempfile
import textwrap
import typing
import unittest

try:
    import pytest

    WITH_PYTEST = True
except ImportError:
    WITH_PYTEST = False


@contextlib.contextmanager
def softhsm_testenv(base_dir: str | None = None) -> typing.Generator[None, None, None]:
    """Context manager to execute a piece of code in a softhsm2 environment.

    Executes with a temporary config file and state directory, as to not affect
    the system copy.
    """

    tmpdir = tempfile.TemporaryDirectory(prefix="pkcs11-testenv.", dir=base_dir)
    tmpdir_path = pathlib.Path(tmpdir.name)

    print(f"Creating temporary directory for SoftHSM 2: {tmpdir_path}")

    softhsm_token_dir = tmpdir_path / "softhsm2"
    softhsm_token_dir.mkdir()

    softhsm_config = tmpdir_path / "softhsm2.conf"
    softhsm_config.write_text(
        textwrap.dedent(
            f"""
            directories.tokendir = {softhsm_token_dir}
            objectstore.backend = file
            log.level = INFO
            """
        )
    )

    # Inject variables to the subprocess & unittest environment
    # softhsm2 expects SOFTHSM2_CONF, while the unit tests expect PKCS11_*
    os.environ["SOFTHSM2_CONF"] = str(softhsm_config)
    os.environ["PKCS11_MODULE"] = "/usr/lib/softhsm/libsofthsm2.so"
    os.environ["PKCS11_TOKEN_LABEL"] = "TEST"
    os.environ["PKCS11_TOKEN_PIN"] = "1234"
    os.environ["PKCS11_TOKEN_SO_PIN"] = "5678"

    # Initialize a new token
    print("Initializing a new token with softhsm2-util")
    sys.stdout.flush()
    subprocess.run(
        [
            "softhsm2-util",
            "--init-token",
            "--free",
            "--label",
            os.environ["PKCS11_TOKEN_LABEL"],
            "--pin",
            os.environ["PKCS11_TOKEN_PIN"],
            "--so-pin",
            os.environ["PKCS11_TOKEN_SO_PIN"],
        ],
        check=True,
    )

    print("Running in the test environment...")
    sys.stdout.flush()
    yield
    sys.stdout.flush()
    print("Done")

    # Delete the token. This is not necessary since we nuke the directory
    # anyway, but acts as an additional safeguard that SoftHSM still works
    print("Deleting the token from SoftHSM 2")
    sys.stdout.flush()
    subprocess.run(
        [
            "softhsm2-util",
            "--delete-token",
            "--token",
            os.environ["PKCS11_TOKEN_LABEL"],
        ],
        check=True,
    )

    # Cleanup the tmpdir (the garbage collector would do this anyway)
    print(f"Removing temporary directory {tmpdir_path}")
    tmpdir.cleanup()


def run_testsuite_with_softhsm() -> int:
    """Execute the testsuite with the SoftHSM as the module."""

    with softhsm_testenv(base_dir="tests"):
        if WITH_PYTEST:
            return pytest.main()
        else:
            testprogram = unittest.main(module=None, verbosity=1, exit=False)
            return not testprogram.result.wasSuccessful()


if __name__ == "__main__":
    sys.exit(run_testsuite_with_softhsm())