feat(bdr-discovery): backup-eligibility discovery for Windows endpoints#81
Draft
Gumbees wants to merge 6 commits into
Draft
feat(bdr-discovery): backup-eligibility discovery for Windows endpoints#81Gumbees wants to merge 6 commits into
Gumbees wants to merge 6 commits into
Conversation
…67) * improvement(docs): sync CLAUDE.md with DTC canonical change-taxonomy Replace the deprecated enhancement/ + problem/ two-prefix model with the canonical four-prefix taxonomy (bug/, refactor/, improvement/, feature/) and two-tier GitHub labels (type:* + category:*). Mirrors https://kb.dtctoday.com/books/developer-operations-devops/page/change-taxonomy. - Rewrite Git Workflow section to reflect main-as-release (this repo has no development branch; the prior section described a model that did not match the actual repo). - Add Halo Type / Category / GitHub labels / Branch prefix / Default semver mapping table. - Note BREAKING: PR title override as future-state (no semver yet). - Add dependabot categorization rule and 'name the branch after the change' guidance. - Mark legacy enhancement/ and problem/ prefixes accepted on existing branches; new work uses the four-prefix model. - Add db-* to the Category Organization list (db-mysql/ exists on disk). * docs(taxonomy): add Enhancement/Refactor row + clarify Refactor spans both types
* Add NinjaRMM GUID to Halo PSA GUID Sync Script Syncs DTC Org GUID from NinjaRMM custom fields to DTC Client GUID field in Halo PSA for all matching clients by name. * Update ninja-halo-guid-sync.ps1 Fix Halo custom field name to CFDtcClientGuid * Fix NinjaClientSecret placeholder comment typo * Remove hardcoded credentials — replace with placeholders Secrets were exposed in script body. Rotated all credentials. Real values stored in NinjaRMM script body (never leaves Ninja) and 1Password. GitHub copy uses placeholders only. * Update script — use Script Variable injection for secrets Refactored to inject client secrets via NinjaRMM Script Variables at runtime. Client IDs hardcoded (not secrets). Secrets never stored in repo. Validated working in production. * Fix: Bring script into compliance with DTC PowerShell engineering standard Addresses CodeRabbit review concerns on PR #49: - Add RMM variable declaration block per script-template-powershell.ps1 - Add Start-Transcript/Stop-Transcript with C:\ProgramData\DTC\Logs\ output - Add $ScriptLogName and $Description audit trail variables - Replace Write-Host with Write-Information per output stream standard - Add $ErrorActionPreference = 'Stop' and $ProgressPreference = 'SilentlyContinue' - Add explicit exit codes (0/1/2 per DTC convention) - Wrap all work in try/catch/finally per page 3299
New SYSTEM-context Ninja script that decides whether an endpoint needs a backup. Hard signals (Hyper-V host -> NO; DC, Windows Server, non-embedded DB -> YES) decide outright; workstations with no DC/ server/DB signal get triaged by Claude (Opus 4.7) using a soft-signal census (user profile data, non-admin SMB shares, file-extension mix). Soft signals include Office (incl. macro-enabled variants), email stores, local DB files, QuickBooks, designer/CAD, DICOM (HIPAA), and virtual-disk files (.vhd/.vhdx/.vmdk/.vdi/.qcow2/.ova) -- local VMs almost always hold business data. Writes backupDiscoveryNeedsBackup + reason + AI verdict + HTML details + multi-line JSON payload to NinjaRMM custom fields. Reads the hostClassIs* fields from msft-windows-host-classification.ps1 when available; falls back to local Win32 detection so the script is resilient to inventory-not-yet-run cases. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Code review is billed via overage credits. To resume reviews, an organization admin can raise the monthly limit at claude.ai/admin-settings/claude-code.
Once credits are available, push a new commit or reopen this pull request to trigger a review.
The per-profile sweep previously walked only Desktop/Documents/Pictures/ Videos/Downloads, missing the default Outlook location entirely. A workstation with an archive PST in %LOCALAPPDATA%\Microsoft\Outlook\ would have been triaged as if it had no email data at all. Also exclude .ost bytes from the user-data footprint total: OSTs are server-side mailbox caches that routinely run 20+ GB and would false-positive the AI's ~5 GB business-data threshold. .ost still contributes to the extension count as a "user has email" presence signal; only its size is excluded. AI prompt updated to call PST presence out as a strong YES signal (unreplaceable user-created archive) and to treat .ost-only as presence-not-backup-needed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
OST files are offline caches of an Exchange/M365 mailbox -- the mailbox is already backed up in the cloud, so there's no reason to flag the local cache. Removed .ost from the extension census and dropped the OST-specific byte-skip workaround entirely. PSTs (and VHDs, QuickBooks files, Access databases, DICOM images, VM disks) can live anywhere on disk -- root of D:, C:\Backup, C:\Hyper-V, a custom data drive. The previous sweep only walked Desktop / Documents / Pictures / Videos / Downloads per profile, so anything outside those folders was invisible. Added Find-CriticalFiles which walks every fixed drive once (skipping Windows / Recycle Bin / System Volume Information / PerfLogs) and surfaces every match with path, kind, size, and modified time. Results land in soft_signals.critical_files in both the Claude payload and the final audit JSON, and the top 25 hits render in the HTML details field. The AI prompt was rewritten around the new block: a non-empty critical_files list is now an explicit YES signal, and OST is no longer mentioned. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… jitter Detection was enterprise-SQL-centric and blind to the dental engines that actually hold patient data. Rework signal collection to be dental-aware: - Test-HasDatabase: match services by Name AND DisplayName via an engine catalog. Dental PMS + QuickBooks engines (SQL Anywhere/Eaglesoft, Pervasive/Actian, Dentrix Ace/FairCom c-tree, DTX Studio Core, QuickBooksDB) are always customer data -> hard YES. Demote SQLWriter/SQLBrowser/SQLAgent/QBCFMonitor to informational companions so a VSS-writer/helper alone no longer forces a false hard YES. - Test-SoftDentServer: registry-based detection (HKLM\SOFTWARE\PWInc / PWSvr) since SoftDent core data is FairCom c-tree flat files with no service or distinctive extension; SoftDent server -> hard YES. - Imaging: add .dex (DEXIS) to the unreplaceable cross-drive scan and census. Add standard raster formats (png/jpg/jpeg/bmp/tif/tiff/gif/ heic/webp) to the census behind a 100 KB floor so icons/thumbnails are excluded (Test-CensusCountable). - Fleet jitter: random 0..ClaudeJitterMaxSeconds (default 600s) sleep before the Claude call in RMM mode to smear API load across a fleet run; documented that 600s only fits Tier 2+ Anthropic rate limits. - QuickBooks: data files scoped as soft signal; the QuickBooksDB service is the hard signal. Update Claude system prompt, AI payload, and HTML summary for the new signals. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
New SYSTEM-context NinjaRMM script that decides whether a Windows endpoint needs to be backed up.
DECISION:,REASONING:, andSHORT_SUMMARY:.msft-windows-host-classification.ps1) hasn't run yet, host-class fields read as null/missing and the script falls back to local Win32 detection (Get-CimInstance Win32_OperatingSystem,Get-Service NTDS,Get-WindowsFeature).File-extension census
Office (incl. macro-enabled and templates), email stores (.pst/.ost/.eml/.msg/.mbox), Access/SQLite/SQL dumps, QuickBooks variants, designer (.psd/.ai/.indd), CAD (.dwg/.step/.skp), DICOM (.dcm) for the dental practice fleet, and virtual disks (.vhd/.vhdx/.vmdk/.vdi/.qcow2/.ova/.ovf). The Claude prompt explicitly flags virtual disks + DICOM + local DB files as strong YES signals.
NinjaRMM custom fields written
backupDiscoveryHasDatabasebackupDiscoveryNeedsBackuppendingso the next scan can retrybackupDiscoveryDecisionReasonbackupDiscoveryAIVerdictnot-required/needed/not-needed/pending/failed-config/failed-retry-laterbackupDiscoveryDetailsbackupDiscoveryAIPayloadExit codes
0-- hard signals decided, or Claude returned a parseable verdict.1-- Claude was needed but unreachable / unparseable after retries (5 transient retries, 3 parse retries with exponential backoff).2-- Claude was needed but auth/config failed (missing key, 401/403, malformed request).Test plan
not-required(hard signal),needsBackup=1, reason"Domain Controller".needsBackup=0, reason cites Hyper-V host exclusion.needed.not-needed.$env:RMM="1"with all custom-field vars defaulted -> writes flagged correctly in transcript.anthropicApiKey-> exit 2,aiVerdict=failed-config; bogus key -> exit 2,aiVerdict=failed-configafter auth rejection.$env:WINDIR\logs\bdr-discovery-needs-backup-detect.log(interactive) and$env:RMMScriptPath\logs\(RMM).Ninja-Property-Get"Unable to find the specified field" returns are treated as missing (local-detection fallback fires) instead of being persisted as a value.🤖 Generated with Claude Code
Update — dental-aware detection, imaging census, fleet jitter (commit c06b476)
The original DB detection was enterprise-SQL-centric and missed every proprietary dental engine. This commit makes signal collection dental-aware.
Database detection (
Test-HasDatabasereworked) — now matches services on Name AND DisplayName via an engine catalog:SQLANYs_*/*SQL Anywhere*/*Sybase*, covers Eaglesoft generally), Pervasive/Actian PSQL (Dentrix), Dentrix Ace Server / FairCom c-tree, DTX Studio Core (DEXIS), QuickBooks DB Server (QuickBooksDB*).SQLWriter/SQLBrowser/SQLAgent/QBCFMonitorService/FDLauncher demoted to informational companions — recorded, never trigger. Fixes the false hard-YES where a lone VSS-writer/helper implied a customer DB.SoftDent (
Test-SoftDentServer, new) — registry-based, since core data is FairCom c-tree flat files with no service/extension. DetectsHKLM\SOFTWARE\PWInc(+ WOW6432Node), infers server role from thePWSvrsubkey /PWsvrprocess, surfaces a data-path value; SoftDent server → hard YES. Exact registry value names are inferred and want confirmation against a live SoftDent server.Imaging —
.dex(DEXIS) added to the unreplaceable cross-drive scan + census (DICOM already covered). Standard raster formats (png/jpg/jpeg/bmp/tif/tiff/gif/heic/heif/webp) added to the census behind a 100 KB floor (Test-CensusCountable) so icons/thumbnails/UI sprites don't inflate counts.QuickBooks — data files (
.qbw/.qbb/.qbm/.qba) scoped as a soft signal (may be copies); theQuickBooksDB*service is the hard signal (proves this box hosts the live company file).Fleet jitter — random
0..$env:ClaudeJitterMaxSeconds(default 600s) sleep before the Claude call in RMM mode to smear API load across a fleet run. Note: 600s only satisfies Tier 2+ Anthropic limits (1000 RPM). At Tier 1 (50 RPM) ~8000 endpoints need a ~5h window; the real fix is reaching Tier 2 or the Message Batches API.Still open
retry-afterheader on 429s (current Claude retry uses fixed backoff, which fights the API at fleet scale).