Changeset - 7a8c83185a93
[Not reviewed]
0 14 0
Branko Majic (branko) - 2 months ago 2024-02-23 18:01:51
branko@majic.rs
GC-45: Drop support for Python 3.5, 3.6, and 3.7:

- Updated documentation, removing references to versions as being
supported.
- Switched the Vagrant test machine to Debian Bullseye (still in LTS
support) to match the main development environment.
- Updated functional tests for output changes in OpenSSL CLI from
Debian Bullseye.
- Updated Tox configuration and instructions.
- Dropped workaround for Python 3.5.
- Updated package requirements.
- Updated release notes.
11 files changed:
0 comments (0 inline, 0 general)
README.rst
Show inline comments
 
@@ -26,17 +26,14 @@ The tool is useful for issuing certificates in:
 
  tests to use certificates in order to ensure the tests are run
 
  properly and in full.
 

	
 
At time of this writing, Gimmecert is compatible with the following
 
Python versions:
 

	
 
- *Python 3.5*
 
- *Python 3.6*
 
- *Python 3.7*
 
- *Python 3.8*
 
- *Python 3.8*
 
- *Python 3.9*
 

	
 

	
 
Why was this tool created?
 
--------------------------
 

	
 
The tool was created to remove the pain of setting-up a CA hierarchy,
Vagrantfile
Show inline comments
 
@@ -3,11 +3,11 @@
 

	
 
# All Vagrant configuration is done below. The "2" in Vagrant.configure
 
# configures the configuration version (we support older styles for
 
# backwards compatibility). Please don't change it unless you know what
 
# you're doing.
 
Vagrant.configure("2") do |config|
 
  config.vm.box = "debian/contrib-stretch64"
 
  config.vm.box = "debian/bullseye64"
 
  config.vm.hostname = "gimmecert-testing"
 

	
 
  config.vm.provision "shell", path: "provision.sh"
 
end
docs/development.rst
Show inline comments
 
@@ -25,13 +25,13 @@ set-up. The process outlined here is centered around
 
<https://virtualenvwrapper.readthedocs.io/>`_. Instructions have been
 
tailored for a GNU/Linux system.
 

	
 
Before proceeding, ensure you have the following system-wide packages
 
installed:
 

	
 
- `Python, version 3.5+ <https://www.python.org/>`_.
 
- `Python, version 3.8+ <https://www.python.org/>`_.
 
- `virtualenvwrapper <https://virtualenvwrapper.readthedocs.io/>`_.
 

	
 
With those in place, do the following:
 

	
 
1. Clone the git repository::
 

	
 
@@ -128,13 +128,13 @@ Tests can also be run using `tox <https://tox.readthedocs.io/>`_:
 
  tox
 

	
 
  # List available tox environments.
 
  tox -l
 

	
 
  # Run tests against specific Python version.
 
  tox -e py35
 
  tox -e py38
 

	
 
  # Run documentation and linting tests only.
 
  tox -e doc,lint
 

	
 

	
 
Running tests on all supproted Python versions
docs/installation.rst
Show inline comments
 
@@ -11,13 +11,13 @@
 
Installation
 
============
 

	
 
Gimmecert can be easily installed using ``pip``. Before installing it,
 
make sure the following requirements have been met:
 

	
 
- You are running *Python 3.5+*.
 
- You are running *Python 3.8+*.
 

	
 
In order to install latest stable release of *Gimmecert* using *pip*, run the
 
following command::
 

	
 
  pip install gimmecert
 

	
docs/releasenotes.rst
Show inline comments
 
@@ -2,12 +2,26 @@ Release notes
 
=============
 

	
 

	
 
NEXT RELEASE
 
------------
 

	
 
.. warning::
 

	
 
   This release contains the following breaking changes:
 

	
 
   - Support for Python 3.5, 3.6, and 3.7 has been dropped. Make sure
 
     that you are using one of the supported Python versions prior to
 
     upgrading *Gimmecert*.
 

	
 
Resolves issues:
 

	
 
- **Tasks**:
 

	
 
  - `GC-45: Drop support for Python 3.5, Python 3.6, and Python 3.7 <https://projects.majic.rs/gimmecert/issues/GC-45>`_
 

	
 

	
 
0.5.0
 
-----
 

	
 
