* ci: add mailu-update workflow to keep the mail stack current
The deploy/mailu compose stack pins the floating series tags
(ghcr.io/mailu/*:2024.06); patch releases within the series only land when
someone runs `docker compose pull`, so the box drifts behind on security fixes.
Add a scheduled (weekly) + on-demand workflow that SSHes to the droplet
(reusing deploy.yml's DEPLOY_* secrets), backs up DKIM keys + the admin DB,
pulls the latest images for the pinned series, recreates the containers, and
health-checks the Mailu front on 127.0.0.1:8080. Shares deploy.yml's
concurrency group so it never races a code deploy. Stays within the pinned
series on purpose — crossing to a future series stays a deliberate PR.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore: bump Forgejo to 11.0.15 + add Dependabot to keep deps current
Audit of every version pin in the repo: Ergo (2.18.0), Go (1.26 → latest
patch via setup-go), the Ubuntu pod base (24.04 LTS), and the GitHub Action
majors are all already current. Only Forgejo was stale — bump 11.0.1 →
11.0.15 (latest patch of the 11.x LTS line; a 15.x major stays a deliberate,
tested upgrade because of DB migrations).
Add .github/dependabot.yml so github-actions, Go modules, and the Docker
image tags (Mailu compose + pod Containerfile) get review-gated update PRs
weekly. Shell-string pins (FORGEJO_VERSION/ERGO_VERSION in setup.sh) can't be
watched by Dependabot; noted inline. Mailu runtime patch level is handled by
the mailu-update workflow.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* mailu: document RECIPIENT_DELIMITER=+ in mailu.env.example
Plus-addressing (chovy+tag@ -> chovy@) is a hard prerequisite for qaaas.dev's
packages/mail but was missing from the example, so tagged mail bounces as an
unknown recipient until an operator sets it by hand. Add it with a note that it
governs DELIVERY only, not login (Mailu auths the exact address; base <name>@
is the single login and already receives all +tagged mail).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
The deploy SSHed into the ~458MB droplet and ran `go build` there. The Go
linker's peak memory OOM-killed the build — and with it the sshd serving the
deploy session — surfacing as "Connection closed by remote host" (exit 255).
It was flaky because it tracked momentary memory pressure from the co-resident
ergo/forgejo/tor/podman/agentbbs processes (run #25 passed, #26 failed on
near-identical code).
Build both binaries on the 16GB GitHub runner instead (pure-Go, modernc
sqlite, so CGO_ENABLED=0 static cross-build), scp them to the droplet, and run
setup.sh with SKIP_BUILD=1 so the box never compiles. Arch is detected from
the droplet so amd64/arm64 both work. setup.sh now also skips the Go toolchain
download when SKIP_BUILD=1.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* Add .github/workflows/test.yml via sh1pt node-pnpm-test@1.1.0
* Convert test workflow to Go (go test ./...)
agentbbs is a Go project (go.mod, go 1.26); the Node/pnpm workflow could
never pass here — pnpm/action-setup found no packageManager. Replace with
go test ./... and trigger on main (was master-only). Build/vet live in ci.yml.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: sh1pt-actions-fleet[bot] <287014002+sh1pt-actions-fleet[bot]@users.noreply.github.com>
Co-authored-by: Anthony Ettinger <anthony@profullstack.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* Add .github/workflows/ci.yml via sh1pt node-pnpm-ci@1.1.0
* Convert CI workflow to Go (build + vet)
agentbbs is a Go project (go.mod, go 1.26); the Node/pnpm workflow could
never pass here — pnpm/action-setup found no packageManager. Replace with
go build + go vet. Companion test.yml runs go test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: sh1pt-actions-fleet[bot] <287014002+sh1pt-actions-fleet[bot]@users.noreply.github.com>
Co-authored-by: Anthony Ettinger <anthony@profullstack.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
- payments: AGENTBBS_COINPAY_MERCHANT_ID -> --business-id on the premium
create/pay commands (coinpay CLI reads COINPAY_API_KEY from env for auth).
- deploy.yml: forward COINPAY_API_KEY + COINPAY_MERCHANT_ID (GitHub secrets,
masked in logs) to the remote setup.sh.
- setup.sh: idempotent upsert_env writes those secrets into agentbbs.env
(COINPAY_API_KEY, AGENTBBS_COINPAY_MERCHANT_ID, COINPAY_BUSINESS_ID),
preserving the rest. No secret values are committed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Deploy automation (idempotent, runs on every deploy):
- .github/workflows/deploy.yml: push to main/master (or dispatch) SSHes to the
droplet and re-runs setup.sh; deploys the pushed branch; smoke-tests :22.
- scripts/self-update.sh + agentbbs-update.timer: autonomous backstop that
redeploys only when origin advances.
- setup.sh hardened: flock, fetch+reset (survives force-push), fixed the
always-skipped arcade asset fetch path.
Membership model:
- Free, email-verified members get their own Docker pod (pod@ paywall removed)
and a /~name homepage (seeded at join@).
- join@ is now interactive: email -> emailed 6-digit code -> enter code.
- Premium ($10 one-time, lifetime via CoinPay) grants a personal
<name>@host email (new internal/forwardemail; forwardemail.net aliases) and
custom domains (domain@ gated to Premium).
- ensurePremium() silently verifies/grants/provisions on hub login, join@, and
domain@. New-signup details emailed to AGENTBBS_SIGNUP_NOTIFY (subject "bbs").
Store: User.Premium + premium/premium_ref cols, ConfirmEmailCode, GrantPremium.
Tests: store_premium_test.go, forwardemail_test.go. Build/vet/gofmt/test green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>