Skip to content
OUTIS DOCS

CLI

outis ships with the Go SDK. It’s for scripts, CI steps and runbooks: anywhere a shell is easier than code.

go install github.com/outis-auth/outis-go/cmd/outis@latest

It reads the API key from OUTIS_API_KEY, and the API from OUTIS_BASE_URL if you’re not on https://api.outis.tech. Flags take a single dash.

outis request -action deploy.production -requester keith -param repo=acme/api -param env=production -idempotency-key deploy-4f2a9c
outis get req-4f2a9c1b8d7e6f50
outis wait req-4f2a9c1b8d7e6f50 -timeout 5m
outis gate -action db.restore -requester keith -param db=payments -timeout 5m ./restore.sh payments
outis verify-webhook -header "Outis-Signature: t=...,v1=..." < body.json
outis hash -action deploy.production -param repo=acme/api
outis init worker -runtime go
Command What it does
request Creates a request and prints it. -param k=v repeats. Also takes -summary, -quorum, -idempotency-key and -callback-url.
get <id> Reads a request as it stands.
wait <id> -timeout D Waits for a decision, at most 30 minutes. Exits 0 only if it was authorized.
gate ... -timeout D command [args] Creates a request, waits, and runs the command only if it was authorized. See below.
verify-webhook Checks a delivery on stdin against the secret in OUTIS_WEBHOOK_SECRET (-secret-env names another variable) and prints the event. Pass each header with -header "Name: value".
hash -action A [-param k=v] Prints the operation hash of an action and its params.
init worker -runtime R Writes a starter worker into the current directory (or -dir): go (the default) or temporal-go. Refuses to overwrite a file. Ask it for node or python and it prints that SDK’s own command.

-json on request, get and wait prints the API’s own request object. outis <command> -h lists a command’s flags.

Code Meaning
0 Done. For wait and gate, authorized.
1 Something went wrong talking to Outis.
2 Bad usage.
3 Not authorized: denied, expired or aborted.
4 The timeout ran out with the request still pending.

Once gate runs its command, it exits with the command’s own code. It exits 126 if the command can’t be run and 127 if it isn’t found.

outis gate asks for a request, waits up to -timeout, and runs the command only if the request was authorized. Everything after the first argument that isn’t a flag belongs to the command, so its own flags pass straight through. The command gets OUTIS_REQUEST_ID and OUTIS_OPERATION_HASH in its environment, and gate forwards SIGTERM to it.

outis gate -action db.restore -requester "$USER" -param db=payments -param snapshot=snap_0412 -timeout 10m ./restore.sh payments snap_0412

It’s a convenience, not a security boundary

Section titled “It’s a convenience, not a security boundary”

Gate only enforces anything when the command can’t be run any other way. That means the privileged credentials exist only where gate runs:

  • a CI job whose secrets are scoped to the step that calls gate
  • a restricted runner nobody can shell into
  • a Kubernetes job whose service account only that job gets
  • a privileged execution service that only runs commands through gate

An operator who can run ./restore.sh directly has bypassed nothing. On a laptop, gate is a polite reminder. To make it hold, move the credentials into one of those four places, and have the command itself check the request before it does anything:

outis wait "$OUTIS_REQUEST_ID" -timeout 5s > /dev/null || exit 3

A decided request answers wait at once, and it exits 0 only if it was authorized.

In code, that check is assertAuthorized with OUTIS_REQUEST_ID, which also confirms the operation matches. See SDKs.

The timeout follows the same rule as wait on the SDKs’ guard: it’s required, and it’s capped at 30 minutes. If approval could take longer, gate is the wrong tool. Use durable execution.