This release adds support for Python 3.9, and updates the package
 
requirements.
functional_tests/base.py
Show inline comments
 
@@ -17,13 +17,12 @@
 
# You should have received a copy of the GNU General Public License along with
 
# Gimmecert.  If not, see <http://www.gnu.org/licenses/>.
 
#
 

	
 

	
 
import io
 
import os
 
import subprocess
 

	
 
import pexpect
 

	
 

	
 
def run_command(command, *args):
 
@@ -44,29 +43,13 @@ def run_command(command, *args):
 
    :rtype: (str, str, int)
 
    """
 

	
 
    invocation = [command]
 
    invocation.extend(args)
 

	
 
    # @TODO: Workaround for masking the Python 3.5 deprecation warning
 
    #        from the Cryptography package.
 
    #
 
    #        This is required in order to continue running functional
 
    #        tests against Python 3.5 since we extensively take
 
    #        advantage of checking the standard error output.
 
    #
 
    #        In case of unit tests it is a non-issue because Pytest
 
    #        will wrap around the deprecation warning, showing them
 
    #        only once (and thus preventing them from affecting the
 
    #        actual test code). However, in case of subprocess
 
    #        invocation, Pytest is unable to provide similar
 
    #        capability.
 
    env = os.environ
 
    env["PYTHONWARNINGS"] = "ignore:Python 3.5 support will be dropped in the next release of cryptography. Please upgrade your Python."
 

	
 
    process = subprocess.Popen(invocation, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
 
    process = subprocess.Popen(invocation, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
 
    stdout, stderr = process.communicate()
 
    stdout, stderr = stdout.decode(), stderr.decode()
 

	
 
    return stdout, stderr, process.returncode
 

	
 

	
 
@@ -99,28 +82,12 @@ def run_interactive_command(prompt_answers, command, *args):
 
    :rtype: (str or None, str, int)
 
    """
 

	
 
    # Assume that all prompts/answers worked as expected.
 
    failure = None
 

	
 
    # @TODO: Workaround for masking the Python 3.5 deprecation warning
 
    #        from the Cryptography package.
 
    #
 
    #        This is required in order to continue running functional
 
    #        tests against Python 3.5 since we extensively take
 
    #        advantage of checking the standard error output.
 
    #
 
    #        In case of unit tests it is a non-issue because Pytest
 
    #        will wrap around the deprecation warning, showing them
 
    #        only once (and thus preventing them from affecting the
 
    #        actual test code). However, in case of subprocess
 
    #        invocation, Pytest is unable to provide similar
 
    #        capability.
 
    env = os.environ
 
    env["PYTHONWARNINGS"] = "ignore:Python 3.5 support will be dropped in the next release of cryptography. Please upgrade your Python."
 

	
 
    # Spawn the process, use dedicated stream for capturin command
 
    # stdout/stderr.
 
    output_stream = io.StringIO()
 
    send_stream = io.StringIO()
 
    process = pexpect.spawnu(command, list(args), timeout=4)
 
    process.logfile_read = output_stream
functional_tests/test_client.py
Show inline comments
 
@@ -85,13 +85,13 @@ def test_client_command_issues_client_certificate(tmpdir):
 
    stdout, stderr, exit_code = run_command('openssl', 'rsa', '-noout', '-text', '-in', '.gimmecert/client/myclient.key.pem')
 

	
 
    # No errors are reported, and John is able to see some details
 
    # about the generated key.
 
    assert exit_code == 0
 
    assert stderr == ""
 
    assert "Private-Key: (2048 bit)" in stdout
 
    assert "Private-Key: (2048 bit, 2 primes)" in stdout
 

	
 
    # John then has a look at the generated certificate file.
 
    stdout, stderr, exit_code = run_command('openssl', 'x509', '-noout', '-text', '-in', '.gimmecert/client/myclient.cert.pem')
 

	
 
    # Once again, there are no errors, and he can see some details
 
    # about the certificate.
functional_tests/test_init.py
Show inline comments
 
