{"id":47516536,"url":"https://github.com/nickprotop/ServerHub","last_synced_at":"2026-04-03T06:01:52.410Z","repository":{"id":333186469,"uuid":"1136482735","full_name":"nickprotop/ServerHub","owner":"nickprotop","description":"A TUI server monitoring and management dashboard for Linux. Real-time metrics, logs, and remote control from your terminal.","archived":false,"fork":false,"pushed_at":"2026-03-25T12:45:24.000Z","size":7334,"stargazers_count":15,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-26T15:51:00.940Z","etag":null,"topics":["cli","csharp","dashboard","developer-tools","dotnet","linux","server-monitoring","terminal","tui"],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nickprotop.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-17T19:14:23.000Z","updated_at":"2026-03-25T12:45:22.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/nickprotop/ServerHub","commit_stats":null,"previous_names":["nickprotop/serverhub"],"tags_count":36,"template":false,"template_full_name":null,"purl":"pkg:github/nickprotop/ServerHub","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickprotop%2FServerHub","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickprotop%2FServerHub/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickprotop%2FServerHub/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickprotop%2FServerHub/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nickprotop","download_url":"https://codeload.github.com/nickprotop/ServerHub/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickprotop%2FServerHub/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31338174,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-03T04:42:29.251Z","status":"ssl_error","status_checked_at":"2026-04-03T04:42:12.667Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","csharp","dashboard","developer-tools","dotnet","linux","server-monitoring","terminal","tui"],"created_at":"2026-03-27T13:01:21.462Z","updated_at":"2026-04-03T06:01:52.402Z","avatar_url":"https://github.com/nickprotop.png","language":"C#","funding_links":[],"categories":["Table of Contents"],"sub_categories":[],"readme":"# ServerHub\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\".github/logo.svg\" alt=\"ServerHub Logo\" width=\"600\"\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![.NET](https://img.shields.io/badge/.NET-9.0-purple.svg)](https://dotnet.microsoft.com/)\n[![Platform](https://img.shields.io/badge/Platform-Linux-orange.svg)]()\n\n\u003c/div\u003e\n\n**An extensible server dashboard that doesn't just watch—it acts.**\n\n\u003cdiv align=\"center\"\u003e\n\n### ⭐ If you find ServerHub useful, please consider giving it a star! ⭐\n\nIt helps others discover the project and motivates continued development.\n\n[![GitHub stars](https://img.shields.io/github/stars/nickprotop/ServerHub?style=for-the-badge\u0026logo=github\u0026color=yellow)](https://github.com/nickprotop/ServerHub/stargazers)\n\n\u003c/div\u003e\n\nServerHub is a terminal control panel for servers and homelabs. Monitor your system, execute actions, and build custom monitoring for your specific setup—all without touching the codebase.\n\n**Monitor. Act. Extend.**\n\n![ServerHub Screenshot](.github/dashboard-overview.png)\n\n**[View more screenshots](docs/SCREENSHOTS.md)**\n\n## Quick Start\n\nGet ServerHub running in 3 steps:\n\n```bash\n# 1. Install ServerHub\ncurl -fsSL https://raw.githubusercontent.com/nickprotop/ServerHub/main/install.sh | bash\n\n# 2. Run it (creates default config automatically)\nserverhub\n\n# 3. Press F3 to browse and install community widgets\n```\n\nThat's it! You now have a working dashboard with 14 bundled widgets. Press `F3` to explore the marketplace, `F2` to configure widgets, or `?` for help.\n\n## Table of Contents\n\n- [What Makes ServerHub Different](#what-makes-serverhub-different)\n- [Core Features](#core-features)\n- [Marketplace](#marketplace) - Browse and install community widgets\n- [Widget Development](docs/WIDGET_DEVELOPMENT.md) - Create and test widgets\n- [Requirements](#requirements)\n- [Installation](#installation)\n- [Usage](#usage)\n- [Configuration](#configuration)\n- [Bundled Widgets](#bundled-widgets)\n- [Custom Widgets](#custom-widgets)\n- [Security](#security)\n- [Screenshots](docs/SCREENSHOTS.md)\n- [Examples](docs/EXAMPLES.md)\n- [Widget Protocol](docs/WIDGET_PROTOCOL.md)\n- [Widget Development](docs/WIDGET_DEVELOPMENT.md)\n\n## What Makes ServerHub Different\n\n**Extensible by design** - Write a script in any language (C#, Python, bash, Node.js, Go, Rust, or compiled binaries). If it outputs to stdout, it's a widget. Monitor anything: custom services, APIs, hardware you built yourself, scripts you already have. Widgets support expanded views - press Enter for full details beyond the dashboard summary.\n\n**Context-aware actions** - Widgets don't just display data—they export actions based on what they're showing. A service widget shows different restart options depending on which services are running. An updates widget exports \"Upgrade All\" only when updates are available. Docker widget offers actions per container. Each widget adapts to the current state.\n\n**Control, not just monitoring** - Upgrade packages, restart services, manage containers, trigger backups—execute actions with confirmation dialogs, progress tracking, and sudo support when needed. Your dashboard becomes a control panel.\n\n**Security-first extensibility** - SHA256 validation for custom widgets with a documented threat model. Minimal environment variables. Path restrictions. Symlink blocking. Professional security without sacrificing flexibility.\n\n## Core Features\n\n- **14 bundled widgets** - CPU, memory, disk, network, Docker, systemd services, package updates, logs, SSL certificates, sensors, and more\n- **Responsive layout** - 1-4 column layout adapts to terminal width\n- **Custom widgets** - Write bash scripts to monitor anything specific to your setup\n- **Action system** - Execute commands directly from widgets with progress tracking\n- **SHA256 validation** - All custom widgets require checksum validation (development mode available)\n- **YAML configuration** - Simple, version-controllable config files\n- **Keyboard navigation** - Tab/Shift+Tab between widgets, arrow keys to scroll\n- **Marketplace** - Browse and install community widgets with F3\n\n## Marketplace\n\nDiscover and install community-contributed widgets from the ServerHub marketplace.\n\n**[Full Marketplace Documentation](docs/MARKETPLACE.md)**\n\n**[Browse the Marketplace](https://nickprotop.github.io/serverhub-registry/)**\n\n### Interactive Browser (TUI)\n\nPress `F3` in the dashboard to open the interactive marketplace browser:\n\n![Marketplace Browser](.github/marketplace-browser.png)\n\n- Browse widgets with visual cards and detailed information\n- Filter by category (monitoring, infrastructure, development, databases, etc.)\n- Filter by verification status (Verified, Community, Unverified)\n- View dependencies and system requirements\n- One-click installation with automatic config integration\n- One-click uninstall for installed widgets (removes file and config)\n- Respects `--widgets-path` if you started ServerHub with a custom widgets directory\n\n**Widget management:**\n- **Install**: Click \"Install\" button on any available widget\n- **Uninstall**: Click \"Uninstall\" button on installed widgets (confirmation required)\n- **Update**: Click \"Update to X.X.X\" when newer versions are available\n- Bundled widgets cannot be uninstalled (only custom/marketplace widgets)\n\n**[View all screenshots](docs/SCREENSHOTS.md)**\n\n### Command Line (CLI)\n\nSearch and install from the terminal:\n\n```bash\n# Search for widgets\nserverhub marketplace search monitoring\n\n# List all widgets\nserverhub marketplace list\n\n# List by category\nserverhub marketplace list --category monitoring\n\n# Get detailed information\nserverhub marketplace info username/widget-name\n```\n\n### Install Widgets\n\n```bash\n# Install latest version\nserverhub marketplace install username/widget-name\n\n# Install specific version\nserverhub marketplace install username/widget-name@1.0.0\n\n# View installed marketplace widgets\nserverhub marketplace list-installed\n```\n\n### Update Widgets\n\n```bash\n# Check for available updates\nserverhub marketplace check-updates\n\n# Update a specific widget\nserverhub marketplace update username/widget-name\n\n# Update to a specific version\nserverhub marketplace update username/widget-name --version 2.0.0\n\n# Update all widgets\nserverhub marketplace update-all\n\n# Auto-confirm updates (skip prompts)\nserverhub marketplace update --yes username/widget-name\n```\n\n\u003e **Note:** Uninstall marketplace widgets via the interactive browser (F3 in dashboard)\n\n## Widget Testing\n\nValidate widget scripts before deployment with the `test-widget` command:\n\n```bash\nserverhub test-widget mywidget.sh              # Interactive test\nserverhub test-widget mywidget.sh --yes        # Skip confirmation (CI/CD)\nserverhub test-widget mywidget.sh --extended   # Test extended mode\n```\n\nThe test command validates protocol compliance, checks action syntax, and provides warnings and suggestions. Returns exit code 0 on success, 1 on failure (CI/CD friendly).\n\n**[Full Widget Testing Documentation](docs/WIDGET_TESTING.md)**\n\n### Security \u0026 Verification\n\nThe marketplace uses a security-first approach:\n\n- **SHA256 checksums** - All widgets have mandatory checksums verified during installation\n- **Verification tiers** - Clear badges indicate review status:\n  - **Verified** (green) - Code reviewed by ServerHub maintainers\n  - **Community** (yellow) - Multiple installs, no reported issues\n  - **Unverified** (red) - New or untested, requires explicit confirmation\n- **GitHub-only hosting** - Widgets must be hosted on GitHub releases\n- **Dependency checking** - Required system commands verified before installation\n- **Code transparency** - All widget code is publicly reviewable\n\n**You are responsible for reviewing code before installing unverified widgets.**\n\n**Want to contribute your own widget?** See [MARKETPLACE.md](docs/MARKETPLACE.md#contributing-widgets) for the submission process.\n\n## Requirements\n\n- Linux (x86_64 or ARM64)\n- Bash (for widget scripts)\n\nNo .NET runtime required - ServerHub ships as a self-contained binary.\n\n## Installation\n\n### Quick Install (Recommended)\n\nDownload and install the latest release:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/nickprotop/ServerHub/main/install.sh | bash\n```\n\nThis automatically:\n- Downloads the binary for your architecture\n- Installs bundled widgets\n- Adds `~/.local/bin` to your PATH\n- Creates default config on first run\n\n### Build from Source\n\nFor development or if you want to build from source:\n\n```bash\ngit clone https://github.com/nickprotop/ServerHub.git\ncd ServerHub\n./build-and-install.sh\n```\n\nRequires .NET 9.0 SDK for building.\n\n## Uninstall\n\nTo remove ServerHub from your system:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/nickprotop/ServerHub/main/uninstall.sh | bash\n```\n\nThis removes:\n- The ServerHub binary from `~/.local/bin`\n- Bundled widgets from `~/.local/share/serverhub`\n- Optionally, your configuration from `~/.config/serverhub` (the script will ask)\n\n## Usage\n\n```bash\nserverhub                                    # Run with default config\nserverhub myconfig.yaml                      # Use custom config file\nserverhub --init-config config.yaml          # Create config by discovering widgets\nserverhub --discover                         # Find and add custom widgets\nserverhub --verify-checksums                 # Verify all widget checksums\nserverhub --dev-mode                         # Development mode (see Security section)\nserverhub test-widget \u003cscript\u003e [--yes]       # Test widget protocol compliance\nserverhub --help                             # Show all options\n```\n\n### Creating Configurations\n\n**First-time setup** - The default config (`~/.config/serverhub/config.yaml`) is automatically created on first run with all bundled widgets.\n\n**Custom configurations** - Use `--init-config` to create a new configuration file by discovering available widgets:\n\n```bash\n# Create config with bundled widgets only\nserverhub --init-config config.production.yaml\n\n# Create config with bundled + custom widgets from specific directory\nserverhub --init-config config.dev.yaml --widgets-path ./widgets/\n```\n\n**How it works:**\n1. Starts with all 14 bundled widgets from the production template\n2. Scans `~/.config/serverhub/widgets/` for custom widgets\n3. Scans `--widgets-path` if provided\n4. Generates config with appropriate `location` fields\n5. Custom widgets have no checksums initially (security - requires `--discover` or `--dev-mode`)\n\n**Note:** Custom config paths (non-default) are not auto-created. You must explicitly use `--init-config` to create them. This prevents accidental file creation from typos.\n\n### Keyboard Shortcuts\n\n| Key | Action |\n|-----|--------|\n| `Tab` / `Shift+Tab` | Navigate between widgets |\n| `Arrow keys` | Scroll within focused widget |\n| `F2` | Configure widgets (add, edit, reorder) |\n| `F3` | Browse marketplace widgets |\n| `F5` | Refresh all widgets |\n| `Space` | Pause/resume refresh |\n| `?` or `F1` | Show help |\n| `Ctrl+Q` | Quit |\n\n## Configuration\n\n### Default Configuration\n\nConfiguration file location: `~/.config/serverhub/config.yaml`\n\nOn first run, ServerHub automatically creates this file with all bundled widgets configured.\n\nFor custom configuration paths, use `--init-config`:\n\n```bash\n# Create a new configuration file\nserverhub --init-config myconfig.yaml\n\n# Create config with widgets from a specific directory\nserverhub --init-config myconfig.yaml --widgets-path ./widgets/\n```\n\n### Configuration Format\n\n```yaml\ndefault_refresh: 5\n\nwidgets:\n  cpu:\n    path: cpu.sh\n    refresh: 2\n    location: bundled  # Optional: bundled, custom, or auto (default)\n\n  memory:\n    path: memory.sh\n    refresh: 2\n\n  docker:\n    path: docker.sh\n    refresh: 30              # Dashboard refreshes every 30s\n    expanded_refresh: 10     # Expanded dialog refreshes every 10s\n    location: bundled\n\n  my-custom:\n    path: my-custom.sh\n    location: custom\n    sha256: a1b2c3d4...  # Required for custom widgets (use --discover)\n    refresh: 10\n\nlayout:\n  order:\n    - cpu\n    - memory\n    - docker\n    - my-custom\n\nbreakpoints:\n  double: 100    # 2 columns at 100+ chars\n  triple: 160    # 3 columns at 160+ chars\n  quad: 220      # 4 columns at 220+ chars\n```\n\n**Refresh Intervals:**\n\nEach widget can have two refresh intervals:\n\n- `refresh` - Refresh rate for the main dashboard (required)\n- `expanded_refresh` - Refresh rate when viewing the expanded dialog (optional)\n\nIf `expanded_refresh` is not set, the widget uses the `refresh` value for both views.\n\n**Common patterns:**\n\n- **Slower expanded refresh** - Reduce resource usage when viewing details:\n  ```yaml\n  alerts:\n    refresh: 30\n    expanded_refresh: 60  # Slower - alerts don't change often\n  ```\n\n- **Faster expanded refresh** - More detail when actively monitoring:\n  ```yaml\n  docker:\n    refresh: 30\n    expanded_refresh: 10  # Faster when viewing container details\n  ```\n\n- **Real-time monitoring** - Keep the same rate for both:\n  ```yaml\n  cpu:\n    refresh: 2  # No expanded_refresh - uses 2s for both views\n  ```\n\n### Widget Path Resolution\n\nThe `location` field controls where ServerHub searches for widget scripts:\n\n- `location: bundled` - Search only in `~/.local/share/serverhub/widgets/`\n- `location: custom` - Search only in `~/.config/serverhub/widgets/` and `--widgets-path`\n- `location: auto` (or omit) - Search all directories in priority order: `--widgets-path` → `~/.config/serverhub/widgets/` → `~/.local/share/serverhub/widgets/` (default)\n\n**Use cases:**\n- Override a bundled widget with a custom version while keeping both\n- Explicitly use the bundled version when custom exists\n- Have multiple versions of the same widget (e.g., `cpu` bundled, `cpu_1` custom)\n\nWhen using `--init-config` with `--widgets-path`, widgets found in the custom path are added with `location: custom` and unique IDs if filenames conflict with bundled widgets.\n\nSee [config.example.yaml](config.example.yaml) for full configuration options.\n\n## Bundled Widgets\n\n| Widget | Description |\n|--------|-------------|\n| `cpu` | CPU usage and load average |\n| `memory` | Memory and swap usage |\n| `disk` | Disk space usage |\n| `network` | Network interface statistics |\n| `processes` | Top processes by CPU/memory |\n| `sysinfo` | System information (hostname, uptime, kernel) |\n| `docker` | Docker container status |\n| `services` | Systemd service status |\n| `updates` | Available package updates |\n| `alerts` | System health alerts |\n| `sensors` | Hardware temperature sensors |\n| `netstat` | Network connections |\n| `logs` | Recent system log entries |\n| `ssl-certs` | SSL certificate expiry status |\n\n## Custom Widgets\n\nWrite widgets in any language - C# scripts, bash, Python, Node.js, Go, Rust, or compiled binaries. As long as it outputs to stdout following our protocol, it works.\n\nPlace custom widget scripts in `~/.config/serverhub/widgets/`.\n\n**All custom widgets require SHA256 checksum validation** (see Security section below).\n\n**[Widget Development Guide](docs/WIDGET_DEVELOPMENT.md)** - Create, test, and deploy widgets\n\n```bash\n# Create widget from template\nserverhub new-widget\n\n# Discover new widgets interactively (recommended)\nserverhub --discover\n\n# Verify checksums for all configured widgets\nserverhub --verify-checksums\n```\n\n### Widget Protocol (Brief)\n\nWidgets output structured text to stdout:\n\n```bash\necho \"title: My Widget\"\necho \"row: [status:ok] Everything is fine\"\necho \"row: [progress:75:inline]\"\necho \"row: [line:10,20,15,30,25:cyan:CPU History:0-100:50:6]\"  # Line graph\necho \"row: [grey70]Last updated: $(date)[/]\"\n```\n\nSee [docs/WIDGET_PROTOCOL.md](docs/WIDGET_PROTOCOL.md) for the full protocol reference.\n\n### Example Use Cases\n\nReal-world examples showing custom widgets for specific scenarios:\n\n- **Development Droplet** - Monitor APIs, Docker services, deployments with one-click actions\n- **Homelab Server** - Track Proxmox VMs, NAS health, backups with control actions\n- **Production Monitor** - Service health, error logs, SSL certs with emergency actions\n\nSee [docs/EXAMPLES.md](docs/EXAMPLES.md) for complete working examples with scripts.\n\n## Security\n\n### Why This Matters\n\nWidgets are **executable scripts that run with your user privileges**. A malicious widget could read your files, make network requests, or do anything else you can do. We'd rather be annoying about checksums than watch your server have a very bad day.\n\n### Threat Model\n\n**What we protect against:**\n\n| Threat | Protection |\n| --- | --- |\n| **Malicious custom widgets** | Checksum requirement forces you to review code before trusting |\n| **Tampering after trust** | Modified files fail checksum validation and won't run |\n| **Copy-paste attacks** | We don't auto-show checksums on failure (see [Why We Don't Auto-Generate Checksums](#why-we-dont-auto-generate-checksums)) |\n| **Accidental execution of untrusted code** | Unknown widgets are blocked by default |\n| **Symlink attacks** | Symlinks are detected and blocked during validation |\n| **Path traversal** | Scripts must be within allowed widget directories |\n| **Environment variable leakage** | Widgets run with minimal environment variables |\n\n**What we DON'T protect against:**\n\n| Threat | Notes |\n| --- | --- |\n| **Compromised build environment** | If attackers modify bundled checksums at build time, they can ship malicious code. Mitigation: reproducible builds, signed releases (future) |\n| **You approving malicious code** | If you `--discover` a widget and approve without reading it, that's on you |\n| **Privilege escalation** | Widgets run as your user. If you run ServerHub as root, widgets run as root. **Don't do this.** |\n| **TOCTOU race conditions** | Small window between checksum validation and execution. Low risk in practice |\n| **Side-channel attacks** | Widget output is displayed; timing or output analysis is possible |\n\n### Trust Hierarchy\n\n| Source | Trust Level | Checksum Source | Failure Behavior |\n| --- | --- | --- | --- |\n| **Bundled widgets** | Highest | Hardcoded at build time (maintainer-reviewed) | Widget disabled with error message in widget area |\n| **Custom widgets** | User-verified | You add `sha256` to config after reviewing code | Widget disabled with error message in widget area |\n\n### Validation Layers\n\nServerHub performs multiple security checks before executing any widget script:\n\n1. **File Existence** - Script file must exist at the specified path\n2. **Symlink Detection** - Symlinks are blocked (prevents following malicious links)\n3. **Path Restriction** - Script must be within allowed widget directories:\n   - `--widgets-path` (if specified)\n   - `~/.config/serverhub/widgets/` (custom widgets)\n   - `~/.local/share/serverhub/widgets/` (bundled widgets)\n4. **Executable Permissions** - Script must have execute permission (Unix systems)\n5. **SHA256 Checksum** - Script content must match trusted checksum\n\nAdditionally during execution:\n- **Minimal Environment** - Widgets run with cleared environment variables (only PATH, HOME, USER, LANG)\n- **Timeout Enforcement** - Scripts are killed if they exceed configured timeout\n\n### Failure Behavior\n\n| Scenario | Behavior |\n| --- | --- |\n| Bundled widget checksum mismatch | Widget refuses to run, displays \"Checksum mismatch\" error |\n| Bundled widget file missing | Widget refuses to run, displays \"Widget not found\" error |\n| Custom widget missing checksum | Widget refuses to run, displays \"No checksum configured\" with instructions |\n| Custom widget checksum mismatch | Widget refuses to run, displays \"Checksum mismatch\" error with expected vs actual |\n| Custom widget file missing | Widget refuses to run, displays \"Widget not found\" error |\n| Symlink detected | Widget refuses to run, displays \"Symlinks are not allowed\" error |\n| Path outside allowed directories | Widget refuses to run, displays \"Script path is not within allowed directories\" error |\n| Script not executable | Widget refuses to run, displays \"Script is not executable\" with chmod instructions |\n\nIn all cases, **other widgets continue to function normally**. A single compromised or misconfigured widget doesn't take down your dashboard.\n\n### How It Works\n\n1. **Bundled widgets** (`~/.local/share/serverhub/widgets/`) are pre-validated with checksums baked into the application at build time. They just work.\n\n2. **Custom widgets** (`~/.config/serverhub/widgets/`) **require** a `sha256` checksum in your config:\n\n```yaml\nwidgets:\n  my-widget:\n    path: my-widget.sh\n    sha256: a1b2c3d4e5f6...  # Required!\n    refresh: 10\n```\n\nWithout a checksum, custom widgets will not run. This is intentional.\n\n### Adding Custom Widgets Safely\n\n**Option 1: Initialize Config with Discovery (Recommended for new configs)**\n\n```bash\n# Create config with auto-discovered widgets\nserverhub --init-config config.yaml --widgets-path ./widgets/\n\n# Then review and add checksums interactively\nserverhub --discover\n```\n\nThis discovers all widgets in bundled and custom locations, generating a config file. Custom widgets are added **without checksums** (security), requiring you to review them via `--discover` or run with `--dev-mode`.\n\n**Option 2: Discovery (Recommended for existing configs)**\n\n```bash\nserverhub --discover\n```\n\nThis shows you a code preview of each unconfigured widget before adding it. When you approve, the checksum is captured at that moment—the \"trusted moment\" when you've actually seen what the code does.\n\n**Option 3: Manual**\n\n```bash\n# 1. Read the script yourself\ncat ~/.config/serverhub/widgets/my-widget.sh\n\n# 2. Calculate the checksum\nsha256sum ~/.config/serverhub/widgets/my-widget.sh\n\n# 3. Add to config with the checksum\nnano ~/.config/serverhub/config.yaml\n```\n\n### Configuration File Creation\n\nServerHub's auto-creation behavior is intentionally restrictive to prevent security issues:\n\n**Auto-created:** `~/.config/serverhub/config.yaml` (default path only)\n- Created automatically on first run\n- Contains only bundled widgets with verified checksums\n- Safe for immediate use\n\n**Not auto-created:** Custom config paths (e.g., `config.dev.yaml`, `myconfig.yaml`)\n- Prevents accidental file creation from typos (e.g., `config.developmnet.yaml`)\n- Prevents wrong defaults when using `--widgets-path`\n- Must use `--init-config` explicitly to create\n\n**Why this matters:**\nRunning `serverhub config.dev.yaml --widgets-path ./widgets/` should fail if the config doesn't exist, not silently create a config that expects bundled widgets while you're pointing at custom widgets. This mismatch causes path resolution issues and confusing behavior.\n\n### Why We Don't Auto-Generate Checksums\n\nWhen a widget fails validation, ServerHub does **not** helpfully show you \"just add this checksum.\" That would defeat the entire security model:\n\n1. Attacker modifies a widget file\n2. You run ServerHub, it fails with \"checksum mismatch\"\n3. If it showed the new checksum, you'd copy-paste it without thinking\n4. Congratulations, you've just blessed malicious code\n\nInstead, you must go through a \"trusted moment\"—either `--discover` (which shows the code) or manually running `sha256sum` (which requires conscious action).\n\n### Why SHA256?\n\nWe use SHA256 for checksum validation. While even older algorithms like SHA1 would provide sufficient collision resistance for integrity checking of small scripts, SHA256 is:\n\n- The current industry standard\n- Unlikely to raise concerns in security audits\n- Widely supported and understood\n- Future-proof for the foreseeable future\n\n### Development Mode\n\nFor **widget development only**, you can skip custom widget checksum validation:\n\n```bash\nserverhub --dev-mode --widgets-path ./my-dev-widgets\n```\n\nDev mode indicators:\n- Orange border around the dashboard\n- Warning in status bar\n- Startup dialog requiring acknowledgment\n\nImportant notes:\n- Bundled widgets are **still validated** even in dev mode\n- Symlink, path, and permission checks **still apply** in dev mode\n- This is for development, not for \"I don't want to deal with checksums\"\n- **Never use `--dev-mode` in production**\n\n### Verification\n\nVerify all configured widget checksums:\n\n```bash\nserverhub --verify-checksums\n```\n\nExample output:\n```\nVerifying widget checksums...\n\n  cpu                  VALID (bundled)\n  memory               VALID (bundled)\n  my-custom-widget     VALID (config)\n  untrusted-widget     NO CHECKSUM\n      Run --discover or manually verify before adding checksum\n  tampered-widget      MISMATCH (config)\n      Expected: a1b2c3d4e5f6...\n      Actual:   f9e8d7c6b5a4...\n  missing-widget       NOT FOUND\n\nResults: 3 valid, 1 mismatch, 2 missing/no-checksum\n```\n\nExit codes:\n- `0` - All widgets valid\n- `1` - One or more failures (mismatch, missing checksum, or not found)\n\nUse in scripts and CI/CD:\n```bash\n# Pre-deployment check\nserverhub --verify-checksums || { echo \"Widget validation failed\"; exit 1; }\n```\n\n### Recommendations\n\n1. **Never run ServerHub as root** — widgets inherit your privileges\n2. **Actually read widget code** during `--discover` — don't just approve blindly\n3. **Run `--verify-checksums` periodically** — catch tampering early (add to cron/systemd timers)\n4. **For high-security environments** — stick to bundled widgets only\n5. **Review widget updates** — if you update a custom widget, you'll need to update its checksum (which forces a re-review)\n6. **Avoid symlinks** — place widget scripts directly in widget directories, don't symlink to other locations\n7. **Check permissions** — ensure widget scripts have appropriate file permissions (chmod +x for execution, not world-writable)\n\n### Future Considerations\n\nThese features are not currently implemented but are under consideration:\n\n**Signed Widgets**\n- GPG-signed widgets with trusted key management\n- Would enable a widget ecosystem where you trust maintainers rather than reviewing every line\n- More complex but scales better than per-widget checksums\n\n**Reproducible Builds**\n- Deterministic builds to verify bundled widget checksums independently\n- Build attestation for supply chain security\n- Allow independent verification of bundled widgets\n\n## Built With\n\n- [SharpConsoleUI](https://github.com/nickprotop/ConsoleEx) - A .NET library for building terminal user interfaces with responsive layouts and window management.\n\n## Author\n\n**Nikolaos Protopapas**\n\n- GitHub: [@nickprotop](https://github.com/nickprotop)\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnickprotop%2FServerHub","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnickprotop%2FServerHub","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnickprotop%2FServerHub/lists"}