Add vaulted_file test (#83717)

* Add vaulted_file test
* fix is_encrypted_file while we are here
Co-authored-by: Martin Krizek <martin.krizek@gmail.com>
pull/83756/head
Brian Coca 4 months ago committed by GitHub
parent 97a60c1e86
commit 797e6bb220
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
bugfixes:
- vault.is_encrypted_file is now optimized to be called in runtime and not for being called in tests
- vault_encrypted test documentation, name and examples have been fixed, other parts were clarified
minor_changes:
- vaulted_file test filter added, to test if the provided path is an 'Ansible vaulted' file

@ -18,7 +18,7 @@ from ansible.module_utils.six import binary_type, text_type
from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
from ansible.parsing.quoting import unquote from ansible.parsing.quoting import unquote
from ansible.parsing.utils.yaml import from_yaml from ansible.parsing.utils.yaml import from_yaml
from ansible.parsing.vault import VaultLib, b_HEADER, is_encrypted, is_encrypted_file, parse_vaulttext_envelope, PromptVaultSecret from ansible.parsing.vault import VaultLib, is_encrypted, is_encrypted_file, parse_vaulttext_envelope, PromptVaultSecret
from ansible.utils.path import unfrackpath from ansible.utils.path import unfrackpath
from ansible.utils.display import Display from ansible.utils.display import Display
@ -388,7 +388,7 @@ class DataLoader:
# Limit how much of the file is read since we do not know # Limit how much of the file is read since we do not know
# whether this is a vault file and therefore it could be very # whether this is a vault file and therefore it could be very
# large. # large.
if is_encrypted_file(f, count=len(b_HEADER)): if is_encrypted_file(f):
# if the file is encrypted and no password was specified, # if the file is encrypted and no password was specified,
# the decrypt call would throw an error, but we check first # the decrypt call would throw an error, but we check first
# since the decrypt function doesn't know the file name # since the decrypt function doesn't know the file name

@ -103,15 +103,17 @@ def is_encrypted(data):
return False return False
def is_encrypted_file(file_obj, start_pos=0, count=-1): def is_encrypted_file(file_obj, start_pos=0, count=len(b_HEADER)):
"""Test if the contents of a file obj are a vault encrypted data blob. """Test if the contents of a file obj are a vault encrypted data blob.
:arg file_obj: A file object that will be read from. :arg file_obj: A file object that will be read from.
:kwarg start_pos: A byte offset in the file to start reading the header :kwarg start_pos: A byte offset in the file to start reading the header
from. Defaults to 0, the beginning of the file. from. Defaults to 0, the beginning of the file.
:kwarg count: Read up to this number of bytes from the file to determine :kwarg count: Read up to this number of bytes from the file to determine
if it looks like encrypted vault data. The default is -1, read to the if it looks like encrypted vault data. The default is the size of the
end of file. the vault header, which is what is needed most times.
For some IO classes, or files that don't begin with the vault itself,
set to -1 to read to the end of file.
:returns: True if the file looks like a vault file. Otherwise, False. :returns: True if the file looks like a vault file. Otherwise, False.
""" """
# read the header and reset the file stream to where it started # read the header and reset the file stream to where it started

@ -25,8 +25,9 @@ from collections.abc import MutableMapping, MutableSequence
from ansible.module_utils.compat.version import LooseVersion, StrictVersion from ansible.module_utils.compat.version import LooseVersion, StrictVersion
from ansible import errors from ansible import errors
from ansible.module_utils.common.text.converters import to_native, to_text from ansible.module_utils.common.text.converters import to_native, to_text, to_bytes
from ansible.module_utils.parsing.convert_bool import boolean from ansible.module_utils.parsing.convert_bool import boolean
from ansible.parsing.vault import is_encrypted_file
from ansible.utils.display import Display from ansible.utils.display import Display
from ansible.utils.version import SemanticVersion from ansible.utils.version import SemanticVersion
@ -143,6 +144,18 @@ def vault_encrypted(value):
return getattr(value, '__ENCRYPTED__', False) and value.is_encrypted() return getattr(value, '__ENCRYPTED__', False) and value.is_encrypted()
def vaulted_file(value):
"""Evaluate whether a file is a vault
.. versionadded:: 2.18
"""
try:
with open(to_bytes(value), 'rb') as f:
return is_encrypted_file(f)
except (OSError, IOError) as e:
raise errors.AnsibleFilterError(f"Cannot test if the file {value} is a vault", orig_exc=e)
def match(value, pattern='', ignorecase=False, multiline=False): def match(value, pattern='', ignorecase=False, multiline=False):
''' Perform a `re.match` returning a boolean ''' ''' Perform a `re.match` returning a boolean '''
return regex(value, pattern, ignorecase, multiline, 'match') return regex(value, pattern, ignorecase, multiline, 'match')
@ -282,4 +295,5 @@ class TestModule(object):
# vault # vault
'vault_encrypted': vault_encrypted, 'vault_encrypted': vault_encrypted,
'vaulted_file': vaulted_file,
} }

@ -1,18 +1,18 @@
DOCUMENTATION: DOCUMENTATION:
name: truthy name: vault_encrypted
author: Ansible Core author: Ansible Core
version_added: "2.10" version_added: "2.10"
short_description: Is this an encrypted vault short_description: Is this an encrypted vault string
description: description:
- Verifies if the input is an Ansible vault. - Verifies if the input string is an Ansible vault or not
options: options:
_input: _input:
description: The possible vault. description: The possible vault string
type: string type: string
required: True required: True
EXAMPLES: | EXAMPLES: |
thisisfalse: '{{ "any string" is ansible_vault }}' thisisfalse: '{{ "any string" is vault_encryped}}'
thisistrue: '{{ "$ANSIBLE_VAULT;1.2;AES256;dev...." is ansible_vault }}' thisistrue: '{{ "$ANSIBLE_VAULT;1.2;AES256;dev...." is vault_encrypted}}'
RETURN: RETURN:
_value: _value:
description: Returns V(True) if the input is a valid ansible vault, V(False) otherwise. description: Returns V(True) if the input is a valid ansible vault, V(False) otherwise.

@ -0,0 +1,19 @@
DOCUMENTATION:
name: vaulted_file
author: Ansible Core
version_added: "2.18"
short_description: Is this file an encrypted vault
description:
- Verifies if the input path is an Ansible vault file.
options:
_input:
description: The path to the possible vault.
type: path
required: True
EXAMPLES: |
thisisfalse: '{{ "/etc/hosts" is vaulted_file}}'
thisistrue: '{{ "/path/to/vaulted/file" is vaulted_file}}'
RETURN:
_value:
description: Returns V(True) if the path is a valid ansible vault, V(False) otherwise.
type: boolean

@ -0,0 +1,6 @@
$ANSIBLE_VAULT;1.1;AES256
36383565336439373638626535313963373838613433343434663465656531316530663865363434
3137636638393164646537643034303962633365613463310a303164353037663062376539313834
65303131346266643934306364653063663061326165323737666636633363383337393731613030
3164613334616465620a386234323862623764363834336364336662313932633866303262646565
3861

@ -0,0 +1,6 @@
$ANSIBLE_VAULT;1.2;AES256;yolo
61303130346664303063346433663231333561616535623536613465663137626332633339326666
3565393632323837663930656461643266663634643332300a343030333136353966636537326537
36383536386164373565636335316436316538313135346264383561316333386461343262323766
6335663033373666370a316432313733303338363936313364663532313335383239646561313864
6663

@ -361,3 +361,10 @@
that: that:
- vaulted_value is vault_encrypted - vaulted_value is vault_encrypted
- inventory_hostname is not vault_encrypted - inventory_hostname is not vault_encrypted
- name: Check vaulted_file test
assert:
that:
- "'files/notvault' is not vaulted_file"
- "'files/vault1' is vaulted_file"
- "'files/vault2' is vaulted_file"

@ -450,12 +450,12 @@ class TestVaultIsEncryptedFile(unittest.TestCase):
data = u"$ANSIBLE_VAULT;9.9;TEST\n%s" % u"ァ ア ィ イ ゥ ウ ェ エ ォ オ カ ガ キ ギ ク グ ケ " data = u"$ANSIBLE_VAULT;9.9;TEST\n%s" % u"ァ ア ィ イ ゥ ウ ェ エ ォ オ カ ガ キ ギ ク グ ケ "
b_data = to_bytes(data) b_data = to_bytes(data)
b_data_fo = io.BytesIO(b_data) b_data_fo = io.BytesIO(b_data)
self.assertFalse(vault.is_encrypted_file(b_data_fo)) self.assertFalse(vault.is_encrypted_file(b_data_fo, count=-1))
def test_text_file_handle_invalid(self): def test_text_file_handle_invalid(self):
data = u"$ANSIBLE_VAULT;9.9;TEST\n%s" % u"ァ ア ィ イ ゥ ウ ェ エ ォ オ カ ガ キ ギ ク グ ケ " data = u"$ANSIBLE_VAULT;9.9;TEST\n%s" % u"ァ ア ィ イ ゥ ウ ェ エ ォ オ カ ガ キ ギ ク グ ケ "
data_fo = io.StringIO(data) data_fo = io.StringIO(data)
self.assertFalse(vault.is_encrypted_file(data_fo)) self.assertFalse(vault.is_encrypted_file(data_fo, count=-1))
def test_file_already_read_from_finds_header(self): def test_file_already_read_from_finds_header(self):
b_data = b"$ANSIBLE_VAULT;9.9;TEST\n%s" % hexlify(b"ansible\ntesting\nfile pos") b_data = b"$ANSIBLE_VAULT;9.9;TEST\n%s" % hexlify(b"ansible\ntesting\nfile pos")

Loading…
Cancel
Save