@@ -70,13 +70,13 @@ def test_initialisation_on_fresh_directory(tmpdir):
 
    stdout, stderr, exit_code = run_command('openssl', 'rsa', '-noout', '-text', '-in', '.gimmecert/ca/level1.key.pem')
 

	
 
    # No errors are reported, and John is able ot see some details
 
    # about the generated key.
 
    assert exit_code == 0
 
    assert stderr == ""
 
    assert "Private-Key: (2048 bit)" in stdout
 
    assert "Private-Key: (2048 bit, 2 primes)" in stdout
 

	
 
    # John then has a look at the generated certificate file.
 
    stdout, stderr, exit_code = run_command('openssl', 'x509', '-noout', '-text', '-in', '.gimmecert/ca/level1.cert.pem')
 

	
 
    # With no errors again, he can see some of the details in
 
    # certificate.
 
@@ -206,21 +206,21 @@ def test_initialisation_with_custom_hierarchy_depth(tmpdir):
 
    stdout1, stderr1, exit_code1 = run_command('openssl', 'rsa', '-noout', '-text', '-in', '.gimmecert/ca/level1.key.pem')
 
    stdout2, stderr2, exit_code2 = run_command('openssl', 'rsa', '-noout', '-text', '-in', '.gimmecert/ca/level2.key.pem')
 
    stdout3, stderr3, exit_code3 = run_command('openssl', 'rsa', '-noout', '-text', '-in', '.gimmecert/ca/level3.key.pem')
 

	
 
    assert exit_code1 == 0
 
    assert stderr1 == ""
 
    assert "Private-Key: (2048 bit)" in stdout1
 
    assert "Private-Key: (2048 bit, 2 primes)" in stdout1
 

	
 
    assert exit_code2 == 0
 
    assert stderr2 == ""
 
    assert "Private-Key: (2048 bit)" in stdout2
 
    assert "Private-Key: (2048 bit, 2 primes)" in stdout2
 

	
 
    assert exit_code3 == 0
 
    assert stderr3 == ""
 
    assert "Private-Key: (2048 bit)" in stdout3
 
    assert "Private-Key: (2048 bit, 2 primes)" in stdout3
 

	
 
    # John then has a look at the generated CA certificate files.
 
    stdout1, stderr1, exit_code1 = run_command('openssl', 'x509', '-noout', '-text', '-in', '.gimmecert/ca/level1.cert.pem')
 
    stdout2, stderr2, exit_code2 = run_command('openssl', 'x509', '-noout', '-text', '-in', '.gimmecert/ca/level2.cert.pem')
 
    stdout3, stderr3, exit_code3 = run_command('openssl', 'x509', '-noout', '-text', '-in', '.gimmecert/ca/level3.cert.pem')
 

	
functional_tests/test_key_specification.py
Show inline comments
 
@@ -148,13 +148,13 @@ def test_initialisation_with_rsa_private_key_specification(tmpdir):
 
    # John goes ahead and inspects the CA private key to ensure his
 
    # private key specification has been accepted.
 
    stdout, stderr, exit_code = run_command('openssl', 'rsa', '-noout', '-text', '-in', '.gimmecert/ca/level1.key.pem')
 

	
 
    assert exit_code == 0
 
    assert stderr == ""
 
    assert "Private-Key: (4096 bit)" in stdout
 
    assert "Private-Key: (4096 bit, 2 primes)" in stdout
 

	
 
    # John also does a quick check on the generated certificate's
 
    # signing and public key algorithm.
 
    stdout, stderr, exit_code = run_command('openssl', 'x509', '-noout', '-text', '-in', '.gimmecert/ca/level1.cert.pem')
 

	
 
    assert exit_code == 0
 
@@ -185,13 +185,13 @@ def test_server_command_default_key_specification_with_rsa(tmpdir):
 
    # He runs a command to see details about the generated private
 
    # key.
 
    stdout, _, _ = run_command('openssl', 'rsa', '-noout', '-text', '-in', '.gimmecert/server/myserver1.key.pem')
 

	
 
    # He can see that the generated private key uses the same size as the
 
    # one he specified for the CA hierarchy.
 
    assert "Private-Key: (1024 bit)" in stdout
 
    assert "Private-Key: (1024 bit, 2 primes)" in stdout
 

	
 

	
 
def test_server_command_key_specification_with_rsa(tmpdir):
 
    # John is working on a project where he has already initialised CA
 
    # hierarchy using strong RSA keys. However, now he has a need to
 
    # issue a couple of weaker RSA keys for performance testing.
 
