RunWatch is a real-time monitoring application for GitHub Actions workflows. It provides an interactive dashboard to track GitHub Action runs, including their status, execution time, and performance trends.
- 🔄 Real-time monitoring of GitHub Actions workflow runs
- 📊 Dashboard displaying current and historical workflow runs
- 🔍 Detailed view of individual workflow runs and jobs
- 📈 Statistics and analytics on workflow performance
- 🔔 WebSocket-based real-time updates
- 🔒 Security hardened: rate limiting, CORS allowlist, helmet headers, MongoDB auth, admin token protection
- Node.js & Express - API and webhook handling
- MongoDB with Mongoose - Data storage
- Socket.IO - Real-time communication
- @octokit/webhooks - GitHub webhook processing
- helmet - HTTP security headers
- express-rate-limit - Rate limiting
- React - UI framework
- Material UI - Component library
- React Router - Navigation
- Chart.js - Data visualization
- Socket.IO Client - Real-time updates
The application is structured as follows:
-
GitHub Webhook Integration: The backend receives webhook events from GitHub when workflow runs start, update, and complete.
-
Data Processing Pipeline: Incoming webhook data is processed, normalized, and stored in the database.
-
Real-time Communication: Updates are broadcast to connected clients via WebSockets.
-
Dashboard UI: The React frontend displays current and historical workflow data.
- Node.js (v18+)
- MongoDB
- GitHub repository with Actions workflows
- Ability to configure GitHub webhooks
-
Copy the example environment file:
cp .env.example .env -
Configure the following environment variables in
.env:# Node environment NODE_ENV=production # Use 'development' locally (enables localhost:3000 CORS origin) # Server Configuration PORT=5001 # Port where the backend server will run # NOTE: dotenv does not expand variables — use a literal connection string here. # The app connects as MONGO_APP_USERNAME (least-privilege), not the root admin. # Replace the placeholders below with the literal values from MONGO_APP_USERNAME / MONGO_APP_PASSWORD. MONGODB_URI=mongodb://<MONGO_APP_USERNAME>:<MONGO_APP_PASSWORD>@mongodb:27017/runwatch?authSource=runwatch # MongoDB Root Credentials (used by docker-compose to initialise the DB) MONGO_ROOT_USERNAME=runwatch_admin MONGO_ROOT_PASSWORD=your_strong_root_password # MongoDB App Credentials (least-privilege user — used by the Node.js application) MONGO_APP_USERNAME=runwatch_app MONGO_APP_PASSWORD=your_strong_app_password # Admin API Token — protects /api/database/backup and /api/database/restore # Generate with: openssl rand -hex 32 ADMIN_API_TOKEN=your_long_random_secret # GitHub Configuration GITHUB_WEBHOOK_SECRET=your_github_webhook_secret # Generated webhook secret GITHUB_APP_ID=your_github_app_id # GitHub App ID GITHUB_APP_PRIVATE_KEY_PATH=./path/to/private-key.pem # Path to GitHub App private key # Client Configuration CLIENT_URL=http://localhost # Base URL for the client application (trusted CORS origin) REACT_APP_API_URL=http://localhost/api # API endpoint URL for the client REACT_APP_WEBSOCKET_URL=ws://localhost # WebSocket URL for real-time updates⚠️ Note:dotenvdoes not perform variable substitution.MONGODB_URImust be a literal connection string — you cannot use${MONGO_ROOT_USERNAME}inside.env. -
Generate a webhook secret:
node scripts/generate-webhook-secret.js -
Generate an admin API token:
openssl rand -hex 32 -
Set up your GitHub App:
- Create a GitHub App in your organization's settings
- Define the below permissions for the App:
Readaccess to actions, metadata, and organization administrationRead and writeaccess to workflows
- Subscribe to the below events:
Workflow JobWorkflow Run
- Note down the App ID
- Generate and download the private key
- Place the private key file in your project directory
- Update the
GITHUB_APP_IDandGITHUB_APP_PRIVATE_KEY_PATHin your.envfile
-
Navigate to the server directory:
cd server -
Install dependencies:
npm install -
Start the development server:
npm run dev
-
Navigate to the client directory:
cd client -
Install dependencies:
npm install -
Start the development server:
npm start
-
In your GitHub repository, go to Settings > Webhooks > Add webhook
-
Configure the webhook:
- Payload URL:
https://your-server-url/api/webhooks/github - Content type:
application/json - Secret: Use the same secret as in your
.envfile - Events: Select "Workflow runs" and "Workflow Jobs"
- Payload URL:
-
Save the webhook
-
After setting up the application and configuring the webhooks, visit
http://localhost:3000to access the dashboard. -
When GitHub Actions workflows run in your repositories, you'll see real-time updates on the dashboard.
-
Click on individual workflow runs to view detailed information about the jobs and steps.
-
Check the Statistics page for insights on workflow performance and trends.
RunWatch ships with several security controls enabled by default:
| Control | Details |
|---|---|
| HTTP security headers | helmet middleware sets X-Content-Type-Options, X-Frame-Options, HSTS, CSP, and more |
| CORS allowlist | Only CLIENT_URL (and localhost:3000 in development) are trusted; all other origins are rejected. CLIENT_URL is required in production — server refuses to start without it |
| Rate limiting | 100 req / 15 min globally per IP; 10 req / min on sync endpoints; GitHub webhook route is exempt |
| MongoDB authentication | Username + password required; port not exposed to the host network |
| Admin token for backup/restore | /api/database/backup and /api/database/restore require Authorization: Bearer <ADMIN_API_TOKEN> or X-Admin-Token: <token> |
| Input validation | Search queries are regex-escaped (ReDoS prevention); pagination values are clamped |
| Body size limit | Default 10 MB; /api/database/restore allows up to 100 MB |
| Socket.IO CORS | Same allowlist as Express CORS; server-to-server clients without Origin header are permitted |
| Proxy awareness | trust proxy 1 configured so rate limiting and IP logging reflect real client IPs behind Nginx |
These endpoints are protected by a pre-shared admin token instead of IP restrictions (IP-based checks are unreliable behind Docker/Nginx):
# Backup
curl -H "Authorization: Bearer $ADMIN_API_TOKEN" http://localhost/api/database/backup
# Restore
curl -X POST \
-H "Authorization: Bearer $ADMIN_API_TOKEN" \
-H "Content-Type: application/json" \
-d @backup.json \
http://localhost/api/database/restoreFor development, you can run both the backend and frontend servers simultaneously:
-
In one terminal, start the backend server:
cd server && npm run dev -
In another terminal, start the frontend:
cd client && npm start
Set
NODE_ENV=developmentin your.envto allow CORS fromhttp://localhost:3000during local development.
The application can be deployed using Docker and Docker Compose. This will create three containers:
- MongoDB database (auth enabled, not exposed to host)
- Node.js backend server
- Nginx serving the React frontend
- Docker
- Docker Compose
- Git
-
Clone the repository:
git clone <repository-url> cd RunWatch -
Create a
.envfile in the root directory with all required variables (see Environment Configuration above). At minimum:NODE_ENV=production MONGO_ROOT_USERNAME=runwatch_admin MONGO_ROOT_PASSWORD=<strong root password> MONGO_APP_USERNAME=runwatch_app MONGO_APP_PASSWORD=<strong app password> MONGODB_URI=mongodb://<MONGO_APP_USERNAME>:<MONGO_APP_PASSWORD>@mongodb:27017/runwatch?authSource=runwatch ADMIN_API_TOKEN=<openssl rand -hex 32> GITHUB_WEBHOOK_SECRET=<your webhook secret> GITHUB_APP_ID=<your app id> GITHUB_APP_PRIVATE_KEY_PATH=./path/to/private-key.pem CLIENT_URL=http://localhost REACT_APP_API_URL=http://localhost/api REACT_APP_WEBSOCKET_URL=ws://localhostdocker-compose uses
${VAR:?msg}syntax for MongoDB credentials — it will refuse to start ifMONGO_ROOT_USERNAMEorMONGO_ROOT_PASSWORDare missing from your environment. -
Use the deployment script to manage the application:
# Start all services ./deploy.sh start # View logs ./deploy.sh logs # Stop all services ./deploy.sh stop # Rebuild services ./deploy.sh build # Check status ./deploy.sh status
-
Access the application:
- Frontend: http://localhost
- Backend API: http://localhost/api
- WebSocket: ws://localhost/socket.io
./deploy.sh start- Start all services./deploy.sh stop- Stop all services./deploy.sh restart- Restart all services./deploy.sh logs- Show logs from all services./deploy.sh build- Rebuild all services./deploy.sh clean- Remove all containers and volumes./deploy.sh status- Show status of all services
The Docker setup includes:
- Automatic container restart on failure
- Volume persistence for MongoDB data
- Nginx reverse proxy configuration
- Network isolation between services (MongoDB not exposed to host)
- Health checks and dependency management
- MongoDB authentication enforced at startup
- Authentication and multi-user support
- More advanced filtering and search capabilities
- Custom notifications for workflow failures
- Integration with other CI/CD platforms
MIT

