appspace/README.md
jmcqueen 025b70de56 Initial commit: Appspace + Webex alerting bot
Node/Express service that:
- Receives Appspace outbound webhooks, enriches with Workspace ONE MDM
  data (matched by serial), and posts Adaptive Card alerts to Webex.
- Runs a Webex bot in WebSocket mode with two commands:
    * `offline [filter]`  - lists currently offline / lost / failed
      Appspace devices, enriched with per-device MDM facts + console links.
    * `restart-offline [filter]` - sends WS1 SoftReset (reboot) to every
      currently-offline device that has a WS1 record. Capped at 50 per
      invocation with bounded concurrency to protect the WS1 API.

Notes on hardening already applied:
- In-flight promise coalescing in mdm.js and index.js so burst webhook
  traffic can't stampede the WS1 token / device-cache refresh or the
  Appspace token refresh.
- Structured logger that serializes Error instances (message, stack,
  code, axios response.status/data) instead of stringifying to "{}".
- Webex 7439-char message-limit handling: `offline` builds its body
  incrementally against a character budget and reports accurate
  "N more not shown" truncation.
- Uses string phrases for `framework.hears(...)` so the framework's
  `(^| )phrase($| )` wrapper handles group-space @mentions correctly,
  and a shared `extractFilterArg()` helper so filter parsing works
  identically in DMs and mentioned messages.

Config, Docker, smoke-test profile, and healthcheck included.
Secrets are managed via `.env` (gitignored); see `.env.example`.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 17:43:53 -04:00

116 lines
4.7 KiB
Markdown

# Appspace Webex Alerts
Lightweight Node/Express service that bridges **Appspace** device health events to **Cisco Webex** via Adaptive Cards, with optional enrichment from **Workspace ONE MDM**.
It also runs an interactive Webex bot (WebSocket mode) for on-demand queries.
## What it does
- Listens for Appspace outbound webhooks (`DEVICE.HEALTHSTATUS.*` and `DEVICE.UNREGISTERED`).
- Ignores PWA devices.
- Enriches alerts with current MDM data (model, OS version, compliance, last sample/seen timestamps in EDT).
- Posts formatted Adaptive Cards to a configured Webex room (with direct links to both consoles).
- Provides a Webex bot with commands:
- `offline [optional filter]` — snapshot of currently offline/lost/failed devices (client-side filter on name or type).
- `help`
## Requirements
- Node 20+
- Appspace instance with outbound webhook + Application refresh token
- Webex bot token + room ID
- (Optional but recommended) Workspace ONE MDM OAuth client for enrichment
## Quick Start (Docker - recommended)
1. Copy env:
```bash
cp .env.example .env
# or .env.dev for the dev profile
```
2. Fill in the required values (see `.env.example` for descriptions).
3. Run:
```bash
# Production profile
npm run docker:prod
# Development (with live reload + volume mount)
npm run docker:dev
# Smoke test (builds image + verifies /health responds "healthy" inside container)
npm run docker:smoke
```
**Port mapping notes**: The container always listens internally on port 3000 (hardened default). Host port 1889 is used for both dev (`docker compose --profile dev up -d app-dev`) and prod (`docker compose up -d`). The `PORT` env inside the container is forced to 3000 via compose. You cannot run both profiles at the same time due to the shared host port.
Direct:
```bash
npm install
npm start
```
Health check: `GET /health`
## Environment Variables
See `.env.example` for the full documented list.
Key ones:
- `WEBEX_BOT_TOKEN`, `WEBEX_ROOM_ID`
- `APPSPACE_INSTANCE_URL`, `APPSPACE_SUBJECT_ID`, `APPSPACE_REFRESH_TOKEN`, `APPSPACE_API_BASE_URL`
- `WS1_*` (for MDM enrichment)
- `WEBHOOK_SECRET` (recommended for the Appspace webhook)
- `DEBUG`, `DEBUG_WEBHOOK` (see below)
## Bot Commands
In the Webex space where the bot is added:
- `offline` — current problematic devices
- `offline tablet` — filter to devices whose name or type contains "tablet"
- `help`
The bot runs in WebSocket mode (no public webhook required).
## Debugging
- `DEBUG=true` — verbose logging for MDM lookups, ignored events, command handling, etc. (very useful in dev, noisy in prod).
- `DEBUG_WEBHOOK=true` — log the **full** incoming Appspace webhook payload (contains device details; do **not** leave on in production).
- `LOG_FORMAT=json` (or `NODE_ENV=production`) — output structured JSON logs (ideal for Docker/K8s log collectors).
You can also set `NODE_ENV=development` for similar verbose behavior.
## Production & Docker Notes
- **Graceful shutdown**: The service handles `SIGTERM` (used by `docker stop`, Kubernetes, etc.) and `SIGINT`. It will:
1. Stop the Webex WebSocket framework (important to avoid "excessive device registrations").
2. Close the HTTP server.
3. Exit cleanly. A hard timeout forces exit after ~8s.
- **Healthcheck**: `/health` returns 200 with basic status. Used by Docker and orchestrators.
- **Logging**: Logs go to stdout/stderr (12-factor / Docker friendly). Use `LOG_FORMAT=json` or `NODE_ENV=production` for structured JSON. Use `DEBUG=true` in non-prod for detail. Pipe to a collector (Loki, CloudWatch, etc.) as needed.
- **Secrets**: Never bake secrets into the image. Use:
- `env_file` for compose (dev/staging only)
- Docker secrets, Kubernetes Secrets, or a secrets manager (Vault, AWS Secrets Manager) for production.
- **Ports**: Container always listens on 3000 internally. Map host ports as needed (see docker-compose.yml).
- **Non-root**: Production image runs as the `node` user.
- **Resources**: In production, set CPU/memory limits in your orchestrator. The bot command does a full device list scan (limit 500) — monitor for large fleets.
## Architecture Notes
- Appspace token uses refresh token + cooldown + safety buffer.
- MDM uses 24h serial→ID cache + fresh detail lookup by ID on every alert (for up-to-date compliance/last-seen).
- WebSocket mode for the bot avoids restart rate limits.
- All enrichment is best-effort; alerts are never blocked by MDM or token issues.
## License / Support
Internal tool. Tweak as needed.
## TODO / Future
- Server-side filtering for the devices list when the Appspace API supports it reliably.
- Metrics / full structured JSON logging.
- Support for more Appspace event types.
- Multi-stage Dockerfile for even smaller prod images.