@@ -209,13 +209,13 @@ def test_server_command_key_specification_with_rsa(tmpdir):
 
    # He runs a command to see details about the generated private
 
    # key.
 
    stdout, _, _ = run_command('openssl', 'rsa', '-noout', '-text', '-in', '.gimmecert/server/myserver1.key.pem')
 

	
 
    # He nods with his head, observing that the generated private key
 
    # uses the same key size as he has requested.
 
    assert "Private-Key: (2048 bit)" in stdout
 
    assert "Private-Key: (2048 bit, 2 primes)" in stdout
 

	
 

	
 
def test_client_command_default_key_specification_with_rsa(tmpdir):
 
    # John needs to perform some quick tests revolving around the use
 
    # of X.509 certificates, but he does not care about the generated
 
    # private key strength. He primarily needs to deal with
 
@@ -237,13 +237,13 @@ def test_client_command_default_key_specification_with_rsa(tmpdir):
 
    # He runs a command to see details about the generated private
 
    # key.
 
    stdout, _, _ = run_command('openssl', 'rsa', '-noout', '-text', '-in', '.gimmecert/client/myclient1.key.pem')
 

	
 
    # He can see that the generated private key uses the same size as the
 
    # one he specified for the CA hierarchy.
 
    assert "Private-Key: (1024 bit)" in stdout
 
    assert "Private-Key: (1024 bit, 2 primes)" in stdout
 

	
 

	
 
def test_client_command_key_specification_with_rsa(tmpdir):
 
    # John is working on a project where he has already initialised CA
 
    # hierarchy using strong RSA keys. However, now he has a need to
 
    # issue a couple of weaker RSA keys for performance testing.
 
@@ -261,13 +261,13 @@ def test_client_command_key_specification_with_rsa(tmpdir):
 
    # He runs a command to see details about the generated private
 
    # key.
 
    stdout, _, _ = run_command('openssl', 'rsa', '-noout', '-text', '-in', '.gimmecert/client/myclient1.key.pem')
 

	
 
    # He nods with his head, observing that the generated private key
 
    # uses the same key size as he has specified.
 
    assert "Private-Key: (2048 bit)" in stdout
 
    assert "Private-Key: (2048 bit, 2 primes)" in stdout
 

	
 

	
 
def test_renew_command_key_specification_with_rsa(tmpdir):
 
    # John has set-up a project where he has issued a couple of
 
    # certificates. For some of them he has used externally-generated
 
    # private keys.
 
@@ -297,23 +297,23 @@ def test_renew_command_key_specification_with_rsa(tmpdir):
 
    assert stderr == ""
 

	
 
    # He checks the details about the generated private key, and
 
    # disovers that Gimmecert generated the key according to his
 
    # wishes.
 
    stdout, _, _ = run_command('openssl', 'rsa', '-noout', '-text', '-in', '.gimmecert/server/myserver1.key.pem')
 
    assert "Private-Key: (1024 bit)" in stdout
 
    assert "Private-Key: (1024 bit, 2 primes)" in stdout
 

	
 
    # John goes ahead and performs a similar operation for his client
 
    # entity.
 
    stdout, stderr, exit_code = run_command("gimmecert", "renew", "client", "-k", "rsa:1024", "-p", "myclient1")
 
    assert exit_code == 0
 
    assert stderr == ""
 

	
 
    # And once again, Gimmecert has created the key with correct size.
 
    stdout, _, _ = run_command('openssl', 'rsa', '-noout', '-text', '-in', '.gimmecert/client/myclient1.key.pem')
 
    assert "Private-Key: (1024 bit)" in stdout
 
    assert "Private-Key: (1024 bit, 2 primes)" in stdout
 

	
 
    # After some further testing, John decides to renew the
 
    # certificates that have been issued using a CSR. He requests new
 
    # private keys to be generated as well.
 
    stdout, stderr, exit_code = run_command("gimmecert", "renew", "server", "-p", "myserver1")
 
    assert exit_code == 0
 
