Files
claudetools/session-logs/2026-06/2026-06-21-howard-bitdefender-live-integration-test.md
Howard Enos aefbc8fce2 sync: auto-sync from HOWARD-HOME at 2026-06-21 16:14:48
Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-06-21 16:14:48
2026-06-21 16:15:20 -07:00

9.6 KiB

User

  • User: Howard Enos (howard)
  • Machine: Howard-Home
  • Role: tech

Session Summary

Continued the bitdefender skill work (after the earlier API build-out session) by running a full live integration test of the GravityZone control surface against a real endpoint, then tearing it down. The goal Howard set: prove every option/report/feature works on a test machine, not just probe param shapes.

Located the test machine via rmm-search (RMM-TEST-MACHINE, AZ Computer Guru / Howard-VM site, online agent 99d6d692-99e0-4359-9f9c-f43be89f49e5; a stale offline re-enrollment duplicate 7d3456f5 also exists). Created a GravityZone test group (ZZ-RMM-TEST) and a test install package (ZZ-RMM-TEST-PKG) under the ACG company 5c428b246c031893678b4569, and pulled install links.

The Bitdefender install was the hard part and drove several findings. The lightweight setup-downloader stub FAILS when run as SYSTEM via the RMM (exit 3, 0-byte installer.xml) and triggers a UAC prompt when run in context: user_session — both unacceptable for unattended deployment. Root cause: the stub needs an interactive elevated session and an external CDN fetch. The fix (matching how Syncro does it) is the OFFLINE FULL KIT (epskit_x64.zip, ~696MB) run by the SYSTEM-level agent: self-contained (no CDN fetch), already elevated (no UAC). The full kit needs API-key auth to download, so to keep the key off the endpoint and out of RMM command history, the kit was staged server-side: the GuruRMM server (its own root RMM agent) downloaded it into /var/www/gururmm/downloads/bdkit-test.zip (served anonymously over http), the endpoint pulled it keyless via BITS, extracted, and ran epskit_x64.exe /bdparams /silent under Task Scheduler (fire-and-forget). The BD API key that briefly appeared in RMM command_text during staging was then scrubbed from the RMM Postgres commands table (verified 0 commands expose secrets). Install succeeded (INSTALL EXIT=0, ~8.5 min) and the endpoint enrolled (managed=True).

With BD installed, exercised the full control surface live and fixed 5 doc-vs-live param-shape bugs the testing exposed. Then tore everything down: managed-uninstalled BD via deleteEndpoint (deleting a managed endpoint auto-creates an uninstall-client task — the GravityZone-initiated removal that bypasses tamper protection, which had blocked the local uninstall tool), deleted the test group + package, removed the staged kit, cleaned endpoint temp/tasks, and rebooted to finalize. selftest 75/75 throughout; all fixes committed and auto-synced.

Key Decisions

  • Install method = OFFLINE FULL KIT run as SYSTEM, not the downloader stub. The stub fails headless (exit 3) and needs UAC in a user session; the full kit is self-contained + SYSTEM-elevated. This is how Syncro/real RMMs deploy BD.
  • Stage the kit server-side (GuruRMM downloads dir, anonymous http) so the endpoint pulls keyless. Keeps the GZ API key off the client endpoint and out of RMM command history — mirrors Syncro keeping credentials server-side. Scrubbed the transient key from the RMM DB afterward.
  • Long endpoint ops (install) run fire-and-forget via Task Scheduler, verified by OUTCOME (GZ enrollment, log files), never live-polled. Per Howard's directive "this needs to happen without us monitoring it."
  • BD removal = GravityZone-initiated (deleteEndpoint -> auto uninstall-client task), not the local uninstall tool. The local BEST_uninstallTool.exe was blocked (exits instantly, no effect) by tamper/self-protection + session-0; the managed uninstall is server-authorized and bypasses that.
  • Did NOT execute write methods that would alter real partner-tenant data (create/delete client companies, console users, notification settings, the one real quarantine item on production DC ACG-DC16). Those stay param-shape + gating verified; executing them just to "tick a box" would create real junk/risk.

Problems Encountered

  • BD downloader stub exit 3 as SYSTEM / UAC in user_session -> switched to offline full kit (see decisions).
  • Full kit needs auth + endpoint link to office server is slow (~3 Mbps, 696MB) and exceeded RMM command timeouts -> staged server-side + pulled via BITS (resumable, survives timeouts).
  • BITS download completed but file not finalized (BITS holds temp until Complete-BitsTransfer) -> called Complete-BitsTransfer explicitly.
  • BD API key landed in RMM command_text during server-side staging -> redacted all matching commands rows via Postgres (peer-auth sudo blocked by agent no-new-privileges; used TCP PGPASSWORD instead; self-redacting pass removed the PG password too).
  • Local BEST_uninstallTool.exe did nothing (tamper/self-protection + session-0) -> used GravityZone-initiated uninstall via deleteEndpoint.
  • 5 doc-vs-live param mismatches (see Configuration Changes) -> fixed in the skill.
  • API 429 rate limit during rapid testing -> added pauses between calls.

Configuration Changes

