Skip to content

Commit aaf14a9

Browse files
committed
test(fips): make the no-native POST tests genuinely backend-free under -S
The fail-closed tests copy the package, strip every .so, and assert import refuses crypto. Under an editable install (pip install -e ., as CI runs), setuptools registers a .pth meta-path finder that maps ama_cryptography.* — including the compiled Cython bindings — back to the developer build tree, so the subprocess resolves a working native backend even though the copy under test has none. The "no native backend" premise was silently false and the tests were passing for the wrong reason. Run those subprocesses with -S (skip site processing, so the .pth finder is never installed). The subprocess then sees only the stripped copy on PYTHONPATH and the stdlib — a genuinely backend-free tree, which is also what a real deployment without the C library looks like (the Cython bindings dynamically link libama_cryptography and cannot load without it). The core package imports with no third-party dependency (INVARIANT-1), so dropping site costs these subprocesses nothing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UvSmEE59hFdt3MJHGWzgCJ
1 parent 7cf9394 commit aaf14a9

1 file changed

Lines changed: 29 additions & 4 deletions

File tree

tests/test_post_failclosed.py

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,37 @@
6262

6363

6464
def _run_python(
65-
code: str, cwd: Path, env_extra: dict[str, str] | None = None
65+
code: str,
66+
cwd: Path,
67+
env_extra: dict[str, str] | None = None,
68+
*,
69+
isolated: bool = False,
6670
) -> subprocess.CompletedProcess[str]:
67-
"""Run ``code`` in a fresh interpreter rooted at ``cwd``."""
71+
"""Run ``code`` in a fresh interpreter rooted at ``cwd``.
72+
73+
``isolated=True`` adds ``-S`` (do not import ``site``). The no-native tests
74+
need it. When this test suite runs against an *editable* install
75+
(``pip install -e .``, as CI does), setuptools registers a meta-path finder
76+
via a ``.pth`` file that maps ``ama_cryptography.*`` — including the compiled
77+
Cython bindings — back to the developer's build tree. That finder resolves
78+
``ama_cryptography.sha3_binding`` even when the copy under ``cwd`` has had
79+
every ``.so`` removed, so ``native_sha3_256`` finds a working Cython backend
80+
and the "no native backend" premise is silently false. ``-S`` skips
81+
``.pth`` processing, so the subprocess sees only the copy on ``PYTHONPATH``
82+
(still honoured under ``-S``) and the stdlib — a genuinely backend-free tree,
83+
which is also what a real deployment without the C library looks like (the
84+
Cython bindings dynamically link ``libama_cryptography`` and cannot load
85+
without it). The core package imports with no third-party dependency
86+
(INVARIANT-1), so dropping ``site`` costs these subprocesses nothing.
87+
"""
6888
env = dict(os.environ)
6989
env.pop("PYTHONPATH", None)
7090
# An installed copy of the package would shadow the tree under test.
7191
env["PYTHONPATH"] = str(cwd)
7292
env.update(env_extra or {})
93+
argv = [sys.executable, "-S", "-c"] if isolated else [sys.executable, "-c"]
7394
return subprocess.run(
74-
[sys.executable, "-c", textwrap.dedent(code)],
95+
[*argv, textwrap.dedent(code)],
7596
cwd=str(cwd),
7697
env=env,
7798
capture_output=True,
@@ -126,6 +147,7 @@ def test_missing_native_backend_makes_import_raise(self, tree_without_native: Pa
126147
print("verified")
127148
""",
128149
cwd=tree_without_native,
150+
isolated=True,
129151
)
130152

131153
assert result.returncode != 0, (
@@ -143,7 +165,7 @@ def test_failure_message_names_the_real_cause(self, tree_without_native: Path) -
143165
``native Ed25519 not built`` was a claim about the C build, and it was
144166
usually false: the library was built and simply not on the search path.
145167
"""
146-
result = _run_python("import ama_cryptography", cwd=tree_without_native)
168+
result = _run_python("import ama_cryptography", cwd=tree_without_native, isolated=True)
147169

148170
combined = result.stdout + result.stderr
149171
assert "no native library found" in combined
@@ -189,6 +211,7 @@ def test_diagnostic_flag_permits_import_but_not_crypto(self, tree_without_native
189211
raise AssertionError("crypto ran in the ERROR state")
190212
""",
191213
cwd=tree_without_native,
214+
isolated=True,
192215
env_extra={"AMA_POST_DIAGNOSTIC_IMPORT": "1"},
193216
)
194217
assert result.returncode == 0, result.stdout + result.stderr
@@ -914,6 +937,7 @@ def test_no_backend_fails_post_rather_than_skipping(self, tree_without_native: P
914937
import ama_cryptography # noqa: F401
915938
""",
916939
cwd=tree_without_native,
940+
isolated=True,
917941
env_extra={"AMA_POST_DIAGNOSTIC_IMPORT": "1"},
918942
)
919943
assert result.returncode == 0, result.stderr
@@ -942,6 +966,7 @@ def test_docs_build_override_is_honoured(self, tree_without_native: Path) -> Non
942966
raise AssertionError("crypto ran under the docs override")
943967
""",
944968
cwd=tree_without_native,
969+
isolated=True,
945970
env_extra={"AMA_SPHINX_BUILD": "1"},
946971
)
947972
assert result.returncode == 0, result.stdout + result.stderr

0 commit comments

Comments
 (0)