diff options
| author | James O'Doherty <james@theodohertyfamily.com> | 2026-06-13 13:50:25 -0400 |
|---|---|---|
| committer | James O'Doherty <james@theodohertyfamily.com> | 2026-06-13 13:50:25 -0400 |
| commit | 5646eca119f80f8f45ebec9fcbe666ca614ebf5d (patch) | |
| tree | a785cb7f30b5a6444e208ae6717a73a758644998 /internal/cli/cli.go | |
| parent | 29621ecbd1e77e6e1a70b6b3ea8fbe3a56e47df3 (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/cli.go')
| -rw-r--r-- | internal/cli/cli.go | 37 |
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") |
