# Insight Updater - Agent Orientation ## Project Purpose Self-hosted update orchestration for Windows (CAU/WSUS) and Linux servers via WinRM/SSH. Web UI to manage inventory, trigger updates, stream live progress via WebSocket. ## Quick Start ```bash # Local development cd ~/projects/insight-updater docker compose up -d --build # Backend only cd backend && pip install -e . && uvicorn app.main:app --reload # Frontend only cd frontend && npm install && npm run dev ``` ## Architecture Overview ``` ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Frontend │────▶│ Backend │────▶│ Database │ │ (Vue 3) │ WS │ (FastAPI) │ │ (SQLite/ │ │ Port 3000 │◀─── │ Port 8000 │ │ PostgreSQL)│ └─────────────┘ └──────┬──────┘ └─────────────┘ │ ┌────────────┼────────────┐ ▼ ▼ ▼ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ WinRM │ │ SSH │ │ CAU │ │ Service │ │ Service │ │ Service │ └─────────┘ └─────────┘ └─────────┘ ``` ## Key Directories | Path | Purpose | |------|---------| | `backend/app/api/` | FastAPI route definitions (REST + WS) | | `backend/app/core/` | Config, security, database, logging | | `backend/app/models/` | SQLAlchemy ORM models | | `backend/app/schemas/` | Pydantic request/response models | | `backend/app/services/` | Business logic: winrm, ssh, cau, audit | | `backend/app/websocket/` | Socket.io handlers for live updates | | `frontend/src/views/` | Page components (Dashboard, Servers, Updates, Audit) | | `frontend/src/components/` | Reusable UI components | | `frontend/src/stores/` | Pinia stores (auth, servers, updates) | | `frontend/src/api/` | Axios/Socket.io client setup | ## Core Models | Model | Description | |-------|-------------| | `Server` | Inventory item: Windows/WinRM, Linux/SSH, CAU-Cluster | | `Credential` | Encrypted credentials (WinRM user/pass, SSH key/pass) | | `UpdateJob` | One update execution: server, status, started_by, started_at, finished_at | | `UpdateLog` | Streamed log lines per job (WebSocket → DB) | | `AuditLog` | Immutable audit trail: user, action, target, result | | `User` | Local admin or LDAP-mapped user | ## Key Services | Service | File | Responsibility | |---------|------|----------------| | `WinRMService` | `services/winrm.py` | Connect, run PS commands, stream output | | `SSHService` | `services/ssh.py` | Connect, run commands, sudo handling | | `CAUService` | `services/cau.py` | `Invoke-CauRun`, cluster status, node phases | | `AuditService` | `services/audit.py` | Structured logging to DB + JSON file | | `EncryptionService` | `core/security.py` | Fernet encrypt/decrypt credentials | ## WebSocket Events | Event | Direction | Payload | |-------|-----------|---------| | `job:start` | Server→Client | `{job_id, server_id, type}` | | `job:log` | Server→Client | `{job_id, line, timestamp, level}` | | `job:progress` | Server→Client | `{job_id, percent, phase, node?}` | | `job:complete` | Server→Client | `{job_id, status, duration}` | | `job:cancel` | Client→Server | `{job_id}` | ## API Endpoints (Key) | Method | Path | Description | |--------|------|-------------| | GET | `/api/servers` | List all servers | | POST | `/api/servers` | Create server | | GET | `/api/servers/{id}/health` | Test WinRM/SSH connectivity | | POST | `/api/updates/trigger` | Start update job | | GET | `/api/updates/{job_id}/logs` | Get job logs (REST fallback) | | WS | `/ws/updates` | Socket.io connection | | GET | `/api/audit` | Paginated audit log | | POST | `/api/auth/login` | JWT login | | GET | `/health` | Health check | ## Environment Variables See `.env.example` — key ones: - `DATABASE_URL` — SQLite (dev) or PostgreSQL (prod) - `SECRET_KEY` — JWT signing (32+ chars) - `ENCRYPTION_KEY` — Fernet key for credentials (32 bytes base64) - `WINRM_TRANSPORT` — `ntlm` \| `kerberos` \| `credssp` - `LDAP_ENABLED` — `true`/`false` (stub) ## Testing ```bash # Backend cd backend && pytest -v # Frontend cd frontend && npm run test # E2E (Playwright) cd frontend && npm run test:e2e ``` ## Deployment **Target**: `monitoring` (10.0.2.105) **User**: `b0rbor4d` (sudo via Vaultwarden) **Reverse Proxy**: Traefik (Docker labels) **Git Remote**: `ssh://git@gitea.insight-it.de:2222/b0rbor4d/insight-updater.git` ```bash # On monitoring host git clone ssh://git@gitea.insight-it.de:2222/b0rbor4d/insight-updater.git cd insight-updater cp .env.example .env # fill secrets docker compose -f docker-compose.prod.yml up -d --build ``` ## Useful Commands ```bash # DB migrations cd backend && alembic upgrade head # Generate keys openssl genrsa -out keys/private.pem 2048 openssl rsa -in keys/private.pem -pubout -out keys/public.pem # Encrypt a test credential python -c "from app.core.security import encrypt; print(encrypt('secret'))" ``` ## Conventions - **Language**: German for user-facing text, English for code/comments - **Logging**: `structlog` JSON, level from `LOG_LEVEL` env - **Errors**: Custom exceptions in `core/exceptions.py`, mapped to HTTP in `main.py` - **Async**: All I/O async (asyncpg, asyncssh, httpx) - **Types**: Strict mypy, Pydantic v2, SQLAlchemy 2.0