fix(bitdefender): doc LOWs + sweep pagination + selftest alignment
Batched the audit doc/LOW findings plus the two pagination LOWs: - Pagination (gz_client): security_sweep and refresh_inventory stopped on a 'total' field some responses omit, truncating after page 1. Now page until a short page (< per_page) - the reliable last-page signal. - isolate/restore docstrings (gz_client): removed the stale 'v1.2 takes an ARRAY endpointIds' lines that contradicted the verified single-endpointId code. - Cache 'no PII' wording corrected (gz_client header + SKILL.md): cache holds infra identifiers (hostnames/FQDNs); no secrets. Dead _require_company_for_sweep removed. - Doc drift fixed: delete-package is '--id <packageId>' not '--package <name>' (SKILL.md + api-reference.md, verified live); module docstring + sweep --company help corrected (sweep with no --company fans out to ALL companies). - selftest aligned to the improved behavior: malformed ids now exit rc2 client-side (H3) instead of rc1; gate-refusal 'Would' messages now assert on stderr (they moved off stdout so --json isn't polluted). 75/75 pass; live sweep verified. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -12,8 +12,10 @@ Credentials: never hardcoded. Loaded at runtime from the SOPS vault, or from
|
||||
the GRAVITYZONE_API_KEY env var (testing override).
|
||||
|
||||
Cache: only the IDENTITY/STRUCTURE tier is cached (company/endpoint/policy
|
||||
id<->name maps, package list). Volatile status (infected, lastSeen, online,
|
||||
signature freshness) is NEVER cached and always pulled live.
|
||||
id<->name maps + endpoint fqdn, package list). No secrets are ever cached;
|
||||
infra identifiers (hostnames/FQDNs) are. Volatile status (infected, lastSeen,
|
||||
online, signature freshness) is NEVER cached and always pulled live. The cache
|
||||
dir is gitignored.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -503,8 +505,10 @@ class GravityZoneClient:
|
||||
)
|
||||
)
|
||||
|
||||
total = data.get("total", 0)
|
||||
if page * per_page >= total:
|
||||
# Stop at the last page. A short page (< per_page) means no more;
|
||||
# do NOT rely on `total` - some responses omit it, which would
|
||||
# truncate the sweep after page 1.
|
||||
if len(items) < per_page:
|
||||
break
|
||||
page += 1
|
||||
|
||||
@@ -714,11 +718,11 @@ class GravityZoneClient:
|
||||
def isolate_endpoints(self, endpoint_ids: list[str]) -> Any:
|
||||
"""Isolate endpoints from the network (incidents.createIsolateEndpointTask).
|
||||
|
||||
v1.2 takes an ARRAY `endpointIds` (max 1000) and returns an array of
|
||||
task ids. STATE-CHANGING - gate behind --confirm at the call site.
|
||||
VERIFIED LIVE 2026-06-21: the API takes a SINGLE `endpointId` per call
|
||||
(an `endpointIds` array errors "not expected"), so we loop. Returns the
|
||||
single task result for one id, else a list. STATE-CHANGING - gate behind
|
||||
--confirm at the call site.
|
||||
"""
|
||||
# VERIFIED LIVE 2026-06-21: the API takes a SINGLE `endpointId` per call
|
||||
# (NOT an `endpointIds` array - that errors "not expected"). Loop for many.
|
||||
results = []
|
||||
for eid in endpoint_ids:
|
||||
results.append(self._jsonrpc_request(
|
||||
@@ -729,11 +733,11 @@ class GravityZoneClient:
|
||||
def restore_endpoints_from_isolation(self, endpoint_ids: list[str]) -> Any:
|
||||
"""Un-isolate endpoints (incidents.createRestoreEndpointFromIsolationTask).
|
||||
|
||||
v1.2 takes an ARRAY `endpointIds` (max 1000) and returns an array of
|
||||
task ids. STATE-CHANGING - gate behind --confirm at the call site.
|
||||
VERIFIED LIVE 2026-06-21: a SINGLE `endpointId` per call (not an array),
|
||||
so we loop. Returns the single task result for one id, else a list.
|
||||
Note: fails if the isolation task is still in progress - wait + retry.
|
||||
STATE-CHANGING - gate behind --confirm at the call site.
|
||||
"""
|
||||
# VERIFIED LIVE 2026-06-21: single `endpointId` per call (not an array).
|
||||
# Note: fails if the isolation task is still in progress - wait + retry.
|
||||
results = []
|
||||
for eid in endpoint_ids:
|
||||
results.append(self._jsonrpc_request(
|
||||
@@ -1244,8 +1248,8 @@ class GravityZoneClient:
|
||||
"company_id": ep.get("companyId", cid),
|
||||
"fqdn": ep.get("fqdn") or ep.get("FQDN") or "",
|
||||
}
|
||||
total = data.get("total", 0)
|
||||
if page * 100 >= total:
|
||||
# Last page = a short page; don't rely on `total` (may be omitted).
|
||||
if len(items) < 100:
|
||||
break
|
||||
page += 1
|
||||
|
||||
|
||||
Reference in New Issue
Block a user