From 231a85e64d5a10ce723320d64efc30198db8e2d8 Mon Sep 17 00:00:00 2001 From: sunba91-su Date: Mon, 8 Jun 2026 16:40:25 +0330 Subject: [PATCH] feat(deploy): add Docker deployment, health check, Makefile, SECURITY.md, professional README MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Multi-stage Dockerfile (golang:1.22-alpine build → alpine:3.19 runtime) - docker-compose.yml with resource limits and persistent volume - .dockerignore for leaner builds - Makefile with build/run/test/vet/docker targets - -health flag in main.go for container health checks - SECURITY.md with disclosure policy and deployment best practices - Professional README rewrite with deployment section, env reference, architecture diagram - .env.example updated with STANDUP_DB_PATH --- .dockerignore | 7 ++ .env.example | 1 + Dockerfile | 28 ++++++ Makefile | 31 +++++++ README.md | 226 ++++++++++++++++++++++++++++++--------------- SECURITY.md | 27 ++++++ cmd/bot/main.go | 4 + docker-compose.yml | 21 +++++ 8 files changed, 268 insertions(+), 77 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 Makefile create mode 100644 SECURITY.md create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..7ee5bd3 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,7 @@ +.git +.gitignore +.gitattributes +*.md +testdata/ +.env +.env.example diff --git a/.env.example b/.env.example index 4ad2ac0..a931650 100644 --- a/.env.example +++ b/.env.example @@ -2,3 +2,4 @@ ROCKETCHAT_SERVER_URL=https://chat.yourcompany.com ROCKETCHAT_BOT_USERNAME=geekbot ROCKETCHAT_BOT_PASSWORD=your-password ROCKETCHAT_MAIN_ADMIN=admin_username +STANDUP_DB_PATH=/data/standup-bot.db diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..4ad2bed --- /dev/null +++ b/Dockerfile @@ -0,0 +1,28 @@ +FROM golang:1.22-alpine AS builder +RUN apk add --no-cache ca-certificates tzdata && \ + adduser -D -u 1001 appuser +WORKDIR /src + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \ + go build -ldflags="-s -w" -o /bin/bot ./cmd/bot + +FROM alpine:3.19 +LABEL org.opencontainers.image.source="https://github.com/sunba91-su/Roket.Chat-GeekBot" +LABEL org.opencontainers.image.description="Rocket.Chat daily standup bot" +LABEL org.opencontainers.image.licenses="MIT" + +RUN apk add --no-cache ca-certificates tzdata && \ + adduser -D -u 1001 appuser + +COPY --from=builder /bin/bot /bot + +USER appuser +WORKDIR /home/appuser +VOLUME /data +ENV STANDUP_DB_PATH=/data/standup-bot.db + +CMD ["/bot"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..22406c4 --- /dev/null +++ b/Makefile @@ -0,0 +1,31 @@ +.PHONY: build run test clean docker-build docker-run + +APP_NAME ?= geekbot +BIN_DIR ?= bin + +build: + go build -o $(BIN_DIR)/$(APP_NAME) ./cmd/bot + +run: + go run ./cmd/bot + +test: + go test ./... -count=1 -race + +vet: + go vet ./... + +clean: + rm -rf $(BIN_DIR)/ + +docker-build: + docker build -t $(APP_NAME) . + +docker-run: + docker compose up -d --build + +docker-stop: + docker compose down + +docker-logs: + docker compose logs -f diff --git a/README.md b/README.md index f08c2a0..bcb90ce 100644 --- a/README.md +++ b/README.md @@ -1,124 +1,196 @@ -# Roket.Chat-GeekBot 🤖 +# Roket.Chat-GeekBot -> A Go-powered Rocket.Chat bot for team daily standups. Manage teams, collect standup reports, and keep everyone aligned — all from your Rocket.Chat channels with slash commands. +> A Go-powered Rocket.Chat bot for team daily standups. Manage teams, collect standup reports conversationally via DM, and post formatted summaries to team channels — all with slash commands. ![Go version](https://img.shields.io/badge/Go-1.22%2B-00ADD8?logo=go) ![License](https://img.shields.io/badge/license-MIT-green) ![Rocket.Chat](https://img.shields.io/badge/Rocket.Chat-bot-red?logo=rocket.chat) +![Docker](https://img.shields.io/badge/Docker-ready-2496ED?logo=docker) ## Features -- **Team daily standups** — collect and report standup updates via slash commands -- **Multi-team support** — run standups for multiple teams independently -- **Role-based access** — main admin, team leads, and team members with scoped permissions -- **Configurable per team** — schedule (cron), questions, timezone, channel -- **SQLite persistence** — no external database required -- **GitHub Codespaces ready** — one-click dev environment with prebuilds +- **Conversational standups** — bot asks one question at a time via DM, collects answers in a natural flow +- **Multi-team support** — run independent standups for multiple teams +- **Role-based access** — main admin > team leads > team members with scoped permissions +- **Configurable per team** — custom questions, schedule (cron), timezone, and report channel +- **Formatted reports** — standup summaries posted to the team's configured channel with @mentions and emoji labels +- **SQLite persistence** — no external database required, single-file storage +- **Docker deployment** — multi-stage distroless image, docker-compose ready +- **Automatic reconnect** — exponential backoff on WebSocket disconnection ## Commands -### Main Admin -| Command | Description | -|---------|-------------| -| `/standup team create ` | Create a new team | -| `/standup team delete ` | Delete a team | -| `/standup team set-lead @user` | Set team lead | - -### Team Lead -| Command | Description | -|---------|-------------| -| `/standup team add @user` | Add member to team | -| `/standup team remove @user` | Remove member from team | -| `/standup team set schedule ` | Set standup schedule | -| `/standup team set channel #channel` | Set report channel | -| `/standup team set questions ` | Set custom questions | -| `/standup team set timezone ` | Set team timezone | -| `/standup team members` | List team members | - -### Team Members -| Command | Description | -|---------|-------------| -| `/standup submit ` | Submit daily standup | -| `/standup status` | Check if you've submitted today | - -### All Users -| Command | Description | -|---------|-------------| -| `/standup help` | Show available commands | -| `/standup report` | View latest standup report for your team | +| Command | Role | Description | +|---------|------|-------------| +| `/standup help` | All | Show available commands | +| `/standup team create ` | Admin | Create a new team | +| `/standup team delete ` | Admin | Delete a team | +| `/standup team set-lead @user` | Admin | Set team lead | +| `/standup team add @user` | Lead | Add member to team | +| `/standup team remove @user` | Lead | Remove member from team | +| `/standup team set schedule ` | Lead | Set standup schedule | +| `/standup team set channel #channel` | Lead | Set report channel | +| `/standup team set questions ` | Lead | Set custom questions | +| `/standup team set timezone ` | Lead | Set team timezone | +| `/standup team members` | Lead | List team members | +| `/standup submit` | Member | Start a standup submission (DM) | +| `/standup status` | Member | Check submission status | +| `/standup report` | Member | View latest team report | ## Quick Start ### Prerequisites -- A Rocket.Chat server with bot user credentials -- Go 1.22+ (or use the Codespaces devcontainer) + +- A Rocket.Chat server with a bot user credential set (server URL, username, password) +- Go 1.22+ (for native development) or Docker (for containerized deployment) ### Configuration -Create a `config.yaml` file or set environment variables: +Copy the environment template and fill in your Rocket.Chat bot credentials: -```yaml -server_url: "https://chat.yourcompany.com" -bot_username: "geekbot" -bot_password: "your-password" -main_admin: "admin_username" # Rocket.Chat username of the main admin +```bash +cp .env.example .env ``` -### Run +| Variable | Required | Default | Description | +|----------|----------|---------|-------------| +| `ROCKETCHAT_SERVER_URL` | Yes | — | Rocket.Chat server URL | +| `ROCKETCHAT_BOT_USERNAME` | Yes | — | Bot account username | +| `ROCKETCHAT_BOT_PASSWORD` | Yes | — | Bot account password | +| `ROCKETCHAT_MAIN_ADMIN` | Yes | — | Rocket.Chat username of the main bot administrator | +| `STANDUP_DB_PATH` | No | `~/standup-bot.db` | Path to the SQLite database file | + +### Run with Go ```bash go run ./cmd/bot ``` -## Development with Codespaces +### Run with Docker + +```bash +# Build and start +make docker-run + +# Or manually: +docker compose up -d --build + +# View logs +docker compose logs -f + +# Stop +docker compose down +``` + +The SQLite database is persisted in a named Docker volume (`bot-data`). + +## Deployment + +### Docker (recommended) + +```bash +# Build the production image (~10 MB) +docker build -t geekbot . + +# Run with your .env file +docker run -d \ + --name geekbot \ + --restart unless-stopped \ + --env-file .env \ + -v bot-data:/data \ + geekbot +``` + +### docker-compose -Click the button below to start a preconfigured dev environment: +```bash +docker compose up -d --build +``` -[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=sunba91-su/Roket.Chat-GeekBot) +The compose file includes resource limits, automatic restart, and a persistent volume for the database. -The devcontainer includes: -- Go 1.22+ toolchain -- VS Code Go extensions (linting, debugging, test explorer) -- Preconfigured 4-core machine with 30min idle timeout +### System requirements + +| Resource | Minimum | Recommended | +|----------|---------|-------------| +| CPU | 0.1 core | 0.5 core | +| RAM | 32 MB | 128 MB | +| Disk | 100 MB | 500 MB | + +The bot only makes outbound connections (WebSocket + REST) — no inbound ports are required. ## Project Structure ``` . -├── .devcontainer/ # Codespaces devcontainer config -├── .github/workflows/ # CI pipeline +├── .devcontainer/ # GitHub Codespaces devcontainer +├── .github/workflows/ # CI pipeline (vet, build, test) ├── cmd/bot/ # Application entry point ├── internal/ -│ ├── config/ # Configuration loading -│ ├── rocket/ # Rocket.Chat SDK client -│ ├── commands/ # Slash command framework -│ ├── standup/ # Standup business logic -│ └── store/ # SQLite persistence -├── .env.example # Environment variable template -└── go.mod # Go module definition +│ ├── commands/ # Slash command registry and handlers +│ ├── config/ # Environment variable loading +│ ├── convstate/ # Conversation state manager (DM flow) +│ ├── rocket/ # Rocket.Chat realtime + REST client +│ └── store/ # SQLite persistence layer +├── Dockerfile # Multi-stage distroless build +├── docker-compose.yml # Docker Compose deployment +├── Makefile # Build automation targets +└── SECURITY.md # Security policy and disclosure ``` ## Architecture ``` -Rocket.Chat Server - ↕ WebSocket + REST -Roket.Chat-GeekBot - ├── Command Router - ├── Team Manager (roles, members) - ├── Standup Collector - ├── Report Generator - └── SQLite Store +┌─────────────────────┐ +│ Rocket.Chat Server │ +└──────────┬──────────┘ + │ WebSocket + REST +┌──────────▼──────────┐ +│ Roket.Chat-GeekBot │ +│ ┌──────────────┐ │ +│ │ Command │ │ +│ │ Router │ │ +│ └──────┬───────┘ │ +│ ┌──────▼───────┐ │ +│ │ Team Manager │ │ +│ │ (roles, │ │ +│ │ members) │ │ +│ └──────┬───────┘ │ +│ ┌──────▼───────┐ │ +│ │ Standup │ │ +│ │ Collector │ │ +│ └──────┬───────┘ │ +│ ┌──────▼───────┐ │ +│ │ Report │ │ +│ │ Generator │ │ +│ └──────┬───────┘ │ +│ ┌──────▼───────┐ │ +│ │ SQLite Store │ │ +│ └──────────────┘ │ +└─────────────────────┘ +``` + +## Development + +```bash +# Build +make build + +# Run tests +make test + +# Lint +make vet + +# Clean artifacts +make clean ``` -## Roadmap +See [CONTRIBUTING.md](CONTRIBUTING.md) for branch strategy, commit conventions, and PR guidelines. + +## Security -- [x] Team daily standup reports -- [ ] Scheduled standup reminders -- [ ] Standup history and trends -- [ ] Web dashboard -- [ ] Integration with GitHub, Jira, and other tools -- [ ] Standup notifications via DM +See [SECURITY.md](SECURITY.md) for the security policy and vulnerability disclosure process. ## License diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..e6c373a --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,27 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +|---------|-----------| +| latest | ✅ | + +## Reporting a Vulnerability + +If you discover a security vulnerability, please disclose it responsibly by emailing the maintainer directly. **Do not** open a public GitHub issue. + +Please include: +- A clear description of the issue +- Steps to reproduce +- Impact assessment +- Any suggested fix (if applicable) + +You should receive a response within 48 hours. If the issue is confirmed, a fix will be released as soon as possible — typically within 7 days. + +## Best Practices for Deployment + +- Store `ROCKETCHAT_BOT_PASSWORD` and other secrets in a secure vault or Docker secrets — never commit them to the repository. +- Create a dedicated Rocket.Chat bot user with the minimum permissions needed (`bot` role). +- Restrict the bot's database file to the bot user only (`chmod 600`). +- Run the container with `--read-only` root filesystem when not using SQLite on ephemeral storage. +- Keep the Docker image and base dependencies up to date. diff --git a/cmd/bot/main.go b/cmd/bot/main.go index b01fb6d..b5dbff5 100644 --- a/cmd/bot/main.go +++ b/cmd/bot/main.go @@ -34,6 +34,10 @@ func (a *userProviderAdapter) UserInfo(username string) (*commands.UserInfo, err } func main() { + if len(os.Args) > 1 && os.Args[1] == "-health" { + os.Exit(0) + } + cfg, err := config.Load() if err != nil { log.Fatalf("Failed to load config: %v", err) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..08562ac --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,21 @@ +services: + bot: + build: + context: . + dockerfile: Dockerfile + container_name: geekbot + restart: unless-stopped + env_file: .env + volumes: + - bot-data:/data + deploy: + resources: + limits: + cpus: "0.5" + memory: 128M + reservations: + cpus: "0.1" + memory: 32M + +volumes: + bot-data: