Changeset - 407076b32362
[Not reviewed]
gc-15
0 6 0
Branko Majic (branko) - 6 years ago 2018-03-04 19:23:38
branko@majic.rs
GC-15: Prevent server command from overwriting artifacts and clean-up incorrect CLI tests:

- Added functional test for scenario where a server certificate has
already been issued.
- Updated server certificate issuance command not to overwrite the
artifacts.
- Fixed a couple of both server and init tests related to CLI parsing
to not create artifacts unless necessary, and if necessary to create
artifacts in temporary (test) directory. Otherwise intermittent
failures will happen.
6 files changed with 96 insertions and 11 deletions:
0 comments (0 inline, 0 general)
functional_tests/test_init.py
Show inline comments
 
@@ -116,9 +116,9 @@ def test_initialisation_on_existing_directory(tmpdir):
 
    # initialised, John is (somewhat pleasantly) surprised to see that
 
    # the tool has informed him the initialisation has already been
 
    # run.
 
    assert exit_code == 0
 
    assert stderr == ""
 
    assert "CA hierarchy has already been initialised." in stdout
 
    assert exit_code != 0
 
    assert stdout == ""
 
    assert stderr == "CA hierarchy has already been initialised.\n"
 

	
 

	
 
def test_initialisation_with_custom_base_name(tmpdir):
functional_tests/test_server.py
Show inline comments
 
@@ -165,3 +165,40 @@ def test_server_command_issues_server_certificate_with_additional_subject_altern
 
    assert "DNS:myserver," in stdout
 
    assert "DNS:myserver.local," in stdout
 
    assert "DNS:myserver.example.com\n" in stdout
 

	
 

	
 
def test_server_command_does_not_overwrite_existing_artifacts(tmpdir):
 
    # John has become an avid user of Gimmecert. He uses it in a lot
 
    # of projects, including one specific project which he had set-up
 
    # a couple of months ago, where he has issued some server
 
    # certificate.
 
    tmpdir.chdir()
 
    run_command("gimmecert", "init")
 
    run_command("gimmecert", "server", "myserver")
 

	
 
    private_key = tmpdir.join(".gimmecert", "server", "myserver.key.pem").read()
 
    certificate = tmpdir.join(".gimmecert", "server", "myserver.cert.pem").read()
 

	
 
    # After a couple of months of inactivity on that particular
 
    # project, John is again asked to do something in relation to
 
    # it. He recalls that he needed to issue a server certificate for
 
    # it, so he goes ahead and tries to do it again.
 
    tmpdir.chdir()
 
    stdout, stderr, exit_code = run_command("gimmecert", "server", "myserver")
 

	
 
    # John realizes in last moment, just as he presses ENTER, that he
 
    # had issued certificate already. He wonders if he'd need to
 
    # redeploy it again now, though. To his (small) relief, he
 
    # realizes is it not necessary, since the tool has refused to
 
    # overwrite the old key and certificate. Instead he is presented
 
    # with an error notifying him that the certificate has already
 
    # been issued.
 
    assert exit_code != 0
 
    assert stderr == "Refusing to overwrite existing data. Certificate has already been issued for server myserver.\n"
 
    assert stdout == ""
 

	
 
    # John double-checks (just to be on the safe side), and can see
 
    # that both the private key and certificate have been left
 
    # unchanged.
 
    assert tmpdir.join(".gimmecert", "server", "myserver.key.pem").read() == private_key
 
    assert tmpdir.join(".gimmecert", "server", "myserver.cert.pem").read() == certificate
gimmecert/cli.py
Show inline comments
 
@@ -68,7 +68,8 @@ def setup_init_subcommand_parser(parser, subparsers):
 
                print("    CA Level %d certificate: .gimmecert/ca/level%d.cert.pem" % (level, level))
 
            print("    Full certificate chain: .gimmecert/ca/chain-full.cert.pem")
 
        else:
 
            print("CA hierarchy has already been initialised.")
 
            print("CA hierarchy has already been initialised.", file=sys.stderr)
 
            exit(ERROR_GENERIC)
 

	
 
    subparser.set_defaults(func=init_wrapper)
 

	
gimmecert/commands.py
Show inline comments
 
