Skip to content

mrf/kubectx-timeout

Repository files navigation

kubectx-timeout

A macOS daemon that automatically switches your kubectl context to a safe default after a period of inactivity, preventing accidental commands against production clusters.

Go Report Card

Overview

Have you ever forgotten you were in a production kubectl context and run a potentially dangerous command? kubectx-timeout solves this by monitoring your kubectl activity and automatically switching to a safe default context after a configurable timeout period.

Goals

  • Safety First: Prevent accidental operations on production clusters by enforcing automatic context timeouts
  • Simple & Reliable: Lightweight daemon with minimal dependencies, designed for local macOS use
  • Configurable: Per-context timeout settings with sensible defaults
  • Non-intrusive: Runs quietly in the background via launchd, only acts when needed
  • Transparent: Logs all context switches and provides status commands

How It Works

  1. A shell wrapper tracks kubectl command activity by writing timestamps to a state file
  2. A background daemon monitors this activity via a periodic check
  3. Optional: File system monitoring (fswatch) detects context switches from any tool
  4. When inactivity exceeds the configured timeout, the daemon switches to your default safe context
  5. You're notified of the switch and can continue working safely

Installation

Quick Start

# 1. Clone and build
git clone https://github.com/YOUR-USERNAME/kubectx-timeout.git
cd kubectx-timeout
make build

# 2. Install binary
sudo cp bin/kubectx-timeout /usr/local/bin/

# 3. Initialize configuration (interactive, selects your safe default context)
kubectx-timeout init

# 4. Install shell integration (auto-detects your shell: bash/zsh/fish)
kubectx-timeout install-shell

# 5. Install and start the daemon (macOS launchd)
kubectx-timeout daemon-install
kubectx-timeout daemon-start

# 6. (Optional but recommended) Install fswatch for automatic context switch detection
brew install fswatch

# 7. Restart your shell
source ~/.bashrc  # or ~/.zshrc

# You're done! kubectl activity is now tracked.

Installation Steps Explained

1. Build and Install Binary

make build
sudo cp bin/kubectx-timeout /usr/local/bin/

2. Initialize Configuration

The init command creates an interactive configuration file:

kubectx-timeout init

This will:

  • Show available kubectl contexts
  • Let you select a safe default context
  • Create ~/.config/kubectx-timeout/config.yaml with sensible defaults

3. Install Shell Integration

The shell integration wraps kubectl to track activity:

# Auto-detect current shell
kubectx-timeout install-shell

# Or specify shell explicitly
kubectx-timeout install-shell bash
kubectx-timeout install-shell zsh
kubectx-timeout install-shell fish

This modifies your shell profile (.bashrc, .zshrc, or config.fish) to wrap kubectl commands.

4. Set Up Daemon (macOS)

Install the launchd agent for automatic daemon startup:

# Install daemon configuration
kubectx-timeout daemon-install

# Start the daemon
kubectx-timeout daemon-start

# Check daemon status
kubectx-timeout daemon-status

Other daemon commands:

  • kubectx-timeout daemon-stop - Stop the daemon
  • kubectx-timeout daemon-restart - Restart the daemon
  • kubectx-timeout daemon-uninstall - Remove daemon configuration

Direct daemon control (alternative to launchd):

# Start daemon in background
kubectx-timeout start

# Check daemon status and timeout info
kubectx-timeout status

# Stop the daemon
kubectx-timeout stop

# Reload configuration without restarting
kubectx-timeout reload

# Reset activity timer (prevent imminent timeout)
kubectx-timeout reset

# Run in foreground (for debugging)
kubectx-timeout daemon

Verification

After installation, verify everything is working:

# Check the binary is installed
kubectx-timeout version

# Run a kubectl command (activity will be tracked)
kubectl get pods

# Check daemon status
kubectx-timeout daemon-status

# View logs
tail -f ~/.local/state/kubectx-timeout/daemon.log

Uninstallation

To uninstall kubectx-timeout, follow these steps:

# 1. Stop and remove the daemon
kubectx-timeout daemon-stop
kubectx-timeout daemon-uninstall

# 2. Remove shell integration
kubectx-timeout uninstall-shell

# 3. Remove configuration and state files (optional)
rm -rf ~/.config/kubectx-timeout
rm -rf ~/.local/state/kubectx-timeout

# 4. Remove the binary (optional)
sudo rm /usr/local/bin/kubectx-timeout

