Automating / Change requests
Change requests
The human gate. Everything the API and CLI propose waits here.
KamalCloud’s API and CLI can read the account’s servers, apps and change requests. Neither can change anything.
What they can do is propose. A proposal becomes a change request: a row saying what was asked for, by which token, with the exact values. It does nothing until a person opens KamalCloud and approves it.
This is what makes a KamalCloud token safe to hand to a script, a CI job or an agent. The worst a stolen read token can do is read. The worst a stolen write token can do is fill a queue somebody has to say no to.
The catalogue
Only a fixed list of actions can be proposed. An action name that is not on it is refused with a 422, and the list comes back with the refusal. Each action takes exactly the keys it declares; any other key is dropped before the request is saved, so nothing reaches a model it was not meant for.
Values are not checked when the request is made. A step that names no fix is saved as asked
and fails only once somebody approves it, with the list of fixes KamalCloud knows in the error.
| Action | Parameters |
|---|---|
servers.create |
connection, provider, name, server_type, location, image |
servers.resize |
server_id, server_type |
servers.harden |
server_id, step |
environments.deploy |
environment_id |
accessories.back_up |
accessory_id |
step is one of firewall, web_ports, cloud_firewall, ssh_password_auth,
ssh_root_login, ssh_keepalive, fail2ban, fail2ban_aggressive, automatic_updates,
upgrade, swap or storage – see Hardening. From the CLI that is
kamal-cloud harden 12 firewall.
GET /api/v1/actions returns this list, with the step names in the servers.harden summary, so
a client finds out what it may propose rather than guessing at names.
Which connection
Where an account holds several connections to one provider, an action that would build something
has to say which: connection names it. Naming only a provider works when that provider has
exactly one connection, and is refused when it does not – building in one of two Hetzner
projects on a coin toss is not a thing KamalCloud will do.
Approving
Change requests lists requests by status, pending first, oldest at the top. Anyone in the account can see the list; only an admin can approve or reject. Each one shows the sentence for the request’s own values – “Build web-3, a cx42 in nbg1, at Production Hetzner” – rather than a generic summary, because approving “build a server” without knowing which is not approving anything.
Approve it and it runs, in the account it was proposed for and as the person who approved it, so whatever it creates is attributed to them rather than to nobody. Reject it and it stops there.
A request moves pending → approved → applied, or to rejected, or to failed if it was
approved and the work itself failed. The error and the result are both recorded.
From the client’s side
POST /api/v1/change_requests answers 202 Accepted – accepted for review, not carried out.
The distinction is the whole feature, so the status code makes it too.
Poll GET /api/v1/change_requests/:id, or use kamal-cloud wait <id> to block until somebody decides.
Read tokens and write tokens
A token is read-only unless it was issued with write access. A read-only token trying to propose is told plainly rather than getting a confusing permission error. Issue read-only tokens by default; there are few reasons for a script to need more.
Issuing and revoking tokens is admin only.