Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@ updates:
schedule:
interval: "weekly"
open-pull-requests-limit: 10
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
- package-ecosystem: "docker"
directory: "/"
schedule:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
strategy:
fail-fast: false
matrix:
language: ['python', 'javascript', 'typescript']
language: ['python', 'javascript']

steps:
- name: Checkout repository
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ build/
*.so
# Logs
*.log
# Pipeline reports
reports/
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends \
nmap \
snmp \
snmp-mibs-downloader \
iputils-ping \
net-tools \
&& rm -rf /var/lib/apt/lists/*
# Note: snmp-mibs-downloader skipped - not available in Debian slim, MIBs optional

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
Expand Down
169 changes: 169 additions & 0 deletions INTENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
# INTENT.md — TeleOps (ORACLE Phase)

> **Phase**: -1 (ORACLE) — Read-only intent reconstruction
> **Date**: 2026-07-05
> **Analyst**: J1-PIPELINE
> **Status**: Complete

---

## What This System Does

**TeleOps** (formerly J1-NOC-Nexus, codename "NetBot") is a **unified Network Operations Center (NOC) platform** that combines a Telegram bot, cross-platform infrastructure agents, SNMP discovery, and a live web dashboard into a single deployable system. It is the operational nerve center for the JorahOne infrastructure estate.

### Technical Architecture

```
┌──────────────────────────────────────────────────────┐
│ Telegram Bot │
│ (Central Controller) │
│ python-telegram-bot · FastAPI · aiohttp │
└───────────────┬──────────────────┬──────────────────┐
│ │ │
┌───────────▼──┐ ┌─────────▼──────┐ ┌───────▼──────┐
│ Windows │ │ Linux │ │ SNMP │
│ Agent │ │ Agent │ │ Scanner │
│ (agent.ps1) │ │ (agent.py) │ │ (pysnmp) │
│ PS 5.1+ │ │ Python 3.8+ │ │ v1/v2c/v3 │
└───────┬──────┘ └───────┬────────┘ └───────┬──────┘
│ │ │
└───────────────────┴────────────────────┘
┌────▼────┐
│ Redis │ ← State / Job Queue
└─────────┘
┌────▼──────────┐
│ Flask + WS │ ← Live Dashboard
│ Dashboard │ (SocketIO)
└───────────────┘
```

### Core Components

| Component | Technology | Role |
|-----------|-----------|------|
| **Telegram Bot** | `python-telegram-bot` 20.7 | Command interface, alert delivery, inline menus |
| **Agent Server** | `aiohttp` (FastAPI-style) | Agent registration, script download, HMAC auth |
| **Windows Agent** | PowerShell 5.1+ | AD/DNS/DHCP management, metrics, command execution |
| **Linux Agent** | Python 3.8+ (psutil) | System stats, services, firewall, logs, arbitrary commands |
| **Network Scanner** | Python (aiohttp) | Auto-discovers agents on port 7845 across subnets |
| **SNMP Scanner** | Python (pysnmp) | Discovers/polls routers, switches, printers via SNMP |
| **Web Dashboard** | Flask + SocketIO | Real-time agent/SNMP metrics via WebSocket push |
| **State Layer** | Redis 7 (alpine) | Job queue, agent state, SNMP device cache |

### Operational Capabilities

- **Zero-config agent discovery**: Scans configured subnets for agents listening on port 7845; agents self-register via HTTP POST
- **Windows Server management**: Active Directory user CRUD, DNS zone/record management, DHCP scope/lease inspection, service control, event log tailing
- **Linux management**: CPU/RAM/disk stats, systemd service control, process listing, netstat, firewall rules, journalctl logs, SSH key inspection, arbitrary shell commands
- **SNMP device polling**: v1/v2c/v3 support, sysName/sysDescr/uptime, interface counters, CPU load, memory utilization
- **Threshold-based alerting**: CPU >90%, memory >85%, disk >90%, service-down detection with configurable cooldown
- **Live dashboard**: Real-time WebSocket-pushed agent cards with CPU/MEM/DISK gauges, SNMP device list, summary stats
- **Cross-platform deployment**: One-liner install scripts for both Windows (PowerShell) and Linux (bash/systemd)
- **HMAC-secured agent communication**: All agent commands signed with SHA-256 HMAC using shared secret

---

## Why This Was Built

### The Real Problem

JorahOne LLC operates a heterogeneous infrastructure estate spanning Windows Server (Active Directory, DNS, DHCP) and Linux servers, alongside traditional SNMP-managed network gear (routers, switches, firewalls). The operational reality before NetBot was fragmented:

1. **Windows AD/DNS/DHCP management** required RDP or dedicated RSAT workstations — no mobile access, no unified interface
2. **Linux server monitoring** used separate SSH sessions, Nagios/Icinga checks, or ad-hoc scripts
3. **SNMP device polling** required a separate NMS tool (PRTG, SolarWinds, Cacti)
4. **Alerting** was split across multiple channels (email, Slack, SMS) with no single source of truth
5. **Agent deployment** was manual — no auto-discovery, no self-registration

Existing tools were insufficient because:
- **Enterprise NMS platforms** (SolarWinds, PRTG, Nagios XI) are expensive, complex to configure, and require dedicated monitoring infrastructure
- **Cloud monitoring** (Datadog, New Relic) doesn't cover on-prem network gear via SNMP or Windows AD management
- **Individual point tools** (RSAT for AD, SSH for Linux, SNMP walkers) create operational silos and require context switching
- **No existing tool** combined Telegram-based mobile control with cross-platform agent deployment and SNMP in a single open-source package

### What Triggered Development

The JorahOne NOC team needed a **single pane of glass** that could be operated from a mobile device (Telegram) without VPN, without a dedicated monitoring workstation, and without licensing costs. The trigger was the operational overhead of managing a growing hybrid infrastructure with separate tools for Windows, Linux, and network gear — particularly the inability to respond to AD lockouts, DNS issues, or server alerts from outside the office.

### How It Fits the JorahOne Ecosystem

TeleOps is the **observability and operations layer** of the JorahOne stack. It complements:

- **J1-DevOps** (CI/CD pipeline tooling) by providing the runtime monitoring for deployed infrastructure
- **J1-Security** (security tooling) by providing alerting and audit trail for infrastructure events
- **J1-Infra** (infrastructure provisioning) by providing the operational management layer for provisioned servers
- **J1-Automation** (automation framework) by providing the agent-based remote execution substrate

It is designed as a **self-hosted, zero-license-cost** alternative to commercial NMS platforms, optimized for the specific Windows+Linux+SNMP hybrid that characterizes SMB and mid-market IT environments.

---

## Operational Classification

| Dimension | Classification |
|-----------|---------------|
| **Type** | **Production** — designed for 24/7 infrastructure monitoring and management |
| **Domain** | **Observability** + **Automation** — real-time metrics, alerting, and remote control |
| **Maturity** | v1.0.0 — initial release, functional but early-stage |
| **Deployment** | Docker Compose (bot + Redis) + per-server agent install |
| **Security Posture** | Admin whitelist, HMAC-signed agent communication, configurable thresholds |
| **License** | MIT — open source, permissive |

---

## Key Design Decisions

1. **Telegram as primary interface** — Chosen over Slack/Discord/Web UI because Telegram bots require no infrastructure (no webhook setup), work on mobile without VPN, and support rich inline keyboards
2. **Agent self-registration** — Agents register themselves via HTTP POST rather than requiring a central inventory, enabling zero-config auto-discovery
3. **HMAC over TLS** — Agent commands are HMAC-signed rather than requiring mutual TLS, simplifying deployment on networks without PKI
4. **Redis for state** — Chosen over SQLite/Postgres for the job queue pattern; agents are ephemeral state that doesn't need ACID guarantees
5. **Dual dashboard** — Both Telegram (mobile) and Web (desktop) dashboards, with the web dashboard using SocketIO for real-time push rather than polling
6. **psutil-based Linux agent** — Single-file Python agent with no framework dependencies, deployable via curl pipe to bash

---

## Repository Structure

```
|TeleOps/
├── bot/ # Telegram bot + agent server
│ ├── main.py # Bot entry point, command registration
│ ├── handlers.py # All Telegram command handlers
│ ├── keyboards.py # Inline keyboard builders
│ ├── agent_server.py # Agent registration + download HTTP server
│ └── scheduler.py # Background heartbeat/alert/metrics jobs
├── agents/ # Cross-platform agent code
│ ├── linux/
│ │ ├── agent.py # Linux agent (Python, systemd service)
│ │ └── install.sh # Linux one-liner installer
│ └── windows/
│ ├── agent.ps1 # Windows agent (PowerShell, scheduled task)
│ └── install.ps1 # Windows installer script
├── discovery/ # Network discovery engines
│ ├── network_scanner.py # Agent auto-discovery via HTTP probe
│ └── snmp_scanner.py # SNMP device discovery + polling
├── dashboard/ # Web dashboard
│ ├── app.py # Flask + SocketIO server
│ └── templates/
│ └── index.html # Dark-theme real-time dashboard UI
├── config/
│ └── config.yaml.example # Full configuration template
├── tests/
│ └── test_basic.py # HMAC signature + import tests
├── .github/ # CI/CD
│ ├── workflows/codeql.yml
│ ├── dependabot.yml
│ └── ISSUE_TEMPLATE/
├── docker-compose.yml # Bot + Redis stack
├── Dockerfile # Bot container (python:3.11-slim + nmap/snmp)
├── requirements.txt # Python dependencies
├── README.md # Project documentation
├── SECURITY.md # Security policy
├── CONTRIBUTING.md # Contribution guidelines
├── CODE_OF_CONDUCT.md # Code of conduct
├── ROADMAP.md # Development roadmap
├── CHANGELOG.md # Release history
└── LICENSE # MIT license
```
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<br>

<div align="center">
<h1>📡 J1 NOC Nexus</h1>
<h1>📡 TeleOps</h1>
<p><strong>Unified Network Operations Center Platform</strong></p>
<p>Telegram bot, SNMP discovery, live dashboard, and cross-platform agents for infrastructure management</p>
<p>
Expand All @@ -33,11 +33,11 @@
## 🚀 Quick Start

```bash
git clone https://github.com/OneByJorah/J1-NOC-Nexus.git
cd J1-NOC-Nexus
git clone https://github.com/OneByJorah/TeleOps.git
cd TeleOps
pip install -r requirements.txt
# Configure your .env file with Telegram bot token
python3 handlers.py
# Copy and configure config/config.yaml.example → config/config.yaml
python3 bot/main.py
```

Or with Docker:
Expand All @@ -48,7 +48,7 @@ docker-compose up -d
## 🏗️ Architecture

```
J1-NOC-Nexus/
|TeleOps/
├── agents/ # Platform-specific agents
│ ├── agent.ps1 # Windows agent
│ └── install.sh # Linux agent bootstrap
Expand Down
1 change: 1 addition & 0 deletions bot/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# NetBot bot package
1 change: 1 addition & 0 deletions dashboard/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# NetBot dashboard package
4 changes: 3 additions & 1 deletion dashboard/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
sys.path.insert(0, str(Path(__file__).parent.parent))

app = Flask(__name__)
app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY", "netbot-dashboard-secret")
app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY")
if not app.config["SECRET_KEY"]:
raise RuntimeError("SECRET_KEY environment variable must be set for dashboard")
socketio = SocketIO(app, cors_allowed_origins="*")

# Shared state injected from main bot
Expand Down
45 changes: 32 additions & 13 deletions dashboard/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,12 @@
return 'ok';
}

function escapeHtml(str) {
const div = document.createElement('div');
div.appendChild(document.createTextNode(str));
return div.innerHTML;
}

function renderAgents(agents) {
const el = document.getElementById('agent-list');
if (!agents || agents.length === 0) {
Expand All @@ -235,16 +241,21 @@
const mem = parseFloat(a.memory || 0).toFixed(0);
const disk = parseFloat(a.disk || 0).toFixed(0);
const online = a.status === 'online';
const roles = (a.roles || []).map(r => `<span class="role-tag">${r}</span>`).join('');
const hostname = escapeHtml(a.hostname || a.ip || 'Unknown');
const ip = escapeHtml(a.ip || '');
const uptime = escapeHtml(a.uptime || '');
const os = escapeHtml((a.os||'?').toUpperCase());
const status = escapeHtml(a.status || 'offline');
const roles = (a.roles || []).map(r => `<span class="role-tag">${escapeHtml(r)}</span>`).join('');
return `
<div class="agent-card ${online ? '' : 'offline'}">
<div class="status-dot ${a.status || 'offline'}"></div>
<div class="status-dot ${status}"></div>
<div class="agent-info">
<div class="hostname">
${a.hostname || a.ip || 'Unknown'}
<span class="os-badge ${a.os || 'unknown'}" style="margin-left:8px">${(a.os||'?').toUpperCase()}</span>
${hostname}
<span class="os-badge ${a.os || 'unknown'}" style="margin-left:8px">${os}</span>
</div>
<div class="details">${a.ip || ''} ${a.uptime ? '· up ' + a.uptime : ''}</div>
<div class="details">${ip} ${uptime ? '· up ' + uptime : ''}</div>
<div class="roles">${roles}</div>
</div>
<div class="agent-metrics">
Expand All @@ -271,19 +282,27 @@
el.innerHTML = '<div class="empty">No SNMP devices discovered.<br>Make sure SNMP is enabled on your network devices.</div>';
return;
}
el.innerHTML = devices.map(d => `
el.innerHTML = devices.map(d => {
const ip = escapeHtml(d.ip || 'Unknown');
const desc = escapeHtml((d.description || 'Unknown device').substring(0,60));
const uptime = escapeHtml(d.uptime || '?');
const if_in = escapeHtml(d.if_in || '?');
const if_out = escapeHtml(d.if_out || '?');
const status = escapeHtml(d.status || '?');
return `
<div class="snmp-card">
<div>
<div class="snmp-ip">${d.ip || 'Unknown'}</div>
<div class="snmp-desc">${(d.description || 'Unknown device').substring(0,60)}</div>
<div class="snmp-desc">Uptime: ${d.uptime || '?'}</div>
<div class="snmp-ip">${ip}</div>
<div class="snmp-desc">${desc}</div>
<div class="snmp-desc">Uptime: ${uptime}</div>
</div>
<div class="snmp-stats">
↓ ${d.if_in || '?'}<br>
↑ ${d.if_out || '?'}<br>
<span style="color:${d.status==='online'?'var(--green)':'var(--red)'}">${d.status || '?'}</span>
↓ ${if_in}<br>
↑ ${if_out}<br>
<span style="color:${d.status==='online'?'var(--green)':'var(--red)'}">${status}</span>
</div>
</div>`).join('');
</div>`;
}).join('');
}

function updateSummary(agents, snmp) {
Expand Down
1 change: 1 addition & 0 deletions discovery/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# NetBot discovery package
22 changes: 22 additions & 0 deletions docker-compose.deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
services:
nexus:
build:
context: .
dockerfile: Dockerfile
container_name: nexuscore
ports:
- "8081:8080"
- "5001:5000"
environment:
- REDIS_URL=redis://shared-redis:6379
- PYTHONUNBUFFERED=1
networks:
- shared-infrastructure_default
restart: unless-stopped
volumes:
- ./config:/app/config:ro
- ./logs:/app/logs

networks:
shared-infrastructure_default:
external: true
16 changes: 16 additions & 0 deletions j1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
repo: TeleOps
class: Infrastructure
subclasses: [Monitoring, Dashboard, Python, Docker]
org: OneByJorah
owner: Jhonattan L. Jimenez
license: MIT
production_score: 64.5
last_audit: 2026-07-05T20:44:00Z
last_publish: null
standards_version: "2.1"
dependencies: []
deploy_target: scratch
tailscale_only: false
public_facing: false
community_sla_hours: 48
adoption_tracked: false