What gets removed:

  • daemon-uninstall - Removes launchd plist from ~/Library/LaunchAgents/
  • uninstall-shell - Removes shell wrapper from .bashrc, .zshrc, or config.fish
  • Manual cleanup removes config and state directories
  • Manual removal of the binary from /usr/local/bin/

Configuration

File Locations

kubectx-timeout follows the XDG Base Directory Specification for clean, organized file management:

Configuration Files

  • Default: ~/.config/kubectx-timeout/config.yaml
  • Custom: Set $XDG_CONFIG_HOME to override (uses $XDG_CONFIG_HOME/kubectx-timeout/config.yaml)

State Files

  • Default: ~/.local/state/kubectx-timeout/state.json
  • Custom: Set $XDG_STATE_HOME to override (uses $XDG_STATE_HOME/kubectx-timeout/)
  • Log files: Stored alongside state in ~/.local/state/kubectx-timeout/daemon.log

Why XDG?

The XDG Base Directory specification provides:

  • Clean home directory: No dotfiles cluttering ~/
  • Standard locations: Follows modern Unix/Linux conventions
  • User control: Respects $XDG_* environment variables
  • Separation: Config and state are kept in different directories

Configuration File

The configuration file (config.yaml) controls all daemon behavior:

# Global timeout settings
timeout:
  default: 30m          # Default timeout for all contexts
  check_interval: 30s   # How often to check for inactivity

# Context to switch to after timeout
default_context: local  # Should be a safe, non-production context

# Context-specific timeout overrides (optional)
contexts:
  production:
    timeout: 5m         # Production gets a shorter timeout

# Daemon behavior
daemon:
  enabled: true
  log_level: info       # debug, info, warn, error
  log_file: daemon.log
  log_max_size: 10      # MB
  log_max_backups: 5

# Notifications when context switch occurs
notifications:
  enabled: true
  method: both          # terminal, macos, or both

# Safety features
safety:
  check_active_kubectl: true
  validate_default_context: true
  never_switch_to:      # Extra safety
    - production
    - prod

# State file location (relative to state directory)
state_file: state.json

# Shell integration settings
shell:
  generate_wrapper: true
  shells:
    - bash
    - zsh

See examples/config.example.yaml for a fully documented example.

Minimal Configuration

For quick setup, you only need to specify your default (safe) context:

timeout:
  default: 30m

default_context: local  # Change to your safe context

Usage

Command Reference

# Initialize configuration (interactive setup)
kubectx-timeout init

# Install shell integration
kubectx-timeout install-shell bash    # Install for bash
kubectx-timeout install-shell zsh     # Install for zsh

# Run daemon (usually via launchd, but can run manually)
kubectx-timeout daemon

# Check version
kubectx-timeout --version

# Get help
kubectx-timeout --help

# Use custom config/state paths
kubectx-timeout --config /custom/path/config.yaml --state /custom/path/state.json daemon

Daemon Management

The daemon is managed through launchd on macOS for automatic startup and process supervision.

Quick Start:

# Install daemon as launchd service
kubectx-timeout daemon-install

# The daemon will start automatically and on every login
kubectx-timeout daemon-status

Management Commands:

kubectx-timeout daemon-install   # Install daemon as launchd service
kubectx-timeout daemon-uninstall # Remove daemon service
kubectx-timeout daemon-start     # Start the daemon
kubectx-timeout daemon-stop      # Stop the daemon
kubectx-timeout daemon-restart   # Restart the daemon
kubectx-timeout daemon-status    # Show detailed status

Direct Control Commands (alternative to launchd):

# Start daemon in background
kubectx-timeout start

# Check daemon status and timeout information
kubectx-timeout status

# Stop the daemon
kubectx-timeout stop

# Reload configuration without restarting
kubectx-timeout reload

# Reset activity timer to prevent timeout
kubectx-timeout reset

# Run daemon in foreground (for debugging)
kubectx-timeout daemon

For detailed documentation on daemon management, architecture, troubleshooting, and advanced usage, see DAEMON.md.

Uninstallation

kubectx-timeout provides a comprehensive uninstallation command that cleanly removes all components from your system.

Complete Uninstallation

# Interactive uninstallation (prompts for confirmation)
kubectx-timeout uninstall

# Non-interactive (skip confirmation)
kubectx-timeout uninstall --yes

This will:

  1. Stop the running daemon (if active)
  2. Remove launchd configuration (~/Library/LaunchAgents/com.kubectx-timeout.plist)
  3. Remove shell integration from your shell profile(s)
  4. Remove configuration files (~/.config/kubectx-timeout/)
  5. Remove state files (~/.local/state/kubectx-timeout/)
  6. Remove the binary (by default)

