Skip to main content
CLI

Using the CLI in CI

Run restward non-interactively in CI pipelines - log in from secrets, isolate the config per job, parse --json output and rely on exit codes.

The CLI runs unattended. Outside a terminal (when stdin or stdout is redirected, as in every CI runner) it never prompts: anything it would ask for must come from flags or environment variables (or stdin), otherwise the command fails.

Authentication

Credentials come from your CI secret store through environment variables - never from the command line, where other processes on the runner could read them. There are two ways:

1. Log in with a password. Put the account's password in RESTWARD_PASSWORD (or pipe it with --password-stdin) and log in at the start of the job:

Shell
export RESTWARD_API_URL=https://api.restward.tech
restward login --email "$RESTWARD_EMAIL" --password-stdin <<< "$RESTWARD_PASSWORD"
# or, with RESTWARD_PASSWORD set in the job's environment:
restward login --email "$RESTWARD_EMAIL"

The session is stored in the config file and renews itself: the CLI swaps its refresh token for a new access token before the old one expires, so long jobs keep working (a refresh token lasts 7 days with the platform's default settings).

2. Use a token directly. Set RESTWARD_TOKEN to a bearer access token and every command uses it, with no login and no config file:

Shell
export RESTWARD_API_URL=https://api.restward.tech
export RESTWARD_TOKEN=...          # from your secret store
export RESTWARD_ORG=6f1c2a8e-...   # optional: defaults to the token's organization
restward list --json

A token set this way is never stored and never renewed: platform access tokens are short-lived (15 minutes by default), so this fits short jobs or tokens minted by an earlier step. Long-lived automation tokens (personal access / service tokens) are not available on the platform yet. restward login --token stores such a token in the config file instead (read from stdin or RESTWARD_TOKEN, never from the command line).

Precedence

For each value the CLI uses the first one that is set:

Value 1st 2nd 3rd
Access token RESTWARD_TOKEN stored session -
Base URL RESTWARD_API_URL (or RESTWARD_BASE_URL) stored session -
Organization RESTWARD_ORG (a GUID) the token's organization (with RESTWARD_TOKEN) stored session
Password (login) --password-stdin prompt (terminal only) RESTWARD_PASSWORD

--base-url on login wins over the environment. restward whoami shows which source is in use (Authenticated via: RESTWARD_TOKEN or stored session).

A few things to know:

  • Use a dedicated account for automation rather than a person's login.
  • Environment variables are visible to the job's own processes. Prefer your CI system's masked secrets, and runners that are not shared with untrusted jobs.
  • restward logout at the end of the job clears the stored session and revokes that session on the platform (only that one: other jobs and the dashboard stay signed in). If the platform cannot be reached the session is cleared locally and expires on its own; restward logout --everywhere would sign the account out everywhere.

Isolate the config per job

The CLI stores the session in a config file. Point RESTWARD_CONFIG at a job-local path so parallel jobs on one runner do not share or overwrite each other's session, and remove it when the job ends:

Shell
export RESTWARD_CONFIG="$RUNNER_TEMP/restward.json"
restward login ...
# ... your commands ...
restward logout

JSON output

Add --json to any command to get one JSON object on stdout:

JSON
{ "success": true, "value": { ... } }
{ "success": false, "error": "..." }

Progress lines are suppressed in this mode and errors go to stdout as the envelope, so the output is always parseable:

Shell
endpoint=$(restward list --json | jq -r '.value.apis[] | select(.slug == "orders-db") | .endpoint')

The value fields of each command are listed in the command reference.

Exit codes

Code Meaning
0 Success
1 Failure: not logged in, no organization selected, nothing matching to act on, rejected credentials, network or platform errors
2 Usage error: unknown command, unknown or invalid options, missing or extra arguments, an unknown subcommand, or unparsable input such as a malformed connection string or organization id

A 2 means the command line itself is wrong, so retrying it will not help; a 1 can be transient (network, platform) or a missing precondition (log in first).

Example: GitHub Actions

YAML
jobs:
  provision:
    runs-on: ubuntu-latest
    env:
      RESTWARD_API_URL: https://api.restward.tech
      RESTWARD_CONFIG: ${{ runner.temp }}/restward.json
    steps:
      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '10.0.x'
      - run: dotnet tool install -g restward
      - name: Log in
        run: restward login --email "$EMAIL" --json
        env:
          EMAIL: ${{ secrets.RESTWARD_EMAIL }}
          RESTWARD_PASSWORD: ${{ secrets.RESTWARD_PASSWORD }}
      - name: Connect the staging database
        run: restward connect orders-staging --json > connect.json
        env:
          RESTWARD_CONNECTION_STRING: ${{ secrets.ORDERS_STAGING_DB }}
      - name: Log out
        if: always()
        run: restward logout || true   # exits 1 when there is no session (e.g. login failed)

connect.json contains the new API key in plaintext (value.key.plaintext). Move it to your secret store in the same job, and never upload that file as a build artifact or print it to the log.

Reconnecting to server...

Please wait while we restore your connection

Connection lost

Retrying in seconds...

Unable to reconnect

The server connection has been lost.
You may need to log in again.

Session Paused

The server has temporarily paused your session.

Session Expired

Your session could not be resumed.
Please reload the page to continue.