Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
188 lines
10 KiB
Markdown
188 lines
10 KiB
Markdown
# PRD — Tactical RMM Integration
|
||
|
||
- Slug: `tacticalrmm-integration`
|
||
- Date: `2026-02-13`
|
||
- Status: Draft
|
||
|
||
## Summary
|
||
|
||
Add a Tactical RMM integration that works in both Community Edition (CE) and Enterprise Edition (EE). The integration should:
|
||
|
||
- Connect to a Tactical RMM instance using either API key auth or username/password (Knox token) auth (including optional TOTP).
|
||
- Sync Tactical inventory into Alga Assets (clients/sites/agents -> clients/assets + mappings).
|
||
- Support near-real-time updates via Tactical alert-action webhooks (alerts only), plus optional alert backfill via the Tactical alerts API.
|
||
- Fit the existing multi-provider RMM platform patterns established by the NinjaOne integration (shared DB tables, org mapping, device sync, asset fields).
|
||
|
||
## Problem
|
||
|
||
Alga currently has an RMM integration pattern (NinjaOne) that syncs devices and supports webhooks, but it is EE-oriented and provider-specific. We want to support Tactical RMM as an additional provider, available in both CE and EE, and integrate it cleanly into the existing Assets system and the “RMM” Integrations settings tab.
|
||
|
||
## Goals
|
||
|
||
1. CE + EE: Tactical RMM appears in Settings -> Integrations -> RMM and can be configured in both editions.
|
||
2. Connection management:
|
||
- Support Tactical API key auth.
|
||
- Support Tactical username/password auth with TOTP handling (checkcreds + login).
|
||
- Store credentials securely (tenant secrets) and show masked status in UI.
|
||
3. Inventory sync:
|
||
- Sync Tactical Clients into `rmm_organization_mappings`.
|
||
- Map Tactical Clients to Alga Clients (companies) via UI.
|
||
- Sync Tactical Agents into Alga Assets using the beta API at fleet scale.
|
||
4. Asset enrichment:
|
||
- Populate core RMM fields on `assets` (`rmm_provider`, `rmm_device_id`, `rmm_organization_id`, `agent_status`, `last_seen_at`, `last_rmm_sync_at`).
|
||
- Populate cached “RMM vitals” fields when available (current user, uptime, LAN/WAN IP).
|
||
- Add support for Tactical’s “overdue” state (distinct from offline).
|
||
5. Realtime (alerts):
|
||
- Provide a webhook endpoint for Tactical alert actions with shared-secret header validation.
|
||
- On webhook receive, upsert `rmm_alerts` and trigger a targeted “sync single agent” refresh.
|
||
6. Optional: alerts backfill via Tactical alerts API for historical visibility.
|
||
|
||
## Non-goals
|
||
|
||
- Remote access (MeshCentral / remote background): explicitly deferred.
|
||
- Full “device created/updated/deleted” webhooks (Tactical doesn’t provide them natively; only alerts).
|
||
- Patch deployment / remediation (scan + display only, if we even include scan hooks).
|
||
- Deep ticket-automation parity with NinjaOne (auto ticket creation/rules) unless explicitly requested later.
|
||
|
||
## Users and Primary Flows
|
||
|
||
Primary user: MSP admin / system admin configuring integrations.
|
||
|
||
Flows:
|
||
1. Configure Tactical:
|
||
- On the Tactical server, enable the Beta API: set `BETA_API_ENABLED = True` and restart Tactical.
|
||
- Open Settings -> Integrations -> RMM -> Tactical RMM.
|
||
- Enter the Tactical **API host** as the instance URL: the `api.` subdomain (e.g. `https://api.example.com`), not the dashboard (`rmm.`) URL.
|
||
- Choose auth mode:
|
||
- API key: paste key, save, verify.
|
||
- Username/password: enter creds, if TOTP required prompt for code, login, store token.
|
||
2. Sync Tactical Clients:
|
||
- Click “Sync Clients” (organizations).
|
||
- Map Tactical Clients to Alga Clients (companies) in an org mapping table.
|
||
3. Sync Assets:
|
||
- Click “Sync Devices”.
|
||
- Alga upserts Assets and extension records and creates external mappings.
|
||
4. Realtime alerts:
|
||
- Admin copies webhook URL + secret, configures Tactical alert-action webhook with `X-Alga-Webhook-Secret`.
|
||
- Alerts trigger/resolve -> Alga receives webhook -> stores alert -> refreshes affected asset.
|
||
5. Optional: “Sync Alerts” to backfill alerts from Tactical.
|
||
|
||
## UX / UI Notes
|
||
|
||
- Tactical RMM should appear next to NinjaOne under the Integrations “RMM” category tab.
|
||
- Settings card should match the “feel” of NinjaOne settings:
|
||
- Status panel (connected/disconnected, last sync, counts).
|
||
- Credential management section (masked + update).
|
||
- Sync buttons.
|
||
- Organization mapping section.
|
||
- Webhook section (URL, header name, secret, payload template).
|
||
- Since Tactical is CE + EE, the Tactical settings UI must not rely on EE-only dynamic imports.
|
||
|
||
## Requirements
|
||
|
||
### Functional Requirements
|
||
|
||
1. Connection status
|
||
- Show whether Tactical is configured and reachable.
|
||
- Show instance URL and auth mode.
|
||
2. Credential storage
|
||
- Store and retrieve per-tenant credentials via secret provider.
|
||
- Mask secrets in UI (show only last 4 chars).
|
||
3. Sync clients (organizations)
|
||
- Fetch Tactical Clients via beta API.
|
||
- Upsert `rmm_organization_mappings` for provider `tacticalrmm`.
|
||
4. Org mapping management
|
||
- Allow selecting an Alga Client for each Tactical Client mapping.
|
||
- Persist `auto_sync_assets` toggles.
|
||
5. Sync devices (agents)
|
||
- For each mapped Tactical Client:
|
||
- fetch sites (paged) and agents (paged and filtered by `client_id`).
|
||
- upsert `assets` + extension data.
|
||
- upsert `tenant_external_entity_mappings` for the agent.
|
||
- mark missing agents as inactive (optional; see Open Questions).
|
||
6. Agent status mapping
|
||
- Compute `online|offline|overdue` using the provided deterministic rules from `last_seen`, `offline_time`, `overdue_time`.
|
||
- Persist status to `assets.agent_status`.
|
||
7. Realtime alerts via webhooks
|
||
- Provide `POST /api/webhooks/tacticalrmm`.
|
||
- Validate `X-Alga-Webhook-Secret`.
|
||
- Accept a small JSON contract (required: `agent_id`; optional: `alert_id`, `event`, `severity`, `message`, `alert_time`, `client_id`, `site_id`).
|
||
- Upsert `rmm_alerts` and associate to an asset when possible.
|
||
- Trigger “sync single agent” after alert receives/resolves.
|
||
8. Alert backfill (optional but planned)
|
||
- Use Tactical alerts endpoint to fetch active/recent alerts and upsert into `rmm_alerts`.
|
||
9. Software inventory ingestion (bulk, cached)
|
||
- Use Tactical `GET /software/` to ingest cached software inventory without per-agent refresh.
|
||
|
||
### Non-functional Requirements
|
||
|
||
- Fleet-scale pagination: use beta endpoints with `page_size=1000` and loop pages.
|
||
- Resilience:
|
||
- Handle 401 by re-authing (username/password mode) or failing with actionable error (API key mode).
|
||
- Avoid per-agent “refresh” calls by default (software refresh is expensive).
|
||
- Multi-provider safety: Tactical must not break NinjaOne; providers must co-exist in the same tenant.
|
||
|
||
## Data / API / Integrations
|
||
|
||
Point the integration at the Tactical **API host** (the `api.` subdomain), for example `https://api.example.com`. Do not use the dashboard host (`rmm.`). The dashboard serves the single-page app and returns its HTML with a `200` for every path, so sync reads zero records and silently does nothing.
|
||
|
||
Tactical's **Beta API must be enabled** for inventory sync. Set `BETA_API_ENABLED = True` in Tactical and restart it. While it is off, the `/beta/v1/*` endpoints return `404` and both the connection test and sync fail.
|
||
|
||
Tactical endpoints (base URL `https://<tactical-api-host>`, served at the root with no `/api` prefix):
|
||
|
||
- Auth (username/password):
|
||
- `POST /v2/checkcreds/` `{ username, password }` -> `{ totp: true }` or short-lived token
|
||
- `POST /v2/login/` `{ username, password, twofactor? }` -> Knox token response
|
||
- Auth header: `Authorization: Token <knox_token>`
|
||
- Auth (api key):
|
||
- Auth header: `X-API-KEY: <key>`
|
||
- Inventory (beta API, requires `BETA_API_ENABLED`):
|
||
- `GET /beta/v1/client/`
|
||
- `GET /beta/v1/site/?page_size=1000&page=N`
|
||
- `GET /beta/v1/agent/?client_id=<client_pk>&page_size=1000&page=N`
|
||
- Alerts:
|
||
- `PATCH /alerts/` with filter body for backfill/top-N
|
||
- Software:
|
||
- `GET /software/` bulk cached software inventory
|
||
- `PUT /software/<agent_id>/` per-agent refresh (non-goal by default)
|
||
|
||
Alga DB tables involved:
|
||
- `rmm_integrations` (one row per tenant+provider; store instance_url, is_active, settings JSON including webhook secret and auth mode).
|
||
- `rmm_organization_mappings` (Tactical Client PK mapped to Alga Client).
|
||
- `assets` + extension tables (workstation/server fields; cached “vitals” fields already exist).
|
||
- `tenant_external_entity_mappings` (agent_id crosswalk; store client/site in metadata).
|
||
- `rmm_alerts` for alert ingestion and association.
|
||
|
||
## Security / Permissions
|
||
|
||
- Configuration actions require settings permissions (same posture as NinjaOne).
|
||
- Secrets stored in tenant secret store (never in plaintext in DB tables).
|
||
- Webhook endpoint is unauthenticated but must require shared-secret header and be explicitly enabled/configured by admin.
|
||
|
||
## Observability
|
||
|
||
- Minimal: structured logs for sync start/finish/errors and webhook receives.
|
||
- (Optional) publish existing event-bus events where appropriate (RMM_WEBHOOK_RECEIVED, RMM_DEVICE_UPDATED, etc.) to align with NinjaOne patterns.
|
||
|
||
## Rollout / Migration
|
||
|
||
- Add `tacticalrmm` provider to RMM provider unions in Typescript.
|
||
- Potential migration if we choose to add new agent status value (`overdue`) to UI filters and any code expecting only online/offline/unknown.
|
||
- Ensure `/api/webhooks/tacticalrmm` is added to API auth middleware skip paths.
|
||
|
||
## Open Questions
|
||
|
||
- Should we treat Tactical “overdue” as a first-class `agent_status` enum value everywhere (recommended), or map it to `offline`?
|
||
- Do we support marking assets as inactive when agents disappear from Tactical (requires a “full inventory snapshot” delete detection)?
|
||
- Asset type mapping: do we classify Tactical agents as workstation vs server based on OS string heuristics, or introduce a Tactical-specific mapping override?
|
||
- Should alert backfill be limited to “active only” or allow recent resolved (time window)?
|
||
|
||
## Acceptance Criteria (Definition of Done)
|
||
|
||
1. Tactical RMM is visible and configurable in CE and EE under Integrations -> RMM.
|
||
2. Admin can connect using API key or username/password (with TOTP when required), and connection status is shown.
|
||
3. Admin can sync Tactical Clients and map them to Alga Clients.
|
||
4. Admin can sync Tactical Agents into Alga Assets; assets show provider + agent status + last seen where available.
|
||
5. Tactical alert-action webhook can be configured with custom headers; Alga validates `X-Alga-Webhook-Secret`, records alerts, and refreshes the affected asset.
|
||
6. Optional: alerts backfill and bulk software inventory ingestion work without per-agent refresh calls.
|