Uninstallation Options

# Keep configuration and state files
kubectx-timeout uninstall --keep-config

# Keep the binary (remove everything else)
kubectx-timeout uninstall --keep-binary

# Remove everything including binary
kubectx-timeout uninstall --all

# Remove from all shell profiles (bash, zsh, fish)
kubectx-timeout uninstall --all-shells

# Target a specific shell
kubectx-timeout uninstall bash
kubectx-timeout uninstall zsh

# Specify custom binary path
kubectx-timeout uninstall --binary /custom/path/kubectx-timeout

What Gets Removed

The uninstall command removes the following components:

Component Location Removed by Default
Daemon (launchd) ~/Library/LaunchAgents/com.kubectx-timeout.plist Yes
Shell Integration ~/.bashrc, ~/.zshrc, ~/.config/fish/config.fish Yes
Configuration ~/.config/kubectx-timeout/ Yes (unless --keep-config)
State Files ~/.local/state/kubectx-timeout/ Yes (unless --keep-config)
Binary /usr/local/bin/kubectx-timeout (or detected path) Yes (unless --keep-binary)

Backups

The uninstall process automatically creates backups before removing shell integrations:

  • Shell profiles: ~/.bashrc.kubectx-timeout.backup, ~/.zshrc.kubectx-timeout.backup, etc.

Manual Uninstallation

If you prefer to uninstall manually:

# 1. Stop and remove daemon
launchctl unload ~/Library/LaunchAgents/com.kubectx-timeout.plist
rm ~/Library/LaunchAgents/com.kubectx-timeout.plist

# 2. Remove shell integration
kubectx-timeout uninstall-shell bash  # or zsh, fish

# 3. Remove configuration and state
rm -rf ~/.config/kubectx-timeout
rm -rf ~/.local/state/kubectx-timeout

# 4. Remove binary
sudo rm /usr/local/bin/kubectx-timeout

How It Works in Detail

Activity Tracking

When you run kubectl commands, the shell wrapper:

  1. Records the current timestamp to the state file
  2. Records the current context name
  3. Executes the actual kubectl command

The state file is a simple JSON file:

{
  "last_activity": "2025-11-05T15:30:00Z",
  "current_context": "production"
}

File System Monitoring (Optional)

For enhanced detection of context switches made outside the shell wrapper (e.g., IDE plugins, GUI tools, direct kubeconfig edits), kubectx-timeout supports fswatch-based monitoring on macOS.

How It Works

When fswatch is installed, the daemon:

  1. Monitors ~/.kube/config (or $KUBECONFIG path) for file modifications
  2. Uses the macOS FSEvents API for efficient, low-overhead file watching
  3. Detects context switches from ANY tool that modifies the kubeconfig
  4. Automatically records activity and resets the timeout when a context change is detected

Installing fswatch

# macOS (Homebrew)
brew install fswatch

After installation, restart the daemon to enable file monitoring:

kubectx-timeout daemon-restart

Behavior

  • If fswatch is available: Automatic monitoring is enabled at daemon startup
  • If fswatch is not installed: Daemon continues to work normally using only shell-wrapper-based detection
  • Graceful degradation: The daemon logs an informative message and continues without file monitoring

The file watcher runs in a separate goroutine alongside the periodic timeout checker, providing comprehensive coverage:

  • Shell wrapper: Detects kubectl commands
  • File monitoring: Detects context switches from IDE plugins, kubectx, GUI tools, manual edits

Platform Support

File system monitoring is currently macOS-only as it uses the FSEvents API. On other platforms, the daemon will automatically skip file monitoring and rely solely on shell wrapper detection.

Timeout Detection

The daemon uses a simple, efficient polling mechanism:

  1. Checks the state file every check_interval (default: 30 seconds)
  2. Uses mtime-based caching to avoid unnecessary file reads (battery optimization)
  3. Compares current time to last_activity
  4. If time elapsed > timeout for current context:
    • Validates the target (default) context exists
    • Checks if kubectl is currently running (optional safety check)
    • Switches to the default context using kubectl config use-context
    • Sends a notification (macOS notification + terminal output)

Battery Optimization: The daemon is designed to be battery-friendly:

  • File modification time (mtime) is checked before reading the full state file
  • Cached values are used when the file hasn't changed
  • Default 30s check interval is a good balance (can be increased for longer battery life)
  • Timeout checking is not time-critical, so longer intervals (60s+) are acceptable

