Skip to content

feat(gopher): serve BBS content over Gopher + SSH-authenticated "hedgehog"#83

Merged
ralyodio merged 1 commit into
mainfrom
feat/gopher-hedgehog
Jul 7, 2026
Merged

feat(gopher): serve BBS content over Gopher + SSH-authenticated "hedgehog"#83
ralyodio merged 1 commit into
mainfrom
feat/gopher-hedgehog

Conversation

@ralyodio

@ralyodio ralyodio commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Adds Gopher as a co-located AgentBBS protocol service, following the internal/news pattern.

Why two surfaces (gopher and hedgehog)

Classic Gopher (RFC 1436) is a stateless, unauthenticated, one-shot TCP protocol on port 70 — it has no auth verb, so SSH-key auth can't be bolted onto a port-70 server. So this mirrors AgentBBS's existing dual-surface pattern:

  • Public Gopher on :70 (RFC 1436) — open content for any gopher client (lynx, Lagrange, Bombadillo).
  • ssh gopher@ = "hedgehog" — the same gopher wire semantics carried over the authenticated SSH channel (the member's key is the credential), so it additionally reaches members-only selectors. Gopher where gopher can, our own gopher-like thing over SSH where it can't.

Both surfaces share one read-only Resolve engine (internal/gopher/server.go); the only difference is an authed flag.

What it serves

Member directory + homepages (/~namepublic_html), an About page (brand + MOTD), public newsgroups (allowlisted on :70, all groups on hedgehog), and members' public files (/files/~name/public). Selectors are confined to each member's area (path-traversal guarded).

Changes

  • New internal/gopher/ package: RFC-1436 primitives + Menu, the Resolve selector engine, the :70 listener, and the hedgehog Bubble Tea browser TUI. Plus tests (wire-format, selector resolution, traversal guard, public-vs-authed news filtering).
  • Wiring: auth.GopherNames/IsGopherName (+ reserved), app.gopher field, process wiring, router case, handleGopher in cmd/agentbbs/main.go.
  • New AGENTBBS_GOPHER* env vars; docs/gopher.md + README updates (incl. the setcap cap_net_bind_service note for binding privileged :70).

Verification

go build ./... + go vet clean; tests pass. Ran live on a high port: public surface returns valid RFC-1436 menus for root/about/members/files/homepage-dir/file/binary, blocks traversal (/~alice/../../secret.txt3not found), type-3 errors for unknown selectors. Over SSH: non-member key rejected with the members-only hint; a registered member launches the hedgehog TUI cleanly (session recorded as app gopher).

🤖 Generated with Claude Code

…ehog"

Add Gopher (RFC 1436) as a co-located protocol service, following the
internal/news pattern. Two surfaces share one read-only Resolve engine:

  - Public Gopher on :70 (RFC 1436) for any gopher client (lynx, Lagrange).
    Classic gopher is stateless with no auth verb, so this surface serves
    only public content.
  - `ssh gopher@` = "hedgehog": the same gopher wire semantics carried over
    the authenticated SSH channel (the member's key is the credential), so it
    additionally reaches members-only selectors. Gopher where gopher can,
    our own gopher-like thing over SSH where it can't.

Menus surface the member directory + homepages (public_html), an About page
(brand + MOTD), public newsgroups (allowlisted on :70, all groups on
hedgehog), and members' public files. Selectors are confined to each member's
area (path-traversal guarded). New AGENTBBS_GOPHER* env vars; docs/gopher.md
and README updated (incl. the setcap note for binding privileged :70).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

vu1nz Security Review

0 finding(s) in PR #?

No security issues found.

@ralyodio ralyodio merged commit ad76e7f into main Jul 7, 2026
5 checks passed
@ralyodio ralyodio deleted the feat/gopher-hedgehog branch July 7, 2026 12:39
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