Python SDK & CLI
Betreut von: Aether365 Team Zielgruppe: Entwickler und DevOps-Engineers Umfang: Installation und Nutzung des offiziellen aether365 Python SDK und der Kommandozeile
Das Paket aether365 ist das offizielle Python SDK und Kommandozeilen-Tool für die Aether365 API. Es kapselt https://api.aether365.io, übernimmt die Authentifizierung, packt den Response-Envelope aus und wiederholt Anfragen bei vorübergehenden Störungen automatisch. Alles, was mit curl möglich ist, geht auch mit dem SDK oder der CLI.
SDK und CLI verwenden einen API-Schlüssel (ak_live_...) und sprechen den einheitlichen Endpunkt an - Anfragen werden automatisch in die Heimatregion Ihres Tenants geroutet. Wie die Schlüssel funktionieren, steht unter Authentifizierung.
Installation
Das Paket wird intern verteilt (nicht über PyPI). Installieren Sie es direkt aus dem Repository oder einem lokalen Checkout.
bash
# From a local checkout of the monorepo
pip install ./packages/cli
# Or with Poetry, from a path
poetry add ./packages/cliErforderlich ist Python 3.12 oder neuer. Mit der Installation landet auch der Befehl aether365 auf Ihrem PATH.
Konfiguration
SDK und CLI lesen dieselben Umgebungsvariablen:
| Variable | Zweck | Standard |
|---|---|---|
AETHER365_API_KEY | Ihr API-Schlüssel (ak_live_...). Erforderlich. | - |
AETHER365_API_URL | Überschreibt die Basis-URL (zum Beispiel für den Dev-Endpunkt). | https://api.aether365.io |
AETHER365_OUTPUT | Ausgabeformat der CLI: table oder json. | table |
bash
export AETHER365_API_KEY="ak_live_..."Die Region ist automatisch: Die API ermittelt Ihren Tenant anhand des Schlüssels und leitet an die richtige Region weiter - Sie konfigurieren oder übergeben nie eine Region.
Schnellstart: SDK
python
from aether365 import Aether365Client
with Aether365Client() as client: # reads AETHER365_API_KEY
tenant = client.tenants.me()
print(tenant["name"])
# Trigger a scan and wait for it to finish
scan = client.scans.create("compliance")
for snapshot in client.scans.wait(scan["id"]):
print(snapshot["status"])
# Read the findings
findings = client.scans.results(scan["id"], result="Failed")
print(f"{len(findings)} failed checks")Schnellstart: CLI
bash
# Show the authenticated tenant
aether365 tenant me
# Trigger a scan and follow progress until it finishes
aether365 scan run --type compliance --watch
# List scans as JSON
aether365 --output json scan list
# Fail a CI job when a scan has failed findings (exit code 2)
aether365 scan results <SCAN_ID> --fail-on-findingsWas ein API-Schlüssel kann und was nicht
Ein API-Schlüssel ist auf eine sichere, lesende und operative Oberfläche beschränkt. Er kann Ihre Daten lesen, Scans starten und verwalten, Reports erzeugen und Attack-Surface-Ziele verwalten. Er kann keine Aktionen ausführen, die das Konto steuern oder das Directory aussperren könnten - API-Schlüssel-Verwaltung, Abrechnung, Team-Mitgliedschaften, das An- und Abbinden von Verbindungen, SSO, das Anwenden eines Remediation-Plans oder die Conditional-Access-/Break-Glass-Schreibzugriffe des AI Pilot. Diese bleiben einer angemeldeten Sitzung im Dashboard vorbehalten. Eine Anfrage an eine nicht erlaubte Route liefert 403 AUTH_INSUFFICIENT_SCOPE.
Befehls- und Methodenreferenz
Jede Zeile zeigt dieselbe Operation auf drei Arten: als rohes curl, als SDK-Methode und als CLI-Befehl.
Tenant und Konto
| Operation | curl | SDK | CLI |
|---|---|---|---|
| Tenant-Profil abrufen | GET /tenants/me | client.tenants.me() | aether365 tenant me |
| Verbindungen auflisten | GET /tenants/me/connections | client.connections.list() | aether365 tenant connections |
| Benachrichtigungseinstellungen | GET /tenants/me/notifications | client.notifications.get() | aether365 tenant notifications |
| Geplante Scans | GET /tenants/me/scheduled-scans | client.scheduled_scans.list() | aether365 tenant scheduled-scans |
Scans
| Operation | curl | SDK | CLI |
|---|---|---|---|
| Scans auflisten | GET /tenants/me/scans | client.scans.list() | aether365 scan list |
| Scan starten | POST /tenants/me/scans | client.scans.create("compliance") | aether365 scan run --type compliance |
| Scan abrufen | GET /scans/{id} | client.scans.get(id) | aether365 scan get <id> |
| Ergebnisse lesen | GET /scans/{id}/results | client.scans.results(id) | aether365 scan results <id> |
| Scan abbrechen | POST /scans/{id}/cancel | client.scans.cancel(id) | aether365 scan cancel <id> |
| Scan ausblenden | PATCH /scans/{id}/hide | client.scans.hide(id) | aether365 scan hide <id> |
| Scan wieder einblenden | PATCH /scans/{id}/unhide | client.scans.unhide(id) | aether365 scan unhide <id> |
| Scan löschen | DELETE /scans/{id} | client.scans.delete(id) | aether365 scan delete <id> |
Das curl zum Starten eines Scans:
bash
curl -X POST https://api.aether365.io/tenants/me/scans \
-H "Authorization: Bearer $AETHER365_API_KEY" \
-H "Content-Type: application/json" \
-d '{"scanType": "compliance"}'Reports
| Operation | curl | SDK | CLI |
|---|---|---|---|
| Report-Status | GET /scans/{id}/report | client.reports.status(id) | aether365 report status <id> |
| Report erzeugen | POST /scans/{id}/report/generate | client.reports.generate(id) | aether365 report generate <id> |
| Reports auflisten | GET /tenants/me/reports | client.reports.list() | aether365 report list |
| Report herunterladen | GET /scans/{id}/report (presigned) | client.reports.download(id, path) | aether365 report download <id> -o out.pdf |
Der Report-Status ist einer von ready, rendering, orgNameRequired oder locked. Das Erzeugen eines Reports kann ein Report-Guthaben verbrauchen (eine Einmalzahlung, wenn kein Kontingent enthalten ist) - der Schlüsselinhaber stimmt dem durch den Aufruf von generate ausdrücklich zu.
Die Report-Liste ist offset-paginiert: Geben Sie meta["nextCursor"] (einen ganzzahligen Zeilen-Offset, auf der letzten Seite None) als cursor zurück. client.reports.iter_all() folgt dem Cursor für Sie.
Attack Surface
| Operation | curl | SDK | CLI |
|---|---|---|---|
| Überblick | GET /tenants/me/attack-surface | client.attack_surface.summary() | aether365 eas summary |
| Verlauf | GET /tenants/me/attack-surface/history | client.attack_surface.history() | aether365 eas history |
| Ziele auflisten | GET /tenants/me/attack-surface/targets | client.attack_surface.targets() | aether365 eas targets list |
| Ziel hinzufügen | POST /tenants/me/attack-surface/targets | client.attack_surface.add_target(host) | aether365 eas targets add <host> |
| Ziel aktualisieren | PATCH /tenants/me/attack-surface/targets/{id} | client.attack_surface.update_target(id, ...) | aether365 eas targets update <id> --label ... |
| Ziel löschen | DELETE /tenants/me/attack-surface/targets/{id} | client.attack_surface.remove_target(id) | aether365 eas targets remove <id> |
| Ziel verifizieren | POST /tenants/me/attack-surface/targets/{id}/verify | client.attack_surface.verify_target(id) | aether365 eas targets verify <id> |
| EAS-Scan starten | POST /tenants/me/attack-surface/scan | client.attack_surface.scan() | aether365 eas scan |
Posture, Remediation und AI Pilot
| Operation | curl | SDK | CLI |
|---|---|---|---|
| Bedrohungs-/Risikoansicht | GET /tenants/me/threats | client.threats.list() | aether365 threats |
| Policy-Posture | GET /tenants/me/policies | client.policies.list() | aether365 policies |
| Remediation-Fähigkeiten | GET /tenants/me/remediation/capabilities | client.remediation.capabilities() | aether365 remediation capabilities |
| Remediation-Pläne auflisten | GET /tenants/me/remediation-plans | client.remediation.plans() | aether365 remediation plans |
| Remediation-Plan abrufen | GET /tenants/me/remediation-plans/{id} | client.remediation.plan(id) | aether365 remediation plan <id> |
| AI Pilot remediable | GET /tenants/me/ai-pilot/remediable | client.ai_pilot.remediable() | aether365 ai-pilot remediable |
| AI Pilot Break-Glass | GET /tenants/me/ai-pilot/break-glass | client.ai_pilot.break_glass() | aether365 ai-pilot break-glass |
| AI Pilot CA-Policies | GET /tenants/me/ai-pilot/conditional-access | client.ai_pilot.conditional_access() | aether365 ai-pilot conditional-access |
Remediation ist für API-Schlüssel schreibgeschützt. Das Anwenden eines Plans ist nicht verfügbar: Die Action-Registry-Einträge eines Plans können Conditional-Access-/Authorization-Policy-Patches enthalten, die einen Tenant aus seinem eigenen Directory aussperren würden (AADSTS50097). Das Anwenden bleibt deshalb im Dashboard, mit einem Operator im Loop. AI Pilot Conditional-Access und Break-Glass sind aus demselben Grund ebenfalls nur lesend verfügbar.
Fehlerbehandlung und Retries
Jeder API-Fehler wird auf eine typisierte Exception-Unterklasse von Aether365Error abgebildet:
python
from aether365 import Aether365Client
from aether365.exceptions import PermissionError_, PlanLimitError, NotFoundError
with Aether365Client() as client:
try:
client.scans.create("compliance")
except PlanLimitError:
print("Scan quota reached for this plan.")
except PermissionError_:
print("Route not allowed for this key, or plan lacks API access.")
except NotFoundError:
print("Resource not found.")Der Client wiederholt 429 RATE_LIMITED und 503 SERVICE_STARTING (das Aufwärmen der kalten Dev-Datenbank) automatisch mit exponentiellem Backoff und berücksichtigt dabei den Retry-After-Header. Quota-Fehler wie SCAN_PLAN_LIMIT_REACHED werden sofort geworfen - sie werden nicht wiederholt.
Die CLI in CI verwenden
aether365 scan results <id> --fail-on-findings beendet sich mit Exit-Code 2, sobald mindestens ein fehlgeschlagenes Finding vorliegt - damit kann eine Pipeline auf Scan-Ergebnisse gaten:
bash
aether365 scan run --type compliance --watch
aether365 scan results "$SCAN_ID" --fail-on-findingsDie CLI schreibt Fehler nach stderr und beendet sich mit 1 bei jedem API-Fehler und mit 2 am Findings-Gate.