diff --git a/.buildbot/ubuntu/Dockerfile b/.buildbot/ubuntu/Dockerfile index e9ab2d2..803ecbc 100644 --- a/.buildbot/ubuntu/Dockerfile +++ b/.buildbot/ubuntu/Dockerfile @@ -1,16 +1,21 @@ -FROM ubuntu:focal +FROM ubuntu:jammy RUN apt-get update RUN apt-get install -yq software-properties-common -RUN apt-add-repository ppa:purplei2p/i2pd -RUN apt-get update +RUN apt-add-repository ppa:purplei2p/i2pd && apt-get update -qq RUN apt-get install -yq --no-install-suggests --no-install-recommends \ - python3-dev python3-pip python3.9 python3.9-dev python3.9-venv sudo i2pd + python3-dev python3-pip python-is-python3 python3.11-dev python3.11-venv + +RUN apt-get install -yq --no-install-suggests --no-install-recommends sudo i2pd RUN echo 'builder ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers -RUN python3.9 -m pip install setuptools wheel -RUN python3.9 -m pip install --upgrade pip tox virtualenv +RUN pip install setuptools wheel +RUN pip install --upgrade pip tox virtualenv + +ADD . . + +CMD .buildbot/ubuntu/test.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..5a43d7e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +.git +.tox +dist diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2399077..71a97bb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,44 +1,20 @@ -name: Blind Test - -on: push +name: Testing +on: [push] jobs: default: - - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, macos-latest] - python-version: [3.8] - include: - - os: ubuntu-latest - python-version: 3.9 - + runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install python dependencies - run: | - python -m pip install --upgrade pip - pip install wheel - pip install bandit flake8 pylint - pip install -r requirements.txt - python setup.py install - - name: Lint - if: ${{ matrix.os == 'ubuntu-latest' && matrix.python-version == '3.8' }} - run: | - # stop the build if there are Python syntax errors or undefined names - flake8 minode --count --select=E9,F63,F7,F82 --show-source --statistics - flake8 minode --count --statistics - pylint minode --exit-zero --rcfile=tox.ini - bandit -r --exit-zero -x tests minode - - name: Test - run: | - export PYTHONWARNINGS=all - coverage run -a -m tests - - name: Summary - run: coverage report + - name: Install dependencies + run: | + apt-get update + apt-get install -yq --no-install-suggests --no-install-recommends \ + python3-dev python3-pip python3-venv python-is-python3 + pip install setuptools wheel + pip install --upgrade pip tox virtualenv + - name: Check out repository code + uses: actions/checkout@v3 + - name: Quick lint + run: tox -e lint-basic + - name: Run tests + run: tox diff --git a/README.md b/README.md index f7fd2f6..465cc2b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # MiNode -[![Quick Test](https://github.com/g1itch/MiNode/actions/workflows/test.yml/badge.svg)](https://github.com/g1itch/MiNode/actions/workflows/test.yml) +[![Testing](https://git.bitmessage.org/Bitmessage/MiNode/actions/workflows/test.yml/badge.svg)](https://git.bitmessage.org/Bitmessage/MiNode/actions?workflow=test.yml) Python 3 implementation of the Bitmessage protocol. Designed only to route objects inside the network. diff --git a/minode/connection.py b/minode/connection.py index 8c921a3..c74af5d 100644 --- a/minode/connection.py +++ b/minode/connection.py @@ -207,6 +207,13 @@ class Connection(threading.Thread): context.options = ( ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_SINGLE_ECDH_USE | ssl.OP_CIPHER_SERVER_PREFERENCE) + # OP_NO_SSL* is deprecated since 3.6 + try: + # TODO: ssl.TLSVersion.TLSv1 is deprecated + context.minimum_version = ssl.TLSVersion.TLSv1 + context.maximum_version = ssl.TLSVersion.TLSv1_2 + except AttributeError: + pass self.s = context.wrap_socket( self.s, server_side=self.server, do_handshake_on_connect=False) @@ -224,11 +231,14 @@ class Connection(threading.Thread): 'Disconnecting from %s:%s. Reason: %s', self.host_print, self.port, e) self.status = 'disconnecting' - break + if isinstance(e, ssl.SSLError): # pylint: disable=no-member + logging.debug('ssl.SSLError reason: %s', e.reason) + shared.node_pool.discard((self.host, self.port)) + return self.tls = True logging.debug( - 'Established TLS connection with %s:%s', - self.host_print, self.port) + 'Established TLS connection with %s:%s (%s)', + self.host_print, self.port, self.s.version()) def _send_message(self, m): if isinstance(m, message.Message) and m.command == b'object': @@ -256,11 +266,11 @@ class Connection(threading.Thread): if len(shared.node_pool) > 10: addr.update({ structure.NetAddr(1, a[0], a[1]) - for a in random.sample(shared.node_pool, 10)}) + for a in random.sample(tuple(shared.node_pool), 10)}) if len(shared.unchecked_node_pool) > 10: addr.update({ structure.NetAddr(1, a[0], a[1]) - for a in random.sample(shared.unchecked_node_pool, 10)}) + for a in random.sample(tuple(shared.unchecked_node_pool), 10)}) if len(addr) != 0: self.send_queue.put(message.Addr(addr)) @@ -274,7 +284,7 @@ class Connection(threading.Thread): # We limit size of inv messaged to 10000 entries # because they might time out # in very slow networks (I2P) - pack = random.sample(to_send, 10000) + pack = random.sample(tuple(to_send), 10000) self.send_queue.put(message.Inv(pack)) to_send.difference_update(pack) else: @@ -446,7 +456,7 @@ class Connection(threading.Thread): logging.info( 'Queued %s vectors to get', len(self.vectors_to_get)) if len(self.vectors_to_get) > 64: - pack = random.sample(self.vectors_to_get, 64) + pack = random.sample(tuple(self.vectors_to_get), 64) self.send_queue.put(message.GetData(pack)) self.vectors_requested.update({ vector: time.time() for vector in pack @@ -476,7 +486,7 @@ class Connection(threading.Thread): logging.info( 'Preparing to send %s objects', len(self.vectors_to_send)) if len(self.vectors_to_send) > 16: - to_send = random.sample(self.vectors_to_send, 16) + to_send = random.sample(tuple(self.vectors_to_send), 16) self.vectors_to_send.difference_update(to_send) else: to_send = self.vectors_to_send.copy() diff --git a/minode/manager.py b/minode/manager.py index 3ff5f00..93a3f30 100644 --- a/minode/manager.py +++ b/minode/manager.py @@ -98,24 +98,26 @@ class Manager(threading.Thread): if shared.ip_enabled: if len(shared.unchecked_node_pool) > 16: to_connect.update(random.sample( - shared.unchecked_node_pool, 16)) + tuple(shared.unchecked_node_pool), 16)) else: to_connect.update(shared.unchecked_node_pool) shared.unchecked_node_pool.difference_update(to_connect) if len(shared.node_pool) > 8: - to_connect.update(random.sample(shared.node_pool, 8)) + to_connect.update(random.sample( + tuple(shared.node_pool), 8)) else: to_connect.update(shared.node_pool) if shared.i2p_enabled: if len(shared.i2p_unchecked_node_pool) > 16: - to_connect.update( - random.sample(shared.i2p_unchecked_node_pool, 16)) + to_connect.update(random.sample( + tuple(shared.i2p_unchecked_node_pool), 16)) else: to_connect.update(shared.i2p_unchecked_node_pool) shared.i2p_unchecked_node_pool.difference_update(to_connect) if len(shared.i2p_node_pool) > 8: - to_connect.update(random.sample(shared.i2p_node_pool, 8)) + to_connect.update(random.sample( + tuple(shared.i2p_node_pool), 8)) else: to_connect.update(shared.i2p_node_pool) @@ -214,17 +216,18 @@ class Manager(threading.Thread): @staticmethod def pickle_nodes(): if len(shared.node_pool) > 10000: - shared.node_pool = set(random.sample(shared.node_pool, 10000)) + shared.node_pool = set(random.sample( + tuple(shared.node_pool), 10000)) if len(shared.unchecked_node_pool) > 1000: - shared.unchecked_node_pool = set( - random.sample(shared.unchecked_node_pool, 1000)) + shared.unchecked_node_pool = set(random.sample( + tuple(shared.unchecked_node_pool), 1000)) if len(shared.i2p_node_pool) > 1000: - shared.i2p_node_pool = set( - random.sample(shared.i2p_node_pool, 1000)) + shared.i2p_node_pool = set(random.sample( + tuple(shared.i2p_node_pool), 1000)) if len(shared.i2p_unchecked_node_pool) > 100: - shared.i2p_unchecked_node_pool = set( - random.sample(shared.i2p_unchecked_node_pool, 100)) + shared.i2p_unchecked_node_pool = set(random.sample( + tuple(shared.i2p_unchecked_node_pool), 100)) try: with open( diff --git a/minode/tests/test_process.py b/minode/tests/test_process.py index a576644..b6c0b7e 100644 --- a/minode/tests/test_process.py +++ b/minode/tests/test_process.py @@ -69,12 +69,15 @@ class TestProcessProto(unittest.TestCase): class TestProcessShutdown(TestProcessProto): """Separate test case for SIGTERM""" + _wait_time = 30 + # longer wait time because it's not a benchmark + def test_shutdown(self): """Send to minode SIGTERM and ensure it stopped""" - # longer wait time because it's not a benchmark self.assertTrue( - self._stop_process(20), - '%s has not stopped in 20 sec' % ' '.join(self._process_cmd)) + self._stop_process(self._wait_time), + '%s has not stopped in %i sec' % ( + ' '.join(self._process_cmd), self._wait_time)) class TestProcess(TestProcessProto): @@ -105,8 +108,8 @@ class TestProcess(TestProcessProto): time.sleep(0.5) else: self.fail( - 'Failed establish at least %s connections in %s sec' - % (self._connection_limit / 2, self._wait_time)) + 'Failed establish at least %i connections in %s sec' + % (int(self._connection_limit / 2), self._wait_time)) if self._check_limit: continue_check_limit(_time_to_connect) @@ -128,7 +131,6 @@ class TestProcessI2P(TestProcess): """Test minode process with --i2p and no IP""" _process_cmd = ['minode', '--i2p', '--no-ip'] _connection_limit = 4 - _wait_time = 120 _listen = True _listening_port = 8448 diff --git a/tox.ini b/tox.ini index caeb4c6..6843306 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = reset,py{36,37,38,39,310},stats +envlist = reset,py3{6,7,8,9,10,11},stats skip_missing_interpreters = true [testenv]