QueryProxy
Documentation menu

The qp command-line client

File a query request from a terminal or CI, wait for approval and download the masked result with qp, the command-line client for the QueryProxy REST API.

qp is a command-line client for the REST API. It files a query request, waits until a reviewer approves it and the worker has run it, and downloads the result. It is one static binary with nothing to install around it, so it fits a terminal as well as a CI job. It lives in its own repository, QueryProxy/qp.

qp can do only what the API allows. It cannot approve a request, and in particular it cannot approve its owner’s own request or override anything. Nothing runs until a reviewer approves it, exactly as for a request filed in the web UI, and the SQL guards and masking apply as usual.

Install

Download the archive for your platform from the releases page. Binaries exist for Linux, macOS and Windows, on amd64 and arm64. Put qp on your PATH.

The release workflow signs the checksum file keylessly with cosign. Verify the download before you use it:

cosign verify-blob \
  --bundle checksums.txt.sigstore.json \
  --certificate-identity-regexp '^https://github.com/QueryProxy/qp/\.github/workflows/release\.yml@refs/tags/v' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  checksums.txt
sha256sum --ignore-missing -c checksums.txt

Authenticate

Create a personal access token in the web UI (Profile). A token has scopes and an expiry; give it only what the pipeline needs:

To use The token needs
qp submit requests:submit (this also covers looking up a connection by name)
qp submit --wait additionally requests:read, and results:read for the result
qp status requests:read
qp results results:read, plus requests:read for --format json
export QP_URL=https://queryproxy.example.com
export QP_TOKEN='12|qp_...'

--url and --token override the environment. Prefer the environment: a flag value shows up in the process list. qp never prints the token and scrubs it from error messages. A plain http:// URL works, with a warning unless it points at the local machine, but sends the token unencrypted. qp does not follow redirects, so set QP_URL to the final address.

Commands

qp submit

qp submit --conn <id|name> --file report.sql --reason "monthly report" --wait
Flag Meaning
--conn Connection id, or its exact name (a number is always taken as an id)
--file File with the SQL; - reads standard input
--reason Why the statement is needed; the approver sees it
--title Short title, optional
--wait Wait for the approval and the run, then print the result
--timeout With --wait: give up after this long. Default 30m; 0 waits forever
--poll-interval With --wait: how often to ask the server. Default 3s
--format, --output With --wait: as for qp results

Progress goes to standard error. Without --wait, standard output carries only the request id, so id=$(qp submit ...) works. With --wait, it carries only the result. A timeout or Ctrl-C stops the waiting but does not cancel the request: it stays on the server, and qp status <id> follows it.

qp status

qp status <id> prints the request, as JSON with --json. For a finished request it exits with the same codes as qp submit --wait.

qp results

qp results <id> downloads the stored result of a completed request, already masked by the connection’s masking rules.

  • --format csv (the default) writes the result as the server sends it.
  • --format json writes one array of objects keyed by column name, streamed. Values keep their exact text; duplicate column names give duplicate keys.
  • --output <file> writes to a file instead of standard output. The file gets mode 0600, also when it already exists.

If the server cut the result at its row ceiling, qp says so on standard error.

qp version prints the version.

Exit codes

Code Meaning
0 Completed successfully
1 Usage, configuration, network or API error: a bad token, an unknown connection, SQL the guard refused
2 The request was rejected
3 The request failed to run, or was cancelled
4 --timeout ran out before the request finished
130 Interrupted

In a pipeline

- run: qp submit --conn prod-reporting --file sql/report.sql --reason "nightly report $GITHUB_RUN_ID" --wait --timeout 2h --output report.csv
  env:
    QP_URL: ${{ vars.QP_URL }}
    QP_TOKEN: ${{ secrets.QP_TOKEN }}

The job stays blocked until a reviewer decides, so give --timeout a value that fits how fast your team approves, and use a token that expires soon.

Next steps

Arrow keys to move, Enter to open.