Commit graph

8 commits

Author SHA1 Message Date
7aa8c37d1d Add Twilio /calltest for store and direct-dial voice path testing.
Enables outbound PSTN probes via TwiML webhooks with Webex result cards, status polling, and optional store CDR enrichment.
2026-07-23 17:59:10 -04:00
9d0dbb071e Add per-app DPI voice-quality checks + widen WAN window to 7d
Adds three new SD-WAN checks (wanAppRtpMos/Loss/Jitter) that measure
REAL voice-traffic quality on actual RTP frames via Prisma DPI, not
synthetic link probes. Graded against the WORST 5-minute window so
transient degradation the 24h link-probe averages smooth away
actually surfaces.

Voice-app selection is tenant-configurable via PRISMA_APP_ID_VOICE +
PRISMA_APP_NAME_VOICE (Webex_Calling_RTP recommended for Webex
Calling shops — the Webex-specific DPI signature excludes non-Webex
UDP noise). Legacy PRISMA_APP_ID_RTP_BASE still honored with a
one-time deprecation warning.

Widens the default WAN look-back from 24h to 7 days: per-app metrics
only get datapoints when calls actually happen, so sporadic Webex
Calling stores (3-4 calls/day) need a wider window for worst-window
statistics to be meaningful. Interval picker snaps 7d to 1hour
buckets (168 pts) to keep payloads bounded while preserving
worst-hour granularity. Hard-capped at 7d — beyond that Prisma
downsamples to 1-day buckets and the signal collapses.

Also:
- Client-side concurrency limiter (PRISMA_MAX_INFLIGHT, default 3)
  to prevent 429 cascades when /voicediag fans out 10+ parallel
  metric fetches
- "View in Prisma UI" deep links in both /phonestatus WAN follow-up
  and /voicediag details, threading through a new
  integrations/paloalto/urls.js builder
- humanizeMetricUnit maps raw API unit strings ("percentage",
  "milliseconds") to display symbols ("%", "ms") to fix
  "11.83percentage" leaking to the UI
- getAppAudio envelope distinguishes not-configured / fetch-failed /
  no-traffic states so misleading "set env var" messages don't fire
  when the real problem is a 429

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-09 13:54:15 -04:00
b802383441 Add Prisma SD-WAN voice-quality enrichment for /phonestatus + /voicediag
Introduces a full Palo Alto Prisma SD-WAN integration (dual-mode SASE
OAuth 2.0 / legacy CloudGenix auth, pagination, 429 backoff, session
priming) that surfaces per-path latency/jitter/loss/MOS, site
healthscore, link state, and alarm data for a store. Wired into the
/phonestatus WAN follow-up and eight new /voicediag WAN checks graded
against ITU-T G.114 / RFC 3550 defaults (env-overridable via
WAN_STANDARD_*).

Also adds a shape-aware detail renderer for /voicediag (per-link
tables with verdict icons instead of a stringified JSON dump) and a
--window flag (15m / 1h / 6h / 24h / 1d, env default via
WAN_STANDARD_WINDOW_MINUTES) so operators can widen the look-back
without redeploying. scripts/prismaProbe.js is bundled as a CLI for
schema iteration against a live tenant.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-09 09:45:29 -04:00
d12723d010 Voicediag: store voice standards + port-hygiene checks + apply-all card
Refactor every /voicediag check to declare a top-level `standards`
object so the desired state is legible without reading run() logic
and can drive a documented reference table. Upgrade callForwarding
to error severity, tighten voicemail with three send-to-VM error
paths + a `stop_sending_to_voicemail` remediation, and add a
`disable_hoteling` remediation.

Add a port-hygiene check bucket under services/voiceDiag/checks/port
(portType, portVlan, portPoe, portEnabled) that reuses the phone-
status snapshot to enforce switchport standards. Configurable via
VOICE_STANDARD_PHONE_VLAN (default 102) and VOICE_STANDARD_ENABLED
(kill-switch). Preserve Meraki `portType`/`voiceVlan`/`dataVlan`
through the enrichment chain so the checks have clean data to read.

Add an "apply all N fixes" combined card that shows up when 2+
remediations are available. New confirm_voicediag_all /
cancel_voicediag_all actions run each fix in sequence (readable
audit trail, no per-person write-throttle stacking), accumulate
individual failures into a summary rather than aborting.

Adds regression tests asserting every check exposes .standards,
plus coverage for port checks, kill-switch, and combined-card
iteration. 63 tests in the checks file, 188 total, all green.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-08 14:14:38 -04:00
17a8469592 Add DBS-210 status.xml parser + health verdict
Second half of the DECT spike: the read-side "collector" that turns
a raw /admin/status.xml body into a normalized JS object plus a
pure health verdict. This is what will feed the /phonestatus base-
station diagnostics section once we wire it in.

- integrations/cisco-dect/statusXml.js:
  - xmlToObject(): 60-line hand-rolled parser targeted at the
    DBS-210's flat XML shape. No attributes, no CDATA, no comments
    — so we avoid pulling in a generic XML lib. Throws loudly on
    malformed input.
  - parseRebootLine(): decodes the reboot-log entries the device
    keeps in Reboot_Line_1..6, extracting timestamp + sequence #
    + reason name/code + firmware version. Unrecognized shapes come
    back marked `unrecognized:true` instead of being dropped.
  - parseStatusXml(): grouped, camelCased view of the device state
    (device / firmware / time / multiCell / rebootLog / rtp /
    network / security / emergencyNumbers / features). Every field
    is null-safe.
  - summarizeBaseHealth(): pure-function verdict. Flags recent
    reboots (uptime < 10 min), power-loss events in the log,
    DECT RF conflicts, non-zero rx/tx errors. Splits into
    warnings vs info so consumers can render at the right severity.
- tests/statusXml.test.js: 23 tests covering the parser, the
  reboot-line decoder, the higher-level normalizer, and the health
  verdict — using a REDACTED inline copy of a real status.xml
  captured from a lab base. MAC/IP/RFPI/firmware-server URL are
  all obviously-fake so the fixture is safe to commit.
2026-07-02 15:35:34 -04:00
bc56b0a0fb Add Cisco DBS-210 DECT base spike (HTTP Digest client + safe probes)
Spike scaffolding for reverse-engineering the local admin UI on a
Cisco DBS-210 DECT base station. Not wired into the bot yet -- the
plan is a status.xml data-collector next, then a per-store relay
that fronts these calls over a websocket back to the bot.

- utils/httpDigestAuth.js: dependency-free HTTP Digest MD5/qop=auth
  header builder + WWW-Authenticate parser. Preserves empty realm,
  which the DBS-210 sends and which most libs silently drop.
- integrations/cisco-dect/client.js: axios wrapper with self-signed
  TLS bypass and a single-shot Digest challenge/response interceptor.
- integrations/cisco-dect/probes.js: verified-safe read paths only in
  READ_PROBE_PATHS. Every mutating path is quarantined in the
  MUTATING_ACTION_PATHS map and exposed only via explicit trigger
  helpers (reboot/force-reboot/reboot-chain/factory-reset/reconfigure-
  tree) that fetch and attach the CSRF token from /main.html. The
  legacy /admin/reboot.htm alias -- which triggered a real reboot
  during our first blind probe -- is intentionally NOT reachable.
- tests/httpDigestAuth.test.js: 6 unit tests, including the RFC 2617
  canonical example and the DBS-210 empty-realm quirk.
- .env.example: adds DECT_TEST_BASE_IP / _USER / _PASSWORD /
  _TIMEOUT_MS for the local test harness (script itself lives under
  scripts/, which stays gitignored).
- .gitignore: adds .dect-samples/ so lab captures don't leak.
2026-07-02 15:30:42 -04:00
d112e45eb6 Detect and inline-remediate Meraki IGMP snooping in /phonestatus
DECT basestations rely on multicast for handset discovery/registration.
When Meraki switches have IGMP snooping enabled without a querier —
or per-switch overrides that deviate from a DECT-safe policy — those
frames are pruned and DECT handsets silently fail to register.

- integrations/meraki/switches.js: getSwitchMulticastSettings,
  setSwitchMulticastSettings, and pure summarizeMulticast verdict fn.
- services/phoneService.js: fires the multicast fetch as soon as the
  network id is known, overlapping DECT enrichment; attaches
  data.multicast summary to the collector output. Non-fatal on error.
- services/renderers/phoneStatusRenderer.js: emits a single warning
  line inside the DECT Basestations section only when needsFix is
  true, itemizing which parts deviate (default snoop, default flood,
  N overrides).
- commands/igmpFix.js: frozen DECT_SAFE_MULTICAST_PAYLOAD constant
  ({snoop:false, flood:true, overrides:[]}), adaptive-card builder,
  and confirm/cancel handlers.
- commands/phoneStatus.js: appends the adaptive card when needsFix
  and the trigger came from chat (skipped on HTTP path).
- index.js: IGMP_FIX_ACTIONS set + dispatch branch mirroring the
  HOST_ASSIGN pattern (one-shot pending lookup, censorActionCard,
  domain call).
- utils/pendingIgmpFixes.js: 15-min TTL pending-card store.
- tests: 11 summarizer cases (all deviation permutations + malformed
  input), 4 renderer cases (each warning-line shape + silence when
  needsFix false or no DECT), and a frozen-constant regression guard
  on the PUT payload. Full suite: 47/47 passing.
2026-07-02 14:10:33 -04:00
351f89a9a4 Initial commit: CollabFinder Webex bot
Multi-integration Webex chat/HTTP bot that unifies phone, AV, and
network status for retail store support. Consolidates data from
Webex Calling, Meraki, Workspace ONE (MDM), Atlas AMP, RED digital
signage, and OptiSigns into rich per-store status commands.

Key surfaces:
- /phonestatus, /avstatus — per-store phone & AV device reports with
  clickable Meraki deep-links and per-port detail.
- /webexhost — check/assign Webex Meetings host licenses via the
  Service App; adaptive-card confirmation flow, HTTP-API-gated.
- /offboarduser — full Webex Admin offboarding (auth revoke, device
  wipe, license removal); adaptive-card confirmation.
- /jirapoll — on-demand trigger for the hourly Jira poller.
- /bulkavstatuscsv — bulk store CSV export with concurrency limits.

Automation:
- Hourly Jira poller (node-cron) with an X.AI (Grok) ticket classifier
  that categorizes unassigned tickets as phone/av/skip, extracts store
  numbers from free-text, and enriches Jira with the same detailed
  markdown the chat commands emit (converted to Jira ADF, preserves
  bold + Meraki links). Idempotent via a `bot-enriched` Jira label.

Architecture:
- Node.js 20+, ESM, Express 5, webex-node-bot-framework.
- Layered integrations (integrations/*), services (services/*),
  commands (commands/*), utils (utils/*).
- Shared markdown renderers (services/renderers/*) feed both chat
  handlers and the Jira poller so the two surfaces stay in sync.
- Hand-rolled markdown-to-ADF converter (utils/markdownToAdf.js) —
  no new npm dependency.
- Node built-in test runner (`node --test tests/*.test.js`), 30 tests
  covering the converter, renderers, and poller ADF assembly.

Docker + docker-compose deployment. Config via .env
(see .env.example for the full option surface).
2026-07-01 16:55:03 -04:00