TypeScript/Bun ChatOps bot for Mattermost with script orchestration as the primary feature.
Status: All 6 Phases Complete ✅ - Production Ready
- ✅ WebSocket connection to Mattermost with auto-reconnect
- ✅ Exponential backoff reconnection (1s → 60s)
- ✅ Command parsing and routing
- ✅ Plugin system for extensibility
- ✅ Built-in
!pingcommand - ✅ Systemd service deployment
- ✅ Comprehensive test coverage
- ✅ Script allowlist validation
- ✅ Argument validation and sanitization
- ✅ Subprocess execution with timeout enforcement
- ✅ Output streaming to channels
- ✅ Local and Ansible remote execution
- ✅ Audit logging for all script executions
- ✅ SQLite database with migration system
- ✅ User permission levels (admin, operator, user, banned)
- ✅ Custom flags (Eggdrop-style)
- ✅ Permission management commands (!adduser, !deluser, !chattr, !whois)
- ✅ Permission checks enforced on script execution
- ✅ Bootstrap admin script for initial setup
- ✅ Ban/unban commands (!ban, !unban, !banlist)
- ✅ Temporary and permanent bans
- ✅ Automatic ban expiration
- ✅ Router-level enforcement (bans checked before command routing)
- ✅ Cannot ban admin users (safety feature)
- ✅ Ansible playbook integration
- ✅ SSH key authentication support
- ✅ Multi-host orchestration
- ✅ JSON output parsing
- ✅ Extra vars support for parameterized playbooks
- ✅ Comprehensive audit logging
- ✅ Supply chain security (frozen lockfile, 3-day package age policy)
- ✅ SBOM generation and vulnerability scanning
- ✅ Ed25519 digital signatures on audit logs
- ✅ Security documentation (SECURITY.md, MONITORING.md, DEPLOYMENT.md)
- Bun >= 1.0
- Mattermost Server (tested with v9.0+)
- RHEL 9 (for production deployment)
cd ~/projects/mattermost-bot
bun install# Copy template
cp config/bot.config.json.template config/bot.config.json
# Edit with your Mattermost details
# You'll need:
# - Mattermost server URL
# - Bot account token (see "Create Bot Account" below)
# - Bot user ID- Log in to Mattermost as System Admin
- Go to System Console > Integrations > Bot Accounts
- Click Add Bot Account
- Fill in:
- Username:
chatops-bot - Display Name:
ChatOps Bot - Description:
Script orchestration and channel management - Post All: ✅ (required to read messages)
- Username:
- Click Create Bot Account
- Copy the Bot Access Token
- Copy the Bot User ID (from the bot's profile)
Edit config/bot.config.json:
{
"mattermost": {
"url": "https://your-mattermost-server.com",
"token": "YOUR_BOT_TOKEN_HERE",
"botUserId": "YOUR_BOT_USER_ID_HERE"
}
}bun run bot.tsYou should see:
🤖 Mattermost ChatOps Bot
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📋 Loading config from: ./config/bot.config.json
✅ Config loaded successfully
🌐 Mattermost URL: https://your-server.com
🔧 Command prefix: !
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[2026-01-27T...] INFO Connected to Mattermost
[2026-01-27T...] INFO Bot is ready and listening for commands
In any channel where the bot is a member:
!ping
Expected response:
Pong! Bot is alive. 🏓
# All tests
bun test
# Specific component
bun test src/core/bot-client.test.ts
bun test src/core/command-router.test.ts# Install Bun
curl -fsSL https://bun.sh/install | bash
# Create bot user
sudo useradd -r -s /bin/bash -m -d /opt/mattermost-bot mattermost-bot
# Create directory structure
sudo mkdir -p /opt/mattermost-bot/{src,config,scripts,playbooks,data,logs}# Copy project to /opt
sudo cp -r ~/projects/mattermost-bot/* /opt/mattermost-bot/
# Install dependencies (CRITICAL: use --frozen-lockfile)
cd /opt/mattermost-bot
sudo -u mattermost-bot bun install --frozen-lockfile --production
# Set ownership
sudo chown -R mattermost-bot:mattermost-bot /opt/mattermost-bot
# Set permissions
sudo chmod 600 /opt/mattermost-bot/config/bot.config.json
sudo chmod +x /opt/mattermost-bot/bot.ts
sudo chmod +x /opt/mattermost-bot/scripts/*.sh# Copy template
sudo -u mattermost-bot cp /opt/mattermost-bot/config/bot.config.json.template \
/opt/mattermost-bot/config/bot.config.json
# Edit config (use production URLs and tokens)
sudo -u mattermost-bot nano /opt/mattermost-bot/config/bot.config.json# Copy service file
sudo cp /opt/mattermost-bot/mattermost-bot.service /etc/systemd/system/
# Reload systemd
sudo systemctl daemon-reload
# Enable service (start on boot)
sudo systemctl enable mattermost-bot
# Start service
sudo systemctl start mattermost-bot
# Check status
sudo systemctl status mattermost-bot# CRITICAL: Verify supply chain BEFORE starting bot
cd /opt/mattermost-bot
sudo -u mattermost-bot bun run scripts/verify-supply-chain.ts
# View logs
sudo journalctl -u mattermost-bot -f
# Check if bot is running
systemctl is-active mattermost-bot
# Test bot in Mattermost
# !ping/opt/mattermost-bot/
├── bot.ts # Main entrypoint
├── package.json # Dependencies
├── tsconfig.json # TypeScript config
├── mattermost-bot.service # Systemd service file
├── README.md # This file
├── src/
│ ├── core/
│ │ ├── bot-client.ts # Mattermost WebSocket connection
│ │ ├── command-router.ts # Command parsing and routing
│ │ └── script-executor.ts # (Phase 2) Script execution
│ ├── plugins/ # (Phase 3+) Permission, bans, channel ops
│ ├── database/ # (Phase 3) SQLite wrapper
│ └── utils/
│ ├── logger.ts # Structured logging
│ ├── config.ts # Configuration loader
│ └── security.ts # (Phase 2) Input validation
├── scripts/ # Allowlisted scripts
│ └── test-script.sh # Test script for Phase 1
├── config/
│ ├── bot.config.json # Bot configuration (KEEP SECRET!)
│ └── script-allowlist.json # Approved scripts (Phase 2)
├── data/
│ └── bot.db # (Phase 3) SQLite database
└── logs/
├── bot.log # Application logs
└── script-executions.log # (Phase 2) Script execution logs
{
"mattermost": {
"url": "https://mattermost.example.com",
"token": "YOUR_BOT_TOKEN",
"botUserId": "YOUR_BOT_USER_ID",
"websocketUrl": "wss://mattermost.example.com/api/v4/websocket"
},
"database": {
"path": "./data/bot.db"
},
"logging": {
"level": "info",
"file": "./logs/bot.log",
"console": true
},
"scripts": {
"allowlistPath": "./config/script-allowlist.json",
"scriptsDir": "./scripts",
"defaultTimeout": 300000
},
"bot": {
"commandPrefix": "!",
"reconnectDelay": 1000,
"maxReconnectDelay": 60000,
"reconnectBackoff": 2
}
}- Check Mattermost URL is correct
- Verify bot token is valid
- Ensure bot account exists and is not deactivated
- Check firewall allows WebSocket connections
# Test connectivity
curl https://your-mattermost-server.com/api/v4/system/ping
# Check bot logs
sudo journalctl -u mattermost-bot -n 100- Verify bot is member of the channel
- Check bot has "Post All" permission
- Confirm command prefix matches config (default:
!) - Review logs for errors
# Check if bot sees messages
sudo journalctl -u mattermost-bot | grep "Received command"# Check service status
sudo systemctl status mattermost-bot
# Check logs
sudo journalctl -u mattermost-bot -xe
# Verify config file exists
ls -la /opt/mattermost-bot/config/bot.config.json
# Test bot manually
cd /opt/mattermost-bot
sudo -u mattermost-bot bun run bot.ts# Start bot
sudo systemctl start mattermost-bot
# Stop bot
sudo systemctl stop mattermost-bot
# Restart bot
sudo systemctl restart mattermost-bot
# View status
sudo systemctl status mattermost-bot
# View logs (live)
sudo journalctl -u mattermost-bot -f
# View last 100 log lines
sudo journalctl -u mattermost-bot -n 100
# Enable autostart on boot
sudo systemctl enable mattermost-bot
# Disable autostart
sudo systemctl disable mattermost-botbun --watch bot.tsbun test # All tests
bun test src/core/bot-client.test.ts # Bot client only
bun test src/core/command-router.test.ts # Command router onlybun tsc --noEmitAll 6 phases are complete. The bot is production-ready. Follow these steps:
# After deploying to production, create the first admin user
cd /opt/mattermost-bot
sudo -u mattermost-bot bun run scripts/bootstrap-admin.ts <your-mattermost-user-id> <your-username># In Mattermost, verify you're an admin
!whois @yourself
# Add an operator user
!adduser @teammate operator
# Add a regular user
!adduser @user userEdit config/script-allowlist.json to add your scripts:
{
"scripts": [
{
"name": "deploy",
"path": "./scripts/deploy.sh",
"description": "Deploy application to environment",
"requiredPermission": "operator",
"timeout": 1800000,
"allowedChannels": ["ops", "deployments"]
}
]
}For remote execution via Ansible:
# Create playbooks directory
mkdir -p /opt/mattermost-bot/playbooks/inventory
# Add your inventory file
cat > /opt/mattermost-bot/playbooks/inventory/hosts << 'EOF'
[staging]
staging-server-1 ansible_host=192.168.1.10
[production]
prod-server-1 ansible_host=10.0.1.10
prod-server-2 ansible_host=10.0.1.11
EOF
# Generate SSH key for bot
sudo -u mattermost-bot ssh-keygen -t ed25519 -f /opt/mattermost-bot/.ssh/id_ed25519_botSee detailed documentation:
- ALL-PHASES-COMPLETE.md - Complete feature verification
- PHASE3-COMPLETE.md - Permission system details
- SECURITY.md - Security considerations
- MONITORING.md - Monitoring setup
- DEPLOYMENT.md - Deployment procedures
This project implements comprehensive supply chain security measures to protect against dependency attacks.
bunfig.toml - Bun security settings:
frozen = true- Enforces deterministic installs (lockfile not modified)minimumReleaseAge = 259200- Blocks packages newer than 3 days (defense against rapid-publish attacks)allowScripts = false- Disables lifecycle scripts (postinstall, preinstall) by default
package.json - Trusted dependencies:
trustedDependencies: []- Allowlist for packages that need lifecycle scripts- Currently empty - no dependencies require lifecycle scripts
Run supply chain verification before deployment:
bun run scripts/verify-supply-chain.tsThis checks:
- ✅ Lockfile exists
- ✅ Lockfile matches package.json (frozen check)
- ✅ bunfig.toml has security settings
- ✅ trustedDependencies declared
- ✅ No vulnerabilities (bun audit)
Generate Software Bill of Materials (SBOM) for vulnerability tracking:
# Install syft (first time only)
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
# Generate SBOM
./scripts/generate-sbom.sh
# Scan for vulnerabilities
grype sbom:sbom.spdx.jsonCRITICAL: Always use frozen lockfile in production:
# Production install
bun install --frozen-lockfile --production
# Verify supply chain BEFORE deploying
bun run scripts/verify-supply-chain.tsPackages must be published for 3 days before installation. This defends against:
- Rapid-publish attacks - Attacker publishes malicious version, quickly unpublishes
- Typosquatting - Malicious packages get caught by community before installation
- Compromised accounts - Time for maintainers to notice and respond
Exception Process: If you need a package newer than 3 days:
- Review package source code on GitHub
- Verify publisher identity
- Check recent issues/PRs
- Temporarily lower
minimumReleaseAgein bunfig.toml - Install package
- Restore original minimumReleaseAge
Lifecycle scripts (postinstall, preinstall) are DISABLED by default in Bun. This prevents malicious code execution during install.
If a package requires lifecycle scripts:
- Review the script source code
- Add package name to
trustedDependenciesin package.json - Document why it's trusted (e.g., "Official TypeScript package, 10M+ downloads/month")
Current trusted dependencies: None (all dependencies work without lifecycle scripts)
All script executions are cryptographically signed and logged to logs/script-executions.log.
Each entry includes:
- Ed25519 digital signature (tamper-proof)
- SHA-256 hash chain (detects deletion/reordering)
- Full execution context (user, script, arguments, exit code)
Verify log integrity:
bun run scripts/verify-audit-log.ts- Bun Security Scanner API: https://bun.com/docs/install/security-scanner-api
- Bun Audit: https://bun.com/docs/install/audit
- SBOM Format (SPDX): https://spdx.dev/
- Vulnerability Scanner (Grype): https://github.com/anchore/grype
MIT
For issues or questions:
- Check logs:
sudo journalctl -u mattermost-bot -f - Review configuration:
/opt/mattermost-bot/config/bot.config.json - Test manually:
sudo -u mattermost-bot bun run /opt/mattermost-bot/bot.ts