From 4cf34f52213fc1c87d1ecab537f36004263d2bbf Mon Sep 17 00:00:00 2001 From: Howard Enos Date: Sun, 21 Jun 2026 10:14:23 -0700 Subject: [PATCH] feat(bitdefender): doc-verify assignPolicy/push + add full-API build-out tracker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - assign_policy: add inheritFromAbove option; mark VERIFIED via official docs (policyId/targetIds/forcePolicyInheritance/inheritFromAbove; not applied to ENFORCED-policy targets). - setPushEventSettings: documented serviceType (splunk/cef/jsonRPC), TLS 1.2+ receiver requirement, subscribeToEventTypes event-flag map; webhook receiver pattern noted. - api-reference.md: cite GravityZone Support Center as authoritative source. - add references/BUILDOUT.md — master checklist to implement every API method module-by-module; seeded with current done/todo/dead state. - memory: reference_gravityzone_support (+ index). selftest 42/42. Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/memory/MEMORY.md | 1 + .../memory/reference_gravityzone_support.md | 16 ++++ .../skills/bitdefender/references/BUILDOUT.md | 87 +++++++++++++++++++ .../bitdefender/references/api-reference.md | 14 ++- .claude/skills/bitdefender/scripts/gz.py | 6 +- .../skills/bitdefender/scripts/gz_client.py | 13 ++- 6 files changed, 130 insertions(+), 7 deletions(-) create mode 100644 .claude/memory/reference_gravityzone_support.md create mode 100644 .claude/skills/bitdefender/references/BUILDOUT.md diff --git a/.claude/memory/MEMORY.md b/.claude/memory/MEMORY.md index 8a6ed434..2aed6399 100644 --- a/.claude/memory/MEMORY.md +++ b/.claude/memory/MEMORY.md @@ -2,6 +2,7 @@ ## Reference - [ACG resource map](reference_resource_map.md) — **READ THIS FIRST** when a task references a server/service/tenant/API. What we have access to, how to connect from this machine, per-machine exceptions, gotchas. Points at the detail files below. +- [GravityZone support center](reference_gravityzone_support.md) — Authoritative Bitdefender GravityZone product + Public API docs; use to confirm UNVERIFIED `bitdefender` skill methods/param shapes (push setPushEventSettings, assignPolicy, report/account writes, maintenancewindows/integrations names). - [GURU-5070 Rust toolchain](reference_guru5070_rust_toolchain.md) — GURU-5070 now has cargo + MSVC + protoc; build/clippy/test guru-connect LOCALLY (set PROTOC to the winget path) instead of the build host. CI only clippy-checks the Linux server, not the Windows agent. - [ACG Office Network Infrastructure](infra_office_network.md) — IPs/hosts/roles for pfSense/Jupiter/VMs/Docker. Check before assuming; .21 (Uranus) is storage. - [Power Failure Runbook](../POWER_FAILURE_RUNBOOK.md) — Recovery order after a power event: Tailscale routes, libvirt/VMs, Seafile, NPM/DNS. diff --git a/.claude/memory/reference_gravityzone_support.md b/.claude/memory/reference_gravityzone_support.md new file mode 100644 index 00000000..dfdc0485 --- /dev/null +++ b/.claude/memory/reference_gravityzone_support.md @@ -0,0 +1,16 @@ +--- +name: reference_gravityzone_support +description: Authoritative GravityZone product + Public API documentation (Bitdefender Support Center) +metadata: + type: reference +--- + +GravityZone Support Center — authoritative docs for the Bitdefender product and +its Public JSON-RPC API (methods, params, modules): +https://www.bitdefender.com/business/support/en/77211-79436-welcome-to-gravityzone.html + +Use it to confirm UNVERIFIED methods/param shapes before relying on them in the +`bitdefender` skill — e.g. `push.setPushEventSettings` nested shape, +`network.assignPolicy` options, report/account write methods, and the correct +`maintenancewindows`/`integrations` method names. The skill's own verified-vs- +unverified spec lives in `.claude/skills/bitdefender/references/api-reference.md`. diff --git a/.claude/skills/bitdefender/references/BUILDOUT.md b/.claude/skills/bitdefender/references/BUILDOUT.md new file mode 100644 index 00000000..2e0b9b57 --- /dev/null +++ b/.claude/skills/bitdefender/references/BUILDOUT.md @@ -0,0 +1,87 @@ +# Bitdefender skill — full API build-out tracker + +Goal: implement EVERY GravityZone Public API method the docs expose (and the +tenant license allows), one module at a time. Source of truth for method/param +shapes: the GravityZone Support Center +(https://www.bitdefender.com/business/support/en/77209-125277-public-api.html). + +Legend: `[x]` wrapped + tested · `[ ]` todo · `[~]` partial/unverified · +`[DEAD]` in key scope but license/feature OFF on this tenant. + +Per-module workflow: fetch module doc -> list methods + params -> add to +`gz_client.py` + `gz.py` (gate state-changing behind `--confirm`) -> test +(reads live; writes gated-only, never executed on prod during build) -> update +`api-reference.md` + tick here. + +--- + +## general / authentication +- [x] getApiKeyDetails + +## licensing +- [x] getLicenseInfo +- [ ] (enumerate: getMonthlyUsage? / others) + +## companies +- [x] getCompanyDetails +- [ ] getCompaniesList / getCompanyDetailsByUser +- [ ] createCompany / updateCompany / deleteCompany / suspend / activate (enumerate; gated) + +## network +- [x] getNetworkInventoryItems · getEndpointsList · getManagedEndpointDetails +- [x] getScanTasksList · createScanTask · moveEndpoints +- [x] createCustomGroup · deleteCustomGroup · moveCustomGroup · deleteEndpoint +- [x] assignPolicy +- [ ] createReconfigureClientTask (gated) +- [ ] createUninstallTask (gated) +- [ ] setEndpointLabel +- [ ] (enumerate remaining: getEndpointsCounts, getManagedEndpointDetails opts, etc.) + +## packages +- [x] getPackagesList · createPackage · getInstallationLinks · deletePackage +- [ ] getPackageDetails (param: packageId) +- [ ] (enumerate remaining) + +## policies +- [x] getPoliciesList · getPolicyDetails (FULL config) +- [x] assignPolicy (lives in /network) +- [ ] (confirm no other policy methods exist) + +## reports +- [x] getReportsList +- [ ] createReport (param: name, type, targetIds, ...) (gated-ish) +- [ ] getDownloadLinks · deleteReport (enumerate) + +## quarantine +- [x] getQuarantineItemsList (computers) +- [ ] createRemoveQuarantineItemTask (gated) +- [ ] createRestoreQuarantineItemTask (gated) +- [ ] exchange quarantine variants (enumerate) + +## incidents / EDR +- [x] getBlocklistItems · addToBlocklist · removeFromBlocklist +- [x] createIsolateEndpointTask · createRestoreEndpointFromIsolationTask +- [DEAD] getIncidentsList (Method not found on this tenant) +- [ ] custom rules / changeIncidentStatus / updateIncidentNote (enumerate; likely EDR-license gated) + +## push (event service) +- [x] getPushEventSettings · getPushEventStats · setPushEventSettings +- [ ] sendTestPushEvent (enumerate) + +## accounts (fully enumerated from docs) +- [x] getAccountsList +- [x] getNotificationsSettings +- [ ] getAccountDetails +- [ ] createAccount (gated) +- [ ] updateAccount (gated) +- [ ] deleteAccount (gated) +- [ ] configureNotificationsSettings (gated) + +## integrations +- [ ] (enumerate; getPSAIntegrationList was a name-miss — find correct names) + +## maintenance windows +- [DEAD] getMaintenanceWindows / *List → "not available" on this tenant + +## patchmanagement / phasr +- [DEAD] license OFF (managePatchManagement=false; phasr feature off) diff --git a/.claude/skills/bitdefender/references/api-reference.md b/.claude/skills/bitdefender/references/api-reference.md index 3ace2359..794cae8b 100644 --- a/.claude/skills/bitdefender/references/api-reference.md +++ b/.claude/skills/bitdefender/references/api-reference.md @@ -1,5 +1,10 @@ # Bitdefender GravityZone Cloud Public API Reference +> **Authoritative product + API docs:** GravityZone Support Center — +> https://www.bitdefender.com/business/support/en/77211-79436-welcome-to-gravityzone.html +> (everything about the product and the Public API). Use it to confirm any +> UNVERIFIED method/param below before relying on it. + Verified spec for the methods used by this skill. Sourced from Bitdefender's archived Public API documentation. Methods are flagged **VERIFIED** (signature confirmed and exposed in the CLI) or **UNVERIFIED** (signature not confirmed — @@ -110,7 +115,7 @@ In `getNetworkInventoryItems` results, `type == 1` denotes a company node. |---|---|---|---| | `getPoliciesList` | `page?, perPage?` | VERIFIED | List policies (id, name). | | `getPolicyDetails` | `policyId` | VERIFIED | **Full** granular config (not shallow). | -| `assignPolicy` (`/network`) | `policyId, targetIds[], forcePolicyInheritance?` | VERIFIED LIVE (param shape) | Assign existing policy to endpoints/groups. Param shape confirmed via validation probe 2026-06-21. CLI `assign-policy`, gated. STATE-CHANGING. | +| `assignPolicy` (`/network`) | `policyId, targetIds[], forcePolicyInheritance?, inheritFromAbove?` | VERIFIED (official docs + probe) | Assign existing policy to endpoints/containers. NOT applied to targets with an ENFORCED policy. CLI `assign-policy`, gated. STATE-CHANGING. Docs: 77212-924802-assignpolicy.html | ## reports (`/reports`) — VERIFIED LIVE @@ -139,7 +144,12 @@ In `getNetworkInventoryItems` results, `type == 1` denotes a company node. |---|---|---|---| | `getPushEventSettings` | `{}` | VERIFIED LIVE | Current settings. CLI `push-settings`. | | `getPushEventStats` | `{}` | VERIFIED LIVE | Delivery stats. CLI `push-stats`. | -| `setPushEventSettings` | `status (req), serviceType, serviceSettings{url,requireValidSslCertificate,authorization}, subscribeToEventTypes?` | `status` VERIFIED (probe); nested shape UNVERIFIED | Configure the service. CLI `push-set`, gated. STATE-CHANGING. Needs a receiver URL. +| `setPushEventSettings` | `status (req), serviceType, serviceSettings{url,requireValidSslCertificate,authorization}, subscribeToEventTypes{}` | VERIFIED (official docs + probe) | Configure the service. `serviceType` ∈ `splunk`/`cef`/`jsonRPC`. Receiver MUST support TLS 1.2+. `subscribeToEventTypes` is a map of event flags (av, fw, aph, registration, task-status, modules, network-sandboxing, antiexploit, dp, uc, …) set true to subscribe. Returns bool. CLI `push-set`, gated. STATE-CHANGING. Needs a receiver URL. Docs: 77209-135319-setpusheventsettings.html + +> Receiver pattern for the webhook (Phase-2): stand up an HTTPS endpoint (TLS +> 1.2+, valid cert) that accepts GravityZone's event POSTs — a coord-API route +> or an RMM ingest route — then `push-set --status 1 --url +> --confirm`. `serviceType jsonRPC` posts JSON-RPC event batches. ## quarantine (`/quarantine`) diff --git a/.claude/skills/bitdefender/scripts/gz.py b/.claude/skills/bitdefender/scripts/gz.py index f638107c..fbfff980 100644 --- a/.claude/skills/bitdefender/scripts/gz.py +++ b/.claude/skills/bitdefender/scripts/gz.py @@ -276,7 +276,9 @@ def cmd_assign_policy(client, args): if not _gated(desc, args.confirm): return 3 result = client.assign_policy( - args.policy, args.targets, force_inheritance=args.force_inheritance + args.policy, args.targets, + force_inheritance=args.force_inheritance, + inherit_from_above=args.inherit_from_above, ) _emit({"assignedPolicy": args.policy, "targets": args.targets, "result": result}, args.json, _print_kv) @@ -668,6 +670,8 @@ def build_parser() -> argparse.ArgumentParser: help="One or more endpoint/group ids.") sp.add_argument("--force-inheritance", action="store_true", help="Force policy inheritance to sub-items.") + sp.add_argument("--inherit-from-above", action="store_true", + help="Inherit the policy from the parent group.") sp.add_argument("--confirm", action="store_true") sp = sub.add_parser("push-set", diff --git a/.claude/skills/bitdefender/scripts/gz_client.py b/.claude/skills/bitdefender/scripts/gz_client.py index c051c296..fae103f4 100644 --- a/.claude/skills/bitdefender/scripts/gz_client.py +++ b/.claude/skills/bitdefender/scripts/gz_client.py @@ -633,17 +633,22 @@ class GravityZoneClient: policy_id: str, target_ids: list[str], force_inheritance: bool = False, + inherit_from_above: bool = False, ) -> Any: """Assign an existing policy to endpoints/groups (network.assignPolicy). - Param shape VERIFIED LIVE via validation probe (2026-06-21): requires - `policyId` and `targetIds` (a list of endpoint/group ids). - `forcePolicyInheritance` is optional. STATE-CHANGING — gate at the call - site behind --confirm. + Param shape VERIFIED against the official docs + live validation probe + (2026-06-21): `policyId` and `targetIds` (endpoint/container ids) are + required; `forcePolicyInheritance` and `inheritFromAbove` are optional + bools. NOTE: the policy is NOT applied to targets that already carry an + ENFORCED policy. STATE-CHANGING — gate at the call site behind --confirm. + Docs: bitdefender.com/business/support/en/77212-924802-assignpolicy.html """ params: dict = {"policyId": policy_id, "targetIds": target_ids} if force_inheritance: params["forcePolicyInheritance"] = True + if inherit_from_above: + params["inheritFromAbove"] = True return self._jsonrpc_request("network", "assignPolicy", params) def list_scan_tasks(