Skip to content

feat(vpn): add PIA split tunnel config watchdog (Stage 1.5)#63

Merged
smartwatermelon merged 3 commits intomainfrom
claude/feat-pia-split-tunnel-monitor-20260213
Feb 13, 2026
Merged

feat(vpn): add PIA split tunnel config watchdog (Stage 1.5)#63
smartwatermelon merged 3 commits intomainfrom
claude/feat-pia-split-tunnel-monitor-20260213

Conversation

@smartwatermelon
Copy link
Owner

Summary

  • New template: app-setup/templates/pia-split-tunnel-monitor.sh — monitors PIA's settings.json every 60s for split tunnel config drift and auto-restores from a saved reference using piactl -u applysettings
  • Deployment integration: Added PIA monitor deployment section to transmission-setup.sh (save reference + deploy template + create LaunchAgent)
  • Documentation: Updated docs/vpn-transmission.md with Stage 1.5 architecture

Why

PIA frequently "forgets" its split tunnel rules. With the Stage 1 inversion (Bypass VPN for Plex/Backblaze/Safari), forgetting means all traffic goes through VPN — including Plex, which is unusable through a multi-hop overseas connection. This watchdog detects drift within 60 seconds and auto-restores.

Design

  • Separate from vpn-monitor.sh (different frequency, urgency, and recovery action)
  • Uses python3 - with heredoc for JSON parsing (no jq on stock macOS)
  • Backoff after 3 failed fix attempts (5 min cooldown)
  • --save-reference flag for initial setup or manual reference updates
  • Reference save is non-fatal during deployment

Test plan

  • Deploy to server via transmission-setup.sh
  • Verify monitor is running: launchctl list | grep pia-monitor
  • Verify reference file exists: cat ~/.local/etc/pia-split-tunnel-reference.json
  • Test drift detection: toggle split tunnel in PIA GUI, verify restore within 60s
  • Verify log output: tail -f ~/.local/state/tilsit-pia-monitor.log
  • Test backoff: disable piactl (rename binary), verify 3-failure backoff

🤖 Generated with Claude Code

Claude Code Bot and others added 2 commits February 13, 2026 12:11
PIA frequently "forgets" its split tunnel configuration. With the
Stage 1 inversion architecture, this means all traffic goes through
VPN — including Plex, which is unusable through a multi-hop overseas
connection. This watchdog monitors PIA's settings.json every 60s,
detects drift, and auto-restores from a saved reference using
piactl -u applysettings with disconnect/reconnect cycle.

- Create pia-split-tunnel-monitor.sh template (follows vpn-monitor.sh patterns)
- Add deployment section to transmission-setup.sh (save reference + deploy + LaunchAgent)
- Update vpn-transmission.md with Stage 1.5 documentation

AI review: code-reviewer (2 iterations)
Adversarial review: code-critic:adversarial-reviewer (1 iteration) - fixed Python injection via
  shell variable interpolation, made reference save non-fatal
Issues fixed: Python code injection in configs_match() and extract_monitored_fields(),
  non-fatal reference save failure handling

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prefix Stage 1.5 subheadings to be unique (matching the Stage 4
convention), fixing CI markdown lint failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Eliminate TOCTOU race in reference file reads by using atomic
cat-or-fail pattern instead of separate -f check + cat. Both
check_and_fix() and verify_fix() now return 1 on missing reference
(consistent severity). Main loop tolerates check_and_fix() failures
with || true to prevent crash loops under set -e.

Addresses Seer review on PR #63.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@smartwatermelon smartwatermelon merged commit 5d9a1b7 into main Feb 13, 2026
17 checks passed
@smartwatermelon smartwatermelon deleted the claude/feat-pia-split-tunnel-monitor-20260213 branch February 13, 2026 21:02
smartwatermelon pushed a commit that referenced this pull request Feb 13, 2026
Individual template copies by filename silently omitted vpn-monitor.sh
and pia-split-tunnel-monitor.sh (added in PRs #57 and #63). Replace
with a glob loop matching the pattern already used for server scripts
and app-setup scripts, so future templates are picked up automatically.

Core templates (mount-nas-media.sh, start-rclone.sh) retain REQUIRED
severity; app-specific templates are OPTIONAL since their setup scripts
handle missing templates gracefully.

Closes #64

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
smartwatermelon added a commit that referenced this pull request Feb 13, 2026
## Summary

- Replace individual template `copy_with_manifest` calls with a glob
loop, matching the pattern already used for server scripts and app-setup
scripts
- Fixes silent omission of `vpn-monitor.sh` and
`pia-split-tunnel-monitor.sh` (added in PRs #57 and #63)
- Future templates are picked up automatically without code changes
- Core templates (`mount-nas-media.sh`, `start-rclone.sh`) retain
REQUIRED severity; app-specific templates are OPTIONAL

## Test plan

- [x] `shellcheck prep-airdrop.sh` passes
- [x] Code-reviewer: PASS
- [x] Adversarial-reviewer: PASS
- [ ] Verify glob matches 6 deployable templates and skips
`transmission-done-template.sh`

Closes #64

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Code Bot <claude-code@smartwatermelon.github>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant