illumio-pylo 0.3.6__py3-none-any.whl → 0.3.7__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.
- illumio_pylo/API/CredentialsManager.py +22 -1
- illumio_pylo/Helpers/exports.py +1 -1
- illumio_pylo/__init__.py +1 -1
- illumio_pylo/cli/__init__.py +1 -1
- illumio_pylo/cli/commands/credential_manager.py +30 -35
- illumio_pylo/cli/commands/ruleset_export.py +0 -3
- illumio_pylo/cli/commands/ven_duplicate_remover.py +1 -0
- illumio_pylo/cli/commands/workload_import.py +2 -2
- illumio_pylo/cli/commands/workload_update.py +4 -2
- {illumio_pylo-0.3.6.dist-info → illumio_pylo-0.3.7.dist-info}/METADATA +1 -1
- {illumio_pylo-0.3.6.dist-info → illumio_pylo-0.3.7.dist-info}/RECORD +14 -14
- {illumio_pylo-0.3.6.dist-info → illumio_pylo-0.3.7.dist-info}/LICENSE +0 -0
- {illumio_pylo-0.3.6.dist-info → illumio_pylo-0.3.7.dist-info}/WHEEL +0 -0
- {illumio_pylo-0.3.6.dist-info → illumio_pylo-0.3.7.dist-info}/top_level.txt +0 -0
|
@@ -46,7 +46,6 @@ class CredentialProfile:
|
|
|
46
46
|
|
|
47
47
|
self.raw_json: Optional[CredentialFileEntry] = None
|
|
48
48
|
|
|
49
|
-
|
|
50
49
|
@staticmethod
|
|
51
50
|
def from_credentials_file_entry(credential_file_entry: CredentialFileEntry, originating_file: Optional[str] = None):
|
|
52
51
|
return CredentialProfile(credential_file_entry['name'],
|
|
@@ -303,3 +302,25 @@ def find_ssh_key_from_fingerprint(fingerprint: bytes) -> Optional[paramiko.Agent
|
|
|
303
302
|
if key.get_fingerprint() == fingerprint:
|
|
304
303
|
return key
|
|
305
304
|
return None
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def get_supported_keys_from_ssh_agent() -> list[paramiko.AgentKey]:
|
|
308
|
+
keys = paramiko.Agent().get_keys()
|
|
309
|
+
# filter out ECDSA NISTPXXX and sk-ssh-ed25519
|
|
310
|
+
# RSA and ED25519 keys are reported to be working
|
|
311
|
+
return [key for key in keys if not (key.get_name().startswith("ecdsa-sha2-nistp") or
|
|
312
|
+
key.get_name().startswith("sk-ssh-ed25519"))]
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def is_encryption_available() -> bool:
|
|
316
|
+
if paramiko is None:
|
|
317
|
+
return False
|
|
318
|
+
|
|
319
|
+
# does paramiko have an agent module and does it have any supported key?
|
|
320
|
+
if hasattr(paramiko, 'Agent'):
|
|
321
|
+
keys = get_supported_keys_from_ssh_agent()
|
|
322
|
+
return len(keys) > 0
|
|
323
|
+
|
|
324
|
+
return False
|
|
325
|
+
|
|
326
|
+
|
illumio_pylo/Helpers/exports.py
CHANGED
|
@@ -436,7 +436,7 @@ class CsvExcelToObject:
|
|
|
436
436
|
for col_index in range(1, source_worksheet.max_column+1):
|
|
437
437
|
item = source_worksheet.cell(row_count, col_index).value
|
|
438
438
|
if item is None or len(item) < 1:
|
|
439
|
-
raise pylo.PyloEx('Excel headers has blank
|
|
439
|
+
raise pylo.PyloEx('Excel headers has blank field at column #{}'.format(col_index))
|
|
440
440
|
self._detected_headers.append(item.lower())
|
|
441
441
|
if strict_headers and item.lower() not in mandatory_headers_dict:
|
|
442
442
|
raise pylo.PyloEx("CSV/Excel headers have an unexpected header named '{}'".format(item))
|
illumio_pylo/__init__.py
CHANGED
illumio_pylo/cli/__init__.py
CHANGED
|
@@ -151,7 +151,7 @@ def run(forced_command_name: Optional[str] = None):
|
|
|
151
151
|
print("**** END OF {} UTILITY ****".format(selected_command.name.upper()))
|
|
152
152
|
print("Command Specific Execution time: {:.2f} seconds".format(time.perf_counter() - command_execution_time_start))
|
|
153
153
|
print("CLI started at {} and finished at {}".format(cli_start_time, cli_end_time))
|
|
154
|
-
print("CLI Total Execution time: {}".format(cli_end_time - cli_start_time))
|
|
154
|
+
print("CLI Total Execution time: {}".format((cli_end_time - cli_start_time)))
|
|
155
155
|
print()
|
|
156
156
|
|
|
157
157
|
|
|
@@ -9,9 +9,9 @@ import paramiko
|
|
|
9
9
|
import illumio_pylo as pylo
|
|
10
10
|
import click
|
|
11
11
|
from illumio_pylo.API.CredentialsManager import get_all_credentials, create_credential_in_file, CredentialFileEntry, \
|
|
12
|
-
create_credential_in_default_file,
|
|
12
|
+
create_credential_in_default_file, \
|
|
13
13
|
get_credentials_from_file, encrypt_api_key_with_paramiko_ssh_key_chacha20poly1305, \
|
|
14
|
-
decrypt_api_key_with_paramiko_ssh_key_chacha20poly1305,
|
|
14
|
+
decrypt_api_key_with_paramiko_ssh_key_chacha20poly1305, get_supported_keys_from_ssh_agent, is_encryption_available
|
|
15
15
|
|
|
16
16
|
from illumio_pylo import log
|
|
17
17
|
from . import Command
|
|
@@ -117,32 +117,33 @@ def __main(args, **kwargs):
|
|
|
117
117
|
"api_key": api_key
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
120
|
+
if is_encryption_available():
|
|
121
|
+
encrypt_api_key = click.prompt('> Encrypt API (requires an SSH agent running and an RSA or Ed25519 key added to them) ? Y/N', type=bool)
|
|
122
|
+
if encrypt_api_key:
|
|
123
|
+
print("Available keys (ECDSA NISTPXXX keys and a few others are not supported and will be filtered out):")
|
|
124
|
+
ssh_keys = get_supported_keys_from_ssh_agent()
|
|
125
|
+
|
|
126
|
+
# display a table of keys
|
|
127
|
+
print_keys(keys=ssh_keys, display_index=True)
|
|
128
|
+
print()
|
|
129
|
+
|
|
130
|
+
index_of_selected_key = click.prompt('> Select key by ID#', type=click.IntRange(0, len(ssh_keys)-1))
|
|
131
|
+
selected_ssh_key = ssh_keys[index_of_selected_key]
|
|
132
|
+
print("Selected key: {} | {} | {}".format(selected_ssh_key.get_name(),
|
|
133
|
+
selected_ssh_key.get_fingerprint().hex(),
|
|
134
|
+
selected_ssh_key.comment))
|
|
135
|
+
print(" * encrypting API key with selected key (you may be prompted by your SSH agent for confirmation or PIN code) ...", flush=True, end="")
|
|
136
|
+
# encrypted_api_key = encrypt_api_key_with_paramiko_ssh_key_fernet(ssh_key=selected_ssh_key, api_key=api_key)
|
|
137
|
+
encrypted_api_key = encrypt_api_key_with_paramiko_ssh_key_chacha20poly1305(ssh_key=selected_ssh_key, api_key=api_key)
|
|
138
|
+
print("OK!")
|
|
139
|
+
print(" * trying to decrypt the encrypted API key...", flush=True, end="")
|
|
140
|
+
decrypted_api_key = decrypt_api_key_with_paramiko_ssh_key_chacha20poly1305(encrypted_api_key_payload=encrypted_api_key)
|
|
141
|
+
if decrypted_api_key != api_key:
|
|
142
|
+
raise pylo.PyloEx("Decrypted API key does not match original API key")
|
|
143
|
+
print("OK!")
|
|
144
|
+
credentials_data["api_key"] = encrypted_api_key
|
|
145
|
+
else:
|
|
146
|
+
print(" * encryption is not available (no SSH agent or compatible key found), storing API key in plain text...")
|
|
146
147
|
|
|
147
148
|
|
|
148
149
|
cwd = os.getcwd()
|
|
@@ -187,15 +188,9 @@ def __main(args, **kwargs):
|
|
|
187
188
|
else:
|
|
188
189
|
raise pylo.PyloEx("Unknown sub-command '{}'".format(args['sub_command']))
|
|
189
190
|
|
|
190
|
-
command_object = Command(command_name, __main, fill_parser, credentials_manager_mode=True)
|
|
191
191
|
|
|
192
|
+
command_object = Command(command_name, __main, fill_parser, credentials_manager_mode=True)
|
|
192
193
|
|
|
193
|
-
def get_supported_keys_from_ssh_agent() -> list[paramiko.AgentKey]:
|
|
194
|
-
keys = paramiko.Agent().get_keys()
|
|
195
|
-
# filter out ECDSA NISTPXXX and sk-ssh-ed25519
|
|
196
|
-
# RSA and ED25519 keys are reported to be working
|
|
197
|
-
return [key for key in keys if not (key.get_name().startswith("ecdsa-sha2-nistp") or
|
|
198
|
-
key.get_name().startswith("sk-ssh-ed25519"))]
|
|
199
194
|
|
|
200
195
|
def print_keys(keys: list[paramiko.AgentKey], display_index = True) -> None:
|
|
201
196
|
|
|
@@ -25,7 +25,6 @@ def fill_parser(parser: argparse.ArgumentParser):
|
|
|
25
25
|
"Public_NATed")
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
|
|
29
28
|
def __main(args: Dict, org: pylo.Organization, **kwargs):
|
|
30
29
|
|
|
31
30
|
setting_prefix_objects_with_type: bool|str = args['prefix_objects_with_type']
|
|
@@ -33,13 +32,11 @@ def __main(args: Dict, org: pylo.Organization, **kwargs):
|
|
|
33
32
|
settings_output_file_format = args['format']
|
|
34
33
|
settings_output_dir = args['output_dir']
|
|
35
34
|
|
|
36
|
-
|
|
37
35
|
if setting_prefix_objects_with_type is False:
|
|
38
36
|
print(" * Prefix for object types are disabled")
|
|
39
37
|
else:
|
|
40
38
|
print(" * Prefix for object types are enabled")
|
|
41
39
|
|
|
42
|
-
|
|
43
40
|
if setting_object_types_as_section is False:
|
|
44
41
|
print(" * Object types as section are disabled")
|
|
45
42
|
else:
|
|
@@ -288,6 +288,7 @@ def __main(args, org: pylo.Organization, pce_cache_was_used: bool, **kwargs):
|
|
|
288
288
|
# make this command available to the CLI system
|
|
289
289
|
command_object = Command(command_name, __main, fill_parser, objects_load_filter)
|
|
290
290
|
|
|
291
|
+
|
|
291
292
|
class DuplicateRecordManager:
|
|
292
293
|
class DuplicatedRecord:
|
|
293
294
|
def __init__(self, pce_offline_timer_override: Optional[int] = None):
|
|
@@ -283,8 +283,8 @@ def detect_workloads_name_collisions(csv_data, org: pylo.Organization, ignore_al
|
|
|
283
283
|
if csv_object['hostname'] is not None and len(csv_object['hostname']) > 0:
|
|
284
284
|
lower_hostname = csv_object['hostname'].lower()
|
|
285
285
|
if lower_name != lower_hostname:
|
|
286
|
-
if
|
|
287
|
-
name_cache[
|
|
286
|
+
if lower_hostname not in name_cache:
|
|
287
|
+
name_cache[lower_hostname] = WorkloadCollisionItem(from_pce=False, csv_object=csv_object,
|
|
288
288
|
managed=False)
|
|
289
289
|
else:
|
|
290
290
|
if not name_cache[lower_hostname].from_pce:
|
|
@@ -128,6 +128,7 @@ def __main(args, org: pylo.Organization, **kwargs):
|
|
|
128
128
|
|
|
129
129
|
print('OK')
|
|
130
130
|
print(" - CSV has {} columns and {} lines (headers don't count)".format(csv_input_object.count_columns(), csv_input_object.count_lines()))
|
|
131
|
+
context.csv_data = csv_input_object.objects()
|
|
131
132
|
# </editor-fold desc="CSV input file data extraction">
|
|
132
133
|
|
|
133
134
|
|
|
@@ -307,7 +308,7 @@ def check_and_sanitize_csv_input_data(context, input_match_on_hostname, input_ma
|
|
|
307
308
|
if input_match_on_hostname:
|
|
308
309
|
for csv_data in context.csv_data:
|
|
309
310
|
name = csv_data['hostname']
|
|
310
|
-
name = pylo.Workload.static_name_stripped_fqdn(name)
|
|
311
|
+
name = pylo.Workload.static_name_stripped_fqdn(name).lower()
|
|
311
312
|
if name is None or len(name) < 1:
|
|
312
313
|
print(" - ERROR: CSV line #{} has invalid hostname defined: '{}'".format(csv_data['*line*'],
|
|
313
314
|
csv_data['hostname']),
|
|
@@ -332,7 +333,7 @@ def check_and_sanitize_csv_input_data(context, input_match_on_hostname, input_ma
|
|
|
332
333
|
continue
|
|
333
334
|
|
|
334
335
|
if href not in context.csv_href_index:
|
|
335
|
-
context.
|
|
336
|
+
context.csv_href_index[href] = csv_data
|
|
336
337
|
continue
|
|
337
338
|
|
|
338
339
|
print(" - ERROR: CSV line #{} has duplicate href defined from a previous line: '{}'".format(
|
|
@@ -343,6 +344,7 @@ def check_and_sanitize_csv_input_data(context, input_match_on_hostname, input_ma
|
|
|
343
344
|
"ERROR! Several ({}) inconsistencies were found in the CSV, please fix them before you continue!".format(
|
|
344
345
|
csv_check_failed_count))
|
|
345
346
|
sys.exit(1)
|
|
347
|
+
|
|
346
348
|
print(" * Done")
|
|
347
349
|
|
|
348
350
|
|
|
@@ -21,36 +21,36 @@ illumio_pylo/VirtualServiceStore.py,sha256=MNTwo1cvteUuID6JniWUk5oRHQHGY4OwrWvFa
|
|
|
21
21
|
illumio_pylo/Workload.py,sha256=9kZHawayQQ_L-OBzyuuDcViWSa7HzDKEfPtcSHMsInw,19910
|
|
22
22
|
illumio_pylo/WorkloadStore.py,sha256=3C6SMU0wRlet6C6UVbjkYNsTY7vkyK_ZwqM1dlCBpsQ,10989
|
|
23
23
|
illumio_pylo/WorkloadStoreSubClasses.py,sha256=4GBb5sXan38Y5OE7O6aAR-IZrZJar0mYE44FbCSb3_k,6093
|
|
24
|
-
illumio_pylo/__init__.py,sha256=
|
|
24
|
+
illumio_pylo/__init__.py,sha256=NfjWb-G4N-kqGKvsr_N-zQZFy1bGNrUmZNfIIC21P2I,4172
|
|
25
25
|
illumio_pylo/tmp.py,sha256=DYlm07YEP6Nm5qScByfTloGi7TGaN9WtklSqeVROPik,3913
|
|
26
26
|
illumio_pylo/API/APIConnector.py,sha256=pxHuaRvUU_sX_DWgE_TVMR5ktRURVMOVGhkBbuV--Sc,60725
|
|
27
27
|
illumio_pylo/API/AuditLog.py,sha256=p0mfjrE5S8qoJgA5LIP_XGFBP3iL86Nl6BQEmhMVrPA,1533
|
|
28
28
|
illumio_pylo/API/ClusterHealth.py,sha256=GdMpVQrHUW4zLM-409GcPHM8H8b3LAppO37ZcUZyT_Q,5122
|
|
29
|
-
illumio_pylo/API/CredentialsManager.py,sha256
|
|
29
|
+
illumio_pylo/API/CredentialsManager.py,sha256=z-a8O67UwPnbAEmjv_t8C9Wb0eXbSql1PVhLZ8IEUms,12854
|
|
30
30
|
illumio_pylo/API/Explorer.py,sha256=fFAIF-67_uuKgJOP0eZPPJrOGuYmFl33GK75AyMjgJU,47590
|
|
31
31
|
illumio_pylo/API/JsonPayloadTypes.py,sha256=9gql3-tn3cu1qmpOD_JcPCX5b594eOKDgVhTqHu6CsQ,7984
|
|
32
32
|
illumio_pylo/API/RuleSearchQuery.py,sha256=O0-MsUXhwmywoO0G-GXnLq6kkVC9LgmxMZwqVKc_oJE,5325
|
|
33
33
|
illumio_pylo/API/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
34
34
|
illumio_pylo/Helpers/__init__.py,sha256=6E2eTZe-4qfPKGjRRQNtYsPrBhJSAjbdvv_DpniV_rY,49
|
|
35
|
-
illumio_pylo/Helpers/exports.py,sha256=
|
|
35
|
+
illumio_pylo/Helpers/exports.py,sha256=7wXWTRmjkfApgeweJ3gJ4qUXJLOK0xyA49cY_EkkkCg,21898
|
|
36
36
|
illumio_pylo/Helpers/functions.py,sha256=TjI_NmD3cm1Escp3h51SFEDgS1vT9dUa8PX9-e0siao,4680
|
|
37
37
|
illumio_pylo/cli/NativeParsers.py,sha256=nzDL54EV0J-Iz0P9EkeiPl6DWQBSbCu-MpEPRad3j6c,4055
|
|
38
|
-
illumio_pylo/cli/__init__.py,sha256=
|
|
38
|
+
illumio_pylo/cli/__init__.py,sha256=aJDJiuRjUg1_2_ubuDvZgPXy6lNEOVvHUqWac7j8RTU,7739
|
|
39
39
|
illumio_pylo/cli/__main__.py,sha256=ll1gK8k1YL_kPsImI7WVlw2sCyNyhocnuCqko6mGaYI,223
|
|
40
40
|
illumio_pylo/cli/commands/__init__.py,sha256=yoVkXy-qBGiAAziWiayJdjcclx1WTayShXSPqHelcWA,1489
|
|
41
|
-
illumio_pylo/cli/commands/credential_manager.py,sha256=
|
|
41
|
+
illumio_pylo/cli/commands/credential_manager.py,sha256=sAPEvFjxHuxUexfTigy2CR5evU_j9W7rAbalsoSWrLk,9421
|
|
42
42
|
illumio_pylo/cli/commands/iplist_analyzer.py,sha256=vOl6fNd0HrUKnKXtY1sj7jeyx2GtuDZENV7mF79O7yU,3714
|
|
43
43
|
illumio_pylo/cli/commands/iplist_import_from_file.py,sha256=XvC-GlJyjA4dDPzfvGoBFtwelI9g_rQqGzgKgqMYcsI,8284
|
|
44
|
-
illumio_pylo/cli/commands/ruleset_export.py,sha256=
|
|
44
|
+
illumio_pylo/cli/commands/ruleset_export.py,sha256=KC9ifZx8gcAzti6EnTMfS075K00-ovRbLxeKMUg3w8E,5893
|
|
45
45
|
illumio_pylo/cli/commands/update_pce_objects_cache.py,sha256=kNBAmPIbJyw97FRcNREy059A5FLOGm_poKJYGdTWqr4,1256
|
|
46
46
|
illumio_pylo/cli/commands/ven_compatibility_report_export.py,sha256=8ZpgGQfn5zmOslgeE1imwx4-gDHfukdgoXJGZUh9q3o,8120
|
|
47
|
-
illumio_pylo/cli/commands/ven_duplicate_remover.py,sha256=
|
|
47
|
+
illumio_pylo/cli/commands/ven_duplicate_remover.py,sha256=fr9EzLlJb_cizdxTC5yOOflwS_CDIpoWOk4EU9YjaY4,19580
|
|
48
48
|
illumio_pylo/cli/commands/ven_idle_to_visibility.py,sha256=OMcQSB82Pn50TS7OL1_TPOvvN9XFR3jUxVYYizUQinI,13387
|
|
49
49
|
illumio_pylo/cli/commands/ven_upgrader.py,sha256=4cLUA7HSpskJpPOtEkQh41lE4gMGJJiQiKGCd0CKYJk,7222
|
|
50
50
|
illumio_pylo/cli/commands/workload_export.py,sha256=EcQR8AacJVe7rOqYH-HFxyTchwHHQ9ZTc-ALSMt9gDY,11421
|
|
51
|
-
illumio_pylo/cli/commands/workload_import.py,sha256=
|
|
51
|
+
illumio_pylo/cli/commands/workload_import.py,sha256=FuUeLkauqYvKvWgWcS_xfQIxwTScp90ZdUMbUIFSadE,18923
|
|
52
52
|
illumio_pylo/cli/commands/workload_reset_names_to_null.py,sha256=GaO2Th1rx8i7_7yqb9WkGpDz3sdbYNod5fABQnhogig,3383
|
|
53
|
-
illumio_pylo/cli/commands/workload_update.py,sha256=
|
|
53
|
+
illumio_pylo/cli/commands/workload_update.py,sha256=tmzTV8uh4zmJf_F5rhBChuYjfnY_JtcDjSUKhvGK3rM,28543
|
|
54
54
|
illumio_pylo/cli/commands/workload_used_in_rule_finder.py,sha256=2MO9jjYh-mkY6rkfvDyW0Ok6El_AqDWGXiFDYq5YgTk,3361
|
|
55
55
|
illumio_pylo/cli/commands/utils/LabelCreation.py,sha256=qaU7BeP4et2GJxHwgbDNRoQLCA-xWp_y1nJ-m8ANUwA,4883
|
|
56
56
|
illumio_pylo/cli/commands/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -65,8 +65,8 @@ illumio_pylo/utilities/resources/iplists-import-example.xlsx,sha256=VW-7CRr8NA2V
|
|
|
65
65
|
illumio_pylo/utilities/resources/workload-exporter-filter-example.csv,sha256=cn5IA8AGEPjvS-EsPXA_GJ-LFsdF9t_44rSzFTCmAzE,36
|
|
66
66
|
illumio_pylo/utilities/resources/workloads-import-example.csv,sha256=DEOGVikFjxQpMFFI0l0jb3hrxEEeZCpTGkmWkz6GUcY,91
|
|
67
67
|
illumio_pylo/utilities/resources/workloads-import-example.xlsx,sha256=U8Ac2BZidA6NlvBFAVPHqeY5zmg3rjmIAXp5b3b1P5w,17101
|
|
68
|
-
illumio_pylo-0.3.
|
|
69
|
-
illumio_pylo-0.3.
|
|
70
|
-
illumio_pylo-0.3.
|
|
71
|
-
illumio_pylo-0.3.
|
|
72
|
-
illumio_pylo-0.3.
|
|
68
|
+
illumio_pylo-0.3.7.dist-info/LICENSE,sha256=WYmcYJG1QFgu1hfo7qrEkZ3Jhcz8NUWe6XUraZvlIFs,10172
|
|
69
|
+
illumio_pylo-0.3.7.dist-info/METADATA,sha256=wydOUCStSL8nqGPvpBlvDa-xfIjGAqKy2N_OXcQozGk,12224
|
|
70
|
+
illumio_pylo-0.3.7.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
71
|
+
illumio_pylo-0.3.7.dist-info/top_level.txt,sha256=c5cu_ZMuSuxjq48ih58Kc0Tr8-JdQtV8GrKJicvWNFE,13
|
|
72
|
+
illumio_pylo-0.3.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|