feat(bitdefender): doc-verify assignPolicy/push + add full-API build-out tracker

- 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) <noreply@anthropic.com>
This commit is contained in:
2026-06-21 10:14:23 -07:00
parent 5dc5f5f82d
commit 4cf34f5221
6 changed files with 130 additions and 7 deletions

View File

@@ -2,6 +2,7 @@
## Reference ## 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. - [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. - [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. - [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. - [Power Failure Runbook](../POWER_FAILURE_RUNBOOK.md) — Recovery order after a power event: Tailscale routes, libvirt/VMs, Seafile, NPM/DNS.

View File

@@ -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`.

View File

@@ -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)

View File

@@ -1,5 +1,10 @@
# Bitdefender GravityZone Cloud Public API Reference # 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 Verified spec for the methods used by this skill. Sourced from Bitdefender's
archived Public API documentation. Methods are flagged **VERIFIED** (signature archived Public API documentation. Methods are flagged **VERIFIED** (signature
confirmed and exposed in the CLI) or **UNVERIFIED** (signature not confirmed — 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). | | `getPoliciesList` | `page?, perPage?` | VERIFIED | List policies (id, name). |
| `getPolicyDetails` | `policyId` | VERIFIED | **Full** granular config (not shallow). | | `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 ## 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`. | | `getPushEventSettings` | `{}` | VERIFIED LIVE | Current settings. CLI `push-settings`. |
| `getPushEventStats` | `{}` | VERIFIED LIVE | Delivery stats. CLI `push-stats`. | | `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{<event flags>}` | 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 <that-endpoint>
> --confirm`. `serviceType jsonRPC` posts JSON-RPC event batches.
## quarantine (`/quarantine`) ## quarantine (`/quarantine`)

View File

@@ -276,7 +276,9 @@ def cmd_assign_policy(client, args):
if not _gated(desc, args.confirm): if not _gated(desc, args.confirm):
return 3 return 3
result = client.assign_policy( 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, _emit({"assignedPolicy": args.policy, "targets": args.targets,
"result": result}, args.json, _print_kv) "result": result}, args.json, _print_kv)
@@ -668,6 +670,8 @@ def build_parser() -> argparse.ArgumentParser:
help="One or more endpoint/group ids.") help="One or more endpoint/group ids.")
sp.add_argument("--force-inheritance", action="store_true", sp.add_argument("--force-inheritance", action="store_true",
help="Force policy inheritance to sub-items.") 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.add_argument("--confirm", action="store_true")
sp = sub.add_parser("push-set", sp = sub.add_parser("push-set",

View File

@@ -633,17 +633,22 @@ class GravityZoneClient:
policy_id: str, policy_id: str,
target_ids: list[str], target_ids: list[str],
force_inheritance: bool = False, force_inheritance: bool = False,
inherit_from_above: bool = False,
) -> Any: ) -> Any:
"""Assign an existing policy to endpoints/groups (network.assignPolicy). """Assign an existing policy to endpoints/groups (network.assignPolicy).
Param shape VERIFIED LIVE via validation probe (2026-06-21): requires Param shape VERIFIED against the official docs + live validation probe
`policyId` and `targetIds` (a list of endpoint/group ids). (2026-06-21): `policyId` and `targetIds` (endpoint/container ids) are
`forcePolicyInheritance` is optional. STATE-CHANGING — gate at the call required; `forcePolicyInheritance` and `inheritFromAbove` are optional
site behind --confirm. 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} params: dict = {"policyId": policy_id, "targetIds": target_ids}
if force_inheritance: if force_inheritance:
params["forcePolicyInheritance"] = True params["forcePolicyInheritance"] = True
if inherit_from_above:
params["inheritFromAbove"] = True
return self._jsonrpc_request("network", "assignPolicy", params) return self._jsonrpc_request("network", "assignPolicy", params)
def list_scan_tasks( def list_scan_tasks(