{"id":42839062,"url":"https://github.com/plyght/hops","last_synced_at":"2026-02-04T16:00:44.903Z","repository":{"id":335242123,"uuid":"1144872362","full_name":"plyght/hops","owner":"plyght","description":"hops is a lightweight sandboxing tool for running untrusted code on macOS.","archived":false,"fork":false,"pushed_at":"2026-01-30T15:59:33.000Z","size":1959,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-31T01:53:50.773Z","etag":null,"topics":["containerization","containers","macos","rust","sandbox","swift"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/plyght.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-01-29T06:25:00.000Z","updated_at":"2026-01-30T15:59:37.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/plyght/hops","commit_stats":null,"previous_names":["plyght/hops"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/plyght/hops","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plyght%2Fhops","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plyght%2Fhops/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plyght%2Fhops/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plyght%2Fhops/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/plyght","download_url":"https://codeload.github.com/plyght/hops/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plyght%2Fhops/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28941896,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-31T11:39:38.044Z","status":"ssl_error","status_checked_at":"2026-01-31T11:39:27.765Z","response_time":128,"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":["containerization","containers","macos","rust","sandbox","swift"],"created_at":"2026-01-30T11:48:11.183Z","updated_at":"2026-01-31T12:00:33.285Z","avatar_url":"https://github.com/plyght.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"public/images/hops.png\" alt=\"Hops\" width=\"140\" /\u003e\n\u003c/p\u003e\n\n# Hops\n\nLightweight sandboxing for untrusted code on macOS. Hops provides process isolation with fine-grained capability control, letting you run untrusted code safely with filesystem, network, and resource restrictions.\n\n## Overview\n\nHops isolates processes in controlled sandbox environments using [Apple's Containerization framework](https://github.com/apple/containerization) (v0.23.2). A background daemon manages sandbox lifecycle via gRPC while the CLI provides a clean interface for running commands and managing profiles. An optional Rust GUI offers visual profile management.\n\n## Requirements\n\n- **macOS 26 (Sequoia)** or later\n- **Apple Silicon** (M1/M2/M3/M4)\n- **Swift 6.0+**\n- **Rust 1.75+** (GUI only)\n\n### Runtime Prerequisites\n\nBefore starting the daemon, you must have:\n\n1. **Linux Kernel**: `~/.hops/vmlinux` (Kata Containers ARM64 kernel, ~14MB)\n2. **Init Filesystem**: `~/.hops/initfs` (vminitd init system, ~256MB)\n3. **Alpine Rootfs**: `~/.hops/alpine-rootfs.ext4` (Alpine Linux userland, ~512MB)\n\nDownload from [Apple Container releases](https://github.com/apple/container/releases) or see [docs/setup.md](docs/setup.md) for detailed installation.\n\n## Features\n\n- **Fine-Grained Capabilities**: Control network access (disabled, outbound, loopback, full), filesystem permissions, and process limits per sandbox\n- **Policy-Based Configuration**: Define reusable security profiles in TOML with explicit allow/deny path lists\n- **Resource Limits**: Constrain CPU cores, memory allocation, and maximum process count\n- **Daemon Architecture**: Background service manages sandbox lifecycle with gRPC over Unix socket\n- **Profile System**: Create, share, and reuse sandbox configurations across projects\n- **Secure Defaults**: Network disabled, minimal filesystem access, symlink attack prevention\n- **Interactive TTY Support**: Run interactive shells with full stdin/stdout/stderr support using `--interactive` or `-it` flag\n- **Automatic Daemon Management**: Daemon starts automatically when needed, no manual lifecycle management required\n- **Desktop GUI**: Iced-based Rust application for visual profile management and run history\n\n## Quick Start\n\n### Option 1: Automated Installation (Recommended)\n\n```bash\ngit clone https://github.com/plyght/hops.git\ncd hops\nmake install\n```\n\nThe installation script will:\n- Build the project in release mode\n- Code sign hopsd with proper entitlements\n- Install binaries to /usr/local/bin\n- Create ~/.hops directory structure\n- Download runtime files (vmlinux, initfs)\n- Create Alpine rootfs image\n\nThen run your first command:\n\n```bash\nhops run /tmp -- /bin/echo \"Hello from Hops!\"\n```\n\nThe daemon starts automatically when needed. To manage it manually:\n\n```bash\nhops system start   # Explicitly start daemon\nhops system status  # Check daemon status\nhops system stop    # Stop daemon\n```\n\n### Option 2: Manual Installation\n\nIf you prefer manual control:\n\n```bash\ngit clone https://github.com/plyght/hops.git\ncd hops\nmake build\nsudo cp .build/release/hops /usr/local/bin/\nsudo cp .build/release/hopsd /usr/local/bin/\nsudo cp .build/release/hops-create-rootfs /usr/local/bin/\nhops init\n```\n\n### Option 3: Step-by-Step (Legacy)\n\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand manual steps\u003c/summary\u003e\n\n#### 1. Build and Install\n\n```bash\ngit clone https://github.com/plyght/hops.git\ncd hops\nswift build -c release\ncodesign -s - --entitlements hopsd.entitlements --force .build/release/hopsd\nsudo cp .build/release/hops /usr/local/bin/\nsudo cp .build/release/hopsd /usr/local/bin/\nsudo cp .build/release/hops-create-rootfs /usr/local/bin/\n```\n\n#### 2. Download Runtime Files\n\n```bash\nmkdir -p ~/.hops\ncd ~/.hops\ncurl -L -o vmlinux https://github.com/apple/container/releases/latest/download/vmlinux\ncurl -L -o initfs https://github.com/apple/container/releases/latest/download/init.block\ncurl -L -o alpine-minirootfs.tar.gz https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/aarch64/alpine-minirootfs-3.19.1-aarch64.tar.gz\n```\n\n#### 3. Create Alpine Rootfs\n\n```bash\nhops-create-rootfs\n```\n\n#### 4. Run a Command\n\n```bash\nhops run /tmp -- /bin/echo \"Hello from Hops!\"\n```\n\n\u003c/details\u003e\n\nSee [docs/setup.md](docs/setup.md) for detailed installation and [launchd/README.md](launchd/README.md) for daemon management.\n\n### GUI (Optional)\n\n```bash\ncd hops-gui\ncargo build --release\ncp target/release/hops-gui /usr/local/bin/\nhops-gui\n```\n\n## Usage\n\n### Basic Commands\n\n```bash\n# Initialize environment (download runtime files)\nhops init\n\n# Check environment setup\nhops init --check-only\n\n# Verify system health\nhops doctor\n\n# Run a command in sandbox (daemon starts automatically)\nhops run /tmp -- /bin/echo \"Hello\"\n\n# Run shell commands\nhops run /tmp -- /bin/sh -c \"uname -a\"\n\n# Interactive shell (SSH-like experience with prompts)\nhops run /tmp -- /bin/sh\n# You'll see a prompt: / $\n# Type commands in real-time and see immediate output\n# Exit with ctrl-d or \"exit\"\n\n# Piped input also works\necho \"ls -la\" | hops run /tmp -- /bin/sh\necho \"hello\" | hops run /tmp -- /bin/cat\n\n# Disable interactive mode if needed\nhops run --no-interactive /tmp -- /bin/sh\n\n# With resource limits\nhops run --cpus 2 --memory 512M /tmp -- /bin/ls\n\n# With network access (NAT with DNS)\nhops run --network outbound /tmp -- /bin/ping -c 2 google.com\nhops run --network outbound /tmp -- /bin/wget -O- example.com\n\n# Manual daemon management (optional - daemon auto-starts by default)\nhops system status        # Check daemon status\nhops system start         # Explicitly start daemon\nhops system stop          # Stop daemon\nhops system restart       # Restart daemon\n```\n\n### Profile Management\n\n```bash\n# List available profiles\nhops profile list\n\n# Run with profile\nhops run --profile untrusted /tmp -- /bin/sh\n\n# Create custom profile\nhops profile create custom --template restrictive\n```\n\n### GUI\n\n```bash\nhops-gui\n```\n\nFeatures:\n- Visual profile editor\n- Real-time sandbox status\n- Run history with gRPC integration\n- Connection status indicator\n\n## Configuration\n\nPolicies are TOML files defining sandbox behavior:\n\n```toml\nname = \"build\"\nversion = \"1.0.0\"\ndescription = \"Build environment with network access\"\n\n[capabilities]\nnetwork = \"outbound\"\nfilesystem = [\"read\", \"write\", \"execute\"]\nallowed_paths = [\"/usr\", \"/lib\", \"/bin\"]\ndenied_paths = [\"/etc/shadow\", \"/etc/passwd\", \"/root/.ssh\"]\n\n[capabilities.resource_limits]\ncpus = 4\nmemory_bytes = 4294967296\nmax_processes = 256\n\n[sandbox]\nroot_path = \"/\"\nhostname = \"build-sandbox\"\nworking_directory = \"/\"\n\n[[sandbox.mounts]]\nsource = \"/usr\"\ndestination = \"/usr\"\ntype = \"bind\"\nmode = \"ro\"\n\n[[sandbox.mounts]]\nsource = \"tmpfs\"\ndestination = \"/tmp\"\ntype = \"tmpfs\"\nmode = \"rw\"\n```\n\nProfiles are stored in `~/.hops/profiles/` and selected with `--profile \u003cname\u003e`.\n\nSee [config/README.md](config/README.md) for more examples and the full schema.\n\n## Architecture\n\n```\nhops (CLI)\n  Commands/\n    RunCommand.swift       Command execution with gRPC client\n    ProfileCommand.swift   Profile CRUD operations\n    SystemCommand.swift    Daemon lifecycle control\n\nhopsd (Daemon)\n  HopsDaemon.swift         Unix socket server and lifecycle\n  SandboxManager.swift     Container orchestration via Containerization.framework\n  ContainerService.swift   gRPC service implementation (Hops_HopsServiceAsyncProvider)\n  CapabilityEnforcer.swift Policy-to-container translation\n\nHopsCore (Library)\n  Policy.swift             Policy and sandbox configuration models\n  Capability.swift         Network, filesystem, and resource capability types\n  Mount.swift              Mount configuration types\n  PolicyParser.swift       TOML parsing with TOMLKit\n  PolicyValidator.swift    Security validation (path canonicalization, symlink prevention)\n\nHopsProto (Library)\n  hops.pb.swift            Generated protobuf messages\n  hops.grpc.swift          Generated gRPC client and server stubs\n\nhops-gui (Rust)\n  app.rs                   Iced application state and message handling\n  models/                  Policy, Capability, Profile structs (synced with HopsCore)\n  views/                   Profile editor, list, and run history views\n```\n\n### Communication Flow\n\n```\n┌─────────┐     gRPC/Unix Socket     ┌─────────┐     Containerization     ┌───────────┐\n│  hops   │ ──────────────────────▶  │  hopsd  │ ──────────────────────▶  │  Sandbox  │\n│  (CLI)  │    ~/.hops/hops.sock     │ (Daemon)│      VZVirtualMachine    │  (Linux)  │\n└─────────┘                          └─────────┘                          └───────────┘\n```\n\n## Development\n\n```bash\n# Build with Makefile (recommended)\nmake build                  # Release build with code signing\nmake build BUILD_MODE=debug # Debug build\n\n# Or build manually\nswift build\n\n# Code signing (required for hopsd to use virtualization)\ncodesign -s - --entitlements hopsd.entitlements --force .build/debug/hopsd\n\n# Run tests\nmake test\n# Or: swift test\n\n# Clean build artifacts\nmake clean\n\n# Install locally\nmake install\n\n# Uninstall\nmake uninstall\n\n# Regenerate gRPC stubs (after modifying proto/hops.proto)\n./generate-proto.sh\n```\n\n### Dependencies\n\n**Swift**:\n- swift-argument-parser - CLI parsing\n- TOMLKit - TOML configuration parsing\n- grpc-swift - gRPC communication\n- swift-nio - Async networking\n- Containerization (0.23.2) - Apple's sandbox framework\n\n**Rust**:\n- iced (0.13) - Cross-platform GUI\n- tonic (0.12) - gRPC client\n- serde - Serialization\n- toml - TOML parsing\n\n## Status\n\n**Current Version**: Fully functional end-to-end\n\nWorking:\n- Daemon lifecycle (start/stop/status)\n- Container execution with Alpine Linux userland\n- Streaming stdout/stderr with exit code propagation\n- Resource limits (CPU, memory, process count)\n- Per-container filesystem isolation with writable rootfs copies\n- gRPC CLI-daemon communication\n- Rust GUI with live daemon integration\n- Automatic container cleanup on daemon restart\n- Interactive TTY support with shell prompts (SSH-like experience, default behavior)\n- Network capabilities (disabled/loopback/outbound/full with NAT and DNS)\n\nKnown Limitations:\n- None currently identified\n\n## Documentation\n\n- [docs/setup.md](docs/setup.md) - Detailed installation and configuration\n- [config/README.md](config/README.md) - Policy configuration reference\n- [launchd/README.md](launchd/README.md) - Daemon management\n- [docs/testing.md](docs/testing.md) - Test coverage report\n\n## Quick Reference\n\n### Installation\n```bash\nmake install              # Automated installation\nmake build                # Build only\nmake uninstall            # Remove binaries\n```\n\n### Setup\n```bash\nhops init                 # Download runtime files\nhops init --check-only    # Verify setup\nhops doctor               # Diagnose issues\n```\n\n### Daemon\n```bash\nhops system start         # Start daemon\nhops system stop          # Stop daemon\nhops system status        # Check status\nhops system restart       # Restart daemon\n```\n\n### Running Commands\n```bash\nhops run \u003cpath\u003e -- \u003ccmd\u003e                    # Basic usage\nhops run --network outbound \u003cpath\u003e -- \u003ccmd\u003e # With network\nhops run --cpus 2 --memory 512M \u003cpath\u003e -- \u003ccmd\u003e # Resource limits\nhops run --profile untrusted \u003cpath\u003e -- \u003ccmd\u003e    # With profile\n```\n\n### Profiles\n```bash\nhops profile list                           # List profiles\nhops profile show \u003cname\u003e                    # Show profile\nhops profile create \u003cname\u003e                  # Create profile\n```\n\n## License\n\nMIT License\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplyght%2Fhops","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fplyght%2Fhops","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplyght%2Fhops/lists"}