Skip to content

Commit 22f833f

Browse files
authored
docs: refresh the readme and cli help for invitations (#12)
1 parent 70ada90 commit 22f833f

2 files changed

Lines changed: 48 additions & 22 deletions

File tree

README.md

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,13 @@ traversal, and relay fallback.
3030

3131
Access is default deny and per peer. Each machine runs one long-lived daemon with
3232
a stable identity, a keypair. You grant a specific port to a specific peer's key,
33-
and that peer alone can reach it. A machine you have not met enrolls with a
34-
one-time token, so you can boot a fleet of untrusted workloads that phone home,
35-
each with exactly the access you granted and none aware of its siblings.
33+
and that peer alone can reach it. A machine you have not met gets in with a
34+
one-time invitation, so you can boot a fleet of untrusted workloads that phone
35+
home, each with exactly the access you granted and none aware of its siblings.
36+
37+
Two machines link by invitation. One extends it, the other takes it up, and
38+
neither is complete alone. It works the same whether you are booting a workload
39+
that dials home or connecting two laptops that already exist.
3640

3741
The peers you can reach live on a private network the daemon runs for you. Each
3842
one gets its own address on that network and a name to match, so you reach its
@@ -84,9 +88,12 @@ Spin up something new on the VM and expose it live:
8488

8589
```sh
8690
http-nu :3002 -c '{|req| "hello from a new experiment"}'
87-
pai-sho expose 3002 --to <laptop-key>
91+
pai-sho expose 3002 --all
8892
```
8993

94+
`--all` means every peer this VM knows right now, which is my laptop and nothing
95+
else. It is not a standing rule: a peer admitted later gets nothing.
96+
9097
`vibenv-ndyg` is already on my network, so `3002` binds under it too, reachable at
9198
`http://vibenv-ndyg.pai-sho:3002` right away. Done with it? `pai-sho unexpose 3002`.
9299

@@ -180,7 +187,7 @@ pai-sho [--socket <path>] <command>
180187

181188
```
182189
daemon [options] Start the daemon
183-
key Print this daemon's key
190+
key Print this daemon's key (hand this to a peer)
184191
invite [<key>] [--as <n>] [--expose <port>...]
185192
Extend an invitation. With a key, to that key alone
186193
(host-attested, no secret). Without one, print a
@@ -195,6 +202,8 @@ unproject <peer> Take a peer's surface down (unbind its ports)
195202
list Peers, grants, and where their ports are bound (JSON)
196203
```
197204

205+
`--socket` is global, not specific to `daemon`.
206+
198207
### Daemon Options
199208

200209
| Option | Default | Description |
@@ -203,7 +212,6 @@ list Peers, grants, and where their ports are bound (JSON)
203212
| `-a, --accept` | | Take up an invitation, or a peer's key, on startup (repeatable) |
204213
| `-e, --expose` | | Expose port to the `--accept` peers (repeat or comma-separate) |
205214
| `--key` | `~/.local/state/pai-sho/key` | Secret key path (created if missing) |
206-
| `--socket` | `/tmp/pai-sho.sock` | Unix socket path |
207215
| `--tun` | | Put surfaces on a private TUN network (`utun` on macOS, a pre-created device like `ps0` on Linux); the resolver answers in-stack on `10.99.0.53:53` |
208216
| `--resolver` | | Loopback mode, an alternative to `--tun`: serve the `*.pai-sho` resolver on this UDP address (e.g. `127.0.0.1:5353`) |
209217

@@ -229,7 +237,8 @@ who to dial, and the proof you may. When you already know a peer's key,
229237

230238
**Forwarding.** Each peer hears only the ports granted to it, and traffic runs
231239
over the encrypted QUIC connection. It goes both ways: something on your own
232-
`:4001` becomes reachable on a peer with `pai-sho expose 4001 --to <key>`.
240+
`:4001` becomes reachable on a peer with `pai-sho expose 4001 --to <key>`, where
241+
the key comes from `pai-sho key` on the machine you are granting to.
233242

234243
**The network.** With `--tun`, the daemon runs its own TCP/IP stack on a private
235244
network interface. The daemon sits at `10.99.0.1`, peers get addresses on
@@ -238,9 +247,9 @@ interface is created ahead of time and owned by the daemon's user, so the daemon
238247
needs no elevated capability. On macOS the daemon creates a utun itself, which
239248
needs root.
240249

241-
**Surfaces.** A peer's ports are addressed together at one address, named after
242-
its enrollment label. A peer is projected automatically the first time it
243-
announces a granted port. Because each peer owns its address, two peers can serve
250+
**Surfaces.** A peer's ports are addressed together at one address, under the
251+
name you gave it, or a short form of its key if nothing named it. A peer is
252+
projected automatically the first time it announces a granted port. Because each peer owns its address, two peers can serve
244253
the same port without colliding. `project` overrides the automatic choice (pin an
245254
address with `--ip`, rename with `--as`), `unproject` takes a surface down, and
246255
projections survive a restart ([ADR 0004](docs/adr/0004-peer-surfaces.md)).
@@ -274,4 +283,14 @@ which keeps it easy to reason about exactly what is reachable.
274283
[pigeons](https://pigeons.computer), SSH over iroh from the same team, is where
275284
pai-sho's connection handling comes from.
276285

286+
## More
287+
288+
[docs/scenarios.md](docs/scenarios.md) works two flows end to end: a shared build
289+
box reached from a laptop, and a laptop booting a vibenv. Each says what has to
290+
be true, what travels between the machines, and why the commands are shaped the
291+
way they are.
292+
293+
The [ADRs](docs/adr) record the decisions: directed grants, invitations,
294+
host-attested enrollment, peer surfaces, and the owned resolver.
295+
277296
Questions or ideas: come by the [Discord](https://discord.com/invite/YNbScHBHrh).

src/main.rs

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@ mod tunnel;
1919
#[derive(Parser)]
2020
#[clap(
2121
name = "pai-sho",
22-
about = "What happens when you want dumbpipe to stay running, handle a few ports at once, and reconnect when your laptop wakes up",
22+
about = "Reach a machine's ports from your laptop, each under its own name",
23+
long_about = "Spin up a box in the middle of nowhere, with no way in. Drop one \
24+
binary on it. No open ports, no public IP: it dials home and punches through. \
25+
Reach your boxes from your laptop, each under its own name like \
26+
vibenv-ndyg.pai-sho.\n\n\
27+
Access is default deny and per peer. You grant a specific port to a specific \
28+
peer's key, and that peer alone can reach it.",
2329
version
2430
)]
2531
struct Cli {
@@ -70,11 +76,11 @@ pub enum Command {
7076
name: Option<String>,
7177
},
7278

73-
/// Extend an invitation. With a key, to that key alone. Without one,
74-
/// prints a one-time invitation valid for 5 minutes.
79+
/// Extend an invitation. Without a key, prints a one-time invitation valid
80+
/// 5 minutes. With one, authorizes that key alone and creates no secret.
7581
Invite {
76-
/// Peer's key, when you already know it and nothing secret can travel
77-
/// to it. See docs/adr/0003-host-attested-enrollment.md
82+
/// Peer's key, for when nothing secret can safely travel to it.
83+
/// See docs/adr/0003-host-attested-enrollment.md
7884
key: Option<String>,
7985
/// What to call the peer that takes this up
8086
#[arg(long = "as")]
@@ -84,7 +90,7 @@ pub enum Command {
8490
expose: Vec<u16>,
8591
},
8692

87-
/// Take up an invitation, or reach a peer you know by key
93+
/// Take up an invitation, or reach a peer you already know by key
8894
Accept {
8995
/// An invitation, or a bare key
9096
handle: String,
@@ -99,7 +105,7 @@ pub enum Command {
99105
peer: String,
100106
},
101107

102-
/// Expose a port to specific peers (a directed grant)
108+
/// Grant a local port to named peers. Nothing is reachable without one.
103109
#[command(group = ArgGroup::new("grantees").required(true).args(["to", "all"]))]
104110
Expose {
105111
port: u16,
@@ -112,7 +118,7 @@ pub enum Command {
112118
all: bool,
113119
},
114120

115-
/// Revoke grants for a port
121+
/// Revoke grants for a port. Bare, it revokes every grant for that port.
116122
Unexpose {
117123
port: u16,
118124
/// Revoke only this peer's grant; defaults to every grant for the port
@@ -126,22 +132,23 @@ pub enum Command {
126132
/// Print this daemon's key
127133
Key,
128134

129-
/// Project a peer's surface to a local address so its ports are reachable.
135+
/// Override where a peer's ports are bound. Peers are projected
136+
/// automatically, so this is only needed to pin an address or rename one.
130137
/// See docs/adr/0004-peer-surfaces.md.
131138
Project {
132-
/// Peer to project (an endpoint key or an enrollment label)
139+
/// Peer to project (a key or the name you gave it)
133140
peer: String,
134141
/// Local address to bind at; allocated from 127.0.1.0/24 if omitted
135142
#[arg(long)]
136143
ip: Option<IpAddr>,
137-
/// DNS handle to add in /etc/hosts (e.g. `broker`)
144+
/// Rename this peer's surface (e.g. `broker`)
138145
#[arg(long = "as")]
139146
name: Option<String>,
140147
},
141148

142149
/// Take a peer's surface down: unbind its ports, drop its address and name
143150
Unproject {
144-
/// Peer to unproject (an endpoint key or an enrollment label)
151+
/// Peer to unproject (a key or the name you gave it)
145152
peer: String,
146153
},
147154
}

0 commit comments

Comments
 (0)