Blog · Guida · 29 ottobre 2026
Avviare un workflow AEGIS da un webhook firmato
Trasparenza: AEGIS è sviluppato da 100monkeys.ai, quindi leggete questa guida come il resoconto di chi lo costruisce. L'ha scritta in bozza uno dei nostri agenti di IA a partire dalla documentazione pubblica di AEGIS, Configuring Webhooks, e l'azienda l'ha rivista; questa edizione italiana è una traduzione della guida originale in inglese. Ogni comando e blocco di codice qui sotto è copiato da quella pagina; nessuno è stato eseguito per questa guida. Le citazioni restano in inglese con la traduzione accanto. Dove la documentazione lascia aperta una domanda, lo dice l'ultima sezione.
AEGIS by 100monkeys.ai, in beta, può avviare un workflow quando un altro sistema gli invia un evento: un push su GitHub, un job di CI che termina, qualsiasi servizio capace di fare una richiesta HTTP. Il mittente non ha bisogno di un account sul vostro nodo. Con le parole della documentazione, "Authentication is handled by HMAC-SHA256 signature verification, not OAuth." (l'autenticazione avviene con la verifica di una firma HMAC-SHA256, non con OAuth). Questa guida configura una sorgente da capo a fondo, dal segreto condiviso a una richiesta provata, e passa in rassegna gli errori che incontrerete lungo la strada.
Passo 1. Date un nome alla sorgente
Ogni webhook arriva a POST /v1/webhooks/{source}. La sorgente è "a lowercase slug that identifies the system sending the event" (uno slug minuscolo che identifica il sistema che invia l'evento), come github, stripe o my-ci. Sceglietene una per ogni sistema mittente: il segreto, la rotta e il controllo dei duplicati si basano tutti su di essa.
Passo 2. Impostate il segreto condiviso sull'orchestratore
I segreti valgono per tenant e sorgente, quindi due tenant che chiamano entrambi la loro sorgente github hanno "completely independent secrets" (segreti del tutto indipendenti). Ogni coppia è una variabile d'ambiente sull'orchestratore, con un nome che segue questo schema:
# Pattern: AEGIS_WEBHOOK_SECRET_<UPPER_TENANT>_<UPPER_SOURCE>
# Hyphens and dots in tenant id and source name are replaced with underscores
export AEGIS_WEBHOOK_SECRET_U_ABC123_GITHUB="your-shared-secret-here"
export AEGIS_WEBHOOK_SECRET_U_ABC123_STRIPE="another-secret"
export AEGIS_WEBHOOK_SECRET_U_DEF456_MY_CI="third-secret"
Così il tenant u-abc123 con la sorgente my-ci legge AEGIS_WEBHOOK_SECRET_U_ABC123_MY_CI. Se la variabile manca per la coppia risolta, la richiesta viene rifiutata con 401 secret_not_found. Date lo stesso segreto al mittente e a nessun altro.
Passo 3. Instradate la sorgente verso un workflow
Una rotta diretta associa la sorgente a un solo workflow, quindi l'instradamento è "instant and deterministic" (immediato e deterministico). Nella versione attuale le rotte dirette sono "configured via orchestrator workflow routing configuration" (configurate nella configurazione di instradamento dei workflow dell'orchestratore), e la pagina nota che "there is no aegis stimulus routes CLI command yet" (non esiste ancora un comando CLI aegis stimulus routes). Senza una rotta diretta la pipeline ripiega su un RouterAgent configurato, che classifica l'evento con un modello linguistico. Senza nessuno dei due, la richiesta fallisce con 422 no_router_configured. Per un mittente unico e noto conviene la rotta diretta: lo stesso evento avvia sempre lo stesso workflow.
Passo 4. Firmate il corpo grezzo sul mittente
Il mittente calcola un HMAC-SHA256 del corpo grezzo della richiesta con il segreto condiviso e lo invia in X-Aegis-Signature con il prefisso sha256=. L'esempio Python della documentazione:
import hashlib
import hmac
import json
import requests
def sign_payload(body: bytes, secret: str) -> str:
sig = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return f"sha256={sig}"
payload = json.dumps({"event": "push", "ref": "refs/heads/main"}).encode()
signature = sign_payload(payload, WEBHOOK_SECRET)
requests.post(
"https://your-aegis-node/v1/webhooks/github",
data=payload,
headers={
"Content-Type": "application/json",
"X-Aegis-Signature": signature,
},
)
La pagina dà lo stesso anche in Node.js. L'unica regola che mette in grassetto: calcolate l'HMAC sui byte grezzi del corpo prima di qualsiasi parsing, perché "Computing over a re-serialized object will produce a different signature." (calcolarlo su un oggetto riserializzato produce una firma diversa). Firmate esattamente i byte che inviate.
Passo 5. Provate l'endpoint con curl
# Generate a test signature
SECRET="your-shared-secret-here"
BODY='{"event":"push","ref":"refs/heads/main"}'
SIG="sha256=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $2}')"
# Send the test webhook
curl -X POST https://your-aegis-node/v1/webhooks/github \
-H "Content-Type: application/json" \
-H "X-Aegis-Signature: $SIG" \
-d "$BODY"
Un successo risponde con due id:
{
"stimulus_id": "stim-uuid",
"workflow_execution_id": "wfex-uuid"
}
Il secondo è l'esecuzione del workflow avviata dall'evento; seguitela come qualsiasi altra esecuzione.
Passo 6. Fermate le consegne duplicate
I mittenti ritentano. Inoltrate l'id di consegna del provider come X-Idempotency-Key: per GitHub è X-GitHub-Delivery, e per un mittente vostro "Any stable per-event UUID" (qualsiasi UUID stabile per evento). L'orchestratore deduplica su sorgente e chiave per 24 ore, e una ripetizione risponde 409:
{
"error": "idempotent_duplicate",
"original_stimulus_id": "stim-original-uuid"
}
Passo 7. Leggete l'errore che ricevete
La tabella degli errori della pagina, nell'ordine in cui probabilmente li incontrerete:
401 missing_signature: manca l'headerX-Aegis-Signature.400 malformed_signature: l'header non è nella formasha256=<hex>;400 invalid_hex: la parte esadecimale contiene altri caratteri.401 secret_not_found: nessuna variabile per il tenant e la sorgente risolti.401 invalid_signature: il digest non corrisponde; un corpo riserializzato prima della firma è il caso da cui la pagina mette in guardia.409 idempotent_duplicate: già elaborato nelle ultime 24 ore.422 classification_failed: la confidenza del RouterAgent era sotto la soglia;422 no_router_configured: nessuna rotta diretta e nessun RouterAgent.
Passo 8. Usate l'endpoint autenticato per i chiamanti interni
Un servizio che ha già un account Keycloak può fare a meno del segreto condiviso e inviare a POST /v1/stimuli con un bearer token, indicando nel corpo source, content e una idempotency_key. Tenete la rotta webhook per i sistemi che non gestite voi.
Cosa lascia aperto la documentazione
- Come scrivere una rotta diretta. La pagina dice che le rotte stanno nella configurazione di instradamento dei workflow dell'orchestratore, ma non dà chiave, file né esempio, e da quel passo non c'è un link alla Configuration Reference.
- Come si registra un webhook. Il tenant "is resolved from the (tenant, source_name) registration written when the webhook was registered" (viene risolto dalla registrazione (tenant, source_name) scritta quando il webhook è stato registrato); la pagina non mostra quella registrazione.
- Cosa riceve il workflow. La pagina non dice come payload e header compaiano nell'input o nella blackboard del workflow avviato.
- Ruotare un segreto. Non è descritta una finestra di sovrapposizione, e la pagina non dice se una variabile modificata ha effetto senza riavviare l'orchestratore.
E poi
Il workflow avviato da un webhook è una macchina a stati che scrivete voi. La nostra guida Stati e transizioni di un workflow AEGIS, passo per passo ne costruisce una. AEGIS si installa con il comando stampato su 100monkeys.ai:
curl -fsSL https://get.100monkeys.ai | bash