sync: auto-sync from HOWARD-HOME at 2026-06-21 10:42:33
Author: Howard Enos Machine: HOWARD-HOME Timestamp: 2026-06-21 10:42:33
This commit is contained in:
@@ -458,6 +458,118 @@ def cmd_push_set(client, args):
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_push_test(client, args):
|
||||
if not _gated(f"send test push event '{args.event_type}'", args.confirm):
|
||||
return 3
|
||||
extra, rc = _load_json_arg(args.extra_json, "extra-json")
|
||||
if rc:
|
||||
return rc
|
||||
result = client.send_test_push_event(args.event_type, extra=extra or None)
|
||||
_emit({"testEvent": args.event_type, "result": result}, args.json, _print_kv)
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_package_details(client, args):
|
||||
_emit(client.get_package_details(args.package_id), args.json, _print_kv)
|
||||
|
||||
|
||||
def cmd_report_create(client, args):
|
||||
extra, rc = _load_json_arg(args.extra_json, "extra-json")
|
||||
if rc:
|
||||
return rc
|
||||
if not _gated(f"create report '{args.name}'", args.confirm):
|
||||
return 3
|
||||
result = client.create_report(args.name, extra=extra or None)
|
||||
_emit({"createdReport": args.name, "result": result}, args.json, _print_kv)
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_report_links(client, args):
|
||||
_emit(client.get_report_links(args.id), args.json, _print_kv)
|
||||
|
||||
|
||||
def cmd_report_delete(client, args):
|
||||
if not _gated(f"delete report {args.id}", args.confirm):
|
||||
return 3
|
||||
_emit({"deletedReport": args.id, "result": client.delete_report(args.id)},
|
||||
args.json, _print_kv)
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_quarantine_remove(client, args):
|
||||
if not _gated(f"remove {len(args.items)} quarantine item(s)", args.confirm):
|
||||
return 3
|
||||
result = client.remove_quarantine_items(args.items)
|
||||
_emit({"removedQuarantine": args.items, "result": result}, args.json, _print_kv)
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_quarantine_restore(client, args):
|
||||
extra, rc = _load_json_arg(args.extra_json, "extra-json")
|
||||
if rc:
|
||||
return rc
|
||||
if not _gated(f"restore {len(args.items)} quarantine item(s)", args.confirm):
|
||||
return 3
|
||||
result = client.restore_quarantine_items(args.items, extra=extra or None)
|
||||
_emit({"restoredQuarantine": args.items, "result": result}, args.json, _print_kv)
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_custom_rules(client, args):
|
||||
_emit(client.list_custom_rules(page=args.page, per_page=args.per_page),
|
||||
args.json, _print_kv)
|
||||
|
||||
|
||||
def cmd_custom_rule_create(client, args):
|
||||
extra, rc = _load_json_arg(args.extra_json, "extra-json")
|
||||
if rc:
|
||||
return rc
|
||||
if not _gated(f"create custom rule '{args.name}'", args.confirm):
|
||||
return 3
|
||||
result = client.create_custom_rule(args.name, extra=extra or None)
|
||||
_emit({"createdRule": args.name, "result": result}, args.json, _print_kv)
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_custom_rule_delete(client, args):
|
||||
if not _gated(f"delete custom rule {args.id}", args.confirm):
|
||||
return 3
|
||||
_emit({"deletedRule": args.id, "result": client.delete_custom_rule(args.id)},
|
||||
args.json, _print_kv)
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_incident_status(client, args):
|
||||
fields, rc = _load_json_arg(args.set_json, "set-json")
|
||||
if rc:
|
||||
return rc
|
||||
if not _gated(f"change incident status (type={args.type})", args.confirm):
|
||||
return 3
|
||||
result = client.change_incident_status(args.type, fields)
|
||||
_emit({"incidentStatus": "changed", "result": result}, args.json, _print_kv)
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_incident_note(client, args):
|
||||
fields, rc = _load_json_arg(args.set_json, "set-json")
|
||||
if rc:
|
||||
return rc
|
||||
if not _gated(f"update incident note (type={args.type})", args.confirm):
|
||||
return 3
|
||||
result = client.update_incident_note(args.type, fields)
|
||||
_emit({"incidentNote": "updated", "result": result}, args.json, _print_kv)
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_monthly_usage(client, args):
|
||||
_emit(client.get_monthly_usage(), args.json, _print_kv)
|
||||
|
||||
|
||||
def cmd_integrations(client, args):
|
||||
_emit(client.get_configured_integrations(page=args.page, per_page=args.per_page),
|
||||
args.json, _print_kv)
|
||||
|
||||
|
||||
def cmd_packages(client, args):
|
||||
_emit(client.list_packages(), args.json, _print_package_table)
|
||||
|
||||
@@ -556,7 +668,9 @@ DESTRUCTIVE_RAW_PATTERNS = ("delete", "createuninstall", "createremove",
|
||||
"removefromblocklist", "assignpolicy",
|
||||
"setpushevent", "createaccount", "updateaccount",
|
||||
"configurenotif", "createcompany", "suspendcompany",
|
||||
"activatecompany", "setendpointlabel")
|
||||
"activatecompany", "setendpointlabel", "createreport",
|
||||
"createrestore", "createcustomrule", "changeincident",
|
||||
"updateincident", "sendtestpush")
|
||||
|
||||
|
||||
def _is_destructive_method(method: str) -> bool:
|
||||
@@ -754,6 +868,24 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
sub.add_parser("push-stats",
|
||||
help="Show push event service delivery stats.", parents=[common])
|
||||
|
||||
sp = sub.add_parser("package-details", help="Installation package detail.",
|
||||
parents=[common])
|
||||
sp.add_argument("package_id")
|
||||
|
||||
sub.add_parser("monthly-usage", help="Monthly license usage.", parents=[common])
|
||||
sp = sub.add_parser("integrations", help="List configured integrations.",
|
||||
parents=[common])
|
||||
sp.add_argument("--page", type=int, default=1)
|
||||
sp.add_argument("--per-page", type=int, default=100)
|
||||
|
||||
sp = sub.add_parser("custom-rules", help="List EDR custom rules.", parents=[common])
|
||||
sp.add_argument("--page", type=int, default=1)
|
||||
sp.add_argument("--per-page", type=int, default=100)
|
||||
|
||||
sp = sub.add_parser("report-links", help="Get a report's download links.",
|
||||
parents=[common])
|
||||
sp.add_argument("--id", required=True, help="reportId.")
|
||||
|
||||
sp = sub.add_parser("quarantine", help="List quarantine items for a company.",
|
||||
parents=[common])
|
||||
sp.add_argument("--company", required=True)
|
||||
@@ -919,6 +1051,59 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
help="JSON object of the notification settings to apply.")
|
||||
sp.add_argument("--confirm", action="store_true")
|
||||
|
||||
sp = sub.add_parser("push-test", help="Send a test push event (gated).",
|
||||
parents=[common])
|
||||
sp.add_argument("--event-type", required=True)
|
||||
sp.add_argument("--extra-json")
|
||||
sp.add_argument("--confirm", action="store_true")
|
||||
|
||||
sp = sub.add_parser("report-create", help="Create a report (gated).",
|
||||
parents=[common])
|
||||
sp.add_argument("--name", required=True)
|
||||
sp.add_argument("--extra-json", help="JSON: type, targetIds, recurrence, format...")
|
||||
sp.add_argument("--confirm", action="store_true")
|
||||
|
||||
sp = sub.add_parser("report-delete", help="Delete a report (gated).",
|
||||
parents=[common])
|
||||
sp.add_argument("--id", required=True, help="reportId.")
|
||||
sp.add_argument("--confirm", action="store_true")
|
||||
|
||||
sp = sub.add_parser("quarantine-remove",
|
||||
help="Delete quarantined items (gated).", parents=[common])
|
||||
sp.add_argument("--items", nargs="+", required=True,
|
||||
help="quarantineItemsIds.")
|
||||
sp.add_argument("--confirm", action="store_true")
|
||||
|
||||
sp = sub.add_parser("quarantine-restore",
|
||||
help="Restore quarantined items (gated).", parents=[common])
|
||||
sp.add_argument("--items", nargs="+", required=True,
|
||||
help="quarantineItemsIds.")
|
||||
sp.add_argument("--extra-json", help="JSON: addExclusionInPolicy, etc.")
|
||||
sp.add_argument("--confirm", action="store_true")
|
||||
|
||||
sp = sub.add_parser("custom-rule-create",
|
||||
help="Create an EDR custom rule (gated).", parents=[common])
|
||||
sp.add_argument("--name", required=True)
|
||||
sp.add_argument("--extra-json", help="JSON: settings, companyId, tags...")
|
||||
sp.add_argument("--confirm", action="store_true")
|
||||
|
||||
sp = sub.add_parser("custom-rule-delete",
|
||||
help="Delete an EDR custom rule (gated).", parents=[common])
|
||||
sp.add_argument("--id", required=True, help="ruleId.")
|
||||
sp.add_argument("--confirm", action="store_true")
|
||||
|
||||
sp = sub.add_parser("incident-status",
|
||||
help="Change an incident's status (gated).", parents=[common])
|
||||
sp.add_argument("--type", required=True, help="Incident type/category.")
|
||||
sp.add_argument("--set-json", required=True, help="JSON: id, status, ...")
|
||||
sp.add_argument("--confirm", action="store_true")
|
||||
|
||||
sp = sub.add_parser("incident-note",
|
||||
help="Update an incident note (gated).", parents=[common])
|
||||
sp.add_argument("--type", required=True, help="Incident type/category.")
|
||||
sp.add_argument("--set-json", required=True, help="JSON: id, note, ...")
|
||||
sp.add_argument("--confirm", action="store_true")
|
||||
|
||||
sp = sub.add_parser("push-set",
|
||||
help="Configure the push event service (gated).",
|
||||
parents=[common])
|
||||
@@ -966,6 +1151,20 @@ HANDLERS = {
|
||||
"push-stats": cmd_push_stats,
|
||||
"assign-policy": cmd_assign_policy,
|
||||
"push-set": cmd_push_set,
|
||||
"push-test": cmd_push_test,
|
||||
"package-details": cmd_package_details,
|
||||
"monthly-usage": cmd_monthly_usage,
|
||||
"integrations": cmd_integrations,
|
||||
"custom-rules": cmd_custom_rules,
|
||||
"custom-rule-create": cmd_custom_rule_create,
|
||||
"custom-rule-delete": cmd_custom_rule_delete,
|
||||
"incident-status": cmd_incident_status,
|
||||
"incident-note": cmd_incident_note,
|
||||
"report-create": cmd_report_create,
|
||||
"report-links": cmd_report_links,
|
||||
"report-delete": cmd_report_delete,
|
||||
"quarantine-remove": cmd_quarantine_remove,
|
||||
"quarantine-restore": cmd_quarantine_restore,
|
||||
"quarantine": cmd_quarantine,
|
||||
"blocklist": cmd_blocklist,
|
||||
"incidents": cmd_incidents,
|
||||
|
||||
@@ -900,6 +900,127 @@ class GravityZoneClient:
|
||||
params["subscribeToEventTypes"] = subscribe_event_types
|
||||
return self._jsonrpc_request("push", "setPushEventSettings", params)
|
||||
|
||||
def send_test_push_event(self, event_type: str, extra: Optional[dict] = None) -> Any:
|
||||
"""Send a test push event (push.sendTestPushEvent). Requires `eventType`
|
||||
(verified). Fires against the configured receiver — STATE-ADJACENT, gate
|
||||
at the call site behind --confirm."""
|
||||
params: dict = {"eventType": event_type}
|
||||
if extra:
|
||||
params.update(extra)
|
||||
return self._jsonrpc_request("push", "sendTestPushEvent", params)
|
||||
|
||||
# ======================================================================
|
||||
# PACKAGES (detail) — read
|
||||
# ======================================================================
|
||||
def get_package_details(self, package_id: str) -> dict:
|
||||
"""Installation package detail (packages.getPackageDetails). `packageId`
|
||||
required (verified)."""
|
||||
return self._jsonrpc_request(
|
||||
"packages", "getPackageDetails", {"packageId": package_id}
|
||||
) or {}
|
||||
|
||||
# ======================================================================
|
||||
# REPORTS (create / delete) — getReportsList + get_report_links above
|
||||
# ======================================================================
|
||||
def create_report(self, name: str, extra: Optional[dict] = None) -> Any:
|
||||
"""Create a report (reports.createReport). `name` required (verified);
|
||||
`type`, `targetIds`, recurrence/format etc. passed via `extra`.
|
||||
STATE-CHANGING — gate at the call site behind --confirm."""
|
||||
params: dict = {"name": name}
|
||||
if extra:
|
||||
params.update(extra)
|
||||
return self._jsonrpc_request("reports", "createReport", params)
|
||||
|
||||
def delete_report(self, report_id: str) -> Any:
|
||||
"""Delete a report (reports.deleteReport). `reportId` required (verified).
|
||||
STATE-CHANGING — gate at the call site behind --confirm."""
|
||||
return self._jsonrpc_request(
|
||||
"reports", "deleteReport", {"reportId": report_id}
|
||||
)
|
||||
|
||||
# ======================================================================
|
||||
# QUARANTINE (remove / restore) — getQuarantineItemsList above
|
||||
# ======================================================================
|
||||
def remove_quarantine_items(
|
||||
self, quarantine_item_ids: list[str], extra: Optional[dict] = None
|
||||
) -> Any:
|
||||
"""Delete quarantined items (quarantine/computers.createRemoveQuarantineItemTask).
|
||||
`quarantineItemsIds` required (verified). STATE-CHANGING — gate behind --confirm."""
|
||||
params: dict = {"quarantineItemsIds": quarantine_item_ids}
|
||||
if extra:
|
||||
params.update(extra)
|
||||
return self._jsonrpc_request(
|
||||
"quarantine/computers", "createRemoveQuarantineItemTask", params
|
||||
)
|
||||
|
||||
def restore_quarantine_items(
|
||||
self, quarantine_item_ids: list[str], extra: Optional[dict] = None
|
||||
) -> Any:
|
||||
"""Restore quarantined items (quarantine/computers.createRestoreQuarantineItemTask).
|
||||
`quarantineItemsIds` required (verified). `addExclusionInPolicy` etc. via
|
||||
`extra`. STATE-CHANGING — gate behind --confirm."""
|
||||
params: dict = {"quarantineItemsIds": quarantine_item_ids}
|
||||
if extra:
|
||||
params.update(extra)
|
||||
return self._jsonrpc_request(
|
||||
"quarantine/computers", "createRestoreQuarantineItemTask", params
|
||||
)
|
||||
|
||||
# ======================================================================
|
||||
# INCIDENTS — custom rules + incident status/note (read + state-changing)
|
||||
# ======================================================================
|
||||
def list_custom_rules(self, page: int = 1, per_page: int = 100) -> dict:
|
||||
"""List EDR custom rules (incidents.getCustomRulesList). VERIFIED LIVE."""
|
||||
return self._jsonrpc_request(
|
||||
"incidents", "getCustomRulesList", {"page": page, "perPage": per_page}
|
||||
) or {}
|
||||
|
||||
def create_custom_rule(self, name: str, extra: Optional[dict] = None) -> Any:
|
||||
"""Create an EDR custom rule (incidents.createCustomRule). `name` required
|
||||
(verified); rule body (settings/companyId/tags) via `extra`.
|
||||
STATE-CHANGING — gate behind --confirm."""
|
||||
params: dict = {"name": name}
|
||||
if extra:
|
||||
params.update(extra)
|
||||
return self._jsonrpc_request("incidents", "createCustomRule", params)
|
||||
|
||||
def delete_custom_rule(self, rule_id: str) -> Any:
|
||||
"""Delete an EDR custom rule (incidents.deleteCustomRule). `ruleId` required
|
||||
(verified). STATE-CHANGING — gate behind --confirm."""
|
||||
return self._jsonrpc_request(
|
||||
"incidents", "deleteCustomRule", {"ruleId": rule_id}
|
||||
)
|
||||
|
||||
def change_incident_status(self, incident_type: str, fields: dict) -> Any:
|
||||
"""Change an incident's status (incidents.changeIncidentStatus). `type`
|
||||
required (verified) — the incident type/category — plus the incident id +
|
||||
target status in `fields`. STATE-CHANGING — gate behind --confirm."""
|
||||
params: dict = {"type": incident_type}
|
||||
params.update(fields or {})
|
||||
return self._jsonrpc_request("incidents", "changeIncidentStatus", params)
|
||||
|
||||
def update_incident_note(self, incident_type: str, fields: dict) -> Any:
|
||||
"""Update an incident note (incidents.updateIncidentNote). `type` required
|
||||
(verified) plus incident id + note text in `fields`. STATE-CHANGING."""
|
||||
params: dict = {"type": incident_type}
|
||||
params.update(fields or {})
|
||||
return self._jsonrpc_request("incidents", "updateIncidentNote", params)
|
||||
|
||||
# ======================================================================
|
||||
# LICENSING (usage) + INTEGRATIONS — read
|
||||
# ======================================================================
|
||||
def get_monthly_usage(self) -> dict:
|
||||
"""Monthly license usage (licensing.getMonthlyUsage). VERIFIED LIVE."""
|
||||
return self._jsonrpc_request("licensing", "getMonthlyUsage", {}) or {}
|
||||
|
||||
def get_configured_integrations(self, page: int = 1, per_page: int = 100) -> dict:
|
||||
"""Configured third-party integrations (integrations.getConfiguredIntegrations).
|
||||
VERIFIED LIVE."""
|
||||
return self._jsonrpc_request(
|
||||
"integrations", "getConfiguredIntegrations",
|
||||
{"page": page, "perPage": per_page},
|
||||
) or {}
|
||||
|
||||
# ======================================================================
|
||||
# CACHE LAYER (identity / structure only — never volatile status)
|
||||
# ======================================================================
|
||||
|
||||
@@ -105,6 +105,25 @@ check("push-set no confirm -> rc3", ["push-set", "--status", "1", "--url", "http
|
||||
check("push-set enable no url -> rc2", ["push-set", "--status", "1", "--confirm"], want_rc=2)
|
||||
check("raw assignPolicy no confirm -> rc3", ["raw", "--module", "network", "--method", "assignPolicy", "--params", "{}"], want_rc=3)
|
||||
|
||||
# --- remaining modules: reads ---
|
||||
check("monthly-usage", ["monthly-usage"], want_rc=0)
|
||||
check("integrations", ["integrations"], want_rc=0)
|
||||
check("custom-rules", ["custom-rules"], want_rc=0)
|
||||
check("custom-rules json", ["custom-rules", "--json"], want_rc=0, out_json_ok=True)
|
||||
|
||||
# --- remaining modules: gated writes (no-confirm -> rc3) ---
|
||||
check("push-test no confirm -> rc3", ["push-test", "--event-type", "av"], want_rc=3)
|
||||
check("report-create no confirm -> rc3", ["report-create", "--name", "R"], want_rc=3)
|
||||
check("report-delete no confirm -> rc3", ["report-delete", "--id", "x"], want_rc=3)
|
||||
check("quarantine-remove no confirm -> rc3", ["quarantine-remove", "--items", "x"], want_rc=3)
|
||||
check("quarantine-restore no confirm -> rc3", ["quarantine-restore", "--items", "x"], want_rc=3)
|
||||
check("custom-rule-create no confirm -> rc3", ["custom-rule-create", "--name", "R"], want_rc=3)
|
||||
check("custom-rule-delete no confirm -> rc3", ["custom-rule-delete", "--id", "x"], want_rc=3)
|
||||
check("incident-status no confirm -> rc3", ["incident-status", "--type", "t", "--set-json", "{}"], want_rc=3)
|
||||
check("incident-note no confirm -> rc3", ["incident-note", "--type", "t", "--set-json", "{}"], want_rc=3)
|
||||
check("raw createReport no confirm -> rc3", ["raw", "--module", "reports", "--method", "createReport", "--params", "{}"], want_rc=3)
|
||||
check("raw createCustomRule no confirm -> rc3", ["raw", "--module", "incidents", "--method", "createCustomRule", "--params", "{}"], want_rc=3)
|
||||
|
||||
# --- network completion ---
|
||||
check("endpoint-tags", ["endpoint-tags"], want_rc=0)
|
||||
check("set-label no confirm -> rc3", ["set-label", "--endpoint", "x", "--label", "y"], want_rc=3)
|
||||
|
||||
Reference in New Issue
Block a user