@@ -326,20 +326,20 @@ def test_renew_command_key_specification_with_rsa(tmpdir):
 
    # John is unsure if the same key specification has been used. So
 
    # he goes ahead and has a look at the server key.
 
    stdout, _, _ = run_command('openssl', 'rsa', '-noout', '-text', '-in', '.gimmecert/server/myserver1.key.pem')
 

	
 
    # The renew command has used the same key specification for the
 
    # new private key as for the old private key.
 
    assert "Private-Key: (1024 bit)" in stdout
 
    assert "Private-Key: (1024 bit, 2 primes)" in stdout
 

	
 
    # He performs the same check on the client key.
 
    stdout, _, _ = run_command('openssl', 'rsa', '-noout', '-text', '-in', '.gimmecert/client/myclient1.key.pem')
 

	
 
    # The renew command has used the same key specification for the
 
    # new private key as for the old private key.
 
    assert "Private-Key: (1024 bit)" in stdout
 
    assert "Private-Key: (1024 bit, 2 primes)" in stdout
 

	
 
    # After using his manually generated private keys for a while,
 
    # John accidentally deletes them from his managed machine. Instead
 
    # of redoing the whole process with CSRs, he decides to simply
 
    # regenerate the private keys and certificates and copy them over.
 
    run_command('gimmecert', 'renew', 'server', '--new-private-key', 'myserver2')
 
@@ -351,18 +351,18 @@ def test_renew_command_key_specification_with_rsa(tmpdir):
 
    # hierarchy defaults, or the same key size he used when generating
 
    # the keys manually.
 
    #
 
    # He checks the server private key, and everything seems right -
 
    # same key size is used as in case of the old private key.
 
    stdout, stderr, _ = run_command('openssl', 'rsa', '-noout', '-text', '-in', '.gimmecert/server/myserver2.key.pem')
 
    assert "Private-Key: (3072 bit)" in stdout
 
    assert "Private-Key: (3072 bit, 2 primes)" in stdout
 

	
 
    # Then he has a look at the client private key, and that one is
 
    # also using the same key size as the old private key.
 
    stdout, _, _ = run_command('openssl', 'rsa', '-noout', '-text', '-in', '.gimmecert/client/myclient2.key.pem')
 
    assert "Private-Key: (3072 bit)" in stdout
 
    assert "Private-Key: (3072 bit, 2 primes)" in stdout
 

	
 

	
 
def test_initialisation_with_ecdsa_key_specification(tmpdir):
 
    # John wnats to initialise a CA hierarchy using ECDSA keys. He
 
    # switches to his project directory.
 
    tmpdir.chdir()
functional_tests/test_server.py
Show inline comments
 
@@ -89,13 +89,13 @@ def test_server_command_issues_server_certificate(tmpdir):
 
    stdout, stderr, exit_code = run_command('openssl', 'rsa', '-noout', '-text', '-in', '.gimmecert/server/myserver.key.pem')
 

	
 
    # No errors are reported, and John is able to see some details
 
    # about the generated key.
 
    assert exit_code == 0
 
    assert stderr == ""
 
    assert "Private-Key: (2048 bit)" in stdout
 
    assert "Private-Key: (2048 bit, 2 primes)" in stdout
 

	
 
    # John then has a look at the generated certificate file.
 
    stdout, stderr, exit_code = run_command('openssl', 'x509', '-noout', '-text', '-in', '.gimmecert/server/myserver.cert.pem')
 

	
 
    # Once again, there are no errors, and he can see some details
 
    # about the certificate.
provision.sh
Show inline comments
 
@@ -18,19 +18,19 @@ fi
 
apt-get update -qq
 

	
 
# Install development tools.
 
apt-get install -qq -y git virtualenv
 

	
 
# Install Python build dependencies.
 
apt-get install -qq -y make build-essential libssl1.0-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev xz-utils tk-dev libxml2-dev libffi-dev
 
apt-get install -qq -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev xz-utils tk-dev libxml2-dev libffi-dev
 

	
 
# Import public keys for validating Python releases.
 
sudo -i -u vagrant gpg -q --import /vagrant/provision/python_releases_signing_keys.pub
 

	
 
# Download and build additional Python versions.
 
python_versions=("3.5.10" "3.6.12" "3.7.9" "3.8.6" "3.9.0")
 
python_versions=("3.8.18" "3.9.18")
 
work_directory="/home/vagrant/src"
 

	
 
echo "Setting-up work directory."
 
sudo -i -u vagrant mkdir -p "$work_directory"
 

	
 
for version in "${python_versions[@]}"; do

Changeset was too big and was cut off... Show full diff anyway

0 comments (0 inline, 0 general)