import pytest
pkcs11 = pytest.importorskip(
"synta.pkcs11",
reason="synta built without pkcs11-mgmt feature",
)
def test_module_has_expected_names():
assert hasattr(pkcs11, "SlotInfo")
assert hasattr(pkcs11, "KeyInfo")
assert hasattr(pkcs11, "Pkcs11Token")
assert hasattr(pkcs11, "list_slots")
def test_all_lists_public_names():
all_ = pkcs11.__all__
for name in ("SlotInfo", "KeyInfo", "Pkcs11Token", "list_slots"):
assert name in all_, f"{name!r} missing from __all__"
def test_rejects_non_pkcs11_uri():
with pytest.raises(ValueError, match="invalid PKCS#11 URI"):
pkcs11.Pkcs11Token("file:///tmp/key.pem")
def test_rejects_empty_string():
with pytest.raises((ValueError, Exception)):
pkcs11.Pkcs11Token("")
def test_rejects_http_uri():
with pytest.raises((ValueError, Exception)):
pkcs11.Pkcs11Token("https://example.com/token")
def _make_token_repr(uri: str) -> str:
try:
tok = pkcs11.Pkcs11Token(uri)
return repr(tok)
except ValueError as e:
msg = str(e)
if "module" in msg.lower() or "pkcs11" in msg.lower():
pytest.skip(f"no PKCS#11 module available: {e}")
raise
def test_repr_redacts_pin_value():
r = _make_token_repr("pkcs11:token=T;object=k?pin-value=s3cr3t")
assert "s3cr3t" not in r, f"PIN leaked in repr: {r!r}"
assert "***" in r
def test_repr_no_pin_unchanged():
r = _make_token_repr("pkcs11:token=T;object=k")
assert "***" not in r
def test_repr_multi_query_pin_redacted():
r = _make_token_repr("pkcs11:token=T?pin-value=abc&foo=bar")
assert "abc" not in r, f"PIN leaked: {r!r}"
assert "foo=bar" not in r or "***" in r
def test_slot_info_repr_format():
assert callable(pkcs11.SlotInfo)
def test_key_info_repr_format():
assert callable(pkcs11.KeyInfo)
def test_list_slots_bad_module_raises():
with pytest.raises((ValueError, OSError, Exception)):
pkcs11.list_slots(module="/nonexistent/path/token.so")
def test_list_slots_relative_module_raises():
with pytest.raises((ValueError, Exception)):
pkcs11.list_slots(module="relative/path.so")