@@ -94,6 +94,9 @@ def server(project_directory, entity_name, extra_dns_names):
 
    if not gimmecert.storage.is_initialised(project_directory):
 
        return False, "CA hierarchy must be initialised prior to issuing server certificates. Run the gimmecert init command first."
 

	
 
    if os.path.exists(private_key_path) or os.path.exists(certificate_path):
 
        return False, "Refusing to overwrite existing data. Certificate has already been issued for server myserver."
 

	
 
    message = """Server certificate issued.\n
 
    Server private key: .gimmecert/server/%s.key.pem
 
    Server certificate: .gimmecert/server/%s.cert.pem
tests/test_cli.py
Show inline comments
 
@@ -186,29 +186,44 @@ def test_init_command_invoked_with_correct_parameters_with_options(mock_init, tm
 

	
 

	
 
@mock.patch('sys.argv', ['gimmecert', 'init', '--ca-base-name', 'My Project'])
 
def test_init_command_accepts_ca_base_name_option_long_form():
 
@mock.patch('gimmecert.cli.init')
 
def test_init_command_accepts_ca_base_name_option_long_form(mock_init):
 

	
 
    gimmecert.cli.main()  # Should not raise
 

	
 

	
 
@mock.patch('sys.argv', ['gimmecert', 'init', '-b', 'My Project'])
 
def test_init_command_accepts_ca_base_name_option_short_form():
 
@mock.patch('gimmecert.cli.init')
 
def test_init_command_accepts_ca_base_name_option_short_form(mock_init):
 

	
 
    gimmecert.cli.main()  # Should not raise
 

	
 

	
 
@mock.patch('sys.argv', ['gimmecert', 'init', '--ca-hierarchy-depth', '3'])
 
def test_init_command_accepts_ca_hierarchy_depth_option_long_form():
 
@mock.patch('gimmecert.cli.init')
 
def test_init_command_accepts_ca_hierarchy_depth_option_long_form(mock_init):
 

	
 
    gimmecert.cli.main()  # Should not raise
 

	
 

	
 
@mock.patch('sys.argv', ['gimmecert', 'init', '-d', '3'])
 
def test_init_command_accepts_ca_hierarchy_depth_option_short_form():
 
@mock.patch('gimmecert.cli.init')
 
def test_init_command_accepts_ca_hierarchy_depth_option_short_form(mock_init):
 

	
 
    gimmecert.cli.main()  # Should not raise
 

	
 

	
 
@mock.patch('sys.argv', ['gimmecert', 'init'])
 
def test_init_command_exists_with_error_if_hierarchy_already_initialised(tmpdir):
 
    tmpdir.chdir()
 
    gimmecert.commands.init(tmpdir.strpath, tmpdir.basename, 1)
 

	
 
    with pytest.raises(SystemExit) as e_info:
 
        gimmecert.cli.main()
 

	
 
    assert e_info.value.code != 0
 

	
 

	
 
@mock.patch('sys.argv', ['gimmecert', 'server', '-h'])
 
def test_server_command_exists_and_accepts_help_flag():
 
    with pytest.raises(SystemExit) as e_info:
 
@@ -241,19 +256,28 @@ def test_setup_server_subcommand_fails_without_arguments():
 

	
 

	
 
@mock.patch('sys.argv', ['gimmecert', 'server', 'myserver'])
 
def test_setup_server_subcommand_succeeds_with_just_entity_name_argument():
 
@mock.patch('gimmecert.cli.server')
 
def test_setup_server_subcommand_succeeds_with_just_entity_name_argument(mock_server):
 
    # We are just testing the parsing here.
 
    mock_server.return_value = True, "Fake message"
 

	
 
    gimmecert.cli.main()  # Should not raise.
 

	
 

	
 
@mock.patch('sys.argv', ['gimmecert', 'server', 'myserver', 'myserver.example.com'])
 
def test_setup_server_subcommand_succeeds_with_entity_name_argument_and_one_dns_name():
 
@mock.patch('gimmecert.cli.server')
 
def test_setup_server_subcommand_succeeds_with_entity_name_argument_and_one_dns_name(mock_server):
 
    # We are just testing the parsing here.
 
    mock_server.return_value = True, "Fake message"
 

	
 
    gimmecert.cli.main()  # Should not raise.
 

	
 

	
 
@mock.patch('sys.argv', ['gimmecert', 'server', 'myserver', 'myserver1.example.com', 'myserver2.example.com', 'myserver3.example.com', 'myserver4.example.com'])
 
def test_setup_server_subcommand_succeeds_with_entity_name_argument_and_four_dns_names():
 
@mock.patch('gimmecert.cli.server')
 
def test_setup_server_subcommand_succeeds_with_entity_name_argument_and_four_dns_names(mock_server):
 
    # We are just testing the parsing here.
 
    mock_server.return_value = True, "Fake message"
 

	
 
    gimmecert.cli.main()  # Should not raise.
 

	
tests/test_commands.py
Show inline comments
 
@@ -202,3 +202,23 @@ def test_server_outputs_certificate_to_file(tmpdir):
 

	
 
    assert certificate_file_content.startswith('-----BEGIN CERTIFICATE')
 
    assert certificate_file_content.endswith('END CERTIFICATE-----\n')
 

	
 

	
 
def test_server_errors_out_if_certificate_already_issued(tmpdir):
 
    depth = 1
 

	
 
    tmpdir.chdir()
 

	
 
    # Previous run.
 
    gimmecert.commands.init(tmpdir.strpath, tmpdir.basename, depth)
 
    gimmecert.commands.server(tmpdir.strpath, 'myserver', None)
 
    existing_private_key = tmpdir.join('.gimmecert', 'server', 'myserver.key.pem').read()
 
    certificate = tmpdir.join('.gimmecert', 'server', 'myserver.cert.pem').read()
 

	
 
    # New run.
 
    status, message = gimmecert.commands.server(tmpdir.strpath, 'myserver', None)
 

	
 
    assert status is False
 
    assert "already been issued" in message
 
    assert tmpdir.join('.gimmecert', 'server', 'myserver.key.pem').read() == existing_private_key
 
    assert tmpdir.join('.gimmecert', 'server', 'myserver.cert.pem').read() == certificate
0 comments (0 inline, 0 general)