feat(packaging): add Debian packaging and APT repository scripts
debian/DEBIAN/control: package metadata, depends on python3.11+, postgresql-client debian/DEBIAN/postinst: creates activeblue-ai system user, installs venv, enables service debian/DEBIAN/prerm: stops and disables service before removal debian/DEBIAN/postrm: purge removes config, logs, venv, and system user debian/lib/systemd/system/activeblue-ai.service: - Runs as dedicated user with PrivateTmp + ProtectSystem hardening - EnvironmentFile=/etc/activeblue-ai/.env - Restart=on-failure with 5s backoff debian/usr/bin/activeblue-ai: CLI with start/stop/restart/status/logs/migrate/health/sweep/privacy/version build_deb.sh: builds activeblue-ai_X.Y.Z_all.deb in dist/ publish_repo.sh: scans packages, generates Release + checksums, optional GPG signing Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
15
debian/DEBIAN/control
vendored
Normal file
15
debian/DEBIAN/control
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
Package: activeblue-ai
|
||||
Version: 0.1.0
|
||||
Section: misc
|
||||
Priority: optional
|
||||
Architecture: all
|
||||
Depends: python3 (>= 3.11), python3-pip, python3-venv, postgresql-client
|
||||
Maintainer: ActiveBlue <admin@activeblue.net>
|
||||
Homepage: https://activeblue.net
|
||||
Description: ActiveBlue AI Agent Service
|
||||
Multi-agent AI system integrated with Odoo 18 Community.
|
||||
Provides a FastAPI service with 8 specialist AI agents for finance,
|
||||
accounting, CRM, sales, project management, eLearning, expenses, and HR.
|
||||
.
|
||||
Supports local (Ollama), hybrid, and cloud (Claude) LLM backends.
|
||||
HIPAA-sensitive agents are enforced to use local LLM only.
|
||||
47
debian/DEBIAN/postinst
vendored
Normal file
47
debian/DEBIAN/postinst
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
SERVICE_DIR="/usr/lib/activeblue-ai"
|
||||
VENV_DIR="$SERVICE_DIR/venv"
|
||||
CONFIG_DIR="/etc/activeblue-ai"
|
||||
LOG_DIR="/var/log/activeblue-ai"
|
||||
DATA_DIR="/var/lib/activeblue-ai"
|
||||
SERVICE_USER="activeblue-ai"
|
||||
|
||||
# Create service user
|
||||
if ! id "$SERVICE_USER" &>/dev/null; then
|
||||
adduser --system --no-create-home --group --disabled-login \
|
||||
--home "$DATA_DIR" "$SERVICE_USER"
|
||||
echo "Created service user: $SERVICE_USER"
|
||||
fi
|
||||
|
||||
# Create directories
|
||||
install -d -m 755 -o "$SERVICE_USER" -g "$SERVICE_USER" "$LOG_DIR"
|
||||
install -d -m 755 -o "$SERVICE_USER" -g "$SERVICE_USER" "$DATA_DIR"
|
||||
install -d -m 750 -o "$SERVICE_USER" -g "$SERVICE_USER" "$CONFIG_DIR"
|
||||
|
||||
# Create .env if it doesn't exist
|
||||
if [ ! -f "$CONFIG_DIR/.env" ]; then
|
||||
cp "$CONFIG_DIR/.env.example" "$CONFIG_DIR/.env" 2>/dev/null || true
|
||||
chmod 640 "$CONFIG_DIR/.env"
|
||||
chown "$SERVICE_USER:$SERVICE_USER" "$CONFIG_DIR/.env"
|
||||
echo "NOTE: Edit $CONFIG_DIR/.env before starting the service."
|
||||
fi
|
||||
|
||||
# Create and populate virtualenv
|
||||
if [ ! -d "$VENV_DIR" ]; then
|
||||
python3 -m venv "$VENV_DIR"
|
||||
fi
|
||||
"$VENV_DIR/bin/pip" install --quiet --upgrade pip
|
||||
"$VENV_DIR/bin/pip" install --quiet -r "$SERVICE_DIR/requirements.txt"
|
||||
|
||||
# Enable and reload systemd
|
||||
if command -v systemctl &>/dev/null && systemctl is-system-running --quiet 2>/dev/null; then
|
||||
systemctl daemon-reload
|
||||
systemctl enable activeblue-ai.service
|
||||
echo "Service enabled. Run: systemctl start activeblue-ai"
|
||||
fi
|
||||
|
||||
echo "ActiveBlue AI installed successfully."
|
||||
echo "Configure: $CONFIG_DIR/.env"
|
||||
echo "Run migrations: activeblue-ai migrate"
|
||||
12
debian/DEBIAN/postrm
vendored
Normal file
12
debian/DEBIAN/postrm
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
if [ "$1" = "purge" ]; then
|
||||
rm -rf /usr/lib/activeblue-ai/venv
|
||||
rm -rf /var/log/activeblue-ai
|
||||
rm -rf /etc/activeblue-ai
|
||||
if id activeblue-ai &>/dev/null; then
|
||||
deluser --system activeblue-ai || true
|
||||
fi
|
||||
echo "ActiveBlue AI purged."
|
||||
fi
|
||||
16
debian/DEBIAN/prerm
vendored
Normal file
16
debian/DEBIAN/prerm
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
if command -v systemctl &>/dev/null; then
|
||||
if systemctl is-active --quiet activeblue-ai.service 2>/dev/null; then
|
||||
systemctl stop activeblue-ai.service || true
|
||||
fi
|
||||
if systemctl is-enabled --quiet activeblue-ai.service 2>/dev/null; then
|
||||
systemctl disable activeblue-ai.service || true
|
||||
fi
|
||||
systemctl daemon-reload || true
|
||||
fi
|
||||
|
||||
echo "ActiveBlue AI service stopped."
|
||||
echo "Configuration preserved in /etc/activeblue-ai/"
|
||||
echo "Data preserved in /var/lib/activeblue-ai/"
|
||||
35
debian/lib/systemd/system/activeblue-ai.service
vendored
Normal file
35
debian/lib/systemd/system/activeblue-ai.service
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
[Unit]
|
||||
Description=ActiveBlue AI Agent Service
|
||||
Documentation=https://activeblue.net
|
||||
After=network.target postgresql.service
|
||||
Wants=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=activeblue-ai
|
||||
Group=activeblue-ai
|
||||
WorkingDirectory=/usr/lib/activeblue-ai
|
||||
EnvironmentFile=/etc/activeblue-ai/.env
|
||||
ExecStart=/usr/lib/activeblue-ai/venv/bin/uvicorn \
|
||||
agent_service.main:app \
|
||||
--host 0.0.0.0 \
|
||||
--port 8001 \
|
||||
--workers 1 \
|
||||
--no-access-log
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
SyslogIdentifier=activeblue-ai
|
||||
NoNewPrivileges=yes
|
||||
PrivateTmp=yes
|
||||
ProtectSystem=strict
|
||||
ReadWritePaths=/var/log/activeblue-ai /var/lib/activeblue-ai
|
||||
TimeoutStartSec=60
|
||||
TimeoutStopSec=30
|
||||
KillMode=mixed
|
||||
KillSignal=SIGTERM
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
99
debian/usr/bin/activeblue-ai
vendored
Normal file
99
debian/usr/bin/activeblue-ai
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
#!/bin/bash
|
||||
# ActiveBlue AI CLI tool
|
||||
set -e
|
||||
|
||||
SERVICE_DIR="/usr/lib/activeblue-ai"
|
||||
VENV="$SERVICE_DIR/venv"
|
||||
CONFIG="/etc/activeblue-ai/.env"
|
||||
PYTHON="$VENV/bin/python3"
|
||||
|
||||
if [ ! -f "$CONFIG" ]; then
|
||||
echo "ERROR: Config not found at $CONFIG" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export $(grep -v '^#' "$CONFIG" | grep -v '^$' | xargs 2>/dev/null) 2>/dev/null || true
|
||||
|
||||
cmd="${1:-help}"
|
||||
shift || true
|
||||
|
||||
case "$cmd" in
|
||||
start)
|
||||
echo "Starting ActiveBlue AI service..."
|
||||
systemctl start activeblue-ai.service
|
||||
;;
|
||||
stop)
|
||||
echo "Stopping ActiveBlue AI service..."
|
||||
systemctl stop activeblue-ai.service
|
||||
;;
|
||||
restart)
|
||||
echo "Restarting ActiveBlue AI service..."
|
||||
systemctl restart activeblue-ai.service
|
||||
;;
|
||||
status)
|
||||
systemctl status activeblue-ai.service
|
||||
;;
|
||||
logs)
|
||||
journalctl -u activeblue-ai.service -f "${@}"
|
||||
;;
|
||||
migrate)
|
||||
echo "Running Alembic migrations..."
|
||||
cd "$SERVICE_DIR"
|
||||
"$VENV/bin/alembic" -c agent_service/migrations/alembic.ini upgrade head
|
||||
;;
|
||||
health)
|
||||
PORT="${AGENT_SERVICE_PORT:-8001}"
|
||||
curl -sf "http://localhost:${PORT}/health/detailed" | python3 -m json.tool
|
||||
;;
|
||||
sweep)
|
||||
PORT="${AGENT_SERVICE_PORT:-8001}"
|
||||
AGENTS="${1:-}"
|
||||
if [ -n "$AGENTS" ]; then
|
||||
curl -sf -X POST "http://localhost:${PORT}/sweep" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "{\"agents\": [\"$AGENTS\"]}" | python3 -m json.tool
|
||||
else
|
||||
curl -sf -X POST "http://localhost:${PORT}/sweep" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"agents": []}' | python3 -m json.tool
|
||||
fi
|
||||
;;
|
||||
privacy)
|
||||
MODE="${1:-}"
|
||||
if [ -z "$MODE" ]; then
|
||||
echo "Current privacy mode: ${LLM_PRIVACY_MODE:-local}"
|
||||
else
|
||||
sed -i "s/^LLM_PRIVACY_MODE=.*/LLM_PRIVACY_MODE=$MODE/" "$CONFIG"
|
||||
echo "Privacy mode set to: $MODE"
|
||||
echo "Restart the service for changes to take effect: activeblue-ai restart"
|
||||
fi
|
||||
;;
|
||||
version)
|
||||
cat "$SERVICE_DIR/VERSION" 2>/dev/null || echo "0.1.0"
|
||||
;;
|
||||
help|--help|-h)
|
||||
cat <<'HELP'
|
||||
ActiveBlue AI — CLI tool
|
||||
|
||||
Usage: activeblue-ai <command> [options]
|
||||
|
||||
Commands:
|
||||
start Start the agent service
|
||||
stop Stop the agent service
|
||||
restart Restart the agent service
|
||||
status Show systemd service status
|
||||
logs [flags] Follow service logs (passes flags to journalctl)
|
||||
migrate Run Alembic database migrations
|
||||
health Show detailed health status
|
||||
sweep [agent] Trigger a proactive sweep (all agents or named agent)
|
||||
privacy [mode] Get or set LLM privacy mode (local|hybrid|cloud)
|
||||
version Show installed version
|
||||
help Show this help
|
||||
HELP
|
||||
;;
|
||||
*)
|
||||
echo "Unknown command: $cmd" >&2
|
||||
echo "Run 'activeblue-ai help' for usage." >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user