summaryrefslogtreecommitdiff
path: root/internal/cli
diff options
context:
space:
mode:
authorJames O'Doherty <james@theodohertyfamily.com>2026-06-13 13:50:25 -0400
committerJames O'Doherty <james@theodohertyfamily.com>2026-06-13 13:50:25 -0400
commit5646eca119f80f8f45ebec9fcbe666ca614ebf5d (patch)
treea785cb7f30b5a6444e208ae6717a73a758644998 /internal/cli
parent29621ecbd1e77e6e1a70b6b3ea8fbe3a56e47df3 (diff)
feat: implement system preflight checks and health diagnostics
Introduced a tiered system verification mechanism to improve reliability and provide actionable feedback to users, avoiding false positives in the critical execution path. Key changes: - Implement `CheckSystemRequirements` for critical, non-ambiguous requirements (e.g., TUN device availability) to ensure fatal environment issues are caught immediately during bootstrap. - Implement a user-facing `healthcheck` command that provides comprehensive diagnostics and actionable configuration hints for common misconfigurations (e.g., unprivileged user namespaces, subuid/subgid mappings, and kernel sysctls). - Refactor the `FileSystem` interface to support full mockability, allowing for exhaustive unit testing of diagnostic logic. - Add comprehensive unit tests in `internal/namespace/preflight_test.go` covering various Linux distributions, privilege levels, and hardware availability scenarios. - Ensure code quality through formatting, static analysis (golangci-lint), and validation of all existing unit, integration, and E2E tests.
Diffstat (limited to 'internal/cli')
-rw-r--r--internal/cli/cli.go37
1 files changed, 36 insertions, 1 deletions
diff --git a/internal/cli/cli.go b/internal/cli/cli.go
index b38d0d9..ac8c206 100644
--- a/internal/cli/cli.go
+++ b/internal/cli/cli.go
@@ -71,6 +71,8 @@ func (a *App) Route() error {
return a.executeWrapped(a.Args[2:])
case "test-ns":
return a.testNS()
+ case "healthcheck":
+ return a.handleHealthCheck()
case "test-args":
return a.testArgs()
case "test-lifecycle":
@@ -139,6 +141,38 @@ func (a *App) executeWrapped(args []string) error {
return nil
}
+func (a *App) handleHealthCheck() error {
+ fmt.Println("Performing system health check for rootless network namespaces...")
+ fmt.Println()
+
+ results := namespace.RunHealthCheck()
+ allPassed := true
+
+ for _, res := range results {
+ status := "✅ PASSED"
+ if !res.Passed {
+ status = "❌ FAILED"
+ allPassed = false
+ }
+
+ fmt.Printf("%-40s %s\n", res.Name, status)
+ if !res.Passed {
+ fmt.Printf(" Reason: %s\n", res.Message)
+ fmt.Printf(" Hint: %s\n", res.Hint)
+ } else if res.Message != "" {
+ fmt.Printf(" Info: %s\n", res.Message)
+ }
+ fmt.Println()
+ }
+
+ if allPassed {
+ fmt.Println("Overall Status: System is healthy and ready for wg-wrap.")
+ return nil
+ }
+
+ return fmt.Errorf("some system requirements were not met; please follow the hints above")
+}
+
func (a *App) testNS() error {
if !namespace.IsIsolated() {
if err := namespace.Bootstrap(); err != nil {
@@ -183,7 +217,8 @@ func (a *App) printUsage() {
fmt.Fprintf(os.Stderr, " run [options] [-- command] \tRun a command in the wrapped environment\n")
fmt.Fprintf(os.Stderr, " exec [options] [-- command] \tAlias for 'run'\n")
fmt.Fprintf(os.Stderr, " profile <command> \t\tManage WireGuard profiles (list, import, configure, delete, stop)\n")
- fmt.Fprintf(os.Stderr, " show-config \t\t\tDisplay the current configuration and environment details\n\n")
+ fmt.Fprintf(os.Stderr, " show-config \t\t\tDisplay the current configuration and environment details\n")
+ fmt.Fprintf(os.Stderr, " healthcheck \t\t\tCheck system compatibility and configuration hints\n\n")
fmt.Fprintf(os.Stderr, "Run Options:\n")
fmt.Fprintf(os.Stderr, " -profile string \t\tWireGuard profile to use (default \"default\")\n")
fmt.Fprintf(os.Stderr, " -dns-server string \tOverride DNS server to use\n\n")