Hermes 284313f908
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
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

278 lines
20 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Scratchpad — Tanium RMM Integration Plan
- Plan slug: `tanium-rmm-integration-plan`
- Created: `2026-04-06`
## What This Is
Working notes for the Tanium RMM planning effort. This is intentionally biased toward repo seams, official Tanium guidance, and concrete implementation consequences.
## Decisions
- (2026-04-06) Tanium should not be implemented by copying NinjaOne or Tactical RMM. The missing seam is a shared provider registry plus shared normalized ingestion pipeline.
- (2026-04-06) `tenant_external_entity_mappings` is the main simplification-cascade seam. Treat external RMM providers as identity sources that feed one shared asset correlation/upsert path.
- (2026-04-06) Tanium v1 is pull-oriented and Gateway-first.
- (2026-04-06) Tanium Connect is a later optional capability for outbound/event-triggered delivery, not a prerequisite for inventory sync.
- (2026-04-06) Tanium Asset API is a fallback for aged-out endpoint coverage, not the primary default integration surface.
- (2026-04-06) Tanium Direct Connect / Threat Response should be capability-flagged later work, not v1 scope.
- (2026-04-06) Feature `F001` is complete: plan artifacts now capture exact documented Gateway query/object/mutation families for inventory, scope discovery, actions, Connect, and Direct Connect, plus Asset API fallback posture and `assetUpsertEndpoints` usage constraints.
## Discoveries / Constraints
- (2026-04-06) Current RMM UI is hard-coded in `packages/integrations/src/components/settings/integrations/RmmIntegrationsSetup.tsx`.
- (2026-04-06) Current public ingress handling is hard-coded in `server/src/middleware.ts` for `/api/integrations/ninjaone/callback`, `/api/webhooks/ninjaone`, and `/api/webhooks/tacticalrmm`.
- (2026-04-06) Shared RMM types already leak provider specifics, for example `ninja_instance_region` inside `ee/server/src/interfaces/rmm.interfaces.ts`.
- (2026-04-06) NinjaOne sync logic is split across provider-specific strategy/orchestration and duplicated persistence logic in Temporal activities.
- (2026-04-06) Tactical RMM keeps orchestration and persistence mostly inside one large action file, which reinforces the need for a shared ingestion seam before adding Tanium.
- (2026-04-06) Official Tanium docs say Gateway is preferred for querying online and offline systems, managing groups, deploying actions, establishing direct endpoint connections, and inserting/updating Asset records.
- (2026-04-06) Official Tanium docs say Connect is best for scheduled or event-triggered outbound delivery, including webhook destinations and detected-event delivery.
- (2026-04-06) Official Tanium docs say Asset API is useful for endpoints that have aged out of TDS.
- (2026-04-06) Feature `F002` implementation detail: provider unions are duplicated across `packages/types`, `server`, and `ee/server`; adding a provider requires touching all three type seams until a single source-of-truth type export is introduced.
- (2026-04-06) Feature `F003`/`F004` implementation detail: provider metadata and capability gating are now centralized in `packages/integrations/src/lib/rmm/providerRegistry.ts`, while provider settings components remain pluggable in UI composition code.
- (2026-04-06) Feature `F005``F009` implementation detail: normalized RMM contracts and the shared ingestion engine now live in `packages/integrations/src/lib/rmm/`, allowing provider fetchers to hand off provider-neutral snapshots into a single create/update/delete pipeline.
- (2026-04-06) Feature `F010``F018` implementation detail: Tanium v1 is implemented as pull-oriented server actions backed by a Gateway client plus shared ingestion, with no public webhook/callback route additions.
## Gateway Schema Findings
- (2026-04-06) Logged-in Gateway docs expose stable route families under `https://developer.tanium.com/apis/tanium_gateway_schema/{queries|mutations|objects}/...`.
- (2026-04-06) For Tanium inventory, the primary query surface is confirmed in the schema:
- `endpoints(...args)`
- `endpointCounts(input)`
- `endpointIdChanges(...args)`
- `endpointLastSeen(eids)`
- (2026-04-06) The endpoint object family is concrete and broad enough for normalized inventory snapshots:
- `Endpoint`
- `EndpointConnection`
- `EndpointEdge`
- `EndpointOS`
- `EndpointUser`
- `EndpointInstalledApplication`
- `EndpointMetric`
- `EndpointCompliance`
- (2026-04-06) The schema exposes a natural scope/group surface for client mapping:
- queries: `computerGroup(ref)`, `computerGroups(...args)`
- objects: `ComputerGroup`, `ComputerGroupConnection`, `ComputerGroupEdge`
- mutations also exist for later admin workflows: `computerGroupCreate(input)`, `computerGroupDelete(ref)`
- (2026-04-06) The schema exposes Connect as a first-class later event/export surface:
- queries: `connectConnection(ref)`, `connectConnections(...args)`, `connectRun(ref)`, `connectRuns(...args)`
- objects: `ConnectConnection`, `ConnectGraphConnection`, `ConnectRun`, `ConnectRunConnection`
- mutations: `connectConnectionStart(input)`, `connectConnectionStop(input)`
- (2026-04-06) The schema exposes Direct Connect as a first-class later remote-action surface:
- queries: `directConnectConnectionStatus(input)`, `directConnectEndpoint(input)`, `directConnection(connectionID)`, `directEndpoint(input)`
- mutations: `directConnectOpen(input)`, `directConnectClose(input)`, `directConnectPing(input)`, `directConnectProcessTerminate(input)`
- objects: `DirectConnect`, `DirectConnectOpenPayload`, `DirectConnectClosePayload`, `DirectConnectConnectionStatusPayload`, `DirectConnectPingPayload`
- (2026-04-06) Legacy direct-connect mutations still exist, but the docs explicitly mark them as not preferred:
- `closeDirectConnection(input)` is documented as legacy and says to use `directConnectClose` because the `directConnect*` APIs better support tracking slow-to-establish connections.
- `openDirectConnection(input)` and `pingDirectConnection(input)` still appear alongside the newer `directConnect*` family.
- (2026-04-06) Action and scheduled-action surfaces are confirmed in Gateway and should remain capability-gated later work:
- queries: `action(ref)`, `actions(...args)`, `actionGroup(ref)`, `actionGroups(...args)`, `scheduledAction(ref)`, `scheduledActions(...args)`
- mutations: `actionCreate(input)`, `actionPerform(input)`, `actionGroupCreate(input)`, `actionGroupDelete(ref)`, `scheduledActionApprove(ref)`, `scheduledActionCreate(input)`, `scheduledActionDelete(ref)`
- objects: `Action`, `ActionConnection`, `ActionGroup`, `ActionGroupConnection`, `ActionInfo`, `ScheduledAction`
- (2026-04-06) The logged-in object docs and screenshot evidence show `ScheduledAction` is a real first-class object with approval and scheduling metadata such as `approved`, `approver`, `comment`, `creator`, `distributeSeconds`, and `endTime`.
- (2026-04-06) `assetUpsertEndpoints(input)` is the key Tanium Gateway write surface around Asset-managed endpoint records:
- return type: `AssetsUpsertPayload!`
- argument type: `AssetUpsertEndpointsInput!`
- docs say it upserts endpoint records in the given Asset Import API source using the Asset entity/attribute model
- docs say source keys must be present as entity values; matching keys update an existing endpoint, otherwise a new endpoint is created
- docs say TTL is updated for both Asset and TDS
- docs require the Asset solution and `Asset Api User Write`
- (2026-04-06) `assetsImport(input)` is explicitly deprecated in favor of `assetUpsertEndpoints(input)` because `assetUpsertEndpoints` supports multi-row/reference entities.
- (2026-04-06) Working decision from the schema:
- v1 scope discovery should target `computerGroups`
- v1 inventory sync should target `endpoints` and normalize from the `Endpoint*` object family
- `endpointIdChanges` / `endpointLastSeen` are candidates for incremental sync later, not prerequisites for v1
- Direct Connect, action execution, scheduled actions, and Connect export jobs are later capability flags, not part of the base Tanium inventory adapter
- (2026-04-06) Docs-site gotcha: navigating directly to deep links or clicking raw anchors can bounce the browser into Redocly login. Expanding schema sections and changing routes inside the existing authenticated page was reliable; use that workflow if more schema mining is needed.
## Commands / Runbooks
- (2026-04-06) Find the live Tanium docs browser pane:
- `alga-dev list-browsers --allTabs --pretty`
- (2026-04-06) Pull Tanium doc text from the live pane:
- `alga-dev browser-eval --paneId=<pane> --script='(() => (document.body.innerText || \"\").slice(0, 10000))()'`
- (2026-04-06) Fetch official markdown docs directly:
- `python3 - <<'PY'`
- `import requests`
- `print(requests.get('https://developer.tanium.com/guides/core-platform/integration_methods.md').text)`
- `PY`
- (2026-04-06) Scaffold this plan:
- `python3 /Users/roberisaacs/.codex/skills/alga-plan/scripts/scaffold_plan.py --slug tanium-rmm-integration-plan "Tanium RMM Integration Plan"`
- (2026-04-06) Validate F002 targeted changes:
- `npx nx test @alga-psa/assets --testFile=packages/assets/src/lib/rmmProviderDisplay.test.ts`
- `npx nx test @alga-psa/types`
- (2026-04-06) Validate F003/F004 targeted changes:
- `npx nx typecheck @alga-psa/integrations`
- (2026-04-06) Validate F005-F009 targeted changes:
- `npx nx typecheck @alga-psa/integrations`
- (2026-04-06) Validate F010-F018/F020 targeted changes:
- `npx nx typecheck @alga-psa/integrations`
- `npx nx typecheck sebastian-ee`
- (2026-04-06) Validate Tanium + shared RMM tests:
- `npx nx test sebastian-ee -- --run src/__tests__/unit/integrations/taniumActions.test.ts src/__tests__/unit/integrations/TaniumIntegrationSettings.ui.test.tsx src/__tests__/unit/integrations/rmm/syncOrchestration.test.ts`
- `cd server && npx vitest run ../packages/integrations/src/lib/rmm/providerRegistry.test.ts ../packages/integrations/src/components/settings/integrations/RmmIntegrationsSetup.registry.test.tsx ../packages/integrations/src/lib/rmm/sharedAssetIngestionService.test.ts`
- Note: `@alga-psa/integrations` Nx test target currently points to deprecated `@nx/vite:test` without a config file; targeted package tests were executed via server Vitest harness instead.
## Implementation Log
- (2026-04-06) `F002` completed.
- Added `tanium` to `RmmProvider` unions in:
- `packages/types/src/interfaces/asset.interfaces.ts`
- `server/src/interfaces/asset.interfaces.tsx`
- `ee/server/src/interfaces/rmm.interfaces.ts`
- Refactored EE RMM settings typing to separate common settings from provider-specific payloads:
- introduced `RmmCommonIntegrationSettings`
- introduced typed provider payloads (`NinjaOneRmmProviderSettings`, `TacticalRmmProviderSettings`, `TaniumRmmProviderSettings`)
- introduced `RmmProviderConfigurationPayload` and `provider_settings`
- retained `ninja_instance_region` as a compatibility bridge during migration
- Updated provider display utilities/tests to include `tanium`:
- `packages/assets/src/lib/rmmProviderDisplay.ts`
- `packages/assets/src/lib/rmmProviderDisplay.test.ts`
- Expanded type-level coverage:
- `packages/types/src/interfaces/rmmProvider.typecheck.test.ts`
- (2026-04-06) `F003` completed.
- Added shared provider registry with normalized provider metadata and capability flags:
- `packages/integrations/src/lib/rmm/providerRegistry.ts`
- Registry now captures connection/scope/device/events/remote-action capability state per provider and centralizes enterprise/feature-flag availability gates.
- (2026-04-06) `F004` completed.
- Refactored settings selector UI to render provider cards from registry output instead of hard-coded provider branches:
- `packages/integrations/src/components/settings/integrations/RmmIntegrationsSetup.tsx`
- Added Tanium placeholder settings component wiring behind the `tanium-rmm-integration` feature flag so registry-driven rendering can include Tanium metadata without breaking current behavior.
- (2026-04-06) `F005` completed.
- Added normalized provider contracts for scopes and device snapshots:
- `packages/integrations/src/lib/rmm/contracts.ts`
- (2026-04-06) `F006` completed.
- Added shared RMM asset correlation/upsert ingestion service centered on `tenant_external_entity_mappings`:
- `packages/integrations/src/lib/rmm/sharedAssetIngestionService.ts`
- (2026-04-06) `F007` completed.
- Shared ingestion create path now provisions:
- base `assets` row
- extension row (`workstation_assets` / `server_assets` when applicable)
- `tenant_external_entity_mappings` link
- Creation is driven from normalized snapshots and resolved client mapping.
- (2026-04-06) `F008` completed.
- Shared ingestion update path now:
- updates mapped assets
- upserts extension fields
- refreshes mapping metadata/sync timestamps
- Includes fallback correlation to an existing asset by `rmm_provider + rmm_device_id` when an external mapping row is missing.
- (2026-04-06) `F009` completed.
- Shared ingestion now handles lifecycle states `deleted`/`tombstoned` with a single path that marks asset inactive/offline and updates mapping status/metadata (`deleted`, `deletedAt`).
- (2026-04-06) `F010` completed.
- Added transport-agnostic sync orchestration seam:
- `ee/server/src/lib/integrations/rmm/sync/syncOrchestration.ts`
- Tanium full sync now executes through this seam (`runRmmSyncWithTransport`) with direct transport active by default and temporal transport hook points available via env configuration.
- (2026-04-06) `F011` completed.
- Added Tanium Gateway client/query runner:
- `ee/server/src/lib/integrations/tanium/taniumGatewayClient.ts`
- Includes authenticated GraphQL query runner, connection test, scope discovery (`computerGroups`), endpoint inventory (`endpoints`), and optional Asset API fallback fetcher.
- (2026-04-06) `F012` completed.
- Added tenant-scoped Tanium connection lifecycle actions:
- `ee/server/src/lib/actions/integrations/taniumActions.ts`
- Implements settings retrieval, configuration save, connection test (state transition to active on success), and disconnect (secret cleanup + inactive row state).
- (2026-04-06) `F013` completed.
- Added Tanium provider settings UI:
- Enterprise implementation: `ee/server/src/components/settings/integrations/TaniumIntegrationSettings.tsx`
- CE stub path for shared alias resolution: `packages/ee/src/components/settings/integrations/TaniumIntegrationSettings.tsx`
- Selector wiring updated via shared provider registry rendering:
- `packages/integrations/src/components/settings/integrations/RmmIntegrationsSetup.tsx`
- (2026-04-06) `F014` completed.
- Implemented Tanium scope discovery action (`syncTaniumScopes`) with `rmm_organization_mappings` upsert/refresh behavior.
- (2026-04-06) `F015` completed.
- Tanium settings now exposes mapping management using existing `rmm_organization_mappings` flow and client assignment updates (`updateTaniumOrganizationMapping`).
- (2026-04-06) `F016` completed.
- Implemented Tanium full inventory sync action (`triggerTaniumFullSync`) that fetches endpoint inventory, normalizes snapshots, and calls shared ingestion (`ingestNormalizedRmmDeviceSnapshot`).
- (2026-04-06) `F017` completed.
- Implemented constrained Asset API fallback path in full sync when a mapped scope has no Gateway endpoints and fallback is enabled.
- (2026-04-06) `F018` completed.
- Tanium phase-1 implementation remains pull-only: no new `/api/webhooks/*` or callback ingress routes added.
- (2026-04-06) `F020` completed.
- Tanium actions reuse existing `rmm_integrations` sync lifecycle fields (`sync_status`, `sync_error`, `last_sync_at`, `last_full_sync_at`) rather than introducing a separate status subsystem.
- (2026-04-06) `F019` completed.
- Legacy NinjaOne and Tactical settings flows remain operable and are now selected via registry-driven adapter wiring in `RmmIntegrationsSetup` (`providerSettingsComponents`) instead of bespoke top-level branching, allowing transition without rewriting either provider stack.
## Test Implementation Log
- (2026-04-06) `T001` completed.
- Added provider registry capability test:
- `packages/integrations/src/lib/rmm/providerRegistry.test.ts`
- Added selector registry-rendering test:
- `packages/integrations/src/components/settings/integrations/RmmIntegrationsSetup.registry.test.tsx`
- (2026-04-06) `T002` completed.
- Added shared ingestion create-path test:
- `packages/integrations/src/lib/rmm/sharedAssetIngestionService.test.ts`
- (2026-04-06) `T003` completed.
- Added shared ingestion update/no-duplicate test:
- `packages/integrations/src/lib/rmm/sharedAssetIngestionService.test.ts`
- (2026-04-06) `T004` completed.
- Added scope-discovery mapping preservation test in Tanium actions suite:
- `ee/server/src/__tests__/unit/integrations/taniumActions.test.ts`
- (2026-04-06) `T005` completed.
- Added Tanium full-sync happy-path test asserting Gateway fetch + shared ingestion invocation + completed sync status:
- `ee/server/src/__tests__/unit/integrations/taniumActions.test.ts`
- (2026-04-06) `T006` completed.
- Added Tanium fallback test asserting Asset API path ingestion when Gateway scope returns zero endpoints:
- `ee/server/src/__tests__/unit/integrations/taniumActions.test.ts`
- (2026-04-06) `T007` completed.
- Added connection failure test asserting inactive integration and actionable auth error:
- `ee/server/src/__tests__/unit/integrations/taniumActions.test.ts`
- (2026-04-06) `T008` completed.
- Added UI integration-style test for Tanium settings configuration/test/scope-discovery flow:
- `ee/server/src/__tests__/unit/integrations/TaniumIntegrationSettings.ui.test.tsx`
- (2026-04-06) `T009` completed.
- Added shared sync orchestration seam tests:
- `ee/server/src/__tests__/unit/integrations/rmm/syncOrchestration.test.ts`
## Links / References
- Official docs:
- https://developer.tanium.com/guides/core-platform/integration_methods
- https://developer.tanium.com/guides/core-platform/integration_methods.md
- https://developer.tanium.com/apis/api_intro
- https://help.tanium.com/bundle/ug_gateway_cloud/page/gateway/index.html
- https://help.tanium.com/bundle/ug_gateway_cloud/page/gateway/gateway.html
- Alga repo references:
- `server/migrations/20251124000001_create_rmm_integration_tables.cjs`
- `server/migrations/20250502173321_create_tenant_external_entity_mappings.cjs`
- `packages/integrations/src/components/settings/integrations/RmmIntegrationsSetup.tsx`
- `server/src/middleware.ts`
- `ee/server/src/interfaces/rmm.interfaces.ts`
- `ee/server/src/lib/integrations/ninjaone/sync/syncStrategy.ts`
- `ee/server/src/lib/integrations/ninjaone/sync/syncEngine.ts`
- `ee/temporal-workflows/src/activities/ninjaone-sync-activities.ts`
- `packages/integrations/src/actions/integrations/tacticalRmmActions.ts`
- `packages/integrations/src/lib/rmm/tacticalrmm/tacticalApiClient.ts`
## Open Questions
- What exact Tanium auth material should Alga store per tenant for Gateway access?
- Do we need incremental sync in Tanium v1, or is full inventory sync enough until real-world volume proves otherwise?
- Is there an officially documented programmatic management surface for Tanium Connect destinations/jobs, or would later Connect event delivery be console-configured?
- Does `ComputerGroup` map cleanly enough to `rmm_organization_mappings` for real MSP tenant usage, or do we need a provider-specific scope-normalization rule on top of Tanium groups?
- Which exact `Endpoint` fields and nested objects are sufficient for Algas normalized device snapshot without overspecifying the first adapter?