feat: add test_connection command to all integrations for the instance Test button

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Guillaume BOURGEOIS
2026-06-26 00:00:06 +02:00
parent fd6c92047a
commit 5251441962
8 changed files with 169 additions and 10 deletions
+12 -2
View File
@@ -1,8 +1,8 @@
id: crowdstrike
name: CrowdStrike Falcon
version: 1.1.0
version: 1.1.1
description: "CrowdStrike Falcon (OAuth2 API) — full IR coverage: device/IOC/process enrichment, detections & cases, host groups, Real Time Response, ML/IOA exclusions, quarantine, Spotlight/CVE, ODS scans, CSPM, users, IOA rules, CNAPP, and Fusion workflows."
changelog: "1.1.0 — Expanded to 81 commands (host groups, cases, RTR files/scripts/responders, ML/IOA exclusions, quarantine, Spotlight host-by-vuln/CVE, ODS scans, CSPM, users, IOA rules, CNAPP, identity/mobile detection resolve, and workflows). 1.0.0 — Initial release: device/detection enrichment, Spotlight, IOC management, contain/lift, and core RTR."
changelog: "1.1.1 — Added test_connection for the instance Test button. 1.1.0 — Expanded to 81 commands (host groups, cases, RTR files/scripts/responders, ML/IOA exclusions, quarantine, Spotlight host-by-vuln/CVE, ODS scans, CSPM, users, IOA rules, CNAPP, identity/mobile detection resolve, and workflows). 1.0.0 — Initial release: device/detection enrichment, Spotlight, IOC management, contain/lift, and core RTR."
category: endpoint
# Per-instance configuration. Scripts obtain an OAuth2 bearer token from
@@ -1033,3 +1033,13 @@ commands:
email: { type: string, description: "Optional filter by email address (informational; include in query if supported)." }
required: [type]
outputs_schema: { properties: {} }
# ── Connectivity test ─────────────────────────────────────────────────────
- id: test_connection
name: crowdstrike-test-connection
description: "Verify connectivity and credentials (used by the Test button)."
risk: read
inputs_schema:
properties: {}
required: []
outputs_schema: { properties: {} }
@@ -0,0 +1,32 @@
import json, os, sys, urllib.request, urllib.parse, urllib.error
SECRETS = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
INPUTS = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
BASE = SECRETS.get("base_url", "https://api.crowdstrike.com").rstrip("/")
def token():
data = urllib.parse.urlencode({"client_id": SECRETS.get("client_id", ""), "client_secret": SECRETS.get("client_secret", "")}).encode()
req = urllib.request.Request(BASE + "/oauth2/token", data=data, headers={"Content-Type": "application/x-www-form-urlencoded", "Accept": "application/json"}, method="POST")
with urllib.request.urlopen(req, timeout=30) as r:
return json.loads(r.read()).get("access_token", "")
def main():
# Acquiring the OAuth2 token validates client_id/client_secret: bad
# credentials make the exchange fail (HTTPError -> exit 1).
tok = token()
if not tok:
print(json.dumps({"ok": False, "error": "No access token returned"}))
sys.exit(1)
print(json.dumps({"ok": True, "authenticated": True}))
try:
main()
except urllib.error.HTTPError as e:
print(json.dumps({"error": "HTTP " + str(e.code), "detail": e.read().decode("utf-8", "replace")}))
sys.exit(1)
except Exception as e:
print(json.dumps({"error": str(e)}))
sys.exit(1)
+12 -2
View File
@@ -1,8 +1,8 @@
id: harfanglab
name: HarfangLab EDR
version: 1.1.0
version: 1.1.1
description: "HarfangLab EDR — endpoint detection & response: endpoint enrichment, isolation, threat-intelligence (IOC/whitelist), telemetry hunting and forensic collection jobs."
changelog: "1.1.0 — Command names prefixed with 'harfanglab-' (e.g. harfanglab-isolate-endpoint) for easier toolbox search; command IDs unchanged. 1.0.0 — Initial release: endpoint/agent management, isolation, policy assignment, IOC & whitelist management, security-event triage, telemetry hunting (processes, network, DNS, authentications, binaries, event logs), threat hunting by hash, and forensic collection jobs (pipes, prefetch, run keys, scheduled tasks, drivers, services, processes, network, sessions, WMI, IOC scan, artifacts, RAM dump) with their result retrieval commands. Compatible with HarfangLab EDR 2.13.7+."
changelog: "1.1.1 — Added test_connection for the instance Test button. 1.1.0 — Command names prefixed with 'harfanglab-' (e.g. harfanglab-isolate-endpoint) for easier toolbox search; command IDs unchanged. 1.0.0 — Initial release: endpoint/agent management, isolation, policy assignment, IOC & whitelist management, security-event triage, telemetry hunting (processes, network, DNS, authentications, binaries, event logs), threat hunting by hash, and forensic collection jobs (pipes, prefetch, run keys, scheduled tasks, drivers, services, processes, network, sessions, WMI, IOC scan, artifacts, RAM dump) with their result retrieval commands. Compatible with HarfangLab EDR 2.13.7+."
category: endpoint
# Per-instance configuration. Scripts use <url> as the API base and call /api/... paths.
@@ -698,3 +698,13 @@ commands:
job_id: { type: string, description: "Job ID returned by the matching artifact job command" }
required: [job_id]
outputs_schema: { properties: {} }
# ── Connectivity test ─────────────────────────────────────────────────────
- id: test_connection
name: harfanglab-test-connection
description: "Verify connectivity and credentials (used by the Test button)."
risk: read
inputs_schema:
properties: {}
required: []
outputs_schema: { properties: {} }
@@ -0,0 +1,34 @@
import json, os, sys, urllib.request, urllib.parse, urllib.error
def request(method, url, headers, body=None):
data = json.dumps(body).encode("utf-8") if body is not None else None
req = urllib.request.Request(url, data=data, headers=headers, method=method)
with urllib.request.urlopen(req, timeout=60) as resp:
raw = resp.read()
return json.loads(raw) if raw else {}
def main():
secrets = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
base = secrets.get("url", "").rstrip("/")
headers = {
"Authorization": "Token " + secrets.get("api_token", ""),
"Accept": "application/json",
"Content-Type": "application/json",
}
# === per-command logic ===
# Lightweight authenticated GET; a bad token returns 401/403 -> exit 1.
request("GET", base + "/api/version", headers)
print(json.dumps({"ok": True}))
try:
main()
except urllib.error.HTTPError as e:
print(json.dumps({"error": "HTTP " + str(e.code), "detail": e.read().decode("utf-8", "replace")}))
sys.exit(1)
except Exception as e:
print(json.dumps({"error": str(e)}))
sys.exit(1)
+12 -2
View File
@@ -1,8 +1,8 @@
id: sentinelone
name: SentinelOne
version: 1.2.0
version: 1.2.1
description: "SentinelOne Singularity (API v2.1) — endpoint detection & response: triage threats, enrich, isolate/reconnect hosts, mitigate, scan."
changelog: "1.2.0 — Added 13 commands: threat-analysis, threat-download-from-cloud, abort-endpoint-scan, endpoint-fetch-logs, fetch-file, get-remote-script-task-status/results, get-service-users, list-installed-singularity-marketplace-applications, update-uam-alert-status/verdict, run-powerquery and create-tag-rule (83 commands total). 1.1.0 — Command names prefixed with 'sentinelone-' (e.g. sentinelone-isolate-agent) for easier toolbox search; command IDs unchanged. 1.0.0 — Initial release: 70 commands covering agents, threats, alerts, blocklist/exclusions, IOCs, STAR rules, Deep Visibility, remote scripts, tags, firewall and network discovery based on the SentinelOne API v2.1."
changelog: "1.2.1 — Added test_connection for the instance Test button. 1.2.0 — Added 13 commands: threat-analysis, threat-download-from-cloud, abort-endpoint-scan, endpoint-fetch-logs, fetch-file, get-remote-script-task-status/results, get-service-users, list-installed-singularity-marketplace-applications, update-uam-alert-status/verdict, run-powerquery and create-tag-rule (83 commands total). 1.1.0 — Command names prefixed with 'sentinelone-' (e.g. sentinelone-isolate-agent) for easier toolbox search; command IDs unchanged. 1.0.0 — Initial release: 70 commands covering agents, threats, alerts, blocklist/exclusions, IOCs, STAR rules, Deep Visibility, remote scripts, tags, firewall and network discovery based on the SentinelOne API v2.1."
category: endpoint
# Per-instance configuration. The scripts build the API base as <url>/web/api/v2.1.
@@ -955,3 +955,13 @@ commands:
description: { type: string, description: "Rule description." }
required: [name, account_id, tag_id, filter_values]
outputs_schema: { properties: {} }
# ── Connectivity test ─────────────────────────────────────────────────────
- id: test_connection
name: sentinelone-test-connection
description: "Verify connectivity and credentials (used by the Test button)."
risk: read
inputs_schema:
properties: {}
required: []
outputs_schema: { properties: {} }
@@ -0,0 +1,35 @@
import json, os, sys, urllib.request, urllib.parse, urllib.error
def request(method, url, headers, body=None):
data = json.dumps(body).encode("utf-8") if body is not None else None
req = urllib.request.Request(url, data=data, headers=headers, method=method)
with urllib.request.urlopen(req, timeout=30) as resp:
raw = resp.read()
return json.loads(raw) if raw else {}
def main():
secrets = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
inputs = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
base = secrets.get("url", "").rstrip("/") + "/web/api/v2.1"
headers = {
"Authorization": "ApiToken " + secrets.get("api_token", ""),
"Accept": "application/json",
"Content-Type": "application/json",
}
# === REQUEST ===
# Lightweight authenticated GET; a bad token returns 401 -> exit 1.
request("GET", base + "/system/info", headers)
print(json.dumps({"ok": True}))
# === END ===
try:
main()
except urllib.error.HTTPError as e:
print(json.dumps({"error": "HTTP " + str(e.code), "detail": e.read().decode("utf-8", "replace")}))
sys.exit(1)
except Exception as e:
print(json.dumps({"error": str(e)}))
sys.exit(1)
+16 -2
View File
@@ -1,8 +1,8 @@
id: shodan
name: Shodan
version: 1.0.0
version: 1.0.1
description: "Shodan — host & network intelligence: IP enrichment, search, DNS lookups, domain info, and on-demand scanning."
changelog: "1.0.0 — Initial release: host lookup, search, count, DNS resolve/reverse, domain info, api-info, scan status, and active scan."
changelog: "1.0.1 — Added test_connection for the instance Test button. 1.0.0 — Initial release: host lookup, search, count, DNS resolve/reverse, domain info, api-info, scan status, and active scan."
category: enrichment
config_schema:
@@ -158,6 +158,20 @@ commands:
# application/x-www-form-urlencoded body, which the form-based generator
# (JSON body) cannot produce. Marked destructive: it triggers an active,
# outbound crawl of the target and consumes scan credits.
# ── Connectivity test ─────────────────────────────────────────────────────
- id: test_connection
name: shodan-test-connection
description: "Verify connectivity and credentials (used by the Test button)."
risk: read
inputs_schema:
properties: {}
required: []
outputs_schema: { properties: {} }
request:
method: GET
path: /api-info
auth_ref: apikey
- id: scan
name: shodan-scan
description: Request Shodan to actively crawl an IP or netblock (consumes scan credits).
+16 -2
View File
@@ -1,8 +1,8 @@
id: virustotal
name: VirusTotal
version: 1.0.0
version: 1.0.1
description: VirusTotal API v3 — reputation lookups for IPs and domains.
changelog: "1.0.0 — Initial release: IP and domain reputation lookups."
changelog: "1.0.1 — Added test_connection for the instance Test button. 1.0.0 — Initial release: IP and domain reputation lookups."
category: enrichment
config_schema:
@@ -60,3 +60,17 @@ commands:
method: GET
path: /domains/{domain}
auth_ref: apikey
- id: test_connection
name: virustotal-test-connection
description: "Verify connectivity and credentials (used by the Test button)."
risk: read
inputs_schema:
properties: {}
required: []
outputs_schema:
properties: {}
request:
method: GET
path: /ip_addresses/8.8.8.8
auth_ref: apikey