Improve files.write, add decrypt output to file

Add an option, -s, to write decrypted files to a file rather than
stdout. Decryptyed files have their mode set to 600. Also adds a few
improvements to files.write.

Change-Id: Ia1a6de78d401afbea6ee261652f4650071f54b60
This commit is contained in:
Lev Morgan 2019-04-17 11:58:48 -05:00
parent 11edfc07a8
commit 37f922a07e
4 changed files with 66 additions and 12 deletions

View File

@ -670,11 +670,18 @@ documents in the ``filename``.
The absolute path to the pegleg managed encrypted secrets file. The absolute path to the pegleg managed encrypted secrets file.
**-s / save-location** (Optional).
The desired output path for the decrypted file. If not specified, it will be
printed to stdout.
Usage: Usage:
:: ::
./pegleg.sh site <options> secrets decrypt <site_name> -f <file_path> ./pegleg.sh site <options> secrets decrypt <site_name> -f <file_path>
[-s <output_path>]
Examples Examples
"""""""" """"""""

View File

@ -24,6 +24,7 @@ from pegleg import engine
from pegleg.engine import bundle from pegleg.engine import bundle
from pegleg.engine import catalog from pegleg.engine import catalog
from pegleg.engine.secrets import wrap_secret from pegleg.engine.secrets import wrap_secret
from pegleg.engine.util import files
from pegleg.engine.util.pegleg_secret_management import PeglegSecretManagement from pegleg.engine.util.pegleg_secret_management import PeglegSecretManagement
from pegleg.engine.util.shipyard_helper import ShipyardHelper from pegleg.engine.util.shipyard_helper import ShipyardHelper
@ -652,12 +653,24 @@ def encrypt(*, save_location, author, site_name):
'-f', '-f',
'--filename', '--filename',
'file_name', 'file_name',
help='The file name to decrypt and print out to stdout') help='The file to decrypt')
@click.option(
'-s',
'--save-location',
'save_location',
default=None,
help='The destination where the decrypted file should be saved. '
'If not specified, it will be printed to stdout.')
@click.argument('site_name') @click.argument('site_name')
def decrypt(*, file_name, site_name): def decrypt(*, file_name, save_location, site_name):
engine.repository.process_repositories(site_name) engine.repository.process_repositories(site_name)
click.echo(engine.secrets.decrypt(file_name, site_name)) decrypted = engine.secrets.decrypt(file_name, site_name)
if save_location is None:
click.echo(decrypted)
else:
files.write(save_location, decrypted)
os.chmod(save_location, 0o600)
@main.group(help="Miscellaneous generate commands") @main.group(help="Miscellaneous generate commands")

View File

@ -296,18 +296,30 @@ def write(file_path, data):
:param file_path: Destination file for the written data file :param file_path: Destination file for the written data file
:type file_path: str :type file_path: str
:param data: data to be written to the destination file :param data: data to be written to the destination file
:type data: dict or a list of dicts :type data: str, dict, or a list of dicts
""" """
os.makedirs(os.path.dirname(file_path), exist_ok=True) try:
os.makedirs(os.path.dirname(file_path), exist_ok=True)
with open(file_path, 'w') as stream: with open(file_path, 'w') as stream:
yaml.safe_dump_all( if isinstance(data, str):
data, stream.write(data)
stream, elif isinstance(data, (dict, collections.abc.Iterable)):
explicit_start=True, if isinstance(data, dict):
explicit_end=True, data = [data]
default_flow_style=False) yaml.safe_dump_all(
data,
stream,
explicit_start=True,
explicit_end=True,
default_flow_style=False)
else:
raise ValueError('data must be str or dict, '
'not {}'.format(type(data)))
except EnvironmentError as e:
raise click.ClickError(
"Couldn't write data to {}: {}".format(file_path, e))
def _recurse_subdirs(search_path, depth): def _recurse_subdirs(search_path, depth):

View File

@ -14,6 +14,9 @@
import os import os
import pytest
import yaml
from pegleg import config from pegleg import config
from pegleg.engine.util import files from pegleg.engine.util import files
from tests.unit.fixtures import create_tmp_deployment_files from tests.unit.fixtures import create_tmp_deployment_files
@ -37,6 +40,25 @@ class TestFileHelpers(object):
assert not documents, ("Documents returned should be empty for " assert not documents, ("Documents returned should be empty for "
"site-definition.yaml") "site-definition.yaml")
def test_write(self, create_tmp_deployment_files):
path = os.path.join(config.get_site_repo(), 'site', 'cicd',
'test_out.yaml')
files.write(path, "test text")
with open(path, "r") as out_fi:
assert out_fi.read() == "test text"
files.write(path, {"a": 1})
with open(path, "r") as out_fi:
assert yaml.safe_load(out_fi) == {"a": 1}
files.write(path, [{"a": 1}])
with open(path, "r") as out_fi:
assert list(yaml.safe_load_all(out_fi)) == [{"a": 1}]
with pytest.raises(ValueError) as _:
files.write(path, object())
def test_file_in_subdir(): def test_file_in_subdir():
assert files.file_in_subdir("aaa/bbb/ccc.txt", "aaa") assert files.file_in_subdir("aaa/bbb/ccc.txt", "aaa")
assert files.file_in_subdir("aaa/bbb/ccc.txt", "bbb") assert files.file_in_subdir("aaa/bbb/ccc.txt", "bbb")