All in .claude/skills/bitdefender/ (committed + auto-synced):

  • scripts/gz_client.py — 5 fixes: createCustomGroup uses groupName (not name); assignPolicy sends inheritFromAbove:false with policyId (dropped wrong inherit_from_above option); createIsolateEndpointTask/createRestoreEndpointFromIsolationTask use single endpointId (loop, not endpointIds array); deletePackage uses packageId (not packageName/companyId).
  • scripts/gz.py_print_kv tolerates list results (install-links/endpoint-tags); CLI updated (delete-package --id, dropped --inherit-from-above).
  • scripts/selftest.py — updated for new arg shapes; 75/75.
  • references/api-reference.md — live-verified param shapes for the 5 corrected methods.
  • .claude/memory/feedback_bitdefender_unattended_install.md, feedback_rmm_longops_fire_and_forget.md, reference_gravityzone_support.md (earlier in the day).

Credentials & Secrets

  • No new credentials created. GravityZone API key remains in SOPS vault msp-tools/gravityzone.sops.yaml field credentials.api_key (HTTP Basic: key as username, empty password). It was used to download the full kit; scrubbed from RMM command history after staging.
  • GuruRMM server SSH/DB (vault infrastructure/gururmm-server.sops.yaml): host 172.16.3.30, ssh user guru, postgres user gururmm. Used the server's own root RMM agent (no SSH needed) for staging + DB redaction.

Infrastructure & Servers

  • GravityZone Cloud Public API: https://cloud.gravityzone.bitdefender.com/api/v1.0/jsonrpc. ACG company 5c428b246c031893678b4569. Test endpoint GZ id 6a3849a7029f60770fa9d172.
  • Full-kit download (auth): .../api/v1.0/http/downloadPackageFullKit?packageId=<id>&downloadType=20 (x64). Anonymous downloader stub: cloud.gravityzone.bitdefender.com/Packages/BSTWIN/0/setupdownloader_[base64].exe. BEST uninstall tool: https://www.bitdefender.com/files/business/Tools/BEST_uninstallTool.exe (~296KB).
  • GuruRMM server 172.16.3.30: downloads dir /var/www/gururmm/downloads served at http://172.16.3.30/downloads/. gururmm linux agent id 9b92b187-98c7-41b0-9e97-1698d263c42d (runs as root; sandbox blocks sudo via no-new-privileges).
  • RMM-TEST-MACHINE: Windows 11, RMM agent 99d6d692-99e0-4359-9f9c-f43be89f49e5, Howard-VM site.

Commands & Outputs

  • Safe param discovery: gz.py raw --module M --method m --params '{}' --confirm -> "required parameter is missing : X".
  • Working install (offline, unattended): scheduled task running epskit_x64.exe /bdparams /silent as SYSTEM; BITS pull from http://172.16.3.30/downloads/bdkit-test.zip.
  • Working policy assign: assignPolicy {policyId, targetIds:[ep], inheritFromAbove:false} -> true. Inherit mode: {targetIds, inheritFromAbove:true}.
  • Working isolate/unisolate: createIsolateEndpointTask {endpointId} -> true; restore fails while isolate task in progress ("cannot be restored") -> wait + retry.
  • Managed uninstall: gz.py delete-endpoint <gzId> --confirm (creates uninstall-client task; agent self-removes; services gone, dir clears on reboot).
  • DB redaction: PGPASSWORD=... psql -h 127.0.0.1 -U gururmm -d gururmm -c "UPDATE commands SET command_text='[REDACTED]' WHERE command_text LIKE '%downloadPackageFullKit%';".

Pending / Incomplete Tasks

  • Write methods NOT executed (verified by shape+gating only; unsafe/infeasible on live partner tenant): company-create/suspend/activate/delete, account-create/update/delete, notif-configure, quarantine-remove/restore, custom-rule-create/delete (needs full EDR rule body), incident-status/note (getIncidentsList dead on tenant), push-set/push-test (needs a webhook receiver endpoint).
  • Push webhook receiver (HTTPS, TLS1.2+) still not built — required before push-set can be enabled (coord-API or RMM ingest route).
  • RMM push-deploy of BD could be packaged into the skill/rmm as a reusable unattended deploy (the staged-kit + scheduled-task pattern proven here).
  • packetdial skill still needs its NetSapiens API key provisioned (deferred to Mike, earlier).

Reference Information

  • GravityZone docs (authoritative): https://www.bitdefender.com/business/support/en/77211-79436-welcome-to-gravityzone.html ; assignPolicy 77212-924802; createCompany 77211-126236; setPushEventSettings 77209-135319; deleting-endpoints 77209-88049.
  • Skill tracker: .claude/skills/bitdefender/references/BUILDOUT.md (all live modules complete). Spec: references/api-reference.md.
  • Key commits (claudetools): 603773c assignPolicy/isolate fixes; delete_package fix + earlier groupName/_print_kv via auto-sync (be9d6c3 region). guru-rmm 58c1a96 (500-leak tail, earlier).
  • 5 doc-vs-live fixes: createCustomGroup(groupName), _print_kv(list), assignPolicy(inheritFromAbove:false), isolate/unisolate(endpointId), deletePackage(packageId).