wire AgentGit provisioning into verify flow + setup.sh

The internal/forgejo package landed without its call sites. Restore them:
- main.go: provisionGit() called after both email-verify paths (web link +
  interactive code), the forgejo.Config app field, and ConfigFromEnv wiring.
  Every verified member (free + paid) gets a git.profullstack.com account;
  failures are logged, never block verification; no-op when unconfigured.
- setup.sh §9d: install + run the Forgejo backend on a loopback port fronted
  by Caddy at https://git.<root>, members-only, with an admin token minted
  into agentbbs.env. Caddy vhost + done-banner + env template entries.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Anthony Ettinger 2026-06-14 14:38:51 +00:00
parent 7a9e0751b4
commit 5d56e021cc
2 changed files with 179 additions and 1 deletions

View file

@ -53,6 +53,7 @@ import (
"github.com/profullstack/agentbbs/internal/auth"
"github.com/profullstack/agentbbs/internal/calls"
"github.com/profullstack/agentbbs/internal/chat"
"github.com/profullstack/agentbbs/internal/forgejo"
"github.com/profullstack/agentbbs/internal/forwardemail"
"github.com/profullstack/agentbbs/internal/games"
"github.com/profullstack/agentbbs/internal/hub"
@ -97,6 +98,7 @@ type app struct {
sandbox *sandbox.Runner
mail mail.Config
fe forwardemail.Config // premium @bbs email provisioning
forgejo forgejo.Config // AgentGit git.profullstack.com account provisioning
live *liveReg // in-memory live-session registry (admin console)
gamesReg *games.Registry // AgentGames catalog
mm *games.Matchmaker // AgentGames matchmaker (agent-vs-agent)
@ -155,6 +157,7 @@ func main() {
sandbox: sandbox.New(sandbox.Mode(env("AGENTBBS_SANDBOX", "auto"))),
mail: mail.ConfigFromEnv(),
fe: fe,
forgejo: forgejo.ConfigFromEnv(),
live: newLiveReg(),
dataDir: dataDir,
assets: env("AGENTBBS_ASSETS", "./assets"),
@ -576,6 +579,7 @@ func (a *app) verifyEmailInteractive(s ssh.Session, in *bufio.Reader, u *store.U
}
if ok {
*u = vu
a.provisionGit(u)
wish.Println(s, " Email confirmed ✓")
return true
}
@ -754,10 +758,30 @@ func (a *app) handleVerify(w http.ResponseWriter, r *http.Request) {
"Run <code>ssh join@"+a.host+"</code> to get a fresh confirmation link.")))
return
}
a.provisionGit(&u)
_, _ = w.Write([]byte(verifyPage("Email confirmed ✓",
"Welcome, "+u.Name+". Your account is active — <code>ssh "+u.Name+"@"+a.host+"</code>.")))
}
// provisionGit ensures a verified member has a git.profullstack.com account on
// the AgentGit Forgejo backend. Every verified member gets one — free and paid
// alike; plan only affects quotas, enforced by AgentGit, not account existence.
// Failures are logged but never block BBS verification, and it is a no-op when
// Forgejo is unconfigured.
func (a *app) provisionGit(u *store.User) {
if u == nil || !a.forgejo.Configured() || u.Name == "" || u.Email == "" {
return
}
created, err := a.forgejo.EnsureUser(u.Name, u.Email)
if err != nil {
log.Error("forgejo provision", "user", u.Name, "err", err)
return
}
if created {
log.Info("provisioned git account", "user", u.Name, "host", a.forgejo.BaseURL)
}
}
// verifyPage renders the minimal confirmation result page.
func verifyPage(title, body string) string {
return "<!doctype html><meta charset=utf-8><title>" + title + "</title>" +