fix(pair-agent): tunnel activation is consent-gated — and the receipt's consent claim is now real

The tunnel egress receipts have claimed consent: 'pair_agent=on' since v1.63
while no such key or gate existed — ngrok installed+authed was enough for
the CLI to auto-start an internet-facing tunnel. isPairAgentEnabled() (fail-
closed, env-overridable) now gates all three activation points: CLI
auto-start, POST /tunnel/start (refuses with the enable hint), and the
BROWSE_TUNNEL=1 startup bind. Consent-on-first-use, not silent breakage:
the /pair-agent skill asks once (one-way-door posture), sets pair_agent via
gstack-config (registered with on|off validation, default off), and never
asks again; direct API callers get the same hint in the refusal.

Adapted from the fork's gate: their reader targeted config.json, which on
main would have made the gate silently un-enableable — ours reads the
canonical ~/.gstack/config.yaml with the JSON shape as fallback, pinned by
tests either way (11 cases, gate wiring tripwires included).

Ported from time-attack/gstack (GStack 2), store adaptation ours.

Co-authored-by: Sina Matian <sina@time-attack.dev>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-08-14 12:43:24 -07:00
co-authored by Sina Matian Claude Fable 5
parent 93d92c4585
commit b141fb3511
6 changed files with 190 additions and 8 deletions
+21 -1
View File
@@ -125,7 +125,27 @@ using the generic remote flow instead.
### If different machine (option B):
First, detect ngrok status:
**Consent gate (once per machine).** The tunnel exposes this browser beyond
the machine, so it is OFF until the user opts in — the daemon refuses
`/tunnel/start` and `BROWSE_TUNNEL=1` otherwise. Check the standing consent:
```bash
~/.claude/skills/gstack/bin/gstack-config get pair_agent 2>/dev/null || echo "unset"
```
If the value is not `on`, ask via AskUserQuestion (one-way-door posture —
this opens a path from the internet to the local browser):
> "Remote pairing runs an ngrok tunnel from the internet to this machine's
> browser (locked to a 26-command allowlist + scoped token, but still an
> exposure). Enable pair-agent on this machine?"
Options: A) Enable — run `~/.claude/skills/gstack/bin/gstack-config set pair_agent on`, confirm it reads back `on`, and continue. B) No — stop here; local pairing (option A above) still works.
If the value is already `on`, say nothing and continue — consent stands until
`gstack-config set pair_agent off`.
Then detect ngrok status:
```bash
which ngrok 2>/dev/null && echo "NGROK_INSTALLED" || echo "NGROK_NOT_INSTALLED"