Command-line client

midair-cli runs the work on the machine that already holds the checkout, keeps the result there, and sends it to a Midair server on request.

This is the scanner half of the CI story. The Jenkins plugin installs this binary, gives it credentials, runs it, and reads its exit code. The same binary works in GitHub Actions, in GitLab, and on a laptop. See Continuous integration.

Status

The client is early. The commands that sign in work against a real server: login, logout, whoami, use, doctor and config talk to the server and report what it says.

The commands that run an analysis or a suite print what they would run, and then name what is missing.

Commands

midair login | logout | whoami | use      which servers, and who on them
midair doctor | config                    will the next run work, and why
                                          this server
midair token issue | list | revoke        API tokens
midair tool install | list                from the server's distribution
                                          registry
midair analyze [--run URL] [JOBS...] [-- BUILD-COMMAND]
midair test    [--run URL]           [-- RUN-COMMAND]
midair push    [--run URL] [--purge]
midair completions <SHELL>

Two conventions

A run is named by its URL. Copy it out of the browser: https://midair.example.com/analysis/edit?id=12. The URL carries the server, the collection and the record at once, so --server is rarely needed, and push knows what it is pushing. alias:analysis/12 and a bare 12 also work.

Everything after -- is a shell command. For test it replaces the run command of the workspace. For analyze it replaces the build command that the analyser traces. A positional argument before -- is never a shell command; for analyze it is a job name.

A template supplies both, and you can override either one alone:

midair analyze --run URL                       # everything from the template
midair analyze --run URL defects sbom          # jobs overridden
midair analyze --run URL -- make -j8           # build command overridden
midair analyze --run URL defects -- make -j8   # both

The analyser needs a real build to observe. A bare list of files gives it no command line for any file, so no language, no include paths and no toolchain, and it finds nothing.

Output and exit codes

A terminal gets a rendered view. A pipe gets newline-delimited JSON, one object per event, each with a versioned type. A CI job therefore needs no flag. --json forces JSON on a terminal. Nothing parses the rendered view.

Code

Meaning

0

Success.

1

The gate failed. The work ran, and the verdict is no.

2

Usage error.

3

Configuration or authentication error.

4

The run itself failed.

Credentials

midair login --server https://midair.example.com
midair login --server https://midair.example.com -u ci --password-stdin < pw

A sign-in returns a session cookie, and the server keeps no copy of it. The cookie therefore does not expire on its own. A password change, or a sign-out elsewhere, revokes it. whoami and doctor ask the server rather than report what is on disk, and logout ends the session on the server.

The client writes the credentials to the OS keyring. On a machine without one it writes a file with mode 0600, and login says so when that happens.

Neither a password nor a token is accepted as a command-line argument, because every process on the machine can read argv.

A CI job passes MIDAIR_SERVER and MIDAIR_TOKEN in the environment and never runs login. Nothing is written on the agent, and nothing outlives the job.

Make the token with:

midair token issue --name "jenkins" --scopes read,runs

The three token commands take a password themselves. See API tokens and the HTTP API.