API HTTP#
Il contratto completo è la specifica OpenAPI in api/openapi.yaml: un test verifica che corrisponda alle rotte registrate dal server, e l'interfaccia web ne genera i tipi.
L'API è servita da manent-server serve (default :8080). Accetta e restituisce JSON. Il body di un descrittore può essere al massimo di 1 MiB.
Autenticazione#
Con auth.mode: enabled le rotte /api/v1 richiedono un token bearer, OIDC o statico:
| Esito | Risposta |
|---|---|
| Token assente o non valido | 401 Unauthorized, header WWW-Authenticate: Bearer realm="manent" |
| Azione non consentita dai permessi | 403 Forbidden, con il motivo in error |
/healthz non richiede autenticazione. Elenchi di deploy, schedule e inventario contengono solo ciò che l'identità può leggere. Vedi Autenticazione, permessi e audit.
Riepilogo#
| Metodo | Percorso | Descrizione |
|---|---|---|
POST |
/api/v1/deployments |
Accoda un deploy, lo pianifica o crea una schedule. |
GET |
/api/v1/deployments |
Elenca i deploy più recenti. |
POST |
/api/v1/deployments/plan |
Calcola il piano senza avviare nulla. |
POST |
/api/v1/deployments/validate |
Verifica un descrittore come all'accodamento e restituisce il deploy effettivo. |
POST |
/api/v1/environments/validate |
Verifica una configurazione di ambiente candidata (application, environment, config, descriptor facoltativo): vedi CI e infrastruttura come codice. |
GET |
/api/v1/deployments/{id} |
Stato e risultato di un deploy. |
GET |
/api/v1/deployments/{id}/steps |
Timeline degli step. |
GET |
/api/v1/deployments/{id}/logs?offset= |
Log del deploy. |
GET |
/api/v1/deployments/{id}/events |
Stato e log come Server-Sent Events. |
POST |
/api/v1/deployments/{id}/cancel |
Annulla un deploy. |
POST |
/api/v1/deployments/{id}/approve |
Approva un deploy in attesa. |
POST |
/api/v1/deployments/{id}/reject |
Respinge un deploy in attesa. |
GET |
/api/v1/approvals |
Deploy in attesa di una decisione che il chiamante può prendere. |
GET |
/api/v1/me |
Identità del chiamante e ruoli che le si applicano. |
GET |
/api/v1/activity |
Deploy non ancora conclusi: in esecuzione, in attesa di approvazione, in coda, pianificati. |
POST |
/api/v1/releases |
Invia una release composta. |
GET |
/api/v1/releases |
Elenca le release più recenti. |
GET |
/api/v1/releases/{id} |
Stato di una release e dei suoi deploy. |
POST |
/api/v1/releases/{id}/cancel |
Annulla i deploy non conclusi e la release. |
GET |
/api/v1/workers |
Worker registrati con stato, heartbeat, risorse, code e workflow in esecuzione (platform.read). |
GET |
/api/v1/queues |
Code con limiti, workflow in attesa, in esecuzione e pianificati e worker in ascolto (platform.read). |
POST |
/api/v1/promotions |
Promuove un artefatto da un ambiente a un altro. |
POST |
/api/v1/rollbacks |
Torna a una versione precedente. |
GET |
/api/v1/inventory |
Release in esercizio per applicazione e ambiente. |
GET |
/api/v1/freezes |
Finestre di freeze attive e future (deployment.read su almeno un'applicazione). |
GET |
/api/v1/tenants?application=&selector= |
Tenant del registro (i team proprietari delle applicazioni), filtrati dai permessi. |
GET |
/api/v1/tenants/{name} |
Un tenant con le sue applicazioni e i loro tag. |
POST |
/api/v1/freezes |
Crea una finestra di freeze a runtime (freeze.write). |
DELETE |
/api/v1/freezes/{name} |
Elimina una finestra di freeze creata a runtime. |
GET |
/api/v1/policies |
Revisioni della policy di governance e quella in vigore (policy.read). |
POST |
/api/v1/policies |
Carica una revisione in bozza (policy.write). |
GET |
/api/v1/policies/{revision} |
Una revisione con i suoi file. |
POST |
/api/v1/policies/{revision}/evaluate |
Decisione di una revisione su un descrittore (policy.write). |
POST |
/api/v1/policies/{revision}/access |
Permessi di un'identità indicata a mano, differenze rispetto alla revisione attiva ed esito di un'azione (policy.write, rbac.engine: opa). |
GET |
/api/v1/policies/{revision}/impact |
Decisioni dei deploy reali ricalcolate con una revisione (policy.write). |
POST |
/api/v1/policies/{revision}/approve |
Approva e attiva una bozza (policy.approve). |
POST |
/api/v1/policies/{revision}/activate |
Torna a una revisione precedente (policy.approve). |
GET |
/api/v1/metrics/dora |
Metriche DORA. |
GET |
/api/v1/schedules |
Elenca le schedule ricorrenti. |
GET |
/api/v1/schedules/{nome} |
Dettaglio di una schedule. |
POST |
/api/v1/schedules/{nome}/pause |
Sospende una schedule. |
POST |
/api/v1/schedules/{nome}/resume |
Riattiva una schedule. |
DELETE |
/api/v1/schedules/{nome} |
Elimina una schedule. |
GET |
/ui/config.json |
Configurazione pubblica dell'interfaccia web. Senza autenticazione. |
POST |
/integrations/slack/interactions |
Pulsanti di approvazione dei messaggi Slack, autenticati dalla firma di Slack (vedi Chat e change management). Registrata solo con integrations.slack.signing_secret_ref. |
GET |
/healthz |
Il processo è attivo. Senza autenticazione. |
GET |
/readyz |
Il processo raggiunge il database e non è in arresto. Senza autenticazione. |
GET |
/metrics |
Metriche Prometheus (con observability.metrics). Senza autenticazione. |
Deploy#
Accodare un deploy#
| Esito | Risposta |
|---|---|
Deploy accodato o pianificato con schedule.at |
202 Accepted, header Location: /api/v1/deployments/{id} |
Schedule ricorrente creata o aggiornata (schedule.cron) |
201 Created, header Location: /api/v1/schedules/{nome} |
Descrittore non valido o parametro dry_run non booleano |
400 Bad Request |
Richiesta non accettabile (piano non valido, orario nel passato, callback, rollback o sorgente dell'artefatto non ammessi, descrittore non ammesso dalla descriptor_policy o incompatibile con la configurazione di ambiente, freeze attivo, versione non promossa) |
422 Unprocessable Entity |
Azione non consentita (es. deployment.submit sull'ambiente) |
403 Forbidden |
{"id": "4f1c…", "state": "DELAYED", "scheduled_at": "2026-10-10T02:00:00+02:00"}
La compatibilità con la configurazione di ambiente e la descriptor_policy si verifica già qui. Se la configurazione di ambiente non è raggiungibile (es. Consul non disponibile) la richiesta viene accettata e la verifica resta al worker.
Con ?dry_run=true (oppure "dryRun": true nel descrittore) viene accodato un dry-run e la risposta contiene "dry_run": true.
Calcolare il piano#
Richiede deployment.read sull'applicazione e l'ambiente del descrittore.
Verificare un descrittore#
POST /api/v1/deployments/validate esegue le verifiche dell'accodamento (policy sui descrittori, configurazione di ambiente, callback, sorgente dell'artefatto, rollback) senza accodare nulla. È quello che usa manent validate. Richiede deployment.read. Con ?check_artifact=true il server cerca anche l'artefatto nella sua sorgente senza scaricarlo (manent validate --check-artifact, richiede anche deployment.dry-run) e riporta l'esito in artifact.
{
"valid": true,
"plan": [{"name": "secrets", "max_retries": 0}, {"name": "deploy", "max_retries": 2}],
"deploy": {"plugin": "remote-copy", "targets": [{"host": "10.0.0.5", "user": "deploy"}], "params": {"dest_dir": "/opt/myapp"}},
"secrets": ["deploy-key"],
"config": {"source": "consul", "revision": "1842"},
"governance": {"rule": "produzione", "requires": ["preprod"], "approvals": 1},
"warnings": []
}
Con un rilascio a ondate la risposta contiene anche rollout, con gli stadi e i passi che verrebbero eseguiti. Un descrittore non valido produce 422 con il motivo. Se la configurazione di ambiente non è raggiungibile la risposta è comunque 200, con l'avviso in warnings.
Stato di un deploy#
{
"id": "myapp-1.2.3-test",
"state": "SUCCESS",
"application": "myapp",
"environment": "test",
"artifact": "myapp",
"version": "1.2.3",
"sha256": "2d27fbdf…",
"kind": "deploy",
"requested_by": "oidc:alice",
"created_at": "2026-10-09T10:00:00Z",
"updated_at": "2026-10-09T10:01:12Z",
"result": {
"deployment_id": "myapp-1.2.3-test",
"steps": [
{"name": "config", "output": {"source": "consul:manent/untenanted/myapp/myapp/test", "revision": "42", "targets": "1"}},
{"name": "artifacts", "output": {"local_path": "…", "sha256": "…", "size": "10240"}},
{"name": "deploy", "output": {"plugin": "remote-copy", "result": "{…}"}}
]
}
}
| Stato | Significato |
|---|---|
ENQUEUED |
In coda, in attesa di un worker. |
DELAYED |
Pianificato con schedule.at, in attesa dell'orario. |
PENDING |
In esecuzione. |
SUCCESS |
Concluso con successo: result contiene l'output di ogni step. |
ERROR |
Concluso con errore: error contiene il messaggio. |
CANCELLED |
Annullato. |
AWAITING_APPROVAL |
In attesa delle approvazioni: approval riporta le decisioni. |
REJECTED, EXPIRED |
Respinto o non approvato in tempo: il deploy non è stato eseguito. |
WAITING_DEPENDENCY |
In attesa che i deploy in after riescano: after ne riporta lo stato. |
DEPENDENCY_FAILED |
Una dipendenza non è riuscita o l'attesa è scaduta: il deploy non è stato eseguito. |
Un ID inesistente restituisce 404.
| Campo | Significato |
|---|---|
requested_by |
Identità che ha richiesto il deploy; per i deploy di una schedule, chi l'ha creata o aggiornata per ultimo. |
kind, source |
deploy, promotion o rollback; per gli ultimi due, il deploy da cui derivano. |
sha256 |
Hash dell'artefatto rilasciato, registrato al termine del deploy. |
rollback |
Esito del rollback automatico, se eseguito. |
dry_run |
true per un dry-run. |
Elenco#
Restituisce {"deployments": [...]} dal più recente, senza il risultato degli step (da leggere con il dettaglio).
| Parametro | Descrizione |
|---|---|
schedule |
Solo le esecuzioni di una schedule ricorrente. |
application, environment |
Solo i deploy dell'applicazione o dell'ambiente. |
state |
Solo i deploy nello stato indicato (es. AWAITING_APPROVAL). |
limit |
Numero massimo di risultati (default 50), intero positivo. |
cursor |
next_cursor della pagina precedente: l'elenco riparte dal deploy successivo. |
Filtri e permessi non riducono il numero di risultati: l'elenco prosegue sui deploy più vecchi fino a limit (esaminandone al più 10.000). Quando la pagina è piena la risposta ha anche next_cursor, l'ID del suo ultimo deploy.
Annullare#
Risponde 204 No Content, oppure 404 se il deploy non esiste.
Schedule#
GET /api/v1/schedules restituisce {"schedules": [...]}:
{
"name": "myapp-nightly",
"cron": "0 0 2 * * *",
"timezone": "Europe/Rome",
"status": "ACTIVE",
"application": "myapp",
"environment": "test",
"requested_by": "oidc:bob",
"last_fired_at": "2026-10-09T00:00:00Z"
}
pause, resume e DELETE rispondono 204 No Content oppure 404.
Governance#
Vedi Governance dei rilasci per il significato di ogni operazione.
Approvare o respingere#
Il body è facoltativo. Risponde 204; 403 senza il permesso deployment.approve o se chi approva ha richiesto il deploy; 422 se il deploy non è in attesa di approvazione o l'identità ha già deciso. /reject ha la stessa forma.
Promuovere#
POST /api/v1/promotions
{"application": "myapp", "from": "preprod", "to": "prod", "version": "1.4.0",
"deploy": {"targets": [{"host": "prod-1"}]}, "id": "myapp-1.4.0-prod", "dry_run": false, "freeze_override": ""}
Solo application, from e to sono obbligatori. deploy sostituisce la sezione deploy del descrittore di origine, i cui target non vengono mai copiati. Risponde come POST /deployments.
Rollback manuale#
Senza version torna alla versione precedente a quella in esercizio. Accetta anche id, dry_run e freeze_override. Risponde come POST /deployments; 422 se non c'è una versione a cui tornare o il tipo di artefatto non ammette il rollback.
Inventario e freeze#
Restituiscono {"inventory": [...]} e {"freezes": [...]}. Le finestre di freeze sono visibili a ogni identità autenticata.
{"name": "weekend", "applications": ["*"], "environments": ["prod"], "active": false,
"start": "2026-10-16T18:00:00+02:00", "end": "2026-10-19T08:00:00+02:00", "recurring": true}
Freeze a runtime e policy#
POST /api/v1/freezes
{"name": "incidente-881", "reason": "incidente 881", "applications": ["*"], "environments": ["prod"],
"to": "2026-10-18T18:00:00Z", "hard": true}
from vale adesso per default. Risponde 201 con la finestra. Risponde 403 senza freeze.write su ogni applicazione e ambiente della finestra, e 422 per un nome non valido, un duplicato o una finestra nel passato. DELETE /api/v1/freezes/{name} risponde 204, oppure 404 per una finestra non creata a runtime.
POST /api/v1/policies
{"files": {"governance.rego": "package manent.governance\n…", "data.yaml": "…"}, "comment": "approvazione dei DBA"}
Risponde 201 con la revisione in bozza e l'esito dei test, oppure 422 con l'errore di compilazione o i test falliti. {revision} è un numero o current (la revisione in vigore). Vedi Policy in Rego.
Release composte#
POST /api/v1/releases invia una release composta. Il corpo è la release in JSON con i descrittori inclusi (descriptor; file è solo per la CLI):
{
"apiVersion": "manent/v1", "kind": "Release", "id": "shop-2026-10", "onFailure": "rollback",
"deploys": [
{"name": "db", "descriptor": {"apiVersion": "manent/v1", "application": "shop-db", "environment": "prod", "artifact": {"type": "migration", "name": "shop-db", "version": "42", "source": "https://…"}}},
{"name": "api", "after": ["db"], "descriptor": {"apiVersion": "manent/v1", "application": "shop-api", "environment": "prod", "artifact": {"type": "application", "name": "shop-api", "version": "2.4.0", "source": "https://…"}}}
]
}
Risponde 202 con lo stato della release: id, state (PENDING, SUCCESS, ERROR, CANCELLED), on_failure, requested_by, error e deploys, in ordine topologico, con name, deployment_id, application, environment, version, after, state, error, rollback_id e rollback_state. Una release non valida (cicli, dipendenze sconosciute, schedule o dryRun in un deploy) è 400; un deploy rifiutato da policy o governance è 422. Nella risposta i deploy sono ENQUEUED: li accoda subito dopo il workflow della release, e le letture successive ne riportano lo stato effettivo. Inviare di nuovo lo stesso id restituisce la release esistente.
GET /api/v1/releases[?limit=] restituisce {"releases": [...]}, GET /api/v1/releases/{id} una singola release, POST /api/v1/releases/{id}/cancel la annulla (204).
Log, timeline e metriche DORA#
curl -H "Authorization: Bearer $TOKEN" https://manent.example.com/api/v1/deployments/7c0e…/steps
curl -H "Authorization: Bearer $TOKEN" "https://manent.example.com/api/v1/deployments/7c0e…/logs?offset=0"
{
"lines": [
{"time": "2026-10-10T12:03:12Z", "level": "INFO", "step": "artifacts", "message": "artifact fetched",
"attrs": {"sha256": "2d27…"}}
],
"next": 1,
"done": false
}
Per seguire un deploy si ripete la richiesta con offset uguale a next finché done è true. GET /api/v1/metrics/dora?application=&environment=&since= accetta per since una data RFC 3339, una durata (720h) o un numero di giorni (30d, default). Tutte richiedono deployment.read. Vedi Osservabilità.
Eventi in tempo reale#
GET /api/v1/deployments/{id}/events invia lo stato e le nuove righe di log di un deploy come Server-Sent Events, con gli stessi permessi di stato e log:
| Evento | Dati |
|---|---|
status |
Lo stato del deploy, come GET /api/v1/deployments/{id}, ogni volta che cambia. |
log |
Un array di nuove righe di log. L'id dell'evento è l'offset successivo: un client che si riconnette con Last-Event-ID (o ?offset=) riprende da lì. |
end |
Il deploy è concluso e tutte le sue righe sono state inviate; il server chiude lo stream. |
error |
La lettura di stato o log è fallita. |
Un commento : keep-alive ogni 15 secondi tiene aperta la connessione attraverso i proxy. EventSource non può inviare l'intestazione Authorization: con l'autenticazione lo stream si legge con fetch (come fa l'interfaccia web) o con un client che supporta le intestazioni (curl -N).
Identità e approvazioni#
GET /api/v1/me restituisce l'identità della richiesta (subject, name, method, groups), se l'autenticazione è attiva e i ruoli che le si applicano, con applicazioni e ambienti (grants). GET /api/v1/approvals restituisce {"approvals": [...]}: i deploy in attesa di una decisione, prima dell'avvio o tra due ondate, per cui il chiamante ha deployment.approve e che non ha richiesto lui. La CLI li espone come manent whoami e manent approvals.
Attività e worker#
GET /api/v1/activity[?application=&environment=] restituisce i deploy non ancora conclusi, dal più recente, in cinque elenchi: running (con executor, started_at, last_step, l'ultimo step registrato, e rollout_progress), awaiting_approval, waiting_dependency (con after), queued (dal più vecchio: escono dalla coda in quest'ordine) e delayed (per orario di partenza). truncated è true se i workflow attivi erano più di quelli esaminati (1000). Contiene solo i deploy che il chiamante può leggere.
GET /api/v1/workers restituisce {"workers": [...]}: per ogni worker id, state (alive, stale, stopped, unregistered), version (versione dei workflow), build, hostname, region, started_at, heartbeat_at, recovered_by, pending (workflow in sospeso per versione) e tasks, i workflow in esecuzione (kind: deploy, pass, gate, approval, schedule, after, release, con deployment_id, applicazione, ambiente, region e started_at). Richiede platform.read; hidden_tasks conta i workflow delle applicazioni che il chiamante non può leggere. Ogni worker ha anche queues, le code da cui preleva, e resources, il campione che invia a ogni heartbeat: cpus e cpu_limit (CPU dell'host e utilizzabili dal processo, che segue la quota del container), process_cpu_cores (CPU usata dal campione precedente), memory_total_bytes, memory_available_bytes e memory_limit_bytes (host e container), process_memory_bytes, load1/load5/load15, workdir_free_bytes, concurrency, goroutines e sampled_at; i valori che il sistema operativo non fornisce mancano.
GET /api/v1/queues restituisce {"queues": [...]}: per ogni coda name, kind (deployments, approvals, region, other), region, i limiti worker_concurrency, partition_concurrency e global_concurrency, i conteggi enqueued, running e delayed, oldest_enqueued e workers, i worker attivi in ascolto. Richiede platform.read.
La CLI li espone come manent activity, manent workers e manent queues.
Le richieste propagano il contesto di tracing W3C (traceparent): la traccia di un client, ad esempio una pipeline di CI, prosegue nell'API e negli step del worker.
Errori#
Gli errori hanno sempre la forma:
| Status | Significato |
|---|---|
400 |
Richiesta o descrittore malformati. |
401 |
Token mancante o non valido. |
403 |
Permesso negato. |
404 |
Deploy, schedule, revisione o finestra inesistenti. |
422 |
Richiesta non accettabile (policy, governance, orario passato, ...). |
503 |
Temporaneamente non disponibile: ad esempio nessuna policy di governance caricata. Riprovare. |
Log degli accessi#
Ogni richiesta viene registrata nel log applicativo e quindi inoltrata anche al SIEM, con metodo, percorso, status, durata, IP del client e identità (actor). Le azioni rilevanti producono anche una voce di audit.