← dashboard

nrvirtdisplay

model: (cli default) cpp static analysis on 0 PR(s) seen
workspaceninjarmm jira projectNJ review targetsmain · master · develop · release/* · *_release thresholdsseverity ≥ minor · confidence ≥ medium · cap 12 max diff0.4 MB pollevery 300s

What this is

NinjaRemote virtual-display driver (Windows) used by ncpeer to create a virtual monitor for headless / multi-monitor remote sessions.

Project primer

Durable orientation injected into every review as .ai-review/project.md.

nrvirtdisplay — NinjaRemote virtual display driver (review primer)

Windows Indirect Display Driver (IDD) in C++: a **user-mode UMDF2 driver on the WDK IddCx
framework** that presents a synthetic display adapter + virtual monitor(s) to Windows, so
ncpeer can drive headless machines and add monitors for remote sessions. It is a DLL loaded by
the UMDF host process, not a .sys.

Architecture (durable map)

negotiation, swap-chain assign/unassign) and DDI registration.

chain) via a D3D11/DXGI device.

owned by WDF object lifetimes.

What matters most when reviewing here (durable risk areas)

output structures exactly as the framework expects — errors leave the display subsystem
inconsistent or degrade it silently.

hold/double-release → GPU leaks or hangs. On D3D device loss, delete the swap-chain so IddCx
retries — otherwise the pipeline stalls.

use-after-free; WDF object lifetime is the only guard — check callback-context races.

avoid uncaught exceptions / unhandled WDF errors.

arches; a catalog mismatch breaks install under Secure Boot / DSE.

Security-sensitive zones

The INF permits kernel-mode clients to open the UMDF device — treat buffers crossing the IddCx
boundary as untrusted; OS-sized output arrays must not be over-written (OOB). Don't log
sensitive handles/LUIDs at production trace levels.

Compatibility surfaces (contracts that must not silently break)

addresses the driver by these; renaming/restructuring breaks install on existing deployments.

Conventions & gotchas

(WdfDeviceCreateDeviceInterface) lasts the WDFDEVICE's whole life and is only toggled via
WdfDeviceSetDeviceInterfaceState, never deleted; a set-once "created" flag that is never
cleared is normal, not a leak. Keep it distinct from the per-monitor / swap-chain objects,
which DO have real create/destroy pairs (and those are the actual lifetime risk here).

appear in only one configuration.

_Orientation only — verify current specifics in the code; this describes durable architecture &
risk areas, not a snapshot._

Ecosystem map

Shared cross-project relationships, injected as .ai-review/ecosystem.md.

NinjaRemote / NinjaOne project ecosystem (relationship map)

How the monitored repos relate — so a change in one repo is reviewed with its blast
radius in mind (a change upstream of ncpeer can break ncpeer even if it looks local).
Orientation only; verify specifics in code.

NinjaRemote product

speak the NCRP wire protocol (protocol/format changes must stay compatible across
client and server versions).

Cloud-side relays of the ninja-remote system (AWS-hosted, Python/Go)

URLs, it pairs them and forwards frames verbatim. Signed join URLs are minted by the
Ninja backend — the signature scheme is a backend⇄relay contract, and the frame
semantics are a peer⇄peer contract.

a signed upload leg streams to a signed download leg through memory (never stored).
Two parallel implementations (Python ftsv2/ + Go fts_go/) must stay behaviorally
identical; the URL/signature scheme is shared-family with websocket-switch.
NinjaRemote file-transfer features ride on these relays when peers can't go direct.

Pulled INTO ncpeer (and sometimes nmsnj) — upstream of the products

or behaviour change here affects both consumers.

build against**. A dependency bump changes what those products link (security/ABI/build).

through the ncpeer_vcpkg overlay.

Largely independent

shares nccommon and ncpeer_vcpkg with ncpeer.

part of the remote-desktop family). Runs as a child process of the NinjaRMM agent (the
parent owns install/upgrade/policy/launch); NinjaFlow owns the CLI contract, config schema,
credential precedence, DB schema/migrations, and exit-code meanings the parent consumes
those are cross-process contracts. Submits telemetry to the Ninja Backend. Shares no code with
ncpeer/nmsnj; adjacent to nmsnj only in domain (network), not in implementation.

not part of any product's build. It consumes the SBOMs the other products' pipelines emit
(Ninja-Remote/ncpeer, NMS/nmsnj, NinjaFlow all appear in its scope maps), scans them for CVEs
and files Jira issues — a downstream *security-scanning* relationship, not a code dependency.
Shares no code with the others; has its own DB/schema and a toolbox submodule.

authentication component: its pam_ninja.so gates SSH reverse-tunnel access into
Ninja infrastructure with a time-based OTP. Shares no code with the other repos; its
blast radius is operational (who can SSH-tunnel into hosts), not code-level. The client OTP
generators and the module must agree on the OTP scheme + shared secret.

Review implications

these are *upstream* of ncpeer (and nccommon/vcpkg also of nmsnj) — weigh the consumer
side: API/ABI compatibility, build impact, and cross-platform reach.

contract.

Also in every review's context

The reviewer instructions CLAUDE.md (rules, house C++ style, output schema); the PR/ticket block pr.md (title, description, linked Jira + acceptance criteria, commits, changed files); the full diff.patch; and deterministic static_analysis.md (cppcheck on changed lines).