Pay for the work, not for the lease.
Not asciinema. Live.
SID=$(curl -sS -X POST "$ORIGIN/v1/session" | jq -r .id)
# the session's answer also has "allow": ["example.com"]
jq -Rs --arg sid "$SID" '{session:$sid,op:"W",path:"get.go",data:.}' <<'EOF' \
| curl -sS --fail-with-body "$ORIGIN/v1/fs" --json @-
package main
import "io"
import "net/http"
func main() {
resp, err := http.Get("https://example.com/")
if err != nil { println(err.Error()); return }
b, _ := io.ReadAll(resp.Body)
resp.Body.Close()
println(resp.Status)
println(string(b))
}
EOF
curl -sS --fail-with-body "$ORIGIN/v1/exec" \
--json '{"session":"'"$SID"'","line":"go run get.go"}' | jq -r .stdout
A program reaches the network only through the proxy: https only, port 443, host names, not IP literals. A response is at most 1 MiB, the exchange at most 2 seconds, and at most 3 redirects.
An anonymous session's list is the box's, today example.com, and allow in the request is ignored. POST /v1/session answers with "allow", the list that session got. A session of your own hosts needs a key: Authorization: Bearer <secret> and {"allow":["api.example.org"]}, at most 16 hosts. A wrong key is 401. More than 16 hosts is 400. Keys are issued by hand for now.
A refusal names its rule: proxy: host not allowed (not on the list, before DNS), proxy: address refused (the name is metadata, or a DNS answer is not a public address; nothing is dialed), proxy: scheme not allowed (not https), proxy: bad request (an IP literal, or a malformed URL), proxy: too many redirects, proxy: timeout, proxy: too large, proxy: budget exhausted, proxy: unavailable, proxy: no egress (this session has no list).
A line's energy is CPU time × 2 W, at $0.20/kJ. The Graviton has no energy counter.