Safety Features

  • Context Validation: Ensures target context exists before switching
  • Active Command Detection: Optionally prevents switching during active kubectl operations
  • Never-Switch Lists: Contexts you never want to auto-switch from or to
  • Secure Execution: Uses exec.Command (not shell) to prevent injection attacks

Status

Current Phase: Functional MVP

Core features implemented and working:

  • ✅ Configuration management with intelligent defaults
  • ✅ Activity tracking and state management
  • ✅ Daemon with timeout detection and fswatch support
  • ✅ Safe context switching with validation
  • ✅ Security hardening and testing
  • ✅ CI/CD pipeline
  • ✅ XDG Base Directory compliance

In progress:

  • 🚧 Comprehensive logging and observability
  • 🚧 Complete user documentation
  • 🚧 Full unit test coverage

Architecture

  • Language: Go 1.21+ (for single-binary distribution and efficient daemon operation)
  • Platform: macOS (using launchd for daemon management)
  • Dependencies: Only kubectl (no external libraries for runtime)
  • File Locations: Following XDG Base Directory specification
    • Configuration: ~/.config/kubectx-timeout/ (or $XDG_CONFIG_HOME/kubectx-timeout/)
    • State & Logs: ~/.local/state/kubectx-timeout/ (or $XDG_STATE_HOME/kubectx-timeout/)

Project Structure

kubectx-timeout/
├── cmd/kubectx-timeout/    # Main application entry point
│   └── main.go
├── internal/               # Private application code
│   ├── config.go          # Configuration loading & validation
│   ├── daemon.go          # Core daemon logic
│   ├── paths.go           # XDG path management
│   ├── state.go           # State file management
│   ├── switcher.go        # Context switching
│   └── tracker.go         # Activity tracking & shell integration
├── examples/              # Example configurations
│   ├── config.example.yaml
│   ├── config.minimal.yaml
│   └── com.kubectx-timeout.plist
└── Makefile              # Build & development tasks

Troubleshooting

Daemon Not Starting

# Check daemon status
kubectx-timeout daemon-status

# View logs
tail -f ~/.local/state/kubectx-timeout/daemon.stderr.log
tail -f ~/.local/state/kubectx-timeout/daemon.stdout.log

# Try restarting
kubectx-timeout daemon-restart

Activity Not Being Tracked

# Verify shell integration installed
cat ~/.bashrc | grep kubectx-timeout  # or ~/.zshrc

# Test kubectl wrapper manually
which kubectl  # Should show your wrapper function, not /usr/local/bin/kubectl

# Check state file
cat ~/.local/state/kubectx-timeout/state.json

Context Not Switching

# Check timeout configuration
cat ~/.config/kubectx-timeout/config.yaml

# Verify default context exists
kubectl config get-contexts

# Check daemon logs for errors
tail -100 ~/.local/state/kubectx-timeout/daemon.stderr.log

File System Monitoring Not Working

# Check if fswatch is installed
which fswatch
fswatch --version

# Install fswatch (macOS)
brew install fswatch

# Check daemon logs for fswatch status
tail -100 ~/.local/state/kubectx-timeout/daemon.log | grep -i fswatch

# Restart daemon after installing fswatch
kubectx-timeout daemon-restart

# Verify KUBECONFIG path
echo $KUBECONFIG  # Should show path to config, or be empty (uses ~/.kube/config)

# Test fswatch manually
fswatch -1 ~/.kube/config &
# Make a change to kubeconfig in another terminal
# You should see output from fswatch

Development

See CONTRIBUTING.md for contribution guidelines and DEVELOPMENT.md for detailed development practices.

Quick Start for Developers

# Clone repository
git clone https://github.com/YOUR-USERNAME/kubectx-timeout.git
cd kubectx-timeout

# Install development tools
make setup-tools

# Run tests
make test

# Check coverage
make coverage

# Build binary
make build

# Run all pre-commit checks
make pre-commit

Contributing

Contributions are welcome! This is an early-stage project, so please:

  1. Read CONTRIBUTING.md for guidelines
  2. Check existing issues before creating new ones
  3. Follow the code standards and testing requirements
  4. Open PRs against the main branch

For maintainers creating releases, see the Release Process section in CONTRIBUTING.md and VERSIONING.md for versioning strategy.

License

See LICENSE file for details.

Security

Found a security issue? Please email [security contact] instead of opening a public issue.

About

Automatically switch your Kubernetes context to a safe local one if you stop using it

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors