mirror of
https://github.com/profullstack/agentbbs.git
synced 2026-08-13 14:27:27 +00:00
chore: keep all agentbbs services on latest software (#69)
* 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>
This commit is contained in:
parent
d19c5c4c3e
commit
807ecf2530
4 changed files with 190 additions and 1 deletions
42
.github/dependabot.yml
vendored
Normal file
42
.github/dependabot.yml
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# Keep agentbbs's pinned dependencies current automatically. Dependabot opens
|
||||
# (review-gated) PRs when a newer version ships — nothing auto-merges, so a bad
|
||||
# bump can't silently reach production.
|
||||
#
|
||||
# Coverage:
|
||||
# - github-actions : the action pins in .github/workflows/* (checkout, setup-go…)
|
||||
# - gomod : Go module dependencies (go.mod / go.sum)
|
||||
# - docker : image tags in the Mailu compose stack and the pod Containerfile
|
||||
#
|
||||
# NOT covered (Dependabot can't watch shell-string pins): FORGEJO_VERSION and
|
||||
# ERGO_VERSION in setup.sh — bump those by hand, or switch to Renovate (which can
|
||||
# watch them via a custom regex manager). The Mailu *runtime* patch level is kept
|
||||
# current separately by .github/workflows/mailu-update.yml.
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
groups:
|
||||
github-actions:
|
||||
patterns: ["*"]
|
||||
|
||||
- package-ecosystem: gomod
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
groups:
|
||||
go-modules:
|
||||
patterns: ["*"]
|
||||
|
||||
# Mailu compose stack — bumps ghcr.io/mailu/* image tags.
|
||||
- package-ecosystem: docker
|
||||
directory: /deploy/mailu
|
||||
schedule:
|
||||
interval: weekly
|
||||
|
||||
# Pod base image (docker.io/library/ubuntu).
|
||||
- package-ecosystem: docker
|
||||
directory: /pods
|
||||
schedule:
|
||||
interval: weekly
|
||||
137
.github/workflows/mailu-update.yml
vendored
Normal file
137
.github/workflows/mailu-update.yml
vendored
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
name: mailu-update
|
||||
|
||||
# Keep the self-hosted Mailu stack on the latest patch of its pinned series.
|
||||
#
|
||||
# The Mailu compose stack (deploy/mailu) pins the FLOATING series tags
|
||||
# (ghcr.io/mailu/*:2024.06). Upstream ships frequent patch releases within that
|
||||
# series (2024.06.NN) with security fixes, but a running host only picks them up
|
||||
# when someone runs `docker compose pull`. Left alone, the box drifts behind.
|
||||
#
|
||||
# This workflow SSHes to the droplet on a weekly schedule (and on demand), backs
|
||||
# up the irreplaceable state (DKIM keys + admin DB), pulls the newest images for
|
||||
# the pinned series, recreates the containers, and health-checks the result.
|
||||
# It stays WITHIN the pinned series on purpose: crossing to a future series
|
||||
# (e.g. a 2025.xx) can carry DB migrations and config changes, so that is a
|
||||
# deliberate PR that edits the tags in deploy/mailu/*.yml — not an auto-pull.
|
||||
#
|
||||
# The agentbbs Go binary already redeploys on every push (deploy.yml) and the
|
||||
# rootless podman pods rebuild from upstream base images, so this workflow is the
|
||||
# missing piece: it covers the one long-lived docker-compose stack on the box.
|
||||
#
|
||||
# Reuses the same repo secrets as deploy.yml:
|
||||
# DEPLOY_SSH_KEY private key whose public half is in the droplet admin user's
|
||||
# authorized_keys
|
||||
# DEPLOY_HOST bbs.profullstack.com (or the droplet IP)
|
||||
# DEPLOY_USER admin SSH user (default: root)
|
||||
# DEPLOY_PORT admin SSH port (default: 2202)
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# 06:30 UTC every Monday. Off-peak; adjust as you like.
|
||||
- cron: '30 6 * * 1'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
prune:
|
||||
description: 'Prune dangling images after the update'
|
||||
type: boolean
|
||||
default: true
|
||||
|
||||
# Share deploy.yml's concurrency group so an image pull can never race a code
|
||||
# deploy on the same host — whichever starts first runs to completion, the other
|
||||
# queues behind it.
|
||||
concurrency:
|
||||
group: deploy-production
|
||||
cancel-in-progress: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
update:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Configure SSH
|
||||
env:
|
||||
DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
|
||||
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
|
||||
DEPLOY_PORT: ${{ secrets.DEPLOY_PORT || '2202' }}
|
||||
run: |
|
||||
test -n "$DEPLOY_SSH_KEY" || { echo "::error::DEPLOY_SSH_KEY secret is not set"; exit 1; }
|
||||
test -n "$DEPLOY_HOST" || { echo "::error::DEPLOY_HOST secret is not set"; exit 1; }
|
||||
install -d -m 700 ~/.ssh
|
||||
printf '%s\n' "$DEPLOY_SSH_KEY" > ~/.ssh/id_deploy
|
||||
chmod 600 ~/.ssh/id_deploy
|
||||
ssh-keyscan -p "$DEPLOY_PORT" -H "$DEPLOY_HOST" >> ~/.ssh/known_hosts 2>/dev/null
|
||||
|
||||
- name: Pull latest Mailu images, recreate, health-check
|
||||
env:
|
||||
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
|
||||
DEPLOY_USER: ${{ secrets.DEPLOY_USER || 'root' }}
|
||||
DEPLOY_PORT: ${{ secrets.DEPLOY_PORT || '2202' }}
|
||||
PRUNE: ${{ github.event_name == 'schedule' && 'true' || inputs.prune }}
|
||||
run: |
|
||||
ssh -i ~/.ssh/id_deploy -p "$DEPLOY_PORT" \
|
||||
-o BatchMode=yes -o StrictHostKeyChecking=yes \
|
||||
"${DEPLOY_USER}@${DEPLOY_HOST}" \
|
||||
"sudo -n env PRUNE=$(printf %q "$PRUNE") bash -s" <<'REMOTE'
|
||||
set -euo pipefail
|
||||
MAILU_DIR=/opt/agentbbs/deploy/mailu
|
||||
cd "$MAILU_DIR"
|
||||
|
||||
if [ ! -f mailu.env ]; then
|
||||
echo "::notice::mailu.env not present at ${MAILU_DIR} — stack not deployed, nothing to update"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "== images before =="
|
||||
docker compose images
|
||||
|
||||
# Back up the irreplaceable bits before touching anything: the DKIM
|
||||
# signing keys (data/dkim) and the admin database (data/data, sqlite).
|
||||
# Mailboxes (data/mail) are large and are NOT touched by an image pull,
|
||||
# so we deliberately skip them here — back those up separately.
|
||||
ts="$(date -u +%Y%m%dT%H%M%SZ)"
|
||||
install -d -m 700 backups
|
||||
tar czf "backups/mailu-state-${ts}.tgz" \
|
||||
$( [ -d data/dkim ] && echo data/dkim ) \
|
||||
$( [ -d data/data ] && echo data/data ) 2>/dev/null || true
|
||||
echo "::notice::backed up DKIM + admin DB to backups/mailu-state-${ts}.tgz"
|
||||
# Keep only the 10 most recent state backups.
|
||||
ls -1t backups/mailu-state-*.tgz 2>/dev/null | tail -n +11 | xargs -r rm -f
|
||||
|
||||
echo "== pulling latest patch for the pinned series =="
|
||||
docker compose pull
|
||||
|
||||
echo "== recreating containers =="
|
||||
docker compose up -d
|
||||
|
||||
# Give services a moment, then verify. Mailu's front serves HTTP on
|
||||
# 127.0.0.1:8080 (Caddy fronts it); a reachable webmail means the
|
||||
# stack came back up.
|
||||
ok=0
|
||||
code=""
|
||||
for i in $(seq 1 30); do
|
||||
code="$(curl -fsS -o /dev/null -w '%{http_code}' --max-time 5 http://127.0.0.1:8080/ || true)"
|
||||
case "$code" in
|
||||
2??|3??) ok=1; break ;;
|
||||
esac
|
||||
sleep 3
|
||||
done
|
||||
|
||||
echo "== compose status =="
|
||||
docker compose ps
|
||||
|
||||
if [ "$ok" != "1" ]; then
|
||||
echo "::error::Mailu front did not answer on 127.0.0.1:8080 after update — check 'docker compose logs' in ${MAILU_DIR}. Restore from backups/mailu-state-${ts}.tgz if needed."
|
||||
exit 1
|
||||
fi
|
||||
echo "::notice::Mailu front is answering (HTTP ${code}) after update"
|
||||
|
||||
echo "== images after =="
|
||||
docker compose images
|
||||
|
||||
if [ "${PRUNE:-false}" = "true" ]; then
|
||||
echo "== pruning dangling images =="
|
||||
docker image prune -f
|
||||
fi
|
||||
REMOTE
|
||||
|
|
@ -37,6 +37,16 @@ BIND_ADDRESS4=127.0.0.1
|
|||
SUBNET=192.168.203.0/24
|
||||
MESSAGE_SIZE_LIMIT=52428800 # 50 MB
|
||||
|
||||
# --- Addressing --------------------------------------------------------------
|
||||
# Plus-addressing (subaddressing): deliver mail sent to <name>+<tag>@ into the
|
||||
# <name>@ mailbox (keeping the +tag in the To: header for filtering) instead of
|
||||
# bouncing it as an unknown recipient. Required by qaaas.dev's packages/mail,
|
||||
# which mints throwaway addresses like chovy+run-42@bbs.profullstack.com off the
|
||||
# single chovy@ mailbox. NOTE: this affects DELIVERY only — it does NOT let
|
||||
# <name>+<tag>@ be used as a LOGIN (Mailu authenticates the exact address; log
|
||||
# into webmail as the base <name>@ and all +tagged mail is already there).
|
||||
RECIPIENT_DELIMITER=+
|
||||
|
||||
# --- Gateway (the BBS reads/sends on behalf of members) ----------------------
|
||||
# A Dovecot master user lets the agentbbs gateway open any member's mailbox with
|
||||
# one secret (login "<name>*<master>"). Created by deploy/mailu/provision-mailbox.sh.
|
||||
|
|
|
|||
2
setup.sh
2
setup.sh
|
|
@ -52,7 +52,7 @@ IRC_NETWORK="${IRC_NETWORK:-ProfullstackBBS}" # IRC network name shown to clien
|
|||
ERGO_DATA="${ERGO_DATA:-/var/lib/ergo}" # Ergo state dir (ircd.db, tls/)
|
||||
FORGEJO="${FORGEJO:-1}" # set 0 to skip the AgentGit Forgejo backend (git.${DOMAIN#*.})
|
||||
GIT_DOMAIN="${GIT_DOMAIN:-git.${DOMAIN#*.}}" # AgentGit host (default: git.<root-of-DOMAIN>, e.g. git.profullstack.com)
|
||||
FORGEJO_VERSION="${FORGEJO_VERSION:-11.0.1}" # Forgejo release to install
|
||||
FORGEJO_VERSION="${FORGEJO_VERSION:-11.0.15}" # Forgejo release to install (latest 11.0.x LTS patch)
|
||||
MAIL_STACK="${MAIL_STACK:-1}" # set 0 to skip the co-located Mailu mail stack (mail.${DOMAIN#*.}). NOT named MAIL: that is a reserved env var (the mail-spool path, e.g. /var/mail/root) which PAM sets under sudo, so a CI deploy inherited MAIL=/var/mail/root and silently dropped the mail Caddy route + §9e provisioning.
|
||||
MAIL_DOMAIN="${MAIL_DOMAIN:-mail.${DOMAIN#*.}}" # mail host (default: mail.<root-of-DOMAIN>, e.g. mail.profullstack.com)
|
||||
FORGEJO_HTTP_ADDR="${FORGEJO_HTTP_ADDR:-127.0.0.1:3000}" # Forgejo loopback HTTP (Caddy fronts it)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue