Expects Redacted Raw Documents

- Adds a query parameter 'cleartext-secrets' to get full raw documents.
- Adds CLI flag to get full raw documents.

Change-Id: If38974c8433c8360cc47ae1273720ad76e87a6fd
This commit is contained in:
Aaron Sheffield 2018-10-12 09:00:32 -05:00
parent f5774206e5
commit d62f15123d
11 changed files with 58 additions and 21 deletions

View File

@ -220,8 +220,11 @@ Returns the source documents for a collection of documents
Query Parameters Query Parameters
'''''''''''''''' ''''''''''''''''
version=committed | last_site_action | successful_site_action | **buffer** - version=committed | last_site_action | successful_site_action | **buffer**
Return the documents for the version specified - buffer by default. Return the documents for the version specified - buffer by default.
- cleartext-secrets=true/**false**
If true then returns cleartext secrets in encrypted documents, otherwise
those values are redacted.
Responses Responses
''''''''' '''''''''

View File

@ -647,6 +647,7 @@ differences between the 'committed' and 'buffer' revision (default behavior).
shipyard get configdocs shipyard get configdocs
[--collection=<collection>] [--collection=<collection>]
[--committed | --last-site-action | --successful-site-action | --buffer] [--committed | --last-site-action | --successful-site-action | --buffer]
[--cleartext-secrets]
Example: Example:
shipyard get configdocs --collection=design shipyard get configdocs --collection=design
@ -675,6 +676,10 @@ differences between the 'committed' and 'buffer' revision (default behavior).
prior commit. If no documents have been loaded into the buffer for this prior commit. If no documents have been loaded into the buffer for this
collection, this will return an empty response (default) collection, this will return an empty response (default)
\--cleartext-secrets
Returns cleartext secrets in encrypted documents, otherwise those values
are redacted. Only impacts returned documents, not lists of documents.
Sample Sample
^^^^^^ ^^^^^^

View File

@ -98,11 +98,13 @@ class ConfigDocsResource(BaseResource):
Returns a collection of documents Returns a collection of documents
""" """
version = (req.params.get('version') or 'buffer') version = (req.params.get('version') or 'buffer')
cleartext_secrets = req.get_param_as_bool('cleartext-secrets')
self._validate_version_parameter(version) self._validate_version_parameter(version)
helper = ConfigdocsHelper(req.context) helper = ConfigdocsHelper(req.context)
# Not reformatting to JSON or YAML since just passing through # Not reformatting to JSON or YAML since just passing through
resp.body = self.get_collection( resp.body = self.get_collection(
helper=helper, collection_id=collection_id, version=version) helper=helper, collection_id=collection_id, version=version,
cleartext_secrets=cleartext_secrets)
resp.append_header('Content-Type', 'application/x-yaml') resp.append_header('Content-Type', 'application/x-yaml')
resp.status = falcon.HTTP_200 resp.status = falcon.HTTP_200
@ -116,13 +118,15 @@ class ConfigDocsResource(BaseResource):
status=falcon.HTTP_400, status=falcon.HTTP_400,
retry=False, ) retry=False, )
def get_collection(self, helper, collection_id, version='buffer'): def get_collection(self, helper, collection_id, version='buffer',
cleartext_secrets=False):
""" """
Attempts to retrieve the specified collection of documents Attempts to retrieve the specified collection of documents
either from the buffer, committed version, last site action either from the buffer, committed version, last site action
or successful site action, as specified or successful site action, as specified
""" """
return helper.get_collection_docs(version, collection_id) return helper.get_collection_docs(version, collection_id,
cleartext_secrets)
def post_collection(self, def post_collection(self,
helper, helper,

View File

@ -318,18 +318,21 @@ class ConfigdocsHelper(object):
rev = self._get_revision_dict().get(target_revision) rev = self._get_revision_dict().get(target_revision)
return rev['id'] if rev else None return rev['id'] if rev else None
def get_collection_docs(self, version, collection_id): def get_collection_docs(self, version, collection_id,
cleartext_secrets=False):
""" """
Returns the requested collection of docs based on the version Returns the requested collection of docs based on the version
specifier. The default is set as buffer. specifier. The default is set as buffer.
""" """
LOG.info('Retrieving collection %s from %s', collection_id, version) LOG.info('Retrieving collection %s from %s', collection_id, version)
if version in [COMMITTED, LAST_SITE_ACTION, SUCCESSFUL_SITE_ACTION]: if version in [COMMITTED, LAST_SITE_ACTION, SUCCESSFUL_SITE_ACTION]:
return self._get_target_docs(collection_id, version) return self._get_target_docs(collection_id, version,
cleartext_secrets)
return self._get_doc_from_buffer(collection_id) return self._get_doc_from_buffer(collection_id,
cleartext_secrets=cleartext_secrets)
def _get_doc_from_buffer(self, collection_id): def _get_doc_from_buffer(self, collection_id, cleartext_secrets=False):
""" """
Returns the collection if it exists in the buffer. Returns the collection if it exists in the buffer.
If the buffer contains the collection, the latest If the buffer contains the collection, the latest
@ -343,7 +346,8 @@ class ConfigdocsHelper(object):
# revision exists # revision exists
buffer_id = self.get_revision_id(BUFFER) buffer_id = self.get_revision_id(BUFFER)
return self.deckhand.get_docs_from_revision( return self.deckhand.get_docs_from_revision(
revision_id=buffer_id, bucket_id=collection_id) revision_id=buffer_id, bucket_id=collection_id,
cleartext_secrets=cleartext_secrets)
raise ApiError( raise ApiError(
title='No documents to retrieve', title='No documents to retrieve',
description=('The Shipyard buffer is empty or does not contain ' description=('The Shipyard buffer is empty or does not contain '
@ -351,7 +355,8 @@ class ConfigdocsHelper(object):
status=falcon.HTTP_404, status=falcon.HTTP_404,
retry=False) retry=False)
def _get_target_docs(self, collection_id, target_rev): def _get_target_docs(self, collection_id, target_rev,
cleartext_secrets=False):
""" """
Returns the collection if it exists as committed, last_site_action Returns the collection if it exists as committed, last_site_action
or successful_site_action. or successful_site_action.
@ -360,7 +365,8 @@ class ConfigdocsHelper(object):
if revision_id: if revision_id:
return self.deckhand.get_docs_from_revision( return self.deckhand.get_docs_from_revision(
revision_id=revision_id, bucket_id=collection_id) revision_id=revision_id, bucket_id=collection_id,
cleartext_secrets=cleartext_secrets)
raise ApiError( raise ApiError(
title='No documents to retrieve', title='No documents to retrieve',

View File

@ -184,20 +184,25 @@ class DeckhandClient(object):
diff = yaml.safe_load(response.text) diff = yaml.safe_load(response.text)
return diff return diff
def get_docs_from_revision(self, revision_id, bucket_id=None): def get_docs_from_revision(self, revision_id, bucket_id=None,
cleartext_secrets=False):
""" """
Retrieves the collection of docs from the revision specified Retrieves the collection of docs from the revision specified
for the bucket_id specified for the bucket_id specified
cleartext_secrets: Should deckhand show or redact secrets.
:returns: a string representing the response.text from Deckhand :returns: a string representing the response.text from Deckhand
""" """
url = DeckhandClient.get_path( url = DeckhandClient.get_path(
DeckhandPaths.REVISION_DOCS DeckhandPaths.REVISION_DOCS
).format(revision_id) ).format(revision_id)
# if a bucket_id is specified, limit the response to a bucket # if a bucket_id is specified, limit the response to a bucket
query = None query = {}
if bucket_id is not None: if bucket_id is not None:
query = {'status.bucket': bucket_id} query = {'status.bucket': bucket_id}
if cleartext_secrets is True:
query['cleartext-secrets'] = 'true'
response = self._get_request(url, params=query) response = self._get_request(url, params=query)
self._handle_bad_response(response) self._handle_bad_response(response)
return response.text return response.text
@ -336,6 +341,9 @@ class DeckhandClient(object):
'X-Auth-Token': get_token() 'X-Auth-Token': get_token()
} }
if not params:
params = None
DeckhandClient._log_request('GET', url, params) DeckhandClient._log_request('GET', url, params)
response = requests.get( response = requests.get(
url, url,

View File

@ -96,7 +96,7 @@ class TestConfigDocsResource():
helper = ConfigdocsHelper(CTX) helper = ConfigdocsHelper(CTX)
cdr.get_collection(helper, 'apples') cdr.get_collection(helper, 'apples')
mock_method.assert_called_once_with('buffer', 'apples') mock_method.assert_called_once_with('buffer', 'apples', False)
@patch.object(ConfigdocsHelper, 'is_collection_in_buffer', @patch.object(ConfigdocsHelper, 'is_collection_in_buffer',
lambda x, y: True) lambda x, y: True)

View File

@ -503,7 +503,7 @@ def test_get_collection_docs():
""" """
helper = ConfigdocsHelper(CTX) helper = ConfigdocsHelper(CTX)
helper.deckhand.get_docs_from_revision = ( helper.deckhand.get_docs_from_revision = (
lambda revision_id, bucket_id: "{'yaml': 'yaml'}") lambda revision_id, bucket_id, cleartext_secrets: "{'yaml': 'yaml'}")
helper._get_revision_dict = lambda: REV_EMPTY_DICT helper._get_revision_dict = lambda: REV_EMPTY_DICT
helper.deckhand.get_diff = ( helper.deckhand.get_diff = (
lambda old_revision_id, new_revision_id: DIFF_EMPTY_DICT) lambda old_revision_id, new_revision_id: DIFF_EMPTY_DICT)

View File

@ -68,7 +68,8 @@ class ShipyardClient(BaseClient):
) )
return self.post_resp(url, query_params, document_data) return self.post_resp(url, query_params, document_data)
def get_configdocs(self, collection_id=None, version='buffer'): def get_configdocs(self, collection_id=None, version='buffer',
cleartext_secrets=False):
""" """
Get the collection of documents from deckhand specified by Get the collection of documents from deckhand specified by
collection id collection id
@ -78,6 +79,8 @@ class ShipyardClient(BaseClient):
:rtype: Response object :rtype: Response object
""" """
query_params = {"version": version} query_params = {"version": version}
if cleartext_secrets is True:
query_params['cleartext-secrets'] = 'true'
url = ApiPaths.POST_GET_CONFIG.value.format( url = ApiPaths.POST_GET_CONFIG.value.format(
self.get_endpoint(), self.get_endpoint(),
collection_id) collection_id)

View File

@ -48,7 +48,7 @@ class GetActions(CliAction):
class GetConfigdocs(CliAction): class GetConfigdocs(CliAction):
"""Action to Get Configdocs""" """Action to Get Configdocs"""
def __init__(self, ctx, collection, version): def __init__(self, ctx, collection, version, cleartext_secrets=False):
"""Sets parameters.""" """Sets parameters."""
super().__init__(ctx) super().__init__(ctx)
self.logger.debug( self.logger.debug(
@ -56,12 +56,14 @@ class GetConfigdocs(CliAction):
"version=%s" % (collection, version)) "version=%s" % (collection, version))
self.collection = collection self.collection = collection
self.version = version self.version = version
self.cleartext_secrets = cleartext_secrets
def invoke(self): def invoke(self):
"""Calls API Client and formats response from API Client""" """Calls API Client and formats response from API Client"""
self.logger.debug("Calling API Client get_configdocs.") self.logger.debug("Calling API Client get_configdocs.")
return self.get_api_client().get_configdocs( return self.get_api_client().get_configdocs(
collection_id=self.collection, version=self.version) collection_id=self.collection, version=self.version,
cleartext_secrets=self.cleartext_secrets)
# Handle 404 with default error handler for cli. # Handle 404 with default error handler for cli.
cli_handled_err_resp_codes = [404] cli_handled_err_resp_codes = [404]

View File

@ -98,16 +98,22 @@ SHORT_DESC_CONFIGDOCS = ("Retrieve documents loaded into Shipyard, either "
flag_value='successful_site_action', flag_value='successful_site_action',
help='Holds the revision information for the most recent successfully ' help='Holds the revision information for the most recent successfully '
'executed site action.') 'executed site action.')
@click.option(
'--cleartext-secrets',
'-t',
help='Returns cleartext secrets in documents',
is_flag=True)
@click.pass_context @click.pass_context
def get_configdocs(ctx, collection, buffer, committed, last_site_action, def get_configdocs(ctx, collection, buffer, committed, last_site_action,
successful_site_action): successful_site_action, cleartext_secrets):
if collection: if collection:
# Get version # Get version
_version = get_version(ctx, buffer, committed, last_site_action, _version = get_version(ctx, buffer, committed, last_site_action,
successful_site_action) successful_site_action)
click.echo( click.echo(
GetConfigdocs(ctx, collection, _version).invoke_and_return_resp()) GetConfigdocs(ctx, collection, _version,
cleartext_secrets).invoke_and_return_resp())
else: else:
compare_versions = check_reformat_versions(ctx, compare_versions = check_reformat_versions(ctx,

View File

@ -58,7 +58,7 @@ def test_get_configdocs_with_passing_collection(*args):
with patch.object(GetConfigdocs, '__init__') as mock_method: with patch.object(GetConfigdocs, '__init__') as mock_method:
runner.invoke(shipyard, [auth_vars, 'get', 'configdocs', runner.invoke(shipyard, [auth_vars, 'get', 'configdocs',
'--collection=design']) '--collection=design'])
mock_method.assert_called_once_with(ANY, 'design', 'buffer') mock_method.assert_called_once_with(ANY, 'design', 'buffer', False)
def test_get_configdocs_without_passing_collection(*args): def test_get_configdocs_without_passing_collection(*args):