Changeset - 130684592129
[Not reviewed]
0 2 2
Branko Majic (branko) - 6 years ago 2018-02-28 15:48:48
branko@majic.rs
GC-3: Refactored main functionality of the init command into separate function:

- Introduced a new module (commands) where the majority of command
implementation should reside.
- The cli module should now be a thin wrapper around commands, in
charge of processing input system arguments.
- Refactored the tests accordingly.
4 files changed with 111 insertions and 36 deletions:
0 comments (0 inline, 0 general)
gimmecert/cli.py
Show inline comments
 
@@ -23,8 +23,7 @@ import argparse
 
import os
 

	
 
from .decorators import subcommand_parser, get_subcommand_parser_setup_functions
 
from .storage import initialise_storage, write_private_key, write_certificate
 
from .crypto import generate_private_key, issue_certificate, get_dn, get_validity_range
 
from .commands import init
 

	
 

	
 
DESCRIPTION = """\
 
@@ -39,31 +38,17 @@ Examples:
 
def setup_init_subcommand_parser(parser, subparsers):
 
    subparser = subparsers.add_parser('init', description='Initialise CA hierarchy.')
 

	
 
    def init(args):
 
    def init_wrapper(args):
 
        project_directory = os.getcwd()
 
        base_directory = os.path.join(os.getcwd(), '.gimmecert')
 
        ca_directory = os.path.join(base_directory, 'ca')
 
        level1_private_key_path = os.path.join(ca_directory, 'level1.key.pem')
 
        level1_certificate_path = os.path.join(ca_directory, 'level1.cert.pem')
 
        full_chain_path = os.path.join(ca_directory, 'chain-full.cert.pem')
 
        level1_dn = get_dn("%s Level 1" % os.path.basename(project_directory))
 
        not_before, not_after = get_validity_range()
 

	
 
        initialise_storage(project_directory)
 
        level1_private_key = generate_private_key()
 
        level1_certificate = issue_certificate(level1_dn, level1_dn, level1_private_key, level1_private_key.public_key(), not_before, not_after)
 
        full_chain = level1_certificate
 

	
 
        write_private_key(level1_private_key, level1_private_key_path)
 
        write_certificate(level1_certificate, level1_certificate_path)
 
        write_certificate(full_chain, full_chain_path)
 

	
 
        init(project_directory)
 

	
 
        print("CA hierarchy initialised. Generated artefacts:")
 
        print("    CA Level 1 private key: .gimmecert/ca/level1.key.pem")
 
        print("    CA Level 1 certificate: .gimmecert/ca/level1.cert.pem")
 
        print("    Full certificate chain: .gimmecert/ca/chain-full.cert.pem")
 

	
 
    subparser.set_defaults(func=init)
 
    subparser.set_defaults(func=init_wrapper)
 

	
 
    return subparser
 

	
gimmecert/commands.py
Show inline comments
 
new file 100644
 
# -*- coding: utf-8 -*-
 
#
 
# Copyright (C) 2018 Branko Majic
 
#
 
# This file is part of Gimmecert.
 
#
 
# Gimmecert is free software: you can redistribute it and/or modify it
 
# under the terms of the GNU General Public License as published by the Free
 
# Software Foundation, either version 3 of the License, or (at your option) any
 
# later version.
 
#
 
# Gimmecert is distributed in the hope that it will be useful, but
 
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 
# details.
 
#
 
# You should have received a copy of the GNU General Public License along with
 
# Gimmecert.  If not, see <http://www.gnu.org/licenses/>.
 
#
 

	
 
import os
 

	
 
import gimmecert.crypto
 
import gimmecert.storage
 

	
 

	
 
def init(project_directory):
 
    """
 
    Initialises the necessary directory and CA hierarchies for use in
 
    the specified directory.
 

	
 
    :param project_directory: Path to directory where the structure should be initialised. Should be top-level project directory normally.
 
    :type project_directory: str
 
    """
 

	
 
    # Set-up various paths.
 
    base_directory = os.path.join(project_directory, '.gimmecert')
 
    ca_directory = os.path.join(base_directory, 'ca')
 
    level1_private_key_path = os.path.join(ca_directory, 'level1.key.pem')
 
    level1_certificate_path = os.path.join(ca_directory, 'level1.cert.pem')
 
    full_chain_path = os.path.join(ca_directory, 'chain-full.cert.pem')
 

	
 
    # Initialise the directory.
 
    gimmecert.storage.initialise_storage(project_directory)
 

	
 
    # Generate private key and certificate.
 
    level1_dn = gimmecert.crypto.get_dn("%s Level 1" % os.path.basename(project_directory))
 
    not_before, not_after = gimmecert.crypto.get_validity_range()
 
    level1_private_key = gimmecert.crypto.generate_private_key()
 
    level1_certificate = gimmecert.crypto.issue_certificate(level1_dn, level1_dn, level1_private_key, level1_private_key.public_key(), not_before, not_after)
 

	
 
    # Grab the full CA certificate chain.
 
    full_chain = level1_certificate
 

	
 
    # Write-out the artifacts.
 
    gimmecert.storage.write_private_key(level1_private_key, level1_private_key_path)
 
    gimmecert.storage.write_certificate(level1_certificate, level1_certificate_path)
 
    gimmecert.storage.write_certificate(full_chain, full_chain_path)
tests/test_cli.py
Show inline comments
 
@@ -20,7 +20,6 @@
 

	
 

	
 
import argparse
 
import os
 

	
 
import gimmecert.cli
 
import gimmecert.decorators
 
@@ -162,22 +161,10 @@ def test_setup_init_subcommand_sets_function_callback():
 

	
 

	
 
@mock.patch('sys.argv', ['gimmecert', 'init'])
 
def test_init_subcommand_generates_ca_private_key(tmpdir):
 
@mock.patch('gimmecert.cli.init')
 
def test_init_command_invoked_with_correct_parameters(mock_init, tmpdir):
 
    tmpdir.chdir()
 

	
 
    gimmecert.cli.main()
 

	
 
    print(tmpdir.listdir())
 

	
 
    assert os.path.exists(tmpdir.join('.gimmecert', 'ca', 'level1.key.pem').strpath)
 

	
 

	
 
@mock.patch('sys.argv', ['gimmecert', 'init'])
 
def test_init_subcommand_generates_ca_certificate(tmpdir):
 
    tmpdir.chdir()
 

	
 
    gimmecert.cli.main()
 

	
 
    print(tmpdir.listdir())
 

	
 
    assert os.path.exists(tmpdir.join('.gimmecert', 'ca', 'level1.cert.pem').strpath)
 
    mock_init.assert_called_once_with(tmpdir.strpath)
tests/test_commands.py
Show inline comments
 
new file 100644
 
# -*- coding: utf-8 -*-
 
#
 
# Copyright (C) 2018 Branko Majic
 
#
 
# This file is part of Gimmecert.
 
#
 
# Gimmecert is free software: you can redistribute it and/or modify it
 
# under the terms of the GNU General Public License as published by the Free
 
# Software Foundation, either version 3 of the License, or (at your option) any
 
# later version.
 
#
 
# Gimmecert is distributed in the hope that it will be useful, but
 
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 
# details.
 
#
 
# You should have received a copy of the GNU General Public License along with
 
# Gimmecert.  If not, see <http://www.gnu.org/licenses/>.
 
#
 

	
 
import os
 

	
 
import gimmecert.commands
 

	
 

	
 
def test_init_sets_up_directory_structure(tmpdir):
 
    base_dir = tmpdir.join('.gimmecert')
 
    ca_dir = tmpdir.join('.gimmecert')
 

	
 
    tmpdir.chdir()
 

	
 
    gimmecert.commands.init(tmpdir.strpath)
 

	
 
    assert os.path.exists(base_dir.strpath)
 
    assert os.path.exists(ca_dir.strpath)
 

	
 

	
 
def test_init_generates_ca_artifacts(tmpdir):
 
    tmpdir.chdir()
 

	
 
    gimmecert.commands.init(tmpdir.strpath)
 

	
 
    assert os.path.exists(tmpdir.join('.gimmecert', 'ca', 'level1.key.pem').strpath)
 
    assert os.path.exists(tmpdir.join('.gimmecert', 'ca', 'level1.cert.pem').strpath)
 
    assert os.path.exists(tmpdir.join('.gimmecert', 'ca', 'chain-full.cert.pem').strpath)
0 comments (0 inline, 0 general)