clonebox 1.1.14__py3-none-any.whl → 1.1.16__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.
- clonebox/audit.py +5 -1
- clonebox/cli.py +673 -11
- clonebox/cloner.py +358 -179
- clonebox/plugins/manager.py +85 -0
- clonebox/remote.py +511 -0
- clonebox/secrets.py +9 -6
- clonebox/validator.py +140 -53
- {clonebox-1.1.14.dist-info → clonebox-1.1.16.dist-info}/METADATA +5 -1
- {clonebox-1.1.14.dist-info → clonebox-1.1.16.dist-info}/RECORD +13 -12
- {clonebox-1.1.14.dist-info → clonebox-1.1.16.dist-info}/WHEEL +0 -0
- {clonebox-1.1.14.dist-info → clonebox-1.1.16.dist-info}/entry_points.txt +0 -0
- {clonebox-1.1.14.dist-info → clonebox-1.1.16.dist-info}/licenses/LICENSE +0 -0
- {clonebox-1.1.14.dist-info → clonebox-1.1.16.dist-info}/top_level.txt +0 -0
clonebox/validator.py
CHANGED
|
@@ -34,13 +34,21 @@ class VMValidator:
|
|
|
34
34
|
self.results = {
|
|
35
35
|
"mounts": {"passed": 0, "failed": 0, "total": 0, "details": []},
|
|
36
36
|
"packages": {"passed": 0, "failed": 0, "total": 0, "details": []},
|
|
37
|
-
"snap_packages": {
|
|
37
|
+
"snap_packages": {
|
|
38
|
+
"passed": 0,
|
|
39
|
+
"failed": 0,
|
|
40
|
+
"skipped": 0,
|
|
41
|
+
"total": 0,
|
|
42
|
+
"details": [],
|
|
43
|
+
},
|
|
38
44
|
"services": {"passed": 0, "failed": 0, "total": 0, "details": []},
|
|
39
|
-
"apps": {"passed": 0, "failed": 0, "total": 0, "details": []},
|
|
40
|
-
"smoke": {"passed": 0, "failed": 0, "total": 0, "details": []},
|
|
45
|
+
"apps": {"passed": 0, "failed": 0, "skipped": 0, "total": 0, "details": []},
|
|
46
|
+
"smoke": {"passed": 0, "failed": 0, "skipped": 0, "total": 0, "details": []},
|
|
41
47
|
"overall": "unknown",
|
|
42
48
|
}
|
|
43
49
|
|
|
50
|
+
self._setup_in_progress_cache: Optional[bool] = None
|
|
51
|
+
|
|
44
52
|
def _exec_in_vm(self, command: str, timeout: int = 10) -> Optional[str]:
|
|
45
53
|
"""Execute command in VM using QEMU guest agent."""
|
|
46
54
|
try:
|
|
@@ -105,14 +113,32 @@ class VMValidator:
|
|
|
105
113
|
except Exception:
|
|
106
114
|
return None
|
|
107
115
|
|
|
116
|
+
def _setup_in_progress(self) -> Optional[bool]:
|
|
117
|
+
if self._setup_in_progress_cache is not None:
|
|
118
|
+
return self._setup_in_progress_cache
|
|
119
|
+
|
|
120
|
+
out = self._exec_in_vm(
|
|
121
|
+
"test -f /var/lib/cloud/instance/boot-finished && echo no || echo yes",
|
|
122
|
+
timeout=10,
|
|
123
|
+
)
|
|
124
|
+
if out is None:
|
|
125
|
+
self._setup_in_progress_cache = None
|
|
126
|
+
return None
|
|
127
|
+
|
|
128
|
+
self._setup_in_progress_cache = out.strip() == "yes"
|
|
129
|
+
return self._setup_in_progress_cache
|
|
130
|
+
|
|
108
131
|
def validate_mounts(self) -> Dict:
|
|
109
132
|
"""Validate all mount points and copied data paths."""
|
|
110
133
|
self.console.print("\n[bold]💾 Validating Mounts & Data...[/]")
|
|
111
134
|
|
|
112
135
|
paths = self.config.get("paths", {})
|
|
113
|
-
|
|
136
|
+
# Support both v1 (app_data_paths) and v2 (copy_paths) config formats
|
|
137
|
+
copy_paths = self.config.get("copy_paths", None)
|
|
138
|
+
if not isinstance(copy_paths, dict) or not copy_paths:
|
|
139
|
+
copy_paths = self.config.get("app_data_paths", {})
|
|
114
140
|
|
|
115
|
-
if not paths and not
|
|
141
|
+
if not paths and not copy_paths:
|
|
116
142
|
self.console.print("[dim]No mounts or data paths configured[/]")
|
|
117
143
|
return self.results["mounts"]
|
|
118
144
|
|
|
@@ -129,6 +155,7 @@ class VMValidator:
|
|
|
129
155
|
mount_table.add_column("Files", justify="right")
|
|
130
156
|
|
|
131
157
|
# Validate bind mounts (paths)
|
|
158
|
+
setup_in_progress = self._setup_in_progress() is True
|
|
132
159
|
for host_path, guest_path in paths.items():
|
|
133
160
|
self.results["mounts"]["total"] += 1
|
|
134
161
|
|
|
@@ -156,6 +183,9 @@ class VMValidator:
|
|
|
156
183
|
status_icon = "[red]❌ Inaccessible[/]"
|
|
157
184
|
self.results["mounts"]["failed"] += 1
|
|
158
185
|
status = "mounted_but_inaccessible"
|
|
186
|
+
elif setup_in_progress:
|
|
187
|
+
status_icon = "[yellow]⏳ Pending[/]"
|
|
188
|
+
status = "pending"
|
|
159
189
|
else:
|
|
160
190
|
status_icon = "[red]❌ Not Mounted[/]"
|
|
161
191
|
self.results["mounts"]["failed"] += 1
|
|
@@ -171,8 +201,8 @@ class VMValidator:
|
|
|
171
201
|
"status": status
|
|
172
202
|
})
|
|
173
203
|
|
|
174
|
-
# Validate copied paths (app_data_paths)
|
|
175
|
-
for host_path, guest_path in
|
|
204
|
+
# Validate copied paths (copy_paths / app_data_paths)
|
|
205
|
+
for host_path, guest_path in copy_paths.items():
|
|
176
206
|
self.results["mounts"]["total"] += 1
|
|
177
207
|
|
|
178
208
|
# Check if exists and has content
|
|
@@ -193,6 +223,9 @@ class VMValidator:
|
|
|
193
223
|
status_icon = "[green]✅ Copied[/]"
|
|
194
224
|
self.results["mounts"]["passed"] += 1
|
|
195
225
|
status = "pass"
|
|
226
|
+
elif setup_in_progress:
|
|
227
|
+
status_icon = "[yellow]⏳ Pending[/]"
|
|
228
|
+
status = "pending"
|
|
196
229
|
else:
|
|
197
230
|
status_icon = "[red]❌ Missing[/]"
|
|
198
231
|
self.results["mounts"]["failed"] += 1
|
|
@@ -229,6 +262,8 @@ class VMValidator:
|
|
|
229
262
|
pkg_table.add_column("Status", justify="center")
|
|
230
263
|
pkg_table.add_column("Version", style="dim")
|
|
231
264
|
|
|
265
|
+
setup_in_progress = self._setup_in_progress() is True
|
|
266
|
+
|
|
232
267
|
for package in packages:
|
|
233
268
|
self.results["packages"]["total"] += 1
|
|
234
269
|
|
|
@@ -243,11 +278,17 @@ class VMValidator:
|
|
|
243
278
|
{"package": package, "installed": True, "version": version}
|
|
244
279
|
)
|
|
245
280
|
else:
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
281
|
+
if setup_in_progress:
|
|
282
|
+
pkg_table.add_row(package, "[yellow]⏳ Pending[/]", "")
|
|
283
|
+
self.results["packages"]["details"].append(
|
|
284
|
+
{"package": package, "installed": False, "version": None, "pending": True}
|
|
285
|
+
)
|
|
286
|
+
else:
|
|
287
|
+
pkg_table.add_row(package, "[red]❌ Missing[/]", "")
|
|
288
|
+
self.results["packages"]["failed"] += 1
|
|
289
|
+
self.results["packages"]["details"].append(
|
|
290
|
+
{"package": package, "installed": False, "version": None}
|
|
291
|
+
)
|
|
251
292
|
|
|
252
293
|
self.console.print(pkg_table)
|
|
253
294
|
self.console.print(
|
|
@@ -270,6 +311,8 @@ class VMValidator:
|
|
|
270
311
|
snap_table.add_column("Status", justify="center")
|
|
271
312
|
snap_table.add_column("Version", style="dim")
|
|
272
313
|
|
|
314
|
+
setup_in_progress = self._setup_in_progress() is True
|
|
315
|
+
|
|
273
316
|
for package in snap_packages:
|
|
274
317
|
self.results["snap_packages"]["total"] += 1
|
|
275
318
|
|
|
@@ -284,16 +327,29 @@ class VMValidator:
|
|
|
284
327
|
{"package": package, "installed": True, "version": version}
|
|
285
328
|
)
|
|
286
329
|
else:
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
330
|
+
if setup_in_progress:
|
|
331
|
+
snap_table.add_row(package, "[yellow]⏳ Pending[/]", "")
|
|
332
|
+
self.results["snap_packages"]["skipped"] += 1
|
|
333
|
+
self.results["snap_packages"]["details"].append(
|
|
334
|
+
{
|
|
335
|
+
"package": package,
|
|
336
|
+
"installed": False,
|
|
337
|
+
"version": None,
|
|
338
|
+
"pending": True,
|
|
339
|
+
}
|
|
340
|
+
)
|
|
341
|
+
else:
|
|
342
|
+
snap_table.add_row(package, "[red]❌ Missing[/]", "")
|
|
343
|
+
self.results["snap_packages"]["failed"] += 1
|
|
344
|
+
self.results["snap_packages"]["details"].append(
|
|
345
|
+
{"package": package, "installed": False, "version": None}
|
|
346
|
+
)
|
|
292
347
|
|
|
293
348
|
self.console.print(snap_table)
|
|
294
|
-
self.
|
|
295
|
-
|
|
296
|
-
|
|
349
|
+
msg = f"{self.results['snap_packages']['passed']}/{self.results['snap_packages']['total']} snap packages installed"
|
|
350
|
+
if self.results["snap_packages"].get("skipped", 0) > 0:
|
|
351
|
+
msg += f" ({self.results['snap_packages']['skipped']} pending)"
|
|
352
|
+
self.console.print(f"[dim]{msg}[/]")
|
|
297
353
|
|
|
298
354
|
return self.results["snap_packages"]
|
|
299
355
|
|
|
@@ -378,14 +434,14 @@ class VMValidator:
|
|
|
378
434
|
else:
|
|
379
435
|
pid_value = "—"
|
|
380
436
|
|
|
381
|
-
enabled_icon = "[green]✅[/]" if is_enabled else "[yellow]⚠️[/]"
|
|
382
|
-
running_icon = "[green]✅[/]" if is_running else "[red]❌[/]"
|
|
437
|
+
enabled_icon = "[green]✅[/]" if is_enabled else ("[yellow]⏳[/]" if setup_in_progress else "[yellow]⚠️[/]")
|
|
438
|
+
running_icon = "[green]✅[/]" if is_running else ("[yellow]⏳[/]" if setup_in_progress else "[red]❌[/]")
|
|
383
439
|
|
|
384
440
|
svc_table.add_row(service, enabled_icon, running_icon, pid_value, "")
|
|
385
441
|
|
|
386
442
|
if is_enabled and is_running:
|
|
387
443
|
self.results["services"]["passed"] += 1
|
|
388
|
-
|
|
444
|
+
elif not setup_in_progress:
|
|
389
445
|
self.results["services"]["failed"] += 1
|
|
390
446
|
|
|
391
447
|
self.results["services"]["details"].append(
|
|
@@ -410,7 +466,10 @@ class VMValidator:
|
|
|
410
466
|
def validate_apps(self) -> Dict:
|
|
411
467
|
packages = self.config.get("packages", [])
|
|
412
468
|
snap_packages = self.config.get("snap_packages", [])
|
|
413
|
-
|
|
469
|
+
# Support both v1 (app_data_paths) and v2 (copy_paths) config formats
|
|
470
|
+
copy_paths = self.config.get("copy_paths", None)
|
|
471
|
+
if not isinstance(copy_paths, dict) or not copy_paths:
|
|
472
|
+
copy_paths = self.config.get("app_data_paths", {})
|
|
414
473
|
vm_user = self.config.get("vm", {}).get("username", "ubuntu")
|
|
415
474
|
|
|
416
475
|
snap_app_specs = {
|
|
@@ -469,7 +528,7 @@ class VMValidator:
|
|
|
469
528
|
if snap_pkg in snap_app_specs:
|
|
470
529
|
expected.append(snap_pkg)
|
|
471
530
|
|
|
472
|
-
for _, guest_path in
|
|
531
|
+
for _, guest_path in copy_paths.items():
|
|
473
532
|
if guest_path == "/home/ubuntu/.config/google-chrome":
|
|
474
533
|
expected.append("google-chrome")
|
|
475
534
|
break
|
|
@@ -588,6 +647,9 @@ class VMValidator:
|
|
|
588
647
|
running: Optional[bool] = None
|
|
589
648
|
pid: Optional[str] = None
|
|
590
649
|
note = ""
|
|
650
|
+
pending = False
|
|
651
|
+
|
|
652
|
+
setup_in_progress = self._setup_in_progress() is True
|
|
591
653
|
|
|
592
654
|
if app == "firefox":
|
|
593
655
|
installed = (
|
|
@@ -651,6 +713,10 @@ class VMValidator:
|
|
|
651
713
|
if self.require_running_apps and installed and profile_ok and running is None:
|
|
652
714
|
note = note or "running unknown"
|
|
653
715
|
|
|
716
|
+
if setup_in_progress and not installed:
|
|
717
|
+
pending = True
|
|
718
|
+
note = note or "setup in progress"
|
|
719
|
+
|
|
654
720
|
running_icon = (
|
|
655
721
|
"[dim]—[/]"
|
|
656
722
|
if not installed
|
|
@@ -663,20 +729,18 @@ class VMValidator:
|
|
|
663
729
|
|
|
664
730
|
pid_value = "—" if not installed else ("?" if pid is None else (pid or "—"))
|
|
665
731
|
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
running_icon,
|
|
671
|
-
pid_value,
|
|
672
|
-
note,
|
|
673
|
-
)
|
|
732
|
+
installed_icon = "[green]✅[/]" if installed else ("[yellow]⏳[/]" if pending else "[red]❌[/]")
|
|
733
|
+
profile_icon = "[green]✅[/]" if profile_ok else ("[yellow]⏳[/]" if pending else "[red]❌[/]")
|
|
734
|
+
|
|
735
|
+
table.add_row(app, installed_icon, profile_icon, running_icon, pid_value, note)
|
|
674
736
|
|
|
675
737
|
should_pass = installed and profile_ok
|
|
676
738
|
if self.require_running_apps and installed and profile_ok:
|
|
677
739
|
should_pass = running is True
|
|
678
740
|
|
|
679
|
-
if
|
|
741
|
+
if pending:
|
|
742
|
+
self.results["apps"]["skipped"] += 1
|
|
743
|
+
elif should_pass:
|
|
680
744
|
self.results["apps"]["passed"] += 1
|
|
681
745
|
else:
|
|
682
746
|
self.results["apps"]["failed"] += 1
|
|
@@ -689,6 +753,7 @@ class VMValidator:
|
|
|
689
753
|
"running": running,
|
|
690
754
|
"pid": pid,
|
|
691
755
|
"note": note,
|
|
756
|
+
"pending": pending,
|
|
692
757
|
}
|
|
693
758
|
)
|
|
694
759
|
|
|
@@ -703,7 +768,10 @@ class VMValidator:
|
|
|
703
768
|
def validate_smoke_tests(self) -> Dict:
|
|
704
769
|
packages = self.config.get("packages", [])
|
|
705
770
|
snap_packages = self.config.get("snap_packages", [])
|
|
706
|
-
|
|
771
|
+
# Support both v1 (app_data_paths) and v2 (copy_paths) config formats
|
|
772
|
+
copy_paths = self.config.get("copy_paths", None)
|
|
773
|
+
if not isinstance(copy_paths, dict) or not copy_paths:
|
|
774
|
+
copy_paths = self.config.get("app_data_paths", {})
|
|
707
775
|
vm_user = self.config.get("vm", {}).get("username", "ubuntu")
|
|
708
776
|
|
|
709
777
|
expected = []
|
|
@@ -715,7 +783,7 @@ class VMValidator:
|
|
|
715
783
|
if snap_pkg in {"pycharm-community", "chromium", "firefox", "code"}:
|
|
716
784
|
expected.append(snap_pkg)
|
|
717
785
|
|
|
718
|
-
for _, guest_path in
|
|
786
|
+
for _, guest_path in copy_paths.items():
|
|
719
787
|
if guest_path == "/home/ubuntu/.config/google-chrome":
|
|
720
788
|
expected.append("google-chrome")
|
|
721
789
|
break
|
|
@@ -790,7 +858,7 @@ class VMValidator:
|
|
|
790
858
|
|
|
791
859
|
if app == "firefox":
|
|
792
860
|
out = self._exec_in_vm(
|
|
793
|
-
f"{user_env} timeout 20 firefox --headless --
|
|
861
|
+
f"{user_env} timeout 20 firefox --headless --version >/dev/null 2>&1 && echo yes || echo no",
|
|
794
862
|
timeout=30,
|
|
795
863
|
)
|
|
796
864
|
return None if out is None else out.strip() == "yes"
|
|
@@ -820,40 +888,51 @@ class VMValidator:
|
|
|
820
888
|
table.add_column("Launch", justify="center")
|
|
821
889
|
table.add_column("Note", style="dim")
|
|
822
890
|
|
|
891
|
+
setup_in_progress = self._setup_in_progress() is True
|
|
823
892
|
for app in expected:
|
|
824
893
|
self.results["smoke"]["total"] += 1
|
|
825
894
|
installed = _installed(app)
|
|
826
895
|
launched: Optional[bool] = None
|
|
827
896
|
note = ""
|
|
897
|
+
pending = False
|
|
828
898
|
|
|
829
899
|
if installed is True:
|
|
830
900
|
launched = _run_test(app)
|
|
831
901
|
if launched is None:
|
|
832
902
|
note = "test failed to execute"
|
|
903
|
+
elif launched is False and setup_in_progress:
|
|
904
|
+
pending = True
|
|
905
|
+
note = note or "setup in progress"
|
|
833
906
|
elif installed is False:
|
|
834
|
-
|
|
907
|
+
if setup_in_progress:
|
|
908
|
+
pending = True
|
|
909
|
+
note = "setup in progress"
|
|
910
|
+
else:
|
|
911
|
+
note = "not installed"
|
|
835
912
|
else:
|
|
836
913
|
note = "install status unknown"
|
|
837
914
|
|
|
838
915
|
installed_icon = (
|
|
839
916
|
"[green]✅[/]"
|
|
840
917
|
if installed is True
|
|
841
|
-
else "[
|
|
918
|
+
else ("[yellow]⏳[/]" if pending else "[red]❌[/]")
|
|
919
|
+
if installed is False
|
|
920
|
+
else "[dim]?[/]"
|
|
842
921
|
)
|
|
843
922
|
launch_icon = (
|
|
844
923
|
"[green]✅[/]"
|
|
845
924
|
if launched is True
|
|
846
|
-
else (
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
else ("[dim]—[/]" if installed is not True else "[dim]?[/]")
|
|
850
|
-
)
|
|
925
|
+
else ("[yellow]⏳[/]" if pending else "[red]❌[/]")
|
|
926
|
+
if launched is False
|
|
927
|
+
else ("[dim]—[/]" if installed is not True else "[dim]?[/]")
|
|
851
928
|
)
|
|
852
929
|
|
|
853
930
|
table.add_row(app, installed_icon, launch_icon, note)
|
|
854
931
|
|
|
855
932
|
passed = installed is True and launched is True
|
|
856
|
-
if
|
|
933
|
+
if pending:
|
|
934
|
+
self.results["smoke"]["skipped"] += 1
|
|
935
|
+
elif passed:
|
|
857
936
|
self.results["smoke"]["passed"] += 1
|
|
858
937
|
else:
|
|
859
938
|
self.results["smoke"]["failed"] += 1
|
|
@@ -864,6 +943,7 @@ class VMValidator:
|
|
|
864
943
|
"installed": installed,
|
|
865
944
|
"launched": launched,
|
|
866
945
|
"note": note,
|
|
946
|
+
"pending": pending,
|
|
867
947
|
}
|
|
868
948
|
)
|
|
869
949
|
|
|
@@ -929,18 +1009,18 @@ class VMValidator:
|
|
|
929
1009
|
return self.results
|
|
930
1010
|
|
|
931
1011
|
ci_status = self._exec_in_vm("cloud-init status --long 2>/dev/null || cloud-init status 2>/dev/null || true", timeout=20)
|
|
1012
|
+
setup_in_progress = False
|
|
932
1013
|
if ci_status:
|
|
933
1014
|
ci_lower = ci_status.lower()
|
|
934
1015
|
if "running" in ci_lower:
|
|
935
|
-
self.console.print("[yellow]⏳ Cloud-init still running -
|
|
936
|
-
|
|
937
|
-
return self.results
|
|
1016
|
+
self.console.print("[yellow]⏳ Cloud-init still running - deep validation will show pending states[/]")
|
|
1017
|
+
setup_in_progress = True
|
|
938
1018
|
|
|
939
1019
|
ready_msg = self._exec_in_vm(
|
|
940
1020
|
"cat /var/log/clonebox-ready 2>/dev/null || true",
|
|
941
1021
|
timeout=10,
|
|
942
1022
|
)
|
|
943
|
-
if not (ready_msg and "clonebox vm ready" in ready_msg.lower()):
|
|
1023
|
+
if not setup_in_progress and not (ready_msg and "clonebox vm ready" in ready_msg.lower()):
|
|
944
1024
|
self.console.print(
|
|
945
1025
|
"[yellow]⚠️ CloneBox ready marker not found - provisioning may not have completed[/]"
|
|
946
1026
|
)
|
|
@@ -994,6 +1074,10 @@ class VMValidator:
|
|
|
994
1074
|
|
|
995
1075
|
# Get skipped services count
|
|
996
1076
|
skipped_services = self.results["services"].get("skipped", 0)
|
|
1077
|
+
skipped_snaps = self.results["snap_packages"].get("skipped", 0)
|
|
1078
|
+
skipped_apps = self.results["apps"].get("skipped", 0)
|
|
1079
|
+
skipped_smoke = self.results["smoke"].get("skipped", 0) if self.smoke_test else 0
|
|
1080
|
+
total_skipped = skipped_services + skipped_snaps + skipped_apps + skipped_smoke
|
|
997
1081
|
|
|
998
1082
|
# Print summary
|
|
999
1083
|
self.console.print("\n[bold]📊 Validation Summary[/]")
|
|
@@ -1022,7 +1106,7 @@ class VMValidator:
|
|
|
1022
1106
|
"Snap Packages",
|
|
1023
1107
|
str(self.results["snap_packages"]["passed"]),
|
|
1024
1108
|
str(self.results["snap_packages"]["failed"]),
|
|
1025
|
-
"—",
|
|
1109
|
+
str(skipped_snaps) if skipped_snaps else "—",
|
|
1026
1110
|
str(self.results["snap_packages"]["total"]),
|
|
1027
1111
|
)
|
|
1028
1112
|
summary_table.add_row(
|
|
@@ -1036,21 +1120,24 @@ class VMValidator:
|
|
|
1036
1120
|
"Apps",
|
|
1037
1121
|
str(self.results["apps"]["passed"]),
|
|
1038
1122
|
str(self.results["apps"]["failed"]),
|
|
1039
|
-
"—",
|
|
1123
|
+
str(skipped_apps) if skipped_apps else "—",
|
|
1040
1124
|
str(self.results["apps"]["total"]),
|
|
1041
1125
|
)
|
|
1042
1126
|
summary_table.add_row(
|
|
1043
1127
|
"[bold]TOTAL",
|
|
1044
1128
|
f"[bold green]{total_passed}",
|
|
1045
1129
|
f"[bold red]{total_failed}",
|
|
1046
|
-
f"[dim]{
|
|
1130
|
+
f"[dim]{total_skipped}[/]" if total_skipped else "[dim]0[/]",
|
|
1047
1131
|
f"[bold]{total_checks}",
|
|
1048
1132
|
)
|
|
1049
1133
|
|
|
1050
1134
|
self.console.print(summary_table)
|
|
1051
1135
|
|
|
1052
1136
|
# Determine overall status
|
|
1053
|
-
if total_failed == 0 and total_checks > 0:
|
|
1137
|
+
if total_failed == 0 and total_checks > 0 and total_skipped > 0:
|
|
1138
|
+
self.results["overall"] = "pending"
|
|
1139
|
+
self.console.print("\n[bold yellow]⏳ Setup in progress - some checks are pending[/]")
|
|
1140
|
+
elif total_failed == 0 and total_checks > 0:
|
|
1054
1141
|
self.results["overall"] = "pass"
|
|
1055
1142
|
self.console.print("\n[bold green]✅ All validations passed![/]")
|
|
1056
1143
|
elif total_failed > 0:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: clonebox
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.16
|
|
4
4
|
Summary: Clone your workstation environment to an isolated VM with selective apps, paths and services
|
|
5
5
|
Author: CloneBox Team
|
|
6
6
|
License: Apache-2.0
|
|
@@ -49,6 +49,10 @@ Requires-Dist: fastapi>=0.100.0; extra == "test"
|
|
|
49
49
|
Provides-Extra: dashboard
|
|
50
50
|
Requires-Dist: fastapi>=0.100.0; extra == "dashboard"
|
|
51
51
|
Requires-Dist: uvicorn>=0.22.0; extra == "dashboard"
|
|
52
|
+
Provides-Extra: secrets
|
|
53
|
+
Requires-Dist: hvac>=2.0.0; extra == "secrets"
|
|
54
|
+
Provides-Extra: full
|
|
55
|
+
Requires-Dist: hvac>=2.0.0; extra == "full"
|
|
52
56
|
Dynamic: license-file
|
|
53
57
|
|
|
54
58
|
# CloneBox 📦
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
clonebox/__init__.py,sha256=CyfHVVq6KqBr4CNERBpXk_O6Q5B35q03YpdQbokVvvI,408
|
|
2
2
|
clonebox/__main__.py,sha256=Fcoyzwwyz5-eC_sBlQk5a5RbKx8uodQz5sKJ190U0NU,135
|
|
3
|
-
clonebox/audit.py,sha256=
|
|
4
|
-
clonebox/cli.py,sha256=
|
|
5
|
-
clonebox/cloner.py,sha256=
|
|
3
|
+
clonebox/audit.py,sha256=1W9vaIjB0A--_p7CgE3cIP5RNckJG1RxJrL-tOb-QmU,14298
|
|
4
|
+
clonebox/cli.py,sha256=k3q-JrzsiDcGPjhzHbm1jPKajxD2chYJxSGGftCbA20,178481
|
|
5
|
+
clonebox/cloner.py,sha256=ZMeIpEuzT8ZO9fav99JdE3krWT6e06K8pBR7XxDKbos,106958
|
|
6
6
|
clonebox/container.py,sha256=tiYK1ZB-DhdD6A2FuMA0h_sRNkUI7KfYcJ0tFOcdyeM,6105
|
|
7
7
|
clonebox/dashboard.py,sha256=dMY6odvPq3j6FronhRRsX7aY3qdCwznB-aCWKEmHDNw,5768
|
|
8
8
|
clonebox/detector.py,sha256=vS65cvFNPmUBCX1Y_TMTnSRljw6r1Ae9dlVtACs5XFc,23075
|
|
@@ -15,11 +15,12 @@ clonebox/monitor.py,sha256=zlIarNf8w_i34XI8hZGxxrg5PVZK_Yxm6FQnkhLavRI,9181
|
|
|
15
15
|
clonebox/orchestrator.py,sha256=LvoDZIX47g2pdvMYfCW3NJ5sAiRYKKa45KGlujnJZuI,19871
|
|
16
16
|
clonebox/p2p.py,sha256=6o0JnscKqF9-BftQhW5fF1W6YY1wXshY9LEklNcHGJc,5913
|
|
17
17
|
clonebox/profiles.py,sha256=UP37fX_rhrG_O9ehNFJBUcULPmUtN1A8KsJ6cM44oK0,1986
|
|
18
|
+
clonebox/remote.py,sha256=3qd6q3yEDkbO_btOsytkqub2v9lkmsVu_92KcdmHw6U,15336
|
|
18
19
|
clonebox/resource_monitor.py,sha256=lDR9KyPbVtImeeOkOBPPVP-5yCgoL5hsVFPZ_UqsY0w,5286
|
|
19
20
|
clonebox/resources.py,sha256=IkuM4OdSDV4qhyc0eIynwbAHBTv0aVSxxW-gghsnCAs,6815
|
|
20
21
|
clonebox/rollback.py,sha256=hpwO-8Ehe1pW0wHuZvJkC_qxZ6yEo9otCJRhGIUArCo,5711
|
|
21
|
-
clonebox/secrets.py,sha256=
|
|
22
|
-
clonebox/validator.py,sha256=
|
|
22
|
+
clonebox/secrets.py,sha256=l1jwJcEPB1qMoGNLPjyrkKKr1khh9VmftFJI9BWhgK0,10628
|
|
23
|
+
clonebox/validator.py,sha256=uXBkdrWSk8oBhRnD1y4mwxRdxOPduRraroSIs14bAo8,45342
|
|
23
24
|
clonebox/backends/libvirt_backend.py,sha256=sIHFIvFO1hIOXEFR_foSkOGBgIzaJVQs-njOU8GdafA,7170
|
|
24
25
|
clonebox/backends/qemu_disk.py,sha256=YsGjYX5sbEf35Y4yjTpNkZat73a4RGBxY-KTVzJhqIs,1687
|
|
25
26
|
clonebox/backends/subprocess_runner.py,sha256=c-IyaMxM1cmUu64h654oAvulm83K5Mu-VQxXJ_0BOds,1506
|
|
@@ -33,15 +34,15 @@ clonebox/interfaces/network.py,sha256=YPIquxEB7sZHczbpuopcZpffTjWYI6cKmAu3wAEFll
|
|
|
33
34
|
clonebox/interfaces/process.py,sha256=njvAIZw_TCjw01KpyVQKIDoRvhTwl0FfVGbQ6mxTROk,1024
|
|
34
35
|
clonebox/plugins/__init__.py,sha256=3cxlz159nokZCOL2c017WqTwt5z00yyn-o-SemP1g6c,416
|
|
35
36
|
clonebox/plugins/base.py,sha256=A2H-2vrYUczNZCDioQ8cAtvaSob4YpXutx7FWMjksC4,10133
|
|
36
|
-
clonebox/plugins/manager.py,sha256=
|
|
37
|
+
clonebox/plugins/manager.py,sha256=W2ithedEEOh9iWSq3_M5_g2SQWl85aI5qrvrjOKv02I,16842
|
|
37
38
|
clonebox/snapshots/__init__.py,sha256=ndlrIavPAiA8z4Ep3-D_EPhOcjNKYFnP3rIpEKaGdb8,273
|
|
38
39
|
clonebox/snapshots/manager.py,sha256=hGzM8V6ZJPXjTqj47c4Kr8idlE-c1Q3gPUvuw1HvS1A,11393
|
|
39
40
|
clonebox/snapshots/models.py,sha256=sRnn3OZE8JG9FZJlRuA3ihO-JXoPCQ3nD3SQytflAao,6206
|
|
40
41
|
clonebox/templates/profiles/ml-dev.yaml,sha256=w07MToGh31xtxpjbeXTBk9BkpAN8A3gv8HeA3ESKG9M,461
|
|
41
42
|
clonebox/templates/profiles/web-stack.yaml,sha256=EBnnGMzML5vAjXmIUbCpbTCwmRaNJiuWd3EcL43DOK8,485
|
|
42
|
-
clonebox-1.1.
|
|
43
|
-
clonebox-1.1.
|
|
44
|
-
clonebox-1.1.
|
|
45
|
-
clonebox-1.1.
|
|
46
|
-
clonebox-1.1.
|
|
47
|
-
clonebox-1.1.
|
|
43
|
+
clonebox-1.1.16.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
44
|
+
clonebox-1.1.16.dist-info/METADATA,sha256=mPn_uTUwAXlnakSJc8DLWyg1KlNERP5-oIEyWABxuwA,49052
|
|
45
|
+
clonebox-1.1.16.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
46
|
+
clonebox-1.1.16.dist-info/entry_points.txt,sha256=FES95Vi3btfViLEEoHdb8nikNxTqzaooi9ehZw9ZfWI,47
|
|
47
|
+
clonebox-1.1.16.dist-info/top_level.txt,sha256=LdMo2cvCrEcRGH2M8JgQNVsCoszLV0xug6kx1JnaRjo,9
|
|
48
|
+
clonebox-1.1.16.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|