Add CLI passphrase generation
1. Add support to pegleg to generate a passphrase from CLI 2. Update unit test to ensure encryption/decryption supports passphrase rotation 3. Update order of import statements to satisfy pep8 4. Add unit test for CLI passphrase generation 5. Resolve merge conflicts via rebase Change-Id: I5cb9e41b2f0fac2451bd2b74f33c48cda417c22d
This commit is contained in:
parent
e6af6ae87e
commit
4b00a4340c
|
@ -809,3 +809,40 @@ P003 - All repos contain expected directories.
|
||||||
.. _Shipyard: https://github.com/openstack/airship-shipyard
|
.. _Shipyard: https://github.com/openstack/airship-shipyard
|
||||||
.. _CLI documentation: https://airship-shipyard.readthedocs.io/en/latest/CLI.html#openstack-keystone-authorization-environment-variables
|
.. _CLI documentation: https://airship-shipyard.readthedocs.io/en/latest/CLI.html#openstack-keystone-authorization-environment-variables
|
||||||
.. _Pegleg Passphrase Catalog: https://airship-specs.readthedocs.io/en/latest/specs/approved/pegleg-secrets.html#document-generation
|
.. _Pegleg Passphrase Catalog: https://airship-specs.readthedocs.io/en/latest/specs/approved/pegleg-secrets.html#document-generation
|
||||||
|
|
||||||
|
|
||||||
|
Generate
|
||||||
|
========
|
||||||
|
|
||||||
|
Allows you to perform generate operations.
|
||||||
|
|
||||||
|
Passphrase
|
||||||
|
----------
|
||||||
|
|
||||||
|
Generate a passphrase and print to ``stdout``.
|
||||||
|
|
||||||
|
**-l / --length** (Optional).
|
||||||
|
|
||||||
|
Length of passphrase to generate. By default length is 24.
|
||||||
|
Minimum length is 24. No maximum length.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
./pegleg.sh generate passphrase -l <length>
|
||||||
|
|
||||||
|
Examples
|
||||||
|
^^^^^^^^
|
||||||
|
|
||||||
|
Example without length specified:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
./pegleg.sh generate passphrase
|
||||||
|
|
||||||
|
Example with length specified:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
./pegleg.sh generate passphrase -l <length>
|
||||||
|
|
|
@ -528,9 +528,25 @@ def encrypt(*, save_location, author, site_name):
|
||||||
@click.argument('site_name')
|
@click.argument('site_name')
|
||||||
def decrypt(*, file_name, site_name):
|
def decrypt(*, file_name, site_name):
|
||||||
engine.repository.process_repositories(site_name)
|
engine.repository.process_repositories(site_name)
|
||||||
try:
|
|
||||||
click.echo(engine.secrets.decrypt(file_name, site_name))
|
engine.secrets.decrypt(file_name, site_name)
|
||||||
except FileNotFoundError:
|
|
||||||
raise click.exceptions.FileError("Couldn't find file %s, "
|
|
||||||
"check your arguments and try "
|
@main.group(help="Miscellaneous generate commands")
|
||||||
"again." % file_name)
|
def generate():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@generate.command(
|
||||||
|
'passphrase',
|
||||||
|
help='Command to generate a passphrase and print out to stdout')
|
||||||
|
@click.option(
|
||||||
|
'-l',
|
||||||
|
'--length',
|
||||||
|
'length',
|
||||||
|
default=24,
|
||||||
|
help='Generate a passphrase of the given length. '
|
||||||
|
'Length is >= 24, default length is 24, no maximum length')
|
||||||
|
def generate_passphrase(length):
|
||||||
|
click.echo("Generated Passhprase: {}".format(
|
||||||
|
engine.secrets.generate_passphrase(length)))
|
||||||
|
|
|
@ -15,9 +15,10 @@
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from pegleg.engine.generators.passpharase_generator import PassphraseGenerator
|
from pegleg.engine.generators.passphrase_generator import PassphraseGenerator
|
||||||
from pegleg.engine.util import definition
|
from pegleg.engine.util import definition
|
||||||
from pegleg.engine.util import files
|
from pegleg.engine.util import files
|
||||||
|
from pegleg.engine.util.passphrase import Passphrase
|
||||||
from pegleg.engine.util.pegleg_secret_management import PeglegSecretManagement
|
from pegleg.engine.util.pegleg_secret_management import PeglegSecretManagement
|
||||||
|
|
||||||
__all__ = ('encrypt', 'decrypt', 'generate_passphrases')
|
__all__ = ('encrypt', 'decrypt', 'generate_passphrases')
|
||||||
|
@ -129,3 +130,14 @@ def generate_passphrases(site_name, save_location, author, interactive=False):
|
||||||
|
|
||||||
PassphraseGenerator(site_name, save_location, author).generate(
|
PassphraseGenerator(site_name, save_location, author).generate(
|
||||||
interactive=interactive)
|
interactive=interactive)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_passphrase(length):
|
||||||
|
"""
|
||||||
|
Create a passphrase.
|
||||||
|
|
||||||
|
:param int length: Length of passphrase.
|
||||||
|
:rtype: string
|
||||||
|
"""
|
||||||
|
|
||||||
|
return Passphrase().get_pass(length)
|
||||||
|
|
|
@ -20,7 +20,7 @@ import string
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from pegleg.engine.util.passphrase import Passphrase
|
from pegleg.engine.util.passphrase import Passphrase
|
||||||
from pegleg.engine.generators.passpharase_generator import PassphraseGenerator
|
from pegleg.engine.generators.passphrase_generator import PassphraseGenerator
|
||||||
from pegleg.engine.util import encryption
|
from pegleg.engine.util import encryption
|
||||||
from pegleg.engine import util
|
from pegleg.engine import util
|
||||||
import pegleg
|
import pegleg
|
||||||
|
|
|
@ -64,6 +64,12 @@ def test_encrypt_and_decrypt():
|
||||||
enc2 = crypt.encrypt(dec1, passphrase, salt)
|
enc2 = crypt.encrypt(dec1, passphrase, salt)
|
||||||
dec2 = crypt.decrypt(enc2, passphrase, salt)
|
dec2 = crypt.decrypt(enc2, passphrase, salt)
|
||||||
assert data == dec2
|
assert data == dec2
|
||||||
|
passphrase2 = test_utils.rand_name("passphrase2", "pegleg").encode()
|
||||||
|
salt2 = test_utils.rand_name("salt2", "pegleg").encode()
|
||||||
|
enc3 = crypt.encrypt(dec2, passphrase2, salt2)
|
||||||
|
dec3 = crypt.decrypt(enc3, passphrase2, salt2)
|
||||||
|
assert data == dec3
|
||||||
|
assert data != enc3
|
||||||
|
|
||||||
|
|
||||||
@mock.patch.dict(os.environ, {
|
@mock.patch.dict(os.environ, {
|
||||||
|
|
|
@ -383,6 +383,13 @@ class TestSiteCliActions(BaseCLIActionTest):
|
||||||
mock_obj.assert_called_once()
|
mock_obj.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
class TestGenerateActions(BaseCLIActionTest):
|
||||||
|
def test_generate_passphrase(self):
|
||||||
|
result = self.runner.invoke(cli.generate, ['passphrase'])
|
||||||
|
|
||||||
|
assert result.exit_code == 0, result.output
|
||||||
|
|
||||||
|
|
||||||
class TestRepoCliActions(BaseCLIActionTest):
|
class TestRepoCliActions(BaseCLIActionTest):
|
||||||
"""Tests repo-level CLI actions."""
|
"""Tests repo-level CLI actions."""
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue