Skip to content

indrasvat/gp-vpn

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gp-vpn

CI

A command-line interface for managing GlobalProtect VPN connections on macOS.

gp-vpn automates the GlobalProtect UI using AppleScript, providing a fast and scriptable way to manage your VPN connections from the terminal.

Features

  • CLI Commands: Connect, disconnect, check status, and toggle VPN connections
  • Portal Shortcuts: Define shortcuts for frequently used portals in a config file
  • Portal Discovery: Automatically discover configured portals from GlobalProtect Settings
  • Interactive TUI: Terminal user interface with real-time status and keyboard navigation
  • JSON Output: Machine-readable output for scripting and automation
  • Logging: Configurable logging with zerolog

Requirements

  • macOS 14+ (Sonoma or later)
  • GlobalProtect VPN client installed and running
  • Terminal app with Accessibility permissions (see below)

Granting Accessibility Permissions

gp-vpn uses AppleScript to automate the GlobalProtect UI. For this to work, your terminal application needs Accessibility permissions:

  1. Open System Settings > Privacy & Security > Accessibility
  2. Click the + button
  3. Add your terminal app (Terminal.app, iTerm2, Warp, etc.)
  4. Ensure the checkbox is enabled
  5. Restart your terminal app for the permissions to take effect

First Run: The first time you run gp-vpn, macOS may show a prompt asking to allow your terminal to control "System Events". Click OK to allow this - it's required for AppleScript automation to work.

Tip: If you use multiple terminal apps (e.g., Terminal.app and VS Code's integrated terminal), each one needs its own Accessibility permission.

Installation

From Binary (Recommended)

Download the latest release from the Releases page.

# Download and extract (example for arm64)
curl -LO https://github.com/indrasvat/gp-vpn/releases/latest/download/gp-vpn-darwin-arm64.tar.gz
tar -xzf gp-vpn-darwin-arm64.tar.gz

# Remove macOS quarantine attribute (required for unsigned binaries)
xattr -dr com.apple.quarantine gp-vpn

# Move to a directory in your PATH
mkdir -p ~/.local/bin
mv gp-vpn ~/.local/bin/

# Verify installation
gp-vpn version

Note: Since the binary is not signed with an Apple Developer certificate, macOS Gatekeeper will block it by default. The xattr -dr com.apple.quarantine command removes this block. Alternatively, you can right-click the binary in Finder, select "Open", and confirm you want to run it.

From Source

Requires Go 1.25+ installed.

# Clone the repository
git clone https://github.com/indrasvat/gp-vpn.git
cd gp-vpn

# Build and install to ~/.local/bin
make build
make install

# Or install to a custom location
make install INSTALL_DIR=/usr/local/bin

PATH Setup

If ~/.local/bin is not in your PATH, add this to your ~/.zshrc or ~/.bashrc:

export PATH="$HOME/.local/bin:$PATH"

Then restart your terminal or run source ~/.zshrc.

Usage

Basic Commands

# Check connection status
gp-vpn status

# Connect to VPN (uses default portal or currently selected)
gp-vpn connect

# Connect to a specific portal
gp-vpn connect vpn.example.com

# Connect using a shortcut defined in config
gp-vpn connect work

# Connect and wait for connection to establish
gp-vpn connect --wait --timeout 30s

# Switch portals (auto-disconnects and reconnects)
gp-vpn connect backup  # Seamlessly switches from current portal

# Disconnect from VPN
gp-vpn disconnect

# Toggle connection (disconnect if connected, connect if disconnected)
gp-vpn toggle
gp-vpn toggle work  # Toggle with specific portal

# List configured portal shortcuts
gp-vpn portals

# Discover portals from GlobalProtect Settings
gp-vpn portals discover

# Generate config file from discovered portals
gp-vpn config init

# Generate config to stdout
gp-vpn config init -

# Show current configuration
gp-vpn config show

# Launch interactive TUI
gp-vpn tui

# Show version
gp-vpn version

Output Formats

By default, gp-vpn outputs machine-parseable text:

$ gp-vpn status
connected:vpn.example.com

$ gp-vpn status
disconnected

$ gp-vpn connect work
success:vpn.example.com

$ gp-vpn connect work  # When already connected to work
already_connected:vpn.example.com

$ gp-vpn disconnect
success

Use --json for JSON output:

$ gp-vpn status --json
{
  "connected": true,
  "portal": "vpn.example.com"
}

$ gp-vpn version --json
{
  "version": "1.0.0",
  "commit": "abc1234",
  "build_date": "2025-12-24T12:00:00Z",
  "go_version": "go1.25.5",
  "os": "darwin",
  "arch": "arm64",
  "tested_gp_version": "6.3.1"
}

Interactive TUI

Launch the interactive terminal UI with gp-vpn tui:

╭───────────────────────────────────────────────────╮
│                                                   │
│   gp-vpn                                          │
│                                                   │
│        ▄▀▀▀▀▀▀▀▄                                  │
│      ▄▀   ╱▲╲   ▀▄                                │
│     ▐    ▕██▏    ▌   ● Connected                  │
│     ▐────▕██▏────▌   vpn.example.com              │
│     ▐    ▕██▏    ▌                                │
│      ▀▄   ╲▼╱   ▄▀                                │
│        ▀▄▄▄▄▄▄▄▀                                  │
│                                                   │
│   1. ● work         vpn.example.com               │
│   2. › backup       vpn-backup.example.com        │
│   3.   office       office.company.org            │
│                                                   │
│   d disconnect · 1-3 select · ↑↓ nav · r refresh  │
│                                                   │
╰───────────────────────────────────────────────────╯

The TUI features a GlobalProtect-inspired ASCII globe that changes based on connection state:

State Globe Color Description
Connected 🟢 Green Globe with shield overlay
Connecting/Switching 🟡 Yellow Plain globe (animated)
Disconnected ⚪ Gray Plain globe

Keyboard Shortcuts:

  • Enter or c - Connect to selected portal
  • d - Disconnect
  • 1-9 - Quick-select portal by number
  • / or k/j - Navigate portal list
  • r - Refresh status
  • q - Quit

Modern TUI (tui2)

A redesigned terminal interface with card-based layout, 3D status spheres, and network stats. Launch with gp-vpn tui2:

╭──────────────────────────────────────────────────────────────────────────────╮
│                                                                              │
│  VPN Status                                                                  │
│  GlobalProtect Secure                                                        │
│                                                                              │
│                                   ▄▄▄▄▄▄▄                                    │
│                                 ▄▄▄▄▄▄▄▄▄▄▄                                  │
│                                ▄▄▄▄▄▄▄▄▄▄▄▄▄                                 │
│                               ███████████████                                │
│                               ███████✓███████                                │
│                               ███████████████                                │
│                                ▀▀▀▀▀▀▀▀▀▀▀▀▀                                 │
│                                 ▀▀▀▀▀▀▀▀▀▀▀                                  │
│                                   ▀▀▀▀▀▀▀                                    │
│                                  Connected                                   │
│                                 ● 00:14:32                                   │
│                             ▲ vpn.example.com                                │
│                                                                              │
│       ╭────────────────────────╮  ╭────────────────────────╮                 │
│       │ ASSIGNED IP            │  │ EXIT IP                │                 │
│       │ 10.0.42.85             │  │ 203.0.113.42 (42ms)    │                 │
│       ╰────────────────────────╯  ╰────────────────────────╯                 │
│                                                                              │
│  Available Gateways                                          r Refresh       │
│                                                                              │
│  ╭──────────────────────────────────────────────────────────────────────╮    │
│  │ ▶ 1. work           vpn.example.com                             ● ✓  │    │
│  ╰──────────────────────────────────────────────────────────────────────╯    │
│  ╭──────────────────────────────────────────────────────────────────────╮    │
│  │   2. backup         vpn-backup.example.com                        ○  │    │
│  ╰──────────────────────────────────────────────────────────────────────╯    │
│                                                                              │
│                ╭────────────────╮    ╭──────────────────╮                    │
│                │   Disconnect   │    │  Switch Gateway  │                    │
│                ╰────────────────╯    ╰──────────────────╯                    │
│                       [ d ]                    [ ↵ ]                         │
│                                                                              │
│                      ↑↓ navigate · 1-9 select · q quit                       │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯

The modern TUI features 3D shaded spheres that indicate connection state:

State Sphere Description
Connected 🟢 Green 3D sphere Checkmark in center
Connecting/Switching 🟡 Amber 3D sphere Animated spinner
Disconnected ⚪ Gray 3D sphere Muted appearance

Features:

  • Network stats panel showing Assigned IP, Exit IP, and latency
  • Card-based gateway list with selection highlighting
  • Neon-styled action buttons with keyboard hints
  • Real-time uptime counter when connected
  • Auto-selects connected portal on status updates
  • Flash-free stats fetching (no UI flashes from AppleScript)

Configuration

Configuration is stored in TOML format. gp-vpn searches for config in this order:

  1. Path specified with --config flag
  2. GPVPN_CONFIG environment variable
  3. ./gp-vpn.toml (current directory)
  4. ~/.config/gp-vpn/config.toml
  5. ~/.gp-vpn.toml

Example Configuration

# ~/.config/gp-vpn/config.toml

# Default portal shortcut to use when no portal is specified
default_portal = "work"

# Portal shortcuts - map friendly names to full portal addresses
[portals]
work = "vpn.company.com"
backup = "vpn-backup.company.com"
office = "office.company.org"

# TUI settings
[tui]
refresh_interval = "30s"  # Auto-refresh interval (disabled by default, press 'r' to refresh)
theme = "dark"            # dark, light, or auto

# Logging settings
[log]
level = "info"                              # debug, info, warn, error
file = "~/.local/share/gp-vpn/gp-vpn.log"  # Optional log file

Generating Config from GlobalProtect

The easiest way to set up gp-vpn is to generate a config file from your existing GlobalProtect installation:

# Generate config file (writes to ~/.config/gp-vpn/config.toml)
$ gp-vpn config init
Generated config file: /Users/you/.config/gp-vpn/config.toml

Discovered 3 portal(s):
  vpn -> vpn.company.com
  vpn-backup -> vpn-backup.company.com
  office -> office.company.org

This opens GlobalProtect Settings, reads configured portals, and generates a TOML config with shortcuts.

To preview without writing a file:

$ gp-vpn config init -
# gp-vpn Configuration
# Generated by: gp-vpn config init
...

Discovering Portals

To see what portals are configured without generating a config:

$ gp-vpn portals discover
Discovered 3 portal(s):
  vpn.company.com
  vpn-backup.company.com
  office.company.org

Scripting Examples

Check if connected before running a command

#!/bin/bash
if [[ $(gp-vpn status) == disconnected ]]; then
    echo "VPN not connected. Connecting..."
    gp-vpn connect --wait
fi

# Run your command that requires VPN
ssh internal-server.company.com

Auto-connect on terminal startup

Add to your ~/.zshrc or ~/.bashrc:

# Auto-connect to VPN if not connected
if command -v gp-vpn &> /dev/null; then
    if [[ $(gp-vpn status 2>/dev/null) == "disconnected" ]]; then
        echo "Connecting to VPN..."
        gp-vpn connect work
    fi
fi

Integration with tmux

# Show VPN status in tmux status bar
# Add to ~/.tmux.conf:
set -g status-right '#(gp-vpn status 2>/dev/null || echo "vpn:unknown")'

Development

Prerequisites

  • Go 1.25+
  • golangci-lint (optional, for linting)
  • gotestsum (optional, for pretty test output)
  • lefthook (optional, for git hooks)

Building

# Download dependencies
make deps

# Build the binary
make build

# Run all checks (format, vet, lint, test, build)
make ci

# Run tests
make test

# Run tests with coverage
make test-cover

# Format code
make fmt

# Run linter
make lint

# Install development tools
make tools

Make Targets

make help          # Show all available targets

# Build
make build         # Build the binary
make build-debug   # Build with debug symbols
make install       # Install to ~/.local/bin
make install INSTALL_DIR=/usr/local/bin  # Custom install path
make uninstall     # Remove from install location
make clean         # Remove build artifacts

# Development
make dev           # Build and run status command
make run ARGS="status"  # Run without building
make watch         # Watch for changes and rebuild (requires entr)

# Quality
make test          # Run tests
make test-cover    # Run tests with coverage report
make lint          # Run golangci-lint
make fmt           # Format code
make fmt-check     # Check code formatting
make vet           # Run go vet
make staticcheck   # Run staticcheck
make check         # Run all checks
make ci            # Full CI pipeline

# Dependencies
make deps          # Download dependencies
make tidy          # Tidy go.mod
make verify        # Verify dependencies
make update-deps   # Update all dependencies
make tools         # Install development tools

# Git Hooks
make hooks         # Setup lefthook git hooks

# Release
make release       # Build release binaries
make version       # Show version info

Troubleshooting

"gp-vpn" cannot be opened because it is from an unidentified developer

This happens when downloading pre-built binaries. macOS quarantines files from the internet. Fix it with:

xattr -dr com.apple.quarantine ~/.local/bin/gp-vpn

Or right-click the binary in Finder, select Open, and confirm.

"Accessibility denied" error

Your terminal app needs Accessibility permissions. See Granting Accessibility Permissions.

Important: After granting permissions, you must restart your terminal app.

"GlobalProtect process not found"

Ensure GlobalProtect is running. You can start it from Applications or check if it auto-starts on login.

"UI element not found"

This usually means:

  1. GlobalProtect needs re-authentication - open the GP app manually to check
  2. The GP UI has changed in a newer version - please open an issue

"Could not open GlobalProtect popup"

The menu bar icon might be hidden or the popup failed to appear. Try:

  1. Click the GlobalProtect icon manually to ensure it works
  2. Wait a moment and try again
  3. Restart GlobalProtect

Connection times out

When using --wait, the default timeout is 15 seconds. For slower connections:

gp-vpn connect --wait --timeout 60s

Tested Versions

  • GlobalProtect: 6.3.1
  • macOS: 14.0+ (Sonoma)
  • Go: 1.25.5

License

MIT License - see LICENSE for details.

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Run make ci to ensure all checks pass
  5. Submit a pull request

Acknowledgments


This project is not affiliated with, endorsed by, or sponsored by Palo Alto Networks. GlobalProtect is a trademark of Palo Alto Networks, Inc. This is an independent, open-source tool that automates the existing GlobalProtect UI via AppleScript.

About

A macOS Go CLI for the GlobalProtect VPN

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors