Skip to content

Commit e52de94

Browse files
x402: foolproof deps + correct mac/Linux tunnel requirement in manifest
The manifest claimed macOS/Linux need nothing for the tunnel ("WireGuard ships with the OS"). Tracing sentinel-go-sdk shows the CLI does NOT bundle a tunnel -- it shells out: WireGuard nodes run `wg-quick up` (needs system wireguard-tools), V2Ray nodes run `v2ray run --config` (needs a v2ray binary on PATH). Corrected /manifest tldr, platforms, and connectMacLinux to state the real native deps (Go 1.24+, wireguard-tools, v2ray), and added an explicit `install` block + viem to packages so a zero-experience agent has the complete npm set (`npm install @x402/fetch @x402/evm viem blue-js-sdk`) and the out-of-npm native deps spelled out. Also normalize e2e-maclinux.sh to LF / no-BOM / ASCII separators (a prior PowerShell round-trip had reintroduced CRLF and mojibake'd the box-drawing dashes), and surface wg-quick/v2ray as explicit STEP 0 checks in the runner.
1 parent a068e9a commit e52de94

2 files changed

Lines changed: 41 additions & 23 deletions

File tree

fresh-test/e2e-maclinux.sh

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,29 @@
11
#!/usr/bin/env bash
2-
# ─────────────────────────────────────────────────────────────────────────────
3-
# x402 AI Agent — macOS / Linux End-to-End Test (native CLI path)
2+
# ======================================================================
3+
# x402 AI Agent -- macOS / Linux End-to-End Test (native CLI path)
44
#
55
# Proves the documented macOS/Linux connect path actually works end-to-end:
66
# pay USDC on Base over HTTP 402 -> Sentinel provision -> connect via the
77
# native `sentinel-dvpncli` tool (the path /manifest.connectMacLinux prescribes).
88
#
99
# The Windows path is verified by e2e-selffund.mjs. This script is the missing
10-
# piece — run it ON a Mac or Linux host to turn "built" into "verified".
10+
# piece -- run it ON a Mac or Linux host to turn "built" into "verified".
1111
#
1212
# It self-funds: the payment phase reuses pay-phase.mjs which reads the operator
1313
# key from wallets.env and funds a throwaway agent, then runs the x402 402 flow.
1414
#
1515
# Prerequisites on the host:
16-
# - Node 20+ (for the payment phase) - Go 1.24+ (for sentinel-dvpncli)
17-
# - WireGuard (ships with macOS; `apt install wireguard` / `pacman -S wireguard-tools` on Linux)
16+
# - Node 20+ (for the payment phase) - Go 1.24+ (for sentinel-dvpncli)
17+
# - WireGuard tools (wg-quick): apt install wireguard-tools | brew install
18+
# wireguard-tools | pacman -S wireguard-tools. The CLI shells out to it.
1819
# - sudo available (WireGuard nodes bring the interface up as root)
19-
# - NOT Fedora (SELinux blocks VPN interfaces — documented limitation)
20+
# - NOT Fedora (SELinux blocks VPN interfaces -- documented limitation)
2021
#
2122
# Usage:
2223
# bash e2e-maclinux.sh # 1day tier, live server
2324
# TIER=7days bash e2e-maclinux.sh
2425
# SERVER_URL=http://localhost:4020 bash e2e-maclinux.sh
25-
# ─────────────────────────────────────────────────────────────────────────────
26+
# ======================================================================
2627
set -euo pipefail
2728

2829
SERVER_URL="${SERVER_URL:-https://x402.sentinel.co}"
@@ -35,17 +36,17 @@ line() { printf '%s\n' "========================================================
3536
say() { printf '%s\n' "$*"; }
3637

3738
line
38-
say " x402 AI AGENT — macOS/LINUX END-TO-END TEST"
39+
say " x402 AI AGENT -- macOS/LINUX END-TO-END TEST"
3940
say " Server: $SERVER_URL Tier: $TIER"
4041
line
4142

42-
# ─── STEP 0: environment ───
43+
# --- STEP 0: environment ---
4344
say ""
4445
say "--- STEP 0: ENVIRONMENT ---"
4546
uname_s="$(uname -s)"
4647
say " OS: $uname_s"
4748
if [ -f /etc/fedora-release ]; then
48-
say " [FAIL] Fedora detected — SELinux blocks VPN interfaces (documented as unsupported)."
49+
say " [FAIL] Fedora detected -- SELinux blocks VPN interfaces (documented as unsupported)."
4950
exit 2
5051
fi
5152
command -v node >/dev/null 2>&1 || { say " [FAIL] node not found (need Node 20+)"; exit 2; }
@@ -58,9 +59,18 @@ if ! command -v "$CLI" >/dev/null 2>&1; then
5859
exit 2
5960
fi
6061
say " cli: $($CLI version 2>/dev/null | head -1 || echo present)"
61-
command -v wg-quick >/dev/null 2>&1 || command -v wg >/dev/null 2>&1 || say " [WARN] WireGuard tools not found — tunnel bring-up may fail"
62+
# The CLI shells out to wg-quick (WireGuard nodes) or v2ray (V2Ray nodes) -- it
63+
# does NOT bundle a tunnel. Most nodes are WireGuard, so wg-quick is effectively
64+
# required; v2ray is a soft dependency only needed if a V2Ray node is selected.
65+
if command -v wg-quick >/dev/null 2>&1; then
66+
say " wg-quick: $(command -v wg-quick)"
67+
else
68+
say " [WARN] wg-quick not found -- WireGuard nodes will fail to connect."
69+
say " Install: apt install wireguard-tools | brew install wireguard-tools | pacman -S wireguard-tools"
70+
fi
71+
command -v v2ray >/dev/null 2>&1 && say " v2ray: $(command -v v2ray)" || say " [note] v2ray binary not on PATH -- only needed if a V2Ray node is selected."
6272

63-
# ─── STEP 1-4: pay + provision (cross-platform Node phase) ───
73+
# --- STEP 1-4: pay + provision (cross-platform Node phase) ---
6474
say ""
6575
say "--- STEP 1-4: PAY + PROVISION (x402) ---"
6676
# pay-phase.mjs self-funds and runs the 402 flow, then prints a JSON line:
@@ -88,7 +98,7 @@ NODE_ADDR="$(extract nodeAddress)"
8898
[ -z "$MNEMONIC" ] && { say " [FAIL] could not parse mnemonic from provision result"; exit 1; }
8999
say " Provisioned: sub=$SUB_ID node=$NODE_ADDR feeGranter=$FEE_GRANTER"
90100

91-
# ─── STEP 5: keys add (import the funded agent wallet) ───
101+
# --- STEP 5: keys add (import the funded agent wallet) ---
92102
say ""
93103
say "--- STEP 5: IMPORT WALLET (sentinel-dvpncli keys add) ---"
94104
# Remove any stale key of the same name first (idempotent re-runs).
@@ -97,7 +107,7 @@ say "--- STEP 5: IMPORT WALLET (sentinel-dvpncli keys add) ---"
97107
printf '%s\n\n' "$MNEMONIC" | "$CLI" keys add agent --keyring.backend test >/dev/null
98108
say " Imported agent key for $SENT_ADDR"
99109

100-
# ─── STEP 6: session-start (operator fee-grants the gas) ───
110+
# --- STEP 6: session-start (operator fee-grants the gas) ---
101111
say ""
102112
say "--- STEP 6: SESSION-START ---"
103113
"$CLI" tx session-start "$NODE_ADDR" \
@@ -107,7 +117,7 @@ say "--- STEP 6: SESSION-START ---"
107117
--keyring.backend test \
108118
--rpc.chain-id "$CHAIN_ID" \
109119
--output-format json >/dev/null
110-
say " session-start broadcast — resolving session id..."
120+
say " session-start broadcast -- resolving session id..."
111121

112122
# session-start doesn't print the id cleanly; query it back and take the newest.
113123
SESSION_ID=""
@@ -120,7 +130,7 @@ done
120130
[ -z "$SESSION_ID" ] && { say " [FAIL] could not resolve session id after session-start"; exit 1; }
121131
say " Session id: $SESSION_ID"
122132

123-
# ─── STEP 7: connect (build the tunnel) ───
133+
# --- STEP 7: connect (build the tunnel) ---
124134
say ""
125135
say "--- STEP 7: CONNECT ---"
126136
SUDO=""
@@ -133,7 +143,7 @@ sleep 20
133143
VPN_IP="$(curl -s --max-time 15 https://api.ipify.org || echo unknown)"
134144
say " Exit IP through tunnel: $VPN_IP"
135145

136-
# ─── STEP 8: teardown ───
146+
# --- STEP 8: teardown ---
137147
say ""
138148
say "--- STEP 8: DISCONNECT ---"
139149
kill "$CONNECT_PID" >/dev/null 2>&1 || true
@@ -145,14 +155,14 @@ kill "$CONNECT_PID" >/dev/null 2>&1 || true
145155
--output-format json >/dev/null 2>&1 || say " (session-cancel best-effort)"
146156
say " Session $SESSION_ID cancelled."
147157

148-
# ─── Report ───
158+
# --- Report ---
149159
say ""
150160
line
151161
if [ "$VPN_IP" != "unknown" ] && [ -n "$VPN_IP" ]; then
152-
say " RESULT: PASS — agent paid on Base and tunneled out via $VPN_IP (session $SESSION_ID)"
162+
say " RESULT: PASS -- agent paid on Base and tunneled out via $VPN_IP (session $SESSION_ID)"
153163
RC=0
154164
else
155-
say " RESULT: PARTIAL — paid + session started, but tunnel IP could not be verified"
165+
say " RESULT: PARTIAL -- paid + session started, but tunnel IP could not be verified"
156166
RC=1
157167
fi
158168
line

server/src/index.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -299,8 +299,9 @@ app.get('/manifest', (_req, res) => {
299299
description: 'Pay USDC, get a Sentinel dVPN subscription. One HTTP request, one EIP-3009 signature.',
300300
tldr: [
301301
'You need: (a) an EVM wallet with USDC on Base, (b) a Sentinel wallet from `createWallet()` in `blue-js-sdk/ai-path`.',
302+
'Install (agent side only — you do NOT clone this repo): `npm install @x402/fetch @x402/evm viem blue-js-sdk`. That is the complete dependency set for paying and connecting. The express/@x402/express/dotenv packages are operator-only — ignore them.',
302303
`POST ${network === 'eip155:8453' ? 'https://x402.sentinel.co' : '/'}/vpn/connect/{1day|7days|30days} with { sentinelAddr } using @x402/fetch to auto-sign the 402. Tiers cost $0.033 / $0.233 / $1.00 USDC — pick the smallest that covers your need; $0.033 is enough to start. Add { country: "DE" } to get a node in a specific country (GET /nodes lists what is available). Payment is identical on every OS.`,
303-
'Connecting differs by OS. macOS & Linux (easiest): WireGuard ships with the OS — use the native CLI `sentinel-dvpncli` (go install github.com/sentinel-official/sentinel-dvpncli@latest), then import the key (`printf \'%s\\n\\n\' "$MNEMONIC" | sentinel-dvpncli keys add agent --keyring.backend test`), `tx session-start <nodeAddress> --subscription-id <id> --tx.fee-granter-addr <feeGranter> --tx.from-name agent --keyring.backend test`, resolve the id with `query sessions --account-addr <sent1...> --subscription-id <id> --output-format json`, then `connect <sessionId>`. See sentinel.connectMacLinux. Only Fedora is unsupported (SELinux blocks VPNs).',
304+
'Connecting differs by OS. macOS & Linux: use the native CLI `sentinel-dvpncli` (go install github.com/sentinel-official/sentinel-dvpncli@latest — needs Go 1.24+). The CLI shells out to the system tunnel binary, so install `wireguard-tools` (provides `wg-quick`; most nodes are WireGuard) and, for V2Ray nodes, a `v2ray` binary on PATH. Then import the key (`printf \'%s\\n\\n\' "$MNEMONIC" | sentinel-dvpncli keys add agent --keyring.backend test`), `tx session-start <nodeAddress> --subscription-id <id> --tx.fee-granter-addr <feeGranter> --tx.from-name agent --keyring.backend test`, resolve the id with `query sessions --account-addr <sent1...> --subscription-id <id> --output-format json`, then `connect <sessionId>` (sudo to bring the interface up). See sentinel.connectMacLinux. Only Fedora is unsupported (SELinux blocks VPNs).',
304305
'Windows (heavier): run `await setup()` from `blue-js-sdk/ai-path` first — it auto-downloads V2Ray (no admin) and installs WireGuard — then `connect({ mnemonic, subscriptionId, feeGranter, nodeAddress })`. See sentinel.connectWindows.',
305306
'Tunnel is up. You paid as little as $0.033 USDC (1day) up to $1.00 (30day), zero gas on Base, zero gas on Sentinel.',
306307
],
@@ -450,9 +451,15 @@ app.get('/manifest', (_req, res) => {
450451
{ step: 9, actor: 'agent', action: 'MsgStartSession (gas paid by operator via fee grant)' },
451452
{ step: 10, actor: 'agent', action: 'Direct WireGuard/V2Ray handshake with node — tunnel up' },
452453
],
454+
install: {
455+
npm: 'npm install @x402/fetch @x402/evm viem blue-js-sdk',
456+
note: 'Agent side only — you do NOT clone this repo. The four packages above are the complete set for paying + connecting on every OS. express / @x402/express / dotenv are operator-only; do not install them.',
457+
nativeMacLinux: 'The macOS/Linux connect path also needs, OUTSIDE npm: Go 1.24+ (to `go install` sentinel-dvpncli), wireguard-tools (provides `wg-quick`, for WireGuard nodes), and a `v2ray` binary on PATH (for V2Ray nodes). The Windows path needs none of these — setup() fetches them.',
458+
},
453459
packages: {
454460
payment: '@x402/fetch',
455461
scheme: '@x402/evm',
462+
evm: 'viem',
456463
sentinel: 'blue-js-sdk/ai-path',
457464
},
458465
example: {
@@ -517,11 +524,12 @@ app.get('/manifest', (_req, res) => {
517524
returns: { address: 'sent1... (use this as sentinelAddr)', mnemonic: 'string (persist this)' },
518525
note: 'Generate once per agent. The address goes in the request body; the mnemonic signs MsgStartSession.',
519526
},
520-
platforms: 'Payment is identical on every OS; only the connect step differs. macOS & Linux are the easiest path (native CLI, WireGuard ships with the OS — see connectMacLinux). Windows uses the heavier JS-SDK path (see connectWindows / connect). Only Fedora is unsupported: its SELinux blocks VPN interfaces and cannot be bypassed programmatically.',
527+
platforms: 'Payment is identical on every OS; only the connect step differs. macOS & Linux use the native CLI (sentinel-dvpncli + a system tunnel binary — see connectMacLinux). Windows uses the JS-SDK path where setup() fetches the tunnel binaries for you (see connectWindows / connect). Only Fedora is unsupported: its SELinux blocks VPN interfaces and cannot be bypassed programmatically.',
521528
connectMacLinux: {
522529
tool: 'sentinel-dvpncli',
523530
install: 'go install github.com/sentinel-official/sentinel-dvpncli@latest (Go 1.24+); binary lands in $(go env GOPATH)/bin',
524-
why: 'Easiest path — WireGuard ships with macOS and mainstream Linux, so nothing to install for the tunnel. Flag-driven, non-interactive.',
531+
nativeDeps: 'The CLI does NOT bundle a tunnel — it shells out. WireGuard nodes run `wg-quick up` (install wireguard-tools: `apt install wireguard-tools` / `brew install wireguard-tools` / `pacman -S wireguard-tools`). V2Ray nodes run `v2ray run --config` (install a `v2ray` binary on PATH). Most nodes are WireGuard; install wireguard-tools at minimum. Bringing the interface up needs sudo.',
532+
why: 'Flag-driven, non-interactive — good for agents. Trade-off vs Windows: you install the tunnel binary yourself (Windows setup() auto-fetches it).',
525533
steps: [
526534
'keys add: printf \'%s\\n\\n\' "$MNEMONIC" | sentinel-dvpncli keys add agent --keyring.backend test (import the SAME wallet whose sentinelAddr you sent to x402. keys add is INTERACTIVE — no --recover flag: line 1 answers the mnemonic prompt, the blank line 2 accepts the default empty BIP-39 passphrase. A single-line echo would hang on the passphrase prompt.)',
527535
'session-start: sentinel-dvpncli tx session-start <nodeAddress> --subscription-id <subscriptionId> --tx.fee-granter-addr <feeGranter> --tx.from-name agent --keyring.backend test --rpc.chain-id sentinelhub-2 --output-format json (operator fee-grants the gas)',

0 commit comments

Comments
 (0)