diff --git a/.audit/oberstet_fix_1278.md b/.audit/oberstet_fix_1278.md new file mode 100644 index 000000000..a8b4c26ea --- /dev/null +++ b/.audit/oberstet_fix_1278.md @@ -0,0 +1,8 @@ +- [ ] I did **not** use any AI-assistance tools to help create this pull request. +- [x] I **did** use AI-assistance tools to *help* create this pull request. +- [x] I have read, understood and followed the project's AI_POLICY.md when creating code, documentation etc. for this pull request. + +Submitted by: @oberstet +Date: 2026-10-18 +Related issue(s): #1278 +Branch: oberstet:fix_1278 diff --git a/docs/changelog.rst b/docs/changelog.rst index e1b67d848..937a4ad5e 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -20,6 +20,7 @@ Changelog * Run the unit tests (Twisted/trial and asyncio/pytest) in CI on every supported Python: CPython 3.11–3.14 and PyPy 3.11, instead of on CPython 3.14 only, and with all four compression extensions installed (``python-snappy`` is added to the ``dev`` extra; ``just check-compressors`` verifies all four are available) (#1986) * Adopt the contribution workflow shared by all WAMP projects: ``CONTRIBUTING.md``, the pull request template and ``.audit/README.md`` are now deployed byte-identically from wamp-cicd (GitHub issue first, red → green tests, AI-assistance disclosure) and kept in sync by a CI drift check; everything specific to Autobahn|Python moved to a new ``DEVELOPMENT.md`` (also included in the docs). ``.cicd`` is pinned to wamp-cicd ``38ded6a``, the same commit across the WAMP fleet (#1956) +* Remove the opt-in entropy depletion tests (``autobahn/test/test_rng.py``, enabled by ``AUTOBAHN_CI_ENABLE_RNG_DEPLETION_TESTS``, never run in CI): they read ``/proc/sys/kernel/random/entropy_avail``, which has been a constant 256 since Linux 5.18, and ``/dev/random`` no longer blocks since Linux 5.6, so one test passed whatever happened and the other always failed (#1278) * Add an ``import-smoke-lowest`` CI job (``just test-imports-lowest``) that runs the import smoke test on CPython 3.11 with every direct dependency resolved to the lowest version ``pyproject.toml`` allows (``uv --resolution lowest-direct``), so stale version floors are caught. The import smoke test now also covers the Twisted and asyncio bindings, each module imported in a fresh interpreter (#1955) **asyncio** diff --git a/justfile b/justfile index 7882db5b3..bf9e5b883 100644 --- a/justfile +++ b/justfile @@ -1280,11 +1280,6 @@ test-twisted venv="" use_nvx="": (install-tools venv) (install-dev venv) # IMPORTANT: Twisted trial doesn't allow to recurse-and-exclude, and hence we # need this looong explicit list of tests to run because we must exclude "asyncio" - # - # AUTOBAHN_CI_ENABLE_RNG_DEPLETION_TESTS=1: - # This enables "autobahn/test/test_rng.py" (on Linux), which tests entropy depletion, - # and tests how to correctly read _real_ entropy and block if not enough _real_ entropy - # is currently available (see: https://github.com/crossbario/autobahn-python/issues/1275) USE_TWISTED=1 ${VENV_PYTHON} -m twisted.trial --no-recurse \ autobahn.test \ diff --git a/src/autobahn/test/test_rng.py b/src/autobahn/test/test_rng.py deleted file mode 100644 index 31025ef7b..000000000 --- a/src/autobahn/test/test_rng.py +++ /dev/null @@ -1,117 +0,0 @@ -############################################################################### -# -# The MIT License (MIT) -# -# Copyright (c) typedef int GmbH -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -############################################################################### - -import os -import random -import sys -import unittest -import uuid - -from nacl import public, utils - -from autobahn import util - - -@unittest.skipIf( - not ( - "AUTOBAHN_CI_ENABLE_RNG_DEPLETION_TESTS" in os.environ - and os.environ["AUTOBAHN_CI_ENABLE_RNG_DEPLETION_TESTS"] - ), - "entropy depletion tests not enabled (env var AUTOBAHN_CI_ENABLE_RNG_DEPLETION_TESTS not set)", -) -@unittest.skipIf( - not sys.platform.startswith("linux"), - "entropy depletion tests only available on Linux", -) -class TestEntropy(unittest.TestCase): - def test_non_depleting(self): - res = {} - - with open("/dev/urandom", "rb") as rng: - for i in range(1000): - for j in range(100): - # "reseed" (seems pointless, but ..) - random.seed() - - # random UUIDs - v1 = uuid.uuid4() # noqa - - # stdlib random - v2 = random.random() # noqa - v3 = random.getrandbits(32) # noqa - v4 = random.randint(0, 9007199254740992) # noqa - v5 = random.normalvariate(10, 100) # noqa - v6 = random.choice(range(100)) # noqa - - # PyNaCl - v7 = utils.random(public.Box.NONCE_SIZE) # noqa - - # Autobahn utils - v8 = util.generate_token(4, 4) # noqa - v9 = util.id() # noqa - v10 = util.rid() # noqa - v11 = util.newid() # noqa - - # direct procfs access to PRNG - d = rng.read(1000) # noqa - - # check available entropy - with open("/proc/sys/kernel/random/entropy_avail") as ent: - ea = int(ent.read()) // 100 - if ea not in res: - res[ea] = 0 - res[ea] += 1 - - skeys = sorted(res.keys()) - - print("\nsystem entropy depletion stats:") - for k in skeys: - print(f"{k}: {res[k]}") - - self.assertTrue(skeys[0] > 0) - - def test_depleting(self): - res = {} - - with open("/dev/random", "rb") as rng: - for i in range(10000): - # direct procfs access to "real" RNG - d = rng.read(1000) # noqa - - # check available entropy - with open("/proc/sys/kernel/random/entropy_avail") as ent: - ea = int(ent.read()) // 100 - if ea not in res: - res[ea] = 0 - res[ea] += 1 - - skeys = sorted(res.keys()) - - print("\nsystem entropy depletion stats:") - for k in skeys: - print(f"{k}: {res[k]}") - - self.assertTrue(skeys[0] == 0)