fix(bitdefender): third-pass - companies pagination, connect-retry, Retry-After ceiling, ctx mgr

Remaining LOW/NIT items from the second review pass:
- list_all_companies() paginates the company list; sweep-all + refresh_inventory
  no longer truncate a >100-company tenant.
- Pre-send connection failures (httpx ConnectError/ConnectTimeout; urllib URLError
  not wrapping a timeout) are now retried as 'connect' - always safe (no side
  effect) even for non-idempotent writes; ambiguous read-timeouts stay idempotent-gated.
- Explicit Retry-After honored up to RETRY_AFTER_MAX_SECONDS (120s) instead of the
  30s exponential cap, so a server-mandated cooldown isn't cut short.
- GravityZoneClient is now a context manager (__enter__/__exit__ -> close()).
- incident-status/note reject an empty --set-json (rc2), matching account-update/notif.
- selftest: +connect/Retry-After/ctx-mgr unit coverage, incident empty-json assertion. 79/79.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-25 13:52:33 -07:00
parent a96a15a1d2
commit 778e12d83e
3 changed files with 69 additions and 14 deletions

View File

@@ -619,6 +619,10 @@ def cmd_incident_status(client, args):
fields, rc = _load_json_arg(args.set_json, "set-json")
if rc:
return rc
if not fields:
print("[ERROR] --set-json (object of fields to set) is required.",
file=sys.stderr)
return 2
if not _gated(f"change incident status (type={args.type})", args.confirm):
return 3
result = client.change_incident_status(args.type, fields)
@@ -630,6 +634,10 @@ def cmd_incident_note(client, args):
fields, rc = _load_json_arg(args.set_json, "set-json")
if rc:
return rc
if not fields:
print("[ERROR] --set-json (object of fields to set) is required.",
file=sys.stderr)
return 2
if not _gated(f"update incident note (type={args.type})", args.confirm):
return 3
result = client.update_incident_note(args.type, fields)