Run byre and the app on their own embedded Tailscale nodes

This commit is contained in:
Ian Gulliver
2026-10-20 13:32:56 -07:00
parent a7b2333535
commit 2dfcc5de47
29 changed files with 1602 additions and 602 deletions
+37 -15
View File
@@ -6,7 +6,6 @@ import (
"errors"
"fmt"
"log/slog"
"net"
"net/http"
"os"
"path/filepath"
@@ -22,6 +21,8 @@ import (
"g.fc.run/ai/byre/internal/terminal"
"g.fc.run/ai/byre/internal/todo"
"g.fc.run/ai/byre/internal/workflow"
"tailscale.com/client/local"
"tailscale.com/tsnet"
)
type Server struct {
@@ -30,6 +31,8 @@ type Server struct {
hub *hub
clients *clients.Registry
terminals *terminal.Terminals
tailnet *local.Client
hostname string
startedAt time.Time
usersMu sync.Mutex
@@ -38,7 +41,7 @@ type Server struct {
type ctxKey struct{}
func New(dataDir string, portFirst int) (*Server, error) {
func New(dataDir string, portFirst int, ts *tsnet.Server) (*Server, error) {
err := os.MkdirAll(dataDir, 0o755)
if err != nil {
return nil, err
@@ -48,9 +51,15 @@ func New(dataDir string, portFirst int) (*Server, error) {
if err != nil {
return nil, err
}
lc, err := ts.LocalClient()
if err != nil {
return nil, err
}
s := &Server{
hub: newHub(),
terminals: terminals,
tailnet: lc,
hostname: ts.Hostname,
startedAt: time.Now().UTC(),
users: map[string]string{},
}
@@ -73,7 +82,7 @@ func New(dataDir string, portFirst int) (*Server, error) {
}
}
s.agents = agents.New(s.store, filepath.Join(dataDir, "worktrees"), filepath.Join(dataDir, "leads"), filepath.Join(dataDir, "hands"), filepath.Join(dataDir, "codex"), filepath.Join(dataDir, "antigravity"), s.status, s.createProject, s.clients, s.terminals)
s.agents = agents.New(s.store, filepath.Join(dataDir, "worktrees"), filepath.Join(dataDir, "leads"), filepath.Join(dataDir, "hands"), filepath.Join(dataDir, "codex"), filepath.Join(dataDir, "antigravity"), s.status, s.createProject, s.clients, s.terminals, ts)
err = s.agents.Recover(context.Background())
if err != nil {
s.store.Close()
@@ -115,26 +124,39 @@ func (s *Server) Handler() http.Handler {
return mux
}
func (s *Server) LoopbackHandler() http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("GET /api/tailnet", s.GetTailnet)
return mux
}
func (s *Server) GetTailnet(w http.ResponseWriter, r *http.Request) {
st, err := s.tailnet.StatusWithoutPeers(r.Context())
if err != nil {
writeError(w, http.StatusInternalServerError, err)
return
}
origin := ""
if len(st.CertDomains) > 0 {
origin = "https://" + st.CertDomains[0]
}
writeJSON(w, http.StatusOK, api.Tailnet{State: st.BackendState, AuthUrl: st.AuthURL, Hostname: s.hostname, Origin: origin})
}
func (s *Server) identify(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
host, _, err := net.SplitHostPort(r.RemoteAddr)
who, err := s.tailnet.WhoIs(r.Context(), r.RemoteAddr)
if err != nil {
writeError(w, http.StatusForbidden, err)
writeError(w, http.StatusUnauthorized, fmt.Errorf("identify %s on the tailnet: %w", r.RemoteAddr, err))
return
}
ip := net.ParseIP(host)
if ip == nil || !ip.IsLoopback() {
writeError(w, http.StatusForbidden, fmt.Errorf("request from %s did not arrive via tailscale serve", host))
return
}
login := r.Header.Get("Tailscale-User-Login")
name := r.Header.Get("Tailscale-User-Name")
if login == "" || name == "" {
writeError(w, http.StatusUnauthorized, errors.New("missing Tailscale-User-Login or Tailscale-User-Name"))
if who.Node.IsTagged() {
writeError(w, http.StatusForbidden, fmt.Errorf("%s is a tagged node, not a user's", who.Node.Name))
return
}
login := who.UserProfile.LoginName
name := who.UserProfile.DisplayName
err = s.ensureUser(r.Context(), login, name)
if err != nil {
writeError(w, http.StatusInternalServerError, err)