SDK Python & CLI
Maintenu par : Aether365 Team Public : Développeurs et ingénieurs DevOps Périmètre : Installation et utilisation du SDK Python officiel aether365 et de son interface en ligne de commande
Le package aether365 est le SDK Python officiel et l'interface en ligne de commande de l'API Aether365. Il encapsule https://api.aether365.io, gère l'authentification, extrait l'enveloppe de réponse et relance automatiquement les requêtes en cas d'échec transitoire. Tout ce que vous pouvez faire avec curl, vous pouvez le faire avec le SDK ou la CLI.
Le SDK et la CLI utilisent une clé API (ak_live_...) et ciblent l'endpoint unifié : les requêtes sont routées automatiquement vers la région d'origine de votre tenant. Consultez Authentification pour comprendre le fonctionnement des clés.
Installation
Le package est distribué en interne (il n'est pas sur PyPI). Installez-le directement depuis le dépôt ou un checkout local.
bash
# From a local checkout of the monorepo
pip install ./packages/cli
# Or with Poetry, from a path
poetry add ./packages/cliPython 3.12 ou plus récent est requis. L'installation du package ajoute aussi la commande aether365 à votre PATH.
Configuration
Le SDK et la CLI lisent les mêmes variables d'environnement :
| Variable | Rôle | Par défaut |
|---|---|---|
AETHER365_API_KEY | Votre clé API (ak_live_...). Obligatoire. | - |
AETHER365_API_URL | Remplace l'URL de base (par exemple l'endpoint de dev). | https://api.aether365.io |
AETHER365_OUTPUT | Format de sortie de la CLI : table ou json. | table |
bash
export AETHER365_API_KEY="ak_live_..."La région est automatique : l'API identifie votre tenant à partir de la clé et transfère la requête vers la bonne région, vous n'avez donc jamais à configurer ni à passer une région.
Démarrage rapide : 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")Démarrage rapide : 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-findingsCe qu'une clé API peut et ne peut pas faire
Une clé API est limitée à une surface sûre, en lecture plus opérationnelle. Elle peut lire vos données, déclencher et gérer des scans, générer des rapports et gérer les cibles de surface d'attaque. Elle ne peut pas effectuer d'actions de contrôle du compte ni de verrouillage d'annuaire : gestion des clés API, facturation, membres de l'équipe, ajout/retrait de connexions, SSO, application d'un plan de remédiation, ou les écritures AI Pilot conditional-access/break-glass. Ces actions restent réservées à une session connectée dans le dashboard. Une requête vers une route non autorisée renvoie 403 AUTH_INSUFFICIENT_SCOPE.
Référence des commandes et méthodes
Chaque ligne montre la même opération de trois façons : curl brut, la méthode SDK et la commande CLI.
Tenant et compte
| Opération | curl | SDK | CLI |
|---|---|---|---|
| Profil du tenant | GET /tenants/me | client.tenants.me() | aether365 tenant me |
| Lister les connexions | GET /tenants/me/connections | client.connections.list() | aether365 tenant connections |
| Préférences de notification | GET /tenants/me/notifications | client.notifications.get() | aether365 tenant notifications |
| Scans planifiés | GET /tenants/me/scheduled-scans | client.scheduled_scans.list() | aether365 tenant scheduled-scans |
Scans
| Opération | curl | SDK | CLI |
|---|---|---|---|
| Lister les scans | GET /tenants/me/scans | client.scans.list() | aether365 scan list |
| Déclencher un scan | POST /tenants/me/scans | client.scans.create("compliance") | aether365 scan run --type compliance |
| Récupérer un scan | GET /scans/{id} | client.scans.get(id) | aether365 scan get <id> |
| Lire les résultats | GET /scans/{id}/results | client.scans.results(id) | aether365 scan results <id> |
| Annuler un scan | POST /scans/{id}/cancel | client.scans.cancel(id) | aether365 scan cancel <id> |
| Masquer un scan | PATCH /scans/{id}/hide | client.scans.hide(id) | aether365 scan hide <id> |
| Réafficher un scan | PATCH /scans/{id}/unhide | client.scans.unhide(id) | aether365 scan unhide <id> |
| Supprimer un scan | DELETE /scans/{id} | client.scans.delete(id) | aether365 scan delete <id> |
Le curl pour déclencher un scan :
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"}'Rapports
| Opération | curl | SDK | CLI |
|---|---|---|---|
| Statut du rapport | GET /scans/{id}/report | client.reports.status(id) | aether365 report status <id> |
| Générer un rapport | POST /scans/{id}/report/generate | client.reports.generate(id) | aether365 report generate <id> |
| Lister les rapports | GET /tenants/me/reports | client.reports.list() | aether365 report list |
| Télécharger un rapport | GET /scans/{id}/report (presigned) | client.reports.download(id, path) | aether365 report download <id> -o out.pdf |
Le statut d'un rapport est l'une des valeurs ready, rendering, orgNameRequired ou locked. Générer un rapport peut consommer un crédit de rapport (un paiement ponctuel lorsqu'aucune allocation n'est incluse) : c'est le propriétaire de la clé qui y consent en appelant generate.
La liste des rapports est paginée par offset : renvoyez meta["nextCursor"] (un offset de ligne entier, ou None sur la dernière page) comme paramètre cursor. client.reports.iter_all() suit le curseur pour vous.
Surface d'attaque
| Opération | curl | SDK | CLI |
|---|---|---|---|
| Vue d'ensemble | GET /tenants/me/attack-surface | client.attack_surface.summary() | aether365 eas summary |
| Historique | GET /tenants/me/attack-surface/history | client.attack_surface.history() | aether365 eas history |
| Lister les cibles | GET /tenants/me/attack-surface/targets | client.attack_surface.targets() | aether365 eas targets list |
| Ajouter une cible | POST /tenants/me/attack-surface/targets | client.attack_surface.add_target(host) | aether365 eas targets add <host> |
| Mettre à jour une cible | PATCH /tenants/me/attack-surface/targets/{id} | client.attack_surface.update_target(id, ...) | aether365 eas targets update <id> --label ... |
| Supprimer une cible | DELETE /tenants/me/attack-surface/targets/{id} | client.attack_surface.remove_target(id) | aether365 eas targets remove <id> |
| Vérifier une cible | POST /tenants/me/attack-surface/targets/{id}/verify | client.attack_surface.verify_target(id) | aether365 eas targets verify <id> |
| Lancer un scan EAS | POST /tenants/me/attack-surface/scan | client.attack_surface.scan() | aether365 eas scan |
Posture, remédiation et AI Pilot
| Opération | curl | SDK | CLI |
|---|---|---|---|
| Vue menaces / risques | GET /tenants/me/threats | client.threats.list() | aether365 threats |
| Posture des politiques | GET /tenants/me/policies | client.policies.list() | aether365 policies |
| Capacités de remédiation | GET /tenants/me/remediation/capabilities | client.remediation.capabilities() | aether365 remediation capabilities |
| Lister les plans de remédiation | GET /tenants/me/remediation-plans | client.remediation.plans() | aether365 remediation plans |
| Récupérer un plan de remédiation | GET /tenants/me/remediation-plans/{id} | client.remediation.plan(id) | aether365 remediation plan <id> |
| Éléments remédiables AI Pilot | GET /tenants/me/ai-pilot/remediable | client.ai_pilot.remediable() | aether365 ai-pilot remediable |
| Break-glass AI Pilot | GET /tenants/me/ai-pilot/break-glass | client.ai_pilot.break_glass() | aether365 ai-pilot break-glass |
| Politiques CA AI Pilot | GET /tenants/me/ai-pilot/conditional-access | client.ai_pilot.conditional_access() | aether365 ai-pilot conditional-access |
La remédiation est en lecture seule pour les clés API. L'application d'un plan n'est pas exposée : les éléments de l'action-registry d'un plan peuvent inclure des patchs Conditional-Access / authorization-policy susceptibles de verrouiller un tenant hors de son propre annuaire (AADSTS50097), donc l'application reste dans le dashboard avec un opérateur dans la boucle. Les vues AI Pilot conditional-access et break-glass sont, pour la même raison, exposées elles aussi en lecture seule.
Gestion des erreurs et retries
Chaque erreur d'API correspond à une exception typée, sous-classe de Aether365Error :
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.")Le client relance automatiquement 429 RATE_LIMITED et 503 SERVICE_STARTING (le démarrage à froid de la base de données en dev) avec un backoff exponentiel, en respectant l'en-tête Retry-After. Les erreurs de quota comme SCAN_PLAN_LIMIT_REACHED sont levées immédiatement : elles ne sont pas retentées.
Utiliser la CLI en CI
aether365 scan results <id> --fail-on-findings se termine avec le code 2 dès qu'un finding en échec est présent, ce qui permet à un pipeline de conditionner son résultat aux résultats du scan :
bash
aether365 scan run --type compliance --watch
aether365 scan results "$SCAN_ID" --fail-on-findingsLa CLI écrit les erreurs sur stderr et se termine avec 1 sur toute erreur d'API, 2 sur le gate des findings.