ansible-vars 1.0.2__py3-none-any.whl → 1.0.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ansible_vars/cli.py +80 -26
- {ansible_vars-1.0.2.dist-info → ansible_vars-1.0.4.dist-info}/METADATA +21 -3
- {ansible_vars-1.0.2.dist-info → ansible_vars-1.0.4.dist-info}/RECORD +6 -6
- {ansible_vars-1.0.2.dist-info → ansible_vars-1.0.4.dist-info}/WHEEL +0 -0
- {ansible_vars-1.0.2.dist-info → ansible_vars-1.0.4.dist-info}/entry_points.txt +0 -0
- {ansible_vars-1.0.2.dist-info → ansible_vars-1.0.4.dist-info}/licenses/LICENSE +0 -0
ansible_vars/cli.py
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# CLI entry point for ansible-vars
|
5
5
|
|
6
6
|
# Standard library imports
|
7
|
-
import os, re, json, atexit, signal
|
7
|
+
import sys, os, re, json, atexit, signal
|
8
8
|
from glob import glob
|
9
9
|
from time import sleep
|
10
10
|
from enum import StrEnum
|
@@ -12,7 +12,7 @@ from pathlib import Path
|
|
12
12
|
from shutil import rmtree
|
13
13
|
from builtins import print as std_print
|
14
14
|
from subprocess import run as sys_command
|
15
|
-
from tempfile import NamedTemporaryFile,
|
15
|
+
from tempfile import NamedTemporaryFile, gettempdir
|
16
16
|
from typing import Iterator, Type, Hashable, Callable, Any
|
17
17
|
from argparse import ArgumentParser, RawDescriptionHelpFormatter
|
18
18
|
|
@@ -51,6 +51,7 @@ ansible-vars --add-key my_key '<passphrase>' --add-key other_key '<passphrase>'
|
|
51
51
|
# Check if a string value is encrypted (no keys need to be loaded for this)
|
52
52
|
ansible-vars is-encrypted string '<value>'
|
53
53
|
# Recursively search the directory `./host_vars` of vault files for decrypted text matches on a regex pattern
|
54
|
+
# `h:` is a shorthand for `./host_vars`, see tips section below for more information about advanced path resolution
|
54
55
|
ansible-vars grep '# TODO' h:
|
55
56
|
# Get the diff of two vaults
|
56
57
|
ansible-vars diff my_vault.yml.old my_vault.yml
|
@@ -123,7 +124,7 @@ Encrypt a string and return it or fully encrypt a file in-place. This uses the c
|
|
123
124
|
Decrypt a string and return it or fully decrypt a file in-place. Uses the first matching one of the loaded keys.
|
124
125
|
''',
|
125
126
|
'cmd_is_enc': '''
|
126
|
-
Check if a string or file is vault-encrypted.
|
127
|
+
Check if a string or file is (fully) vault-encrypted.
|
127
128
|
''',
|
128
129
|
'cmd_convert': '''
|
129
130
|
Switch a file between full outer and full inner encryption for convenient migrating between encryption schemes.
|
@@ -189,6 +190,9 @@ Deletes a node from a vault if it exists.
|
|
189
190
|
}
|
190
191
|
|
191
192
|
DEFAULT_EDITOR: str = os.environ.get('EDITOR', 'notepad.exe' if os.name == 'nt' else 'vi')
|
193
|
+
DEFAULT_COLOR_MODE: str = os.environ.get('AV_COLOR_MODE', '256')
|
194
|
+
DEFAULT_TEMP_DIR: str = os.environ.get('AV_TEMP_DIR', gettempdir())
|
195
|
+
DEFAULT_CREATE_PLAIN: bool = os.environ.get('AV_CREATE_PLAIN', 'no').lower() in [ 'yes', 'y', 'true', 't', '1' ]
|
192
196
|
|
193
197
|
args: ArgumentParser = ArgumentParser(
|
194
198
|
prog = 'ansible-vars',
|
@@ -218,7 +222,14 @@ def _prefixed_path_completer(prefix: str, **_) -> list[str]:
|
|
218
222
|
# Base args
|
219
223
|
|
220
224
|
args.add_argument('--debug', '-d', action='store_true', help='print debug information')
|
221
|
-
args.add_argument(
|
225
|
+
args.add_argument(
|
226
|
+
'--color-mode', '-C', type=str, choices=['none', 'basic', '256', 'truecolor'], default=DEFAULT_COLOR_MODE,
|
227
|
+
help=f"set terminal color capability (default: { DEFAULT_COLOR_MODE })"
|
228
|
+
)
|
229
|
+
args.add_argument(
|
230
|
+
'--temp-dir', '-T', type=str, metavar='<path>', default=DEFAULT_TEMP_DIR,
|
231
|
+
help=f"use this directory for vault staging instead of the system\'s TMP directory (default: { DEFAULT_TEMP_DIR })"
|
232
|
+
)
|
222
233
|
|
223
234
|
key_args = args.add_argument_group('vault key management', description=HELP['key_args'])
|
224
235
|
# This arg can be repeated (results in [ [id, passphrase], ... ])
|
@@ -232,7 +243,7 @@ log_args = args.add_argument_group('logging vault changes', description=HELP['lo
|
|
232
243
|
log_mutex = log_args.add_mutually_exclusive_group()
|
233
244
|
log_mutex.add_argument('--log', '-l', type=str, metavar='<log path>', help='log to an encrypted logfile (uses the encryption key)')
|
234
245
|
log_mutex.add_argument('--log-plain', '-L', type=str, metavar='<log path>', help='log to a plain logfile (dangerous!)')
|
235
|
-
log_args.add_argument('--logging-key', type=str, metavar='<identifier>', help='use this loaded key for logging instead of the encryption key')
|
246
|
+
log_args.add_argument('--logging-key', '-Q', type=str, metavar='<identifier>', help='use this loaded key for logging instead of the encryption key')
|
236
247
|
|
237
248
|
# Commands
|
238
249
|
commands = args.add_subparsers(dest='command', metavar='<command>', required=True)
|
@@ -244,7 +255,11 @@ cmd_keyring.add_argument('--keys-only', '-o', action='store_false', dest='show_p
|
|
244
255
|
cmd_create = commands.add_parser('create', help='create a new vault', description=HELP['cmd_create'])
|
245
256
|
cmd_create.add_argument('vault_path', type=str, metavar='<vault path>', help='path to create a new vault at') \
|
246
257
|
.completer = _prefixed_path_completer # type: ignore
|
247
|
-
|
258
|
+
# Invert flag if the user wants plain mode by default
|
259
|
+
if DEFAULT_CREATE_PLAIN:
|
260
|
+
cmd_create.add_argument('--no-plain', '-P', action='store_true', dest='encrypt_vault', help='create with full file encryption')
|
261
|
+
else:
|
262
|
+
cmd_create.add_argument('--plain', '-p', action='store_false', dest='encrypt_vault', help='create without full file encryption')
|
248
263
|
cmd_create.add_argument('--make-parents', '-m', action='store_true', help='create all directories in the given path')
|
249
264
|
cmd_mutex = cmd_create.add_mutually_exclusive_group()
|
250
265
|
cmd_mutex.add_argument('--no-edit', '-n', action='store_false', dest='open_edit_mode', help='just create the file, don\'t open it for editing')
|
@@ -318,8 +333,8 @@ cmd_changes.add_argument('new_vault', type=str, metavar='<new vault vault path>'
|
|
318
333
|
.completer = _prefixed_path_completer # type: ignore
|
319
334
|
cmd_changes.add_argument('--json', '-j', action='store_true', dest='as_json', help='print added/changed/removed/decrypted vars as JSON and nothing else')
|
320
335
|
|
321
|
-
cmd_daemon = commands.add_parser('file-daemon', help='
|
322
|
-
cmd_daemon.add_argument('target_root', type=str, metavar='<target root path>', help='root
|
336
|
+
cmd_daemon = commands.add_parser('file-daemon', help='sync decrypted vault copies into a folder', description=HELP['cmd_daemon'])
|
337
|
+
cmd_daemon.add_argument('target_root', type=str, metavar='<target root path>', help='root folder the decrypted files and folders should be synced into (non-existent or empty)') \
|
323
338
|
.completer = _prefixed_path_completer # type: ignore
|
324
339
|
# This arg can be repeated (results in [ [source, rel_target], ... ])
|
325
340
|
cmd_daemon.add_argument(
|
@@ -328,14 +343,16 @@ cmd_daemon.add_argument(
|
|
328
343
|
).completer = _prefixed_path_completer # type: ignore
|
329
344
|
cmd_daemon.add_argument('--no-recurse', '-n', action='store_false', dest='recurse', help='don\'t recurse into source folders\' subfolders')
|
330
345
|
cmd_daemon.add_argument('--no-default-dirs', '-N', action='store_false', dest='include_default_dirs', help='don\'t include default sync sources')
|
331
|
-
cmd_daemon.add_argument('--force', '-f', action='store_true', help='if the target root already exists, delete
|
346
|
+
cmd_daemon.add_argument('--force', '-f', action='store_true', help='if the target root already exists and is not empty, delete its contents')
|
332
347
|
|
333
348
|
cmd_get = commands.add_parser('get', help='get a key\'s (decrypted) value if it exists', description=HELP['cmd_get'])
|
334
349
|
cmd_get.add_argument('vault_path', type=str, metavar='<vault path>', help='path of vault to get value from') \
|
335
350
|
.completer = _prefixed_path_completer # type: ignore
|
336
351
|
cmd_get.add_argument('key_segments', type=str, nargs='+', metavar='<key segment> [<key segment> ...]', help='segment(s) of the key to look up (`[<num>]` for numbers)')
|
337
352
|
cmd_get.add_argument('--no-decrypt', '-n', action='store_false', dest='decrypt_value', help='don\'t decrypt the value if it is encrypted')
|
338
|
-
cmd_get.
|
353
|
+
get_mutex_format = cmd_get.add_mutually_exclusive_group()
|
354
|
+
get_mutex_format.add_argument('--quiet', '-q', action='store_true', help='only output the raw YAML value or set the rc to 100 if the key doesn\'t exist')
|
355
|
+
get_mutex_format.add_argument('--json', '-j', action='store_true', dest='as_json', help='print the value as JSON or set the rc to 100 if the key doesn\'t exist')
|
339
356
|
|
340
357
|
cmd_set = commands.add_parser('set', help='update a key\'s value or add a new key (experimental!)', description=HELP['cmd_set'])
|
341
358
|
cmd_set.add_argument('vault_path', type=str, metavar='<vault path>', help='path of vault to set value in') \
|
@@ -483,6 +500,15 @@ def resolve_vault_path(search_path: str, create_mode: bool = False, allow_dirs:
|
|
483
500
|
|
484
501
|
## CLI logic
|
485
502
|
|
503
|
+
# Print all exceptions unless we're in debug mode
|
504
|
+
def _exc_hook(exctype, value, traceback) -> None:
|
505
|
+
if config.debug:
|
506
|
+
sys.__excepthook__(exctype, value, traceback)
|
507
|
+
else:
|
508
|
+
print(f"{ value.__class__.__name__ }: { value }", Color.BAD)
|
509
|
+
print('Use --debug to get the full stacktrace')
|
510
|
+
sys.excepthook = _exc_hook
|
511
|
+
|
486
512
|
# Load vault keys
|
487
513
|
|
488
514
|
_explicit_keys: list[VaultKey] = [ VaultKey(passphrase, vault_id=id) for id, passphrase in config.keys ]
|
@@ -556,7 +582,7 @@ if config.command in [ 'create', 'edit' ]:
|
|
556
582
|
if getattr(config, 'open_edit_mode', True):
|
557
583
|
print(f"Editing vault at { vault_path }")
|
558
584
|
# Create a secure temporary file to host the editable content
|
559
|
-
with NamedTemporaryFile(mode='w+', prefix='vault_', suffix='.yml') as edit_file:
|
585
|
+
with NamedTemporaryFile(mode='w+', dir=config.temp_dir, prefix='vault_', suffix='.yml') as edit_file:
|
560
586
|
# Write vault contents to temp file
|
561
587
|
editable: str = vault.as_editable()
|
562
588
|
edit_file.write(editable)
|
@@ -586,6 +612,17 @@ if config.command in [ 'create', 'edit' ]:
|
|
586
612
|
if (changes := new_vault.changes(vault))[0]:
|
587
613
|
print(f"\n[!] The following vars have been decrypted in this edit:", Color.MEH)
|
588
614
|
print('\n'.join([ f"- { format_key_path(path) }" for path in changes[0] ]))
|
615
|
+
# Inform about new plain leaf variables
|
616
|
+
new_plain_leaves: list[tuple[Hashable, ...]] = []
|
617
|
+
def _find_new_plain_vars(path: tuple[Hashable, ...], value: Any) -> Any:
|
618
|
+
if path != ( SENTINEL_KEY, ) and type(value) is not EncryptedVar:
|
619
|
+
if vault.get(path, default=Unset) != value:
|
620
|
+
new_plain_leaves.append(path)
|
621
|
+
return value
|
622
|
+
vault._transform_leaves(new_vault._data, _find_new_plain_vars, tuple())
|
623
|
+
if not new_vault.full_encryption and new_plain_leaves:
|
624
|
+
print(f"\n[!] The following plain vars have been added in this edit:", Color.MEH)
|
625
|
+
print('\n'.join([ f"- { format_key_path(path) }" for path in new_plain_leaves ]))
|
589
626
|
# Log changes
|
590
627
|
if log_enabled:
|
591
628
|
logger.add_log_entry(vault, new_vault, comment=f"{ config.command } command via CLI")
|
@@ -654,7 +691,7 @@ if config.command in [ 'encrypt', 'decrypt', 'is-encrypted' ]:
|
|
654
691
|
if config.quiet:
|
655
692
|
exit(0 if vault.full_encryption else 100)
|
656
693
|
else:
|
657
|
-
print(f"Vault is { 'encrypted' if vault.full_encryption else 'plain' }.", Color.GOOD if vault.full_encryption else Color.MEH)
|
694
|
+
print(f"Vault is { 'encrypted' if vault.full_encryption else 'plain or hybrid' }.", Color.GOOD if vault.full_encryption else Color.MEH)
|
658
695
|
# String target
|
659
696
|
else:
|
660
697
|
is_encrypted: bool = VaultKey.is_encrypted(config.target)
|
@@ -866,11 +903,15 @@ if config.command in [ 'diff', 'changes' ]:
|
|
866
903
|
|
867
904
|
if config.command == 'file-daemon':
|
868
905
|
target_path: str = os.path.abspath(config.target_root)
|
869
|
-
if os.path.
|
906
|
+
if os.path.isfile(target_path) or (os.path.isdir(target_path) and os.listdir(target_path)):
|
870
907
|
if config.force:
|
871
|
-
|
908
|
+
for child in map(lambda c: os.path.join(target_path, c), os.listdir(target_path)):
|
909
|
+
if os.path.isfile(child):
|
910
|
+
os.unlink(child)
|
911
|
+
else:
|
912
|
+
rmtree(child, ignore_errors=True)
|
872
913
|
else:
|
873
|
-
raise FileExistsError(f"Cannot
|
914
|
+
raise FileExistsError(f"Cannot create sync root at { target_path } as the path already exist and is not empty")
|
874
915
|
# Resolve sources
|
875
916
|
if config.include_default_dirs:
|
876
917
|
for dir_path in ( 'host_vars', 'group_vars', 'vars' ):
|
@@ -886,14 +927,22 @@ if config.command == 'file-daemon':
|
|
886
927
|
for _path, _target in sources:
|
887
928
|
if _target == subtarget and _path != path:
|
888
929
|
raise ValueError(f"Sources may not have the same target subpath, found identical target for { _path } and { path }")
|
889
|
-
# Create target dir
|
890
|
-
|
891
|
-
os.
|
930
|
+
# Create target dir and record if we had to create it for later cleanup
|
931
|
+
already_existed: bool = os.path.isdir(target_path)
|
932
|
+
os.makedirs(target_path, mode=0o700, exist_ok=True)
|
892
933
|
# Cleanup handler
|
893
|
-
def _cleanup_daemons(daemons) -> None:
|
934
|
+
def _cleanup_daemons(daemons, delete_root) -> None:
|
894
935
|
print('\nStopping file daemons and cleaning up files...')
|
895
936
|
[ daemon.stop(delete=False) for daemon in daemons ] # type: ignore
|
896
|
-
|
937
|
+
# Only delete the root directory if we created it ourselves
|
938
|
+
if delete_root:
|
939
|
+
rmtree(target_path, ignore_errors=True)
|
940
|
+
else:
|
941
|
+
for child in map(lambda c: os.path.join(target_path, c), os.listdir(target_path)):
|
942
|
+
if os.path.isfile(child):
|
943
|
+
os.unlink(child)
|
944
|
+
else:
|
945
|
+
rmtree(child, ignore_errors=True)
|
897
946
|
print('Goodbye.')
|
898
947
|
# Create daemons
|
899
948
|
def _error_callback(daemon: VaultDaemon, operation: str, err: Exception) -> None:
|
@@ -905,13 +954,13 @@ if config.command == 'file-daemon':
|
|
905
954
|
VaultDaemon(path, target, keyring, recurse=config.recurse, error_callback=_error_callback, debug_out=_debug_out)
|
906
955
|
for path, target in sources
|
907
956
|
]
|
908
|
-
atexit.register(_cleanup_daemons, daemons=daemons)
|
957
|
+
atexit.register(_cleanup_daemons, daemons=daemons, delete_root=(not already_existed))
|
909
958
|
# Extra interrupt handler to silence error
|
910
959
|
signal.signal(signal.SIGINT, lambda *_: exit(0))
|
911
960
|
# Start file daemons
|
912
961
|
[ daemon.start(stop_on_exit=False) for daemon in daemons ]
|
913
|
-
print(f"{ len(daemons) } file
|
914
|
-
print('Interrupt the program to stop
|
962
|
+
print(f"{ len(daemons) } file daemon(s) running.", Color.GOOD)
|
963
|
+
print('Interrupt the program to stop and delete the target directory.')
|
915
964
|
# Idle
|
916
965
|
try:
|
917
966
|
while True:
|
@@ -932,10 +981,11 @@ if config.command in [ 'get', 'set', 'del' ]:
|
|
932
981
|
value = value.cipher
|
933
982
|
if type(value) is ProtoEncryptedVar:
|
934
983
|
value = value.plaintext
|
984
|
+
# Early abort
|
985
|
+
if (config.as_json or config.quiet) and value is Unset:
|
986
|
+
exit(100)
|
935
987
|
# Output JSON
|
936
988
|
if config.as_json:
|
937
|
-
if value is Unset:
|
938
|
-
exit(100)
|
939
989
|
# Custom decoder for encrypted vars
|
940
990
|
def _decode_vars(obj) -> Any:
|
941
991
|
if type(obj) is EncryptedVar:
|
@@ -945,7 +995,11 @@ if config.command in [ 'get', 'set', 'del' ]:
|
|
945
995
|
raise TypeError(f"{ type(obj) } cannot be serialized into JSON")
|
946
996
|
json_code: str = json.dumps(value, default=_decode_vars, indent=2)
|
947
997
|
print_json(json_code)
|
948
|
-
# Output
|
998
|
+
# Output nothing but the raw YAML
|
999
|
+
elif config.quiet:
|
1000
|
+
yaml_code: str = vault._dump_to_str(value).strip('\n') if isinstance(value, dict | list | tuple) else str(value)
|
1001
|
+
print_yaml(yaml_code)
|
1002
|
+
# Output text with extra messages
|
949
1003
|
else:
|
950
1004
|
print(f"Key: { format_key_path(key) }")
|
951
1005
|
if value is Unset:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ansible-vars
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.4
|
4
4
|
Summary: Manage vaults and variable files for Ansible
|
5
5
|
Project-URL: Homepage, https://github.com/xorwow/ansible-vars
|
6
6
|
Project-URL: Issues, https://github.com/xorwow/ansible-vars/issues
|
@@ -172,7 +172,7 @@ Shows the amounts of encrypted and decrypted variables in a vault file. Supports
|
|
172
172
|
|
173
173
|
#### encrypt, decrypt, is-encrypted
|
174
174
|
|
175
|
-
En-/Decrypts or checks the encryption status of a file or string value.
|
175
|
+
En-/Decrypts or checks the encryption status of a file or string value. Note that only full file encryption is considered in file mode, a hybrid vault with individually encrypted variables will be counted as plain.
|
176
176
|
|
177
177
|
#### convert
|
178
178
|
|
@@ -192,7 +192,7 @@ Compares two vaults or variable files and prints a tree structure showing differ
|
|
192
192
|
|
193
193
|
#### file-daemon
|
194
194
|
|
195
|
-
Starts a daemon which mirrors the decrypted contents of one or multiple vault or variable file(s)/directories to a target directory. By default, this includes the directories `./host_vars`, `./group_vars`, and `./vars`. Changes to the source files are reflected in the decrypted targets. Changes to the target files are ignored.
|
195
|
+
Starts a daemon which mirrors the decrypted contents of one or multiple vault or variable file(s)/directories to a target directory. By default, this includes the directories `./host_vars`, `./group_vars`, and `./vars`. Changes to the source files are reflected in the decrypted targets. Changes to the target files are ignored. For added security, consider syncing the files to a mounted ramdisk.
|
196
196
|
|
197
197
|
#### get
|
198
198
|
|
@@ -202,6 +202,20 @@ Displays the (decrypted) value of a specified key in a vault or variable file. S
|
|
202
202
|
|
203
203
|
Creates, updates, or deletes a key-value pair from a vault or variable file. When setting a value, you may provide a YAML string which will be parsed into the corresponding objects. Note that these are experimental features, as the current parser has difficulty preserving the metadata for programmatic variable changes. Comments and Jinja2 blocks between the affected key and the next key in the file may be lost.
|
204
204
|
|
205
|
+
### Environment variables
|
206
|
+
|
207
|
+
#### AV_COLOR_MODE
|
208
|
+
|
209
|
+
Set the color mode as you would with `-C <mode>`.
|
210
|
+
|
211
|
+
#### AV_TEMP_DIR
|
212
|
+
|
213
|
+
Set the tempfile/staging root as you would with `-T <path>`.
|
214
|
+
|
215
|
+
#### AV_CREATE_PLAIN
|
216
|
+
|
217
|
+
Invert the default creation mode for files: If unset or `no`, files are created with full encryption unless specified otherwise via the `--plain|-p` flag. This behavior mirrors that of `ansible-vault`. When set to `yes`, the behavior and flag are inverted as files are created without encryption by default unless specified otherwise via the `--no-plain|-P` flag.
|
218
|
+
|
205
219
|
### Python library
|
206
220
|
|
207
221
|
When using `ansible-vars` as a library, import any of these modules from the `ansible_vars` module.
|
@@ -230,6 +244,10 @@ The `VaultDaemon` syncs changes from a source file or directory to a target usin
|
|
230
244
|
|
231
245
|
Custom types and exceptions, and static values. Mostly useful for type hints.
|
232
246
|
|
247
|
+
## Security considerations
|
248
|
+
|
249
|
+
When editing a file or creating a daemon, decrypted vaults are written to disk temporarily. The temporary files can only be accessed by the current user, but could potentially be restored through data recovery methods after deletion. To mitigate this issue, consider creating an in-RAM filesystem ("ramdisk") and using it as the staging directory (`--temp-dir <path>`) or the daemon target.
|
250
|
+
|
233
251
|
## Known issues and limitations
|
234
252
|
|
235
253
|
- YAML round-trip parser
|
@@ -1,12 +1,12 @@
|
|
1
1
|
ansible_vars/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
ansible_vars/cli.py,sha256=
|
2
|
+
ansible_vars/cli.py,sha256=O3DELnEBaRyNyqFTA_jBP-Rafq_fH47chO085DZWU-Y,58778
|
3
3
|
ansible_vars/constants.py,sha256=Nd3sIuSoOvyfUfHfnsnJBDGMW7eNzbMm1NAvEQio9hE,1624
|
4
4
|
ansible_vars/errors.py,sha256=VnViEBMR3rIeioMj460DgdBA5S5FYiDObaDDhG2FMBs,857
|
5
5
|
ansible_vars/util.py,sha256=BzS7n3UzaKqVZ3W78HVkJtdVCYofprqQDtU8wYH1d0Q,21325
|
6
6
|
ansible_vars/vault.py,sha256=_dp1K5_UAFGgcg6iO4on4-L_BaJO2cHP6My3EU6enA4,45593
|
7
7
|
ansible_vars/vault_crypt.py,sha256=JcFc6dTZ6EqhKXv_C5ofggTpBK8hWG3ZwrBrDNYcEIg,9501
|
8
|
-
ansible_vars-1.0.
|
9
|
-
ansible_vars-1.0.
|
10
|
-
ansible_vars-1.0.
|
11
|
-
ansible_vars-1.0.
|
12
|
-
ansible_vars-1.0.
|
8
|
+
ansible_vars-1.0.4.dist-info/METADATA,sha256=T8ZAx8InOTtaMSGnw74znzAUdCzUkSP9FcmGk9bc1nc,16863
|
9
|
+
ansible_vars-1.0.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
10
|
+
ansible_vars-1.0.4.dist-info/entry_points.txt,sha256=RrhkEH0MbfRzflguVrfYfthsFC5V2fkFnizUG3uHMtQ,55
|
11
|
+
ansible_vars-1.0.4.dist-info/licenses/LICENSE,sha256=ocyJHLG5wD12qB4uam2pqWTHIJmzloiyNyTex6Q2DKo,1062
|
12
|
+
ansible_vars-1.0.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|