feat(bitdefender): GravityZone Cloud Public API skill
Adds a /bitdefender skill that drives the ACG GravityZone partner tenant via the JSON-RPC Public API. Read + management ops (companies, endpoints, live security sweep, policies [read-only/shallow], packages, quarantine, scans, groups, move/delete). Identity-tier JSON cache (24h TTL, --refresh); volatile status is always pulled live, never cached. Security hardening: API key loaded from SOPS vault at runtime (never on disk/logs/argv/cache); destructive deletes gated behind --confirm; `raw` also gates destructive methods; upstream error bodies truncated. UNVERIFIED API methods reachable only via `raw`. Reuses the auth/JSON-RPC pattern from api/services/gravityzone_service.py. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
149
.claude/skills/bitdefender/SKILL.md
Normal file
149
.claude/skills/bitdefender/SKILL.md
Normal file
@@ -0,0 +1,149 @@
|
||||
---
|
||||
name: bitdefender
|
||||
description: >-
|
||||
Manage the Arizona Computer Guru (ACG) Bitdefender GravityZone Cloud MSP
|
||||
tenant via the Public JSON-RPC API. Inventory and audit endpoints, run live
|
||||
security sweeps (infected / outdated-signature / outdated-product), list
|
||||
client companies, build and fetch installation packages, manage custom groups,
|
||||
start scans, move/delete endpoints (gated), inspect policies (read-only,
|
||||
shallow), and review quarantine. Invoke for: "bitdefender", "gravityzone",
|
||||
"gravity zone", "add machine to bitdefender", "install bitdefender on",
|
||||
"list endpoints", "infected machines", "av coverage", "security sweep",
|
||||
"endpoint protection", "policy assignment", "quarantine". This skill talks to
|
||||
the real production ACG GravityZone partner tenant — treat destructive actions
|
||||
conservatively.
|
||||
---
|
||||
|
||||
# Bitdefender GravityZone Skill
|
||||
|
||||
Standalone CLI client for the GravityZone Cloud Public API (JSON-RPC). Talks to
|
||||
the live ACG partner tenant. Read-only by default; destructive operations are
|
||||
gated behind `--confirm`.
|
||||
|
||||
## Running the CLI
|
||||
|
||||
This machine's Python launcher is `py` (per identity.json). The scripts also
|
||||
work with `python`/`python3`.
|
||||
|
||||
```bash
|
||||
# from the scripts dir, or pass full paths
|
||||
py "C:/claudetools/.claude/skills/bitdefender/scripts/gz.py" status
|
||||
py "C:/claudetools/.claude/skills/bitdefender/scripts/gz.py" companies
|
||||
py "C:/claudetools/.claude/skills/bitdefender/scripts/gz.py" sweep --company <id> --json
|
||||
```
|
||||
|
||||
Transport auto-selects: uses `httpx` if installed, otherwise stdlib `urllib`
|
||||
(no third-party dependency required).
|
||||
|
||||
## Credentials
|
||||
|
||||
The API key is NEVER hardcoded. At runtime the client loads it from the SOPS
|
||||
vault:
|
||||
|
||||
```
|
||||
bash "$CLAUDETOOLS_ROOT/.claude/scripts/vault.sh" \
|
||||
get-field msp-tools/gravityzone.sops.yaml credentials.api_key
|
||||
```
|
||||
|
||||
`CLAUDETOOLS_ROOT` resolves from the env var, else `claudetools_root` in
|
||||
`C:/claudetools/.claude/identity.json`, else `C:/claudetools`. For testing you
|
||||
can override with `GRAVITYZONE_API_KEY`. Auth is HTTP Basic (key as username,
|
||||
empty password).
|
||||
|
||||
## Cache model (important)
|
||||
|
||||
The CLI keeps a local cache at
|
||||
`.claude/skills/bitdefender/.cache/inventory.json` (gitignored — no secrets, no
|
||||
PII).
|
||||
|
||||
- **Cached (identity / structure tier):** company id<->name map, endpoint
|
||||
id<->name/company/fqdn map, policy id<->name map, package list, and custom
|
||||
groups created via this tool. TTL = 86400s (24h).
|
||||
- **NEVER cached (volatile):** infected status, last-seen, online/offline,
|
||||
signature/product freshness. Those are ALWAYS pulled live — `sweep` and
|
||||
`endpoint` always hit the API.
|
||||
- **Refresh:** `inventory --refresh` forces a full re-pull. `get_inventory()`
|
||||
auto-refreshes when the cache is stale.
|
||||
- **Write-through:** a successful `create-package` or `make-group` updates the
|
||||
cache with the new id immediately, so you don't need a full refresh to
|
||||
reference it.
|
||||
|
||||
## Policy API limitation
|
||||
|
||||
The Public API exposes policies only shallowly. You CAN list policies, read
|
||||
their id/name, audit which endpoints carry which policy (via endpoint detail),
|
||||
and — via the UNVERIFIED `assignPolicy` — assign an existing policy. You CANNOT
|
||||
read the granular module configuration of a policy, and there is NO create /
|
||||
edit / clone policy method in the Public API. For policy authoring, use the
|
||||
GravityZone console.
|
||||
|
||||
## Safety gating
|
||||
|
||||
Destructive subcommands refuse to run without `--confirm`; without it they print
|
||||
what they would do and exit non-zero:
|
||||
|
||||
- `delete-endpoint <id> --confirm`
|
||||
- `delete-package --package <name> --confirm`
|
||||
- `delete-group --group <id> --confirm`
|
||||
|
||||
Never run destructive calls casually against this tenant. UNVERIFIED methods
|
||||
(assignPolicy, uninstall/reconfigure tasks, quarantine remove/restore, set
|
||||
label) are intentionally NOT exposed as dedicated subcommands — reach them only
|
||||
through `raw` after confirming the correct params against
|
||||
`references/api-reference.md` and the official Bitdefender docs.
|
||||
|
||||
## Common commands
|
||||
|
||||
```bash
|
||||
GZ="py C:/claudetools/.claude/skills/bitdefender/scripts/gz.py"
|
||||
|
||||
# Status / inventory
|
||||
$GZ status
|
||||
$GZ companies
|
||||
$GZ inventory --refresh
|
||||
$GZ endpoints --company <companyId>
|
||||
$GZ endpoint <endpointId>
|
||||
|
||||
# Live security posture
|
||||
$GZ sweep --company <companyId> # readable table
|
||||
$GZ sweep --company <companyId> --json # machine output
|
||||
|
||||
# Policies (read-only, shallow)
|
||||
$GZ policies
|
||||
$GZ policy <policyId>
|
||||
|
||||
# Quarantine
|
||||
$GZ quarantine --company <companyId>
|
||||
|
||||
# Deployment
|
||||
$GZ packages
|
||||
$GZ create-package --name "Win Default" --company <companyId>
|
||||
$GZ install-links --package "Win Default" --company <companyId>
|
||||
|
||||
# Org structure
|
||||
$GZ make-group --name "New Site" --parent <parentId>
|
||||
$GZ move --endpoints <id1> <id2> --group <groupId>
|
||||
|
||||
# Scans
|
||||
$GZ scan --targets <id1> <id2> --type 2 --name "Full scan"
|
||||
|
||||
# Power use — call any method directly
|
||||
$GZ raw --module network --method getEndpointsList --params '{"page":1,"perPage":50}'
|
||||
|
||||
# Destructive (gated)
|
||||
$GZ delete-endpoint <id> --confirm
|
||||
```
|
||||
|
||||
## Phase-2 hooks (not yet implemented)
|
||||
|
||||
- **GuruRMM push-deploy:** use `install-links` to fetch the platform installer
|
||||
URL, then push the installer to a target via the GuruRMM agent fleet (`/rmm`)
|
||||
for one-step Bitdefender rollout from RMM.
|
||||
- **Push webhook:** subscribe to GravityZone Push events (new malware /
|
||||
endpoint state changes) and surface them through the coord API / RMM alerts
|
||||
instead of polling `sweep`.
|
||||
|
||||
## Reference
|
||||
|
||||
Full verified vs unverified method spec, JSON-RPC envelope, auth, and the
|
||||
policy/deployment caveats: `references/api-reference.md`.
|
||||
Reference in New Issue
Block a user