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.