Documentation
Surveyor CLI 1f21c27

Surveyor CLI Documentation

How to install and run the spice command-line tool, with recorded sessions of the real thing. Everything on this page works offline.

How Spice Labs works

Spice Labs builds an inventory of the cryptography in everything you ship, then tells you what needs to change for post-quantum migration and which fixes to make first. It works from built software (jars, wars, ears, container images, VM and device images), so it needs no source code, no agents in your applications and no changes to your builds.

The Surveyor and Topographer

The Surveyor is a command you run on your machines and in your CI. It is not an agent: it runs only when you run it, adds nothing to your applications, and leaves nothing running after a survey finishes. It reads every file in what you survey and computes a cryptographic fingerprint of each one.

The one exception is a runtime survey: it attaches a recorder to the single Java process you start under it, for as long as that process runs.

Topographer is the hosted service, used through the dashboard at dashboard.spicelabs.io, the REST API and AI assistants. It matches the fingerprints against a large graph of known open-source software and cryptographic libraries and builds the results:

  • a component inventory, including copies of open source that appear in no manifest because they were vendored, renamed or bundled into other files;
  • a cryptography inventory: the algorithms, keys and certificates found, each classified for post-quantum readiness, delivered as CycloneDX CBOMs;
  • vulnerability findings for the components that are really present;
  • a Portfolio that scores every application and ranks the fixes that improve the most applications at once.

What leaves your machine

A survey runs where your software is. The Surveyor builds an encrypted model of what it found and uploads only that model, using a Spice Pass that can upload to one project and do nothing else. Your files and source code never leave your machine.

Three kinds of survey

SurveyAnswersGuide
InventoryWhat cryptography and which components are present in this build?Inventory surveys
ImageThe same question, for a container image pulled by nameImage surveys
RuntimeWhich cryptography does this Java application actually use when it runs?Runtime surveys

An inventory survey and a runtime survey of the same artifact combine into one CBOM that separates cryptography that is merely present from cryptography confirmed to run.

Reports and history

Each survey is kept. When Spice Labs’ knowledge of software and cryptography improves, existing reports are marked stale and can be regenerated from the stored survey, so you get better answers without surveying again. Surveying the same application over time shows findings going away as fixes land.

Next steps

Quick start

Survey one application and see what cryptography it contains, how ready it is for post-quantum migration, and what to fix first. It takes about ten minutes.

Before you start

  • A Spice Labs account. Start a free trial or contact us. If someone invited you, use the link in your invitation email.
  • Docker, installed and running. The Surveyor CLI runs in a container. Get Docker.
  • Something to survey: a built Java application (a .jar, .war or .ear file, or the folder your build writes them to), or a container image. Surveys read built artifacts, not source code.

Survey your first application

  1. Sign in to Topographer

    Go to dashboard.spicelabs.io and sign in with your email address (you get a sign-in link by email) or with Google. Open the project you want to survey into. If you only see sample data, create a project first: a sample project cannot have a Spice Pass.

  2. Generate a Spice Pass

    Open the menu (☰) and choose Survey setup. In step 1, Generate a Spice Pass, pick how long it should last under Expires in, select Generate, then Copy. The Spice Pass lets the CLI upload surveys to this project and nothing else.

    Step 1 of the Survey setup page, Generate a Spice Pass, with the Expires in menu set to 2 weeks and a Generate button.
  3. Install the Surveyor CLI

    curl -sSfL https://install.spicelabs.io | bash
    irm -UseBasicParsing -Uri https://install.spicelabs.io | iex

    If the installer says its folder is not on your PATH, follow its instructions and open a new terminal. Details are in Install the Surveyor CLI.

  4. Set your Spice Pass

    export SPICE_PASS="<your Spice Pass>"
    $env:SPICE_PASS = "<your Spice Pass>"
  5. Run a survey

    Every survey needs a subject: the name this application has in Spice Labs. You make the name up; it is what the Portfolio, reports and Data health show. Use the application’s real name, such as payments-api, not a version, branch or date, and use exactly the same name every time you survey this application.

    spice survey inventory payments-api ./build/libs/payments-api.jar

    Here payments-api is the subject you chose, and ./build/libs/payments-api.jar is the build to survey.

    To survey a container image from its registry instead, give the image with a docker:// prefix:

    spice survey inventory payments-api docker://<registry>/<image>:<tag>

    For an image, the subject is optional. Without it, the image name without its tag becomes the subject, so every version of the image lands on one subject.

    The CLI surveys on your machine and uploads only an encrypted model of what it found. Your files and source code never leave your machine.

  6. See the results

    Back in the dashboard, open Portfolio in the top bar. Your subject appears with its scores once the survey has been analyzed, usually within a few minutes; Data health shows the survey’s progress until then. What to fix next lists the fixes that improve the most, and the subject’s post-quantum readiness report is under Reports in the menu.

If something goes wrong

  • spice: command not found: open a new terminal, and check that the folder the installer printed is on your PATH.
  • SPICE_PASS must be set via SPICE_PASS env var for upload: set SPICE_PASS in the same terminal you run spice in.
  • An upload is refused: your Spice Pass may have expired. Run spice pass decode to see its expiry, and generate a new one if needed.

More fixes are in Troubleshooting.

Next steps

Install the Surveyor CLI

The Surveyor CLI is the spice command. It surveys software on your own machines and uploads the encrypted results to your Topographer project. The installer puts a small wrapper script on your machine, and the wrapper runs the CLI in Docker.

Before you start

  • Docker, installed and running. Get Docker. If you cannot use Docker, see Run without Docker.
  • Linux containers. The CLI runs in a Linux container. On Windows, Docker Desktop runs Linux containers by default; if it was switched to Windows containers, switch it back (right-click the Docker icon, Switch to Linux containers). Windows Server’s Docker Engine runs only Windows containers.
  • A Spice Pass, to upload surveys to your project. Generate one in the dashboard. A survey run with --no-upload does not need one.

The installer writes only to your home folder, so it needs no administrator rights.

Run the installer

curl -sSfL https://install.spicelabs.io | bash

The installer:

  • Downloads the spice wrapper script to ~/.local/bin/spice.
  • Pulls the spicelabs/spice-labs-cli image and generates Bash and Zsh tab completion from it, in ~/.local/share/spice/completions/.
  • Adds a line that loads tab completion to ~/.bashrc and ~/.zshrc, when those files exist.
  • Warns you if ~/.local/bin is not on your PATH, if SPICE_PASS is not set, or if Docker is missing. It does not change your PATH itself.

Run this in PowerShell:

irm -UseBasicParsing -Uri https://install.spicelabs.io | iex

The installer:

  • Downloads spice.ps1 and a spice.cmd shim to %USERPROFILE%\.spice\bin, so spice works from PowerShell and from cmd.exe.
  • Pulls the spicelabs/spice-labs-cli image, generates PowerShell tab completion from it in %USERPROFILE%\.spice\completions, and loads it from your PowerShell profile.
  • Warns you if %USERPROFILE%\.spice\bin is not on your PATH, if SPICE_PASS is not set, or if Docker is missing. It does not change your PATH itself.

If Docker is missing or the image cannot be pulled, the installer skips tab completion and prints the command that generates it later.

Set your PATH and Spice Pass

Add the install folder to your PATH and set SPICE_PASS to the Spice Pass you copied from the dashboard.

For the current terminal:

export PATH="$PATH:$HOME/.local/bin"
export SPICE_PASS="<your-spice-pass>"

To keep them, add the same lines to your shell profile (~/.bashrc or ~/.zshrc) and open a new terminal.

For the current PowerShell session:

$env:Path += ';' + (Join-Path $HOME '.spice\bin')
$env:SPICE_PASS = '<your-spice-pass>'

For the current cmd.exe session:

set "PATH=%PATH%;%USERPROFILE%\.spice\bin"
set "SPICE_PASS=<your-spice-pass>"

To keep them for your user account, run this in PowerShell, then open a new terminal:

$add = Join-Path $HOME '.spice\bin'
$path = [Environment]::GetEnvironmentVariable('Path', 'User')
if (($path -split ';') -notcontains $add) {
  [Environment]::SetEnvironmentVariable('Path', (($path, $add) -join ';').Trim(';'), 'User')
}
[Environment]::SetEnvironmentVariable('SPICE_PASS', '<your-spice-pass>', 'User')

You can also search the Start menu for “environment variables”, choose Edit environment variables for your account, add %USERPROFILE%\.spice\bin to Path, and add a variable named SPICE_PASS.

Check the installation

Run spice --version to confirm the wrapper can reach the CLI. The first run pulls the CLI image, so it can take a minute. It prints the hash of the wrapper script, then the CLI version and the commit it was built from. These are the lines to quote when asking for support.

spice --version
~ ❯ spice --version
script version 499912f5957fb1cda5b582edd22ca611f393c531eecc06d894bfb5e062840320
1.9.3
https://github.com/spice-labs-inc/spice-labs-cli git commit: 7fdcf719a78a9f076830a8946bff760d91170a8f

On Windows the first two lines are Powershell Script hash and the hash. Then check your Spice Pass:

spice pass decode

It prints a table of the pass’s claims, such as Project ID, Expires At and Upload Server, and ends with a Status line such as Valid (expires in ...). If the table includes Artifact Cutoff (only trial and demo passes have one), see Artifact cutoff.

Keep it up to date

There are two parts to keep current:

  • The CLI image. Before each run, the wrapper pulls the latest image for its tag (latest unless you choose a version). If the pull fails and you have a local copy, the run continues with it and prints Using local copy.
  • The wrapper script. After the pull, the wrapper compares itself with the latest release. When yours is older, it prints A newer version of this script is available. Run: followed by the install command. Run the installer again to update it.

To pin a CLI version instead of following latest, or to skip the pull, see Pin the CLI version.

Run without Docker

JVM mode runs the CLI with Java on your machine instead of in Docker. Set SPICE_LABS_CLI_USE_JVM=1 and point SPICE_LABS_CLI_JAR at the CLI jar. JVM mode needs Java 21 or later and a few tools the Docker image otherwise provides: see JVM mode. To build the jar yourself, see the spice-labs-cli repository.

Uninstall

rm ~/.local/bin/spice
rm -rf ~/.local/share/spice ~/.cache/spice
docker rmi spicelabs/spice-labs-cli

Then delete the lines under # Spice CLI tab completion from ~/.bashrc and ~/.zshrc, and remove SPICE_PASS from your shell profile.

Remove-Item -Recurse -Force (Join-Path $HOME '.spice')
Remove-Item -Recurse -Force (Join-Path $env:LOCALAPPDATA 'spice') -ErrorAction SilentlyContinue
docker rmi spicelabs/spice-labs-cli

Then remove %USERPROFILE%\.spice\bin from your Path, delete the SPICE_PASS variable, and delete the lines under # Spice CLI tab completion from your PowerShell profile (the file named by $PROFILE.CurrentUserAllHosts).

Uninstalling leaves your survey results alone: results you wrote with --output stay where you put them, and recordings kept with --keep-recording stay under ~/.spicelabs/runtime-survey or the --output folder you chose.

Next steps

Inventory surveys

Available in:
  • Surveyor CLI

An inventory survey reads the files you point it at and records what is present: every file, the packages they belong to, and the cryptography they contain. Run one on your build output, a release archive or a folder of artifacts.

The results are uploaded to your Topographer project as encrypted Artifact Dependency Graphs (ADGs).

Run a survey

spice survey inventory <subject> <input>
  • <subject> is the name you choose for this application in Spice Labs. See Choose a subject.
  • <input> is a folder or a single file: a jar, war or ear, a .tar archive, a docker save tarball, a disk image and so on. See Supported file types.
# Survey a build output folder and upload the results
spice survey inventory payments-api ./build/libs

# Survey a single archive
spice survey inventory payments-api ./dist/payments-api.tar

By default, the survey uploads its results to your Topographer project, which needs SPICE_PASS set to a Spice Pass for that project. To survey without uploading, see Survey locally and upload later.

To survey a container image straight from a registry, use an image survey.

What a survey finds

The survey opens archives, images and file systems inside your input, however deeply they are nested, and fingerprints every file it finds. From those files it identifies:

  • Packages: Java archives, OS packages (such as Debian, RPM and Alpine packages), Go modules built into binaries, and dependencies declared in lockfiles, including npm, cargo and Python packages.
  • Cryptography: algorithms, certificates, keys and cryptographic configuration.

The run log reports how many packages it found, for example Writing 290 Package URLs. Because the survey reads built artifacts rather than manifests, it also finds components that were copied, renamed or bundled into other files.

Choose a subject

The subject is the name you give an application in Spice Labs. Spice Labs does not read it from your build: whatever you type is what the Portfolio, reports and Data health show, and surveys with the same subject are compared over time.

  • One subject per application, named the way your team names it, such as payments-api or customer-portal.
  • The same name on every run, from every machine and pipeline that surveys that application. payments-api and payments_api are two different applications.
  • No versions, build numbers, branch names or dates in the name. Each different name becomes a separate application with its own history. Record those details with --tag-json instead:
spice survey inventory payments-api ./build/libs --tag-json='{"version":"2.3.0","branch":"main"}'

Survey locally and upload later

Add --no-upload to survey on your machine only. Always pass --output with it, so the results land in a folder you choose:

spice survey inventory payments-api ./build/libs --no-upload --output ./spice-results
You do not need a Spice Pass for a --no-upload run.
  1. This example surveys a small project directory, my-app, and keeps the results on disk with --no-upload and --output.

  2. ls my-app
    ~ ❯ ls my-app
    Sample.java  readme.txt

    The input is an ordinary directory, here holding a source file and a text file. Any mix of jars, wheels, archives, images exported to disk and other files can be surveyed; the survey identifies each file by its content, not by its name.

  3. spice survey inventory my-app ./my-app \
      --no-upload --output ./out --log-level info
    ~ ❯ spice survey inventory my-app ./my-app \
    >   --no-upload --output ./out --log-level info
    INFO  🌶️  Spice Labs Surveyor CLI v1.9.3
    INFO  📦 Surveying artifacts...
    INFO  Blocking build db until there's at least 1 item in the work queue
    INFO  Found all files, count 2
    INFO  MIME pass complete: 2 total, 2 completed
    INFO  Kicking off work queue consumer threads
    INFO  Finished processing 2, vertices 14 at PT0.211573965S
    INFO  Finished multi-thread consumer loop 1 at PT1.334011602S
    INFO  Writing 0 Package URLs
    INFO  Post-sort at PT0.00789278S
    INFO  Post CBOR cache at PT0.026915297S
    INFO  Wrote 14 entries in PT0.062446991S
    INFO  Total build time for survey PT0.275699866S, write took PT0.063646876S
    INFO  Done with run

    The survey runs in the foreground and logs its progress: the files it found, how many it has classified by type, then the analysis and the writing of the results. This is the default info level of detail, which the example also sets explicitly; --log-level changes it.

  4. find out -maxdepth 2 | head -20
    ~ ❯ find out -maxdepth 2 | head -20
    out
    out/surveyor
    out/surveyor/survey-10920091818720119692

    The results are written under the --output directory, in surveyor/survey-<id>. It can be uploaded later with --upload-only. Without --no-upload, and with SPICE_PASS set, the same command uploads the results to your project as soon as the analysis finishes.

Each run creates its own folder inside the one you name, so repeat runs never overwrite each other:

spice-results/
  surveyor/
    survey-<random-id>/
      survey/        the ADGs

To upload those results later without surveying again, point --upload-only at the survey-<random-id> folder from that run:

spice survey inventory payments-api ./spice-results/surveyor/survey-<random-id> --upload-only

You cannot combine --no-upload and --upload-only in one run.

Tag a survey with metadata

Use --tag-json to attach your own labels, such as the environment, branch or owning team. The value must be a JSON object:

spice survey inventory payments-api ./build/libs --tag-json='{"env":"prod","team":"platform"}'

PowerShell 7 accepts the same syntax. Windows PowerShell 5.1 strips the outer quotes, so assign the JSON to a variable first:

$json = '{"env":"prod","team":"platform"}'
spice survey inventory payments-api C:\path\to\build --tag-json=$json

Tune large surveys

OptionWhat it controlsDefault
--threadsNumber of analysis threads (1 or more)Half your CPU cores
--max-recordsRecords processed per batch5000

--chunk-size sets the upload chunk size in MB; by default Spice Labs chooses it.

For example, to use fewer threads on a shared build machine:

spice survey inventory payments-api ./build/libs --threads=2

To use the same values on every run, put them in a configuration file instead.

Keep a log of the run

Use --log-level for more or less detail (error, warn, info, debug or trace) and --log-file to save a copy of everything the run prints:

spice survey inventory payments-api ./build/libs --log-level=debug --log-file=./spice.log

The log file is appended to, not replaced, so one file can hold several runs.

Artifact cutoff

A Spice Pass issued for a trial or a demo can carry an artifact cutoff: a date after which published artifacts are left out of the survey, together with anything that contains them. Spice Passes for paid projects have no cutoff and survey everything.

When your credential has a cutoff, the run says so:

Ignoring artifacts published after 2026-01-01T00:00:00Z

The cutoff comes from the credential, so no option or setting changes it. To check yours, run spice pass decode and look for Artifact Cutoff.

See the results

When the upload finishes, the survey appears in your project in the dashboard, and Topographer builds its reports from it, including the post-quantum readiness report and the CBOM. To correlate this survey with what your application does at run time, also run a runtime survey anchored to the same artifact.

Image surveys

Available in:
  • Surveyor CLI

An image survey is an inventory survey of a container image’s contents. Give spice survey inventory the image with a docker:// prefix, and the CLI pulls it from its registry with oras, which is built into the CLI’s container, so there is no docker pull and no tar export. It surveys the image’s contents and handles the result like any inventory survey, with the same options (--no-upload, --output and the rest) and the same artifact cutoff.

Run a survey

spice survey inventory [<subject>] docker://<image>
  • <image> is the image reference, in the form name[:tag][@digest]. oci://<image> means the same as docker://<image>.
  • <subject> is the name you choose for this application in Spice Labs; see Choose a subject. Without it, the image’s repository name, without its tag or digest, becomes the subject, so every version of the image lands on one subject. Set it when you want a different name.

Without the prefix, nginx:1.27 is read as a path. When no such file exists, the CLI stops and says to use docker://nginx:1.27.

Survey a public image:

spice survey inventory docker://nginx:1.27
spice survey inventory web-frontend docker://ghcr.io/myorg/web:2.3.0

The first survey is labeled nginx; the second, web-frontend.

By default, the survey uploads its results to your Topographer project, which needs SPICE_PASS set to a Spice Pass for that project. To survey without uploading, see Survey locally and upload later.

How image names are expanded

spice expands short names to their full form. The default subject is the repository name, without the tag or digest:

You typespice surveysDefault subject
docker://nginxdocker.io/library/nginx:latestnginx
docker://nginx:1.27docker.io/library/nginx:1.27nginx
docker://myorg/appdocker.io/myorg/app:latestmyorg/app
docker://ghcr.io/myorg/app:2.3.0Exactly what you typedghcr.io/myorg/app
docker://ubuntu@sha256:<digest>That exact image digestubuntu
docker://registry.example.internal:5000/team/app:1.0Exactly what you typedregistry.example.internal:5000/team/app

Pin a tag or a digest when you need repeatable results, because latest changes over time.

Survey a private image

spice uses the registry credentials already stored on your machine. Log in once with Docker, then survey as normal:

docker login ghcr.io
spice survey inventory docker://ghcr.io/myorg/app:2.3.0

The wrapper shares your Docker configuration folder with the CLI, read-only. It uses $DOCKER_CONFIG if you set it, and ~/.docker otherwise. If your credentials live somewhere else, set DOCKER_CONFIG to that folder before running spice.

Docker Desktop keeps logins in a credential helper (the macOS Keychain or Windows Credential Manager) rather than in that folder. When it does, the wrapper asks the helper for the login to that one registry and passes it to the CLI in a temporary file, which is deleted when the run ends. Without a login, public images still work and private ones fail with an authentication error.

Survey a saved image

An image saved as an OCI image layout folder, for example with oras cp --to-oci-layout, needs no prefix. Survey the folder like any other, with a subject:

spice survey inventory web-frontend ./saved-image

Survey locally and upload later

Add --no-upload to survey on your machine only. Always pass --output with it, so the results land in a folder you choose:

spice survey inventory web-frontend docker://nginx:1.27 --no-upload --output ./spice-results

Each run creates its own folder inside the one you name, with the same layout as an inventory survey. While the survey runs, the image itself is downloaded into a temporary folder under --output and removed afterwards, so point --output at a disk with room for the image.

You do not need a Spice Pass for a --no-upload run. To upload those results later without surveying again, use --upload-only, pointed at the survey-<random-id> folder from that run instead of the image, and with the same subject:

spice survey inventory web-frontend ./spice-results/surveyor/survey-<random-id> --upload-only

You cannot combine --no-upload and --upload-only in one run.

Other options

Image surveys accept the same options as other inventory surveys: --tag-json, --threads, --max-records, --log-level, --log-file and --analysis-args, and for the upload --chunk-size and --upload-args. See Inventory surveys for how to use them.

The artifact cutoff of a trial or demo Spice Pass applies here too.

The older command

Before image surveys moved into spice survey inventory, they had a command of their own, spice survey image <image> [--subject=<subject>]. It still runs, but it is hidden from the help, prints a notice naming the new form, and will be removed. Its default subject now also drops the tag.

Runtime surveys

Available in:
  • Surveyor CLI

A runtime survey runs your Java application, or its test suite, with recording turned on and captures the cryptographic operations it actually performs. An inventory survey tells you what cryptography is present in an artifact; a runtime survey tells you what that artifact used. Survey the same artifact both ways to get a combined view.

Run a survey

spice survey runtime <subject> --jfr -- <command>
  • <subject> is the name you choose for this application in Spice Labs. Use the same name as its inventory surveys; see Choose a subject.
  • --jfr selects JDK Flight Recorder instrumentation. Always include it.
  • -- separates the spice options from the command to run.
  • <command> is the command that starts your Java application or tests.
# Run an application under the survey
spice survey runtime payments-api --jfr -- java -jar app.jar

# Run a test suite under the survey
spice survey runtime payments-api --jfr -- mvn test

The target application must run on JDK 11 or later.

By default, the survey uploads its results to your Topographer project, which needs SPICE_PASS set to a Spice Pass for that project; see Upload the results. To survey without uploading, see Survey locally without uploading.

What happens during a run

  1. spice prepares a working folder with the Spice Labs recording agent and the recording settings.
  2. It downloads the probe configuration for the agent from Spice Labs.
  3. It runs your command on your own machine, not in a container, with recording turned on.
  4. When your command exits, it analyzes the recordings, prints a summary and uploads the results.

Because your command runs on your machine, it needs everything it normally needs there: the right Java version, your build tool and your project files. Exercise the parts of the application you care about, then stop it normally. The survey sees only cryptography that actually runs, and the recording is written when the JVM exits.

spice adds its settings to JAVA_TOOL_OPTIONS for your command, keeping any value you already had there. If your command fails (for example, a failing test), spice still collects and analyzes the recordings. It then exits with your command’s exit code, so your build still sees the failure.

Upload the results

A runtime survey uploads in the same run: when your command exits, spice analyzes the recordings and uploads the results to your Topographer project. Set SPICE_PASS to a Spice Pass for that project before you start:

export SPICE_PASS="<your Spice Pass>"
spice survey runtime payments-api --jfr -- java -jar app.jar
$env:SPICE_PASS = "<your Spice Pass>"
spice survey runtime payments-api --jfr -- java -jar app.jar

There is no separate upload step, and no way to upload a runtime survey afterwards: a run with --no-upload is analyzed on your machine only. Once the upload is processed, the survey appears in your project; see See the results.

Run without the agent

--native-only records only the security events built into the JDK and skips the Spice Labs agent:

spice survey runtime payments-api --jfr --native-only -- java -jar app.jar

Use it if the agent conflicts with another agent in your application. It captures less detail.

spice also falls back to this mode on its own, with the warning Could not download probe config. Using native-only mode., when it cannot download the probe configuration.

Survey locally without uploading

Add --no-upload to analyze the recordings on your machine and print a summary, without uploading anything. You do not need a Spice Pass for this:

spice survey runtime payments-api --jfr --no-upload -- java -jar app.jar

Unlike inventory and image surveys, a runtime survey cannot be uploaded later. To get its results into Topographer, run the survey again without --no-upload, with SPICE_PASS set.

The probe configuration download needs your Spice Pass. A --no-upload run without SPICE_PASS falls back to native-only mode with a warning; add --native-only to skip the download.

Keep the recordings

GoalAdd
Keep the .jfr recording files after the run--keep-recording
Choose where the working files go--output=<dir>
spice survey runtime payments-api --jfr --keep-recording --output=./rec -- java -jar app.jar

Each run works in a survey-<random-id> folder under --output, by default ~/.spicelabs/runtime-survey. Without --keep-recording that folder is deleted at the end. With it, spice prints Recordings kept in: and the folder path.

Anchor the survey to an artifact

To correlate a runtime survey with an inventory survey of the same artifact, pass that jar, war or ear with --anchor:

spice survey runtime payments-api --anchor=./build/libs/app.jar --jfr -- java -jar ./build/libs/app.jar

spice fingerprints the anchor file so it can be matched to the inventory survey that indexed it, and the two combined into one CBOM. Without --anchor, the survey still produces its own results but is not correlated, and the run warns: No --anchor given; this survey will not correlate into a combined CBOM.

See the results

After the upload, the survey appears in your project. Its post-quantum readiness report also records the runtime environment and the TLS connections and certificates observed while the application ran. If no recordings appear, see Troubleshooting.

GitHub Actions

The Spice Labs Surveyor action runs an inventory survey or an image survey in your workflow and uploads the results to your Topographer project. Add it after your build step so every push or release is surveyed.

Set up the action

  1. Store your Spice Pass as a secret

    Generate a Spice Pass for the project the surveys should go to, and choose an Expires in that suits a pipeline. In your repository, open Settings, then Secrets and variables, then Actions, and select New repository secret. Name it SPICE_PASS and paste the Spice Pass as its value.

  2. Add the workflow

    Create .github/workflows/spice-survey.yml:

    name: Spice Labs survey
    
    on:
      push:
        branches: [main]
    
    permissions:
      contents: read
    
    jobs:
      survey:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
    
          - name: Build
            run: ./gradlew build
    
          - name: Survey build output
            uses: spice-labs-inc/action-spice-labs-surveyor@v5
            with:
              subject: payments-api
              input: ./build/libs
              spice_pass: ${{ secrets.SPICE_PASS }}

    Replace the build step with your own, and point input at the folder your build writes its artifacts to.

  3. Commit and push

    The next push to main runs the survey. The survey appears in your project when the upload finishes.

The action installs the Surveyor CLI and runs it in Docker, so use a Linux runner such as ubuntu-latest.

Inputs

InputRequiredDefaultDescription
subjectYes, for filesThe name you choose for this application in Spice Labs. Keep it the same on every run. With image, it defaults to the image name without its tag
spice_passYesYour Spice Pass. Pass it from a secret. If it is empty, the action stops before it surveys, with an error that names spice_pass.
inputNo.Path to the files to survey. Ignored when image is set.
imageNoContainer image reference to survey instead of local files, for example ghcr.io/myorg/app:2.3.0
log_levelNoinfodebug, info, warn or error
cli_imageNospicelabs/spice-labs-cliThe CLI image to run. Add a tag or digest to pin a version, for example spicelabs/spice-labs-cli:1.9.3.

The action has no outputs. It runs spice survey inventory, with docker://<image> as the input when image is set. For runtime surveys, --no-upload, --tag-json or other options, run the CLI directly.

Survey a container image

Set image to survey an image from its registry instead of local files. For a private registry, log in first:

- uses: docker/login-action@v3
  with:
    registry: ghcr.io
    username: ${{ github.actor }}
    password: ${{ secrets.GITHUB_TOKEN }}

- uses: spice-labs-inc/action-spice-labs-surveyor@v5
  with:
    subject: payments-api
    image: ghcr.io/myorg/app:${{ github.sha }}
    spice_pass: ${{ secrets.SPICE_PASS }}

The CLI uses the runner’s Docker credentials to pull the image. When you use GITHUB_TOKEN to read packages, give the job packages: read permission. See Image surveys.

Survey several components

Survey each component under its own subject, so each one has its own results in the dashboard:

jobs:
  survey-frontend:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: spice-labs-inc/action-spice-labs-surveyor@v5
        with:
          subject: frontend
          input: ./frontend/dist
          spice_pass: ${{ secrets.SPICE_PASS }}

  survey-backend:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: spice-labs-inc/action-spice-labs-surveyor@v5
        with:
          subject: backend
          input: ./backend/build/libs
          spice_pass: ${{ secrets.SPICE_PASS }}

Pin the CLI version

The action installs the newest wrapper script and, by default, runs the latest CLI image. To keep results repeatable between runs, name the CLI image with its version in cli_image:

with:
  subject: payments-api
  spice_pass: ${{ secrets.SPICE_PASS }}
  cli_image: spicelabs/spice-labs-cli:1.9.3

To run the CLI from your own copy of the image, name that copy the same way, for example cli_image: registry.example.com/mirror/spice-labs-cli:1.9.3. A digest works in place of the tag.

Run the CLI directly

When you need an option the action does not expose, install the CLI in a step and run spice yourself:

jobs:
  survey:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build
        run: ./gradlew build

      - name: Install the Surveyor CLI
        run: |
          curl -sSfL https://install.spicelabs.io | bash
          echo "$HOME/.local/bin" >> "$GITHUB_PATH"

      - name: Survey build output
        env:
          SPICE_PASS: ${{ secrets.SPICE_PASS }}
          SPICE_IMAGE_TAG: "1.9.2"
        run: spice survey inventory payments-api ./build/libs --tag-json='{"branch":"${{ github.ref_name }}"}'

SPICE_IMAGE_TAG pins the CLI version here. It applies only while SPICE_IMAGE is unset: if you set SPICE_IMAGE, put the tag in it (spicelabs/spice-labs-cli:1.9.2). On a self-hosted runner that already has the image, you can set SPICE_LABS_CLI_SKIP_PULL=1 to skip the pull and the update check. See Configuration.

Keep the pipeline secure

  • Pass the Spice Pass only from a secret, never in the workflow file.
  • Give the workflow the least permissions it needs, such as contents: read.
  • A Spice Pass works for one project only. Use a separate secret for each project you survey into.
  • When the Spice Pass expires, uploads stop working. Generate a new one and update the secret, or revoke the old one on the Credentials page if it leaks.

Configuration

Two kinds of settings control a survey. Host environment variables tell the spice wrapper how to run the CLI: which image, whether to pull it, and whether to use Docker at all. Survey settings, such as thread counts and log level, live in a configuration file and can be overridden by environment variables and options.

Credentials

SPICE_PASS holds your Spice Pass, which uploads need; generate one in the dashboard. It has no configuration file setting.

Host environment variables

The wrapper reads these on your machine before the CLI starts.

VariableDefaultWhat it does
SPICE_IMAGEspicelabs/spice-labs-cliThe CLI image to run. When set, it is used exactly as written, including any tag.
SPICE_IMAGE_TAGlatestThe image tag. Used only when SPICE_IMAGE is not set.
SPICE_LABS_CLI_SKIP_PULL01 skips pulling the image and the wrapper’s update check. The image must already be on the machine.
SPICE_DOCKER_NETWORKhostThe network the CLI’s container uses. none cuts it off from the network.
SPICE_DOCKER_FLAGSnoneExtra options added to the docker run command, separated by spaces. Not applied to runtime surveys.
DOCKER_CONFIG~/.dockerThe Docker configuration folder whose registry credentials image surveys use, mounted read-only.
SPICE_LABS_JVM_ARGS-XX:MaxRAMPercentage=75Options for the JVM that runs the CLI. It is passed into the container when you set it.

Pin the CLI version

By default every run pulls spicelabs/spice-labs-cli:latest. To stay on one version, set the tag:

export SPICE_IMAGE_TAG=1.9.2
$env:SPICE_IMAGE_TAG = "1.9.2"

SPICE_IMAGE takes priority over everything else that picks an image. When it is set, spice runs exactly that reference: SPICE_IMAGE_TAG and the --features option are ignored, and an image named without a tag means latest. So if you set SPICE_IMAGE, put the tag in it:

export SPICE_IMAGE=spicelabs/spice-labs-cli:1.9.2
$env:SPICE_IMAGE = "spicelabs/spice-labs-cli:1.9.2"

Run without network access

To prove a survey makes no network calls, cut the container off from the network and skip the upload:

SPICE_DOCKER_NETWORK=none spice survey inventory payments-api ./build/libs --no-upload --output ./spice-results
$env:SPICE_DOCKER_NETWORK = "none"
spice survey inventory payments-api .\build\libs --no-upload --output .\spice-results
Remove-Item Env:SPICE_DOCKER_NETWORK

The wrapper still pulls the image and checks for a newer wrapper script on your machine before the run. Set SPICE_LABS_CLI_SKIP_PULL=1 as well to skip both.

JVM mode (running without Docker)

With SPICE_LABS_CLI_USE_JVM=1, the wrapper runs the CLI jar with your local Java instead of in Docker. Paths are used as they are, and --features is ignored. Docker mode is the one these docs describe and the one to use when you can. JVM mode needs:

  • Java 21 or later on your PATH.
  • The CLI jar at the path in SPICE_LABS_CLI_JAR. Build it from the spice-labs-cli repository. Plugins are loaded from a plugins/ folder beside the jar.
  • oras on your PATH for image surveys.
  • syft on your PATH to identify OS packages, Go modules and lockfile dependencies. Without it the survey still runs but finds far fewer packages, and prints no warning.

The Docker image includes all of these. On Windows, set SPICE_LABS_JVM_ARGS to a single JVM option, such as -XX:MaxRAMPercentage=75, when you use JVM mode.

VariableDefaultWhat it does
SPICE_LABS_CLI_USE_JVM01 runs the CLI with Java on your machine instead of in Docker.
SPICE_LABS_CLI_JAR/opt/spice-labs-cli/spice-labs-cli.jarThe CLI jar used in JVM mode.

Configuration file

Settings you use on every run can live in a TOML file instead of on the command line. spice reads one file per run.

Where the file is found

PlatformLocation, first match wins
AnyThe file you name with spice --config <file>
macOS and Linux$XDG_CONFIG_HOME/spice/config.toml (by default ~/.config/spice/config.toml), then spice/config.toml in each $XDG_CONFIG_DIRS folder (by default /etc/xdg)
Windows%APPDATA%\spice\config.toml, then %PROGRAMDATA%\spice\config.toml

The first file found is the only one used. Naming a file that does not exist with --config is an error, but finding no file at the default locations just means there is no configuration file. --config belongs to spice itself, so it goes before the subcommand:

spice --config ./ci.toml survey inventory payments-api ./build/libs

Settings

Settings are grouped by the job they describe:

[analysis]
threads = 16
max_records = 100000

[upload]
target_chunk_size = 64

[logging]
level = "debug"
GroupKeys
analysisthreads (default: half your CPU cores), max_records (default: 5000)
uploadtarget_chunk_size (MB), encrypt_only, skip_key, comment, bundle_format_version
logginglevel: error, warn, info, debug or trace (default: info)

A group at the top of the file applies to every command that reads it. To change one command only, write the group under that command’s name:

[analysis]
threads = 16

[survey.inventory.analysis]
threads = 4

The log file cannot be set in the configuration file. Use the --log-file option instead: the wrapper writes the log on your machine, and a path named anywhere else would be written inside the container and lost.

Other paths named in the configuration file are mounted into the container automatically, so they resolve to the same place as on your machine.

One setting, three names

Every setting has the same name in all three places:

FormShapeExample
Configuration keysnake_case in a group[analysis] max_records
Optionkebab-case--max-records
Environment variableSPICE_<GROUP>_<KEY>SPICE_ANALYSIS_MAX_RECORDS

Which value wins

defaults  <  [group]  <  [command.group]  <  environment  <  command line

When one source overrides another, the run logs it, for example analysis.threads = 8 (SPICE_ANALYSIS_THREADS) overrides 16 ([analysis] in ...).

Check what a run will use

spice config explain shows every setting a command would use and where each value came from, without running a survey. For example, with this configuration file at ~/.config/spice/config.toml:

[analysis]
threads = 4

[survey.inventory.analysis]
max_records = 20000

[logging]
level = "debug"

and the log level set from the environment:

SPICE_DOCKER_FLAGS="-e SPICE_LOGGING_LEVEL=warn" spice config explain survey inventory
$env:SPICE_DOCKER_FLAGS = "-e SPICE_LOGGING_LEVEL=warn"
spice config explain survey inventory
Remove-Item Env:SPICE_DOCKER_FLAGS

the output names the source of each value, and logs the override:

# /home/you/.config/spice/config.toml

INFO ⚙️  logging.level = warn (SPICE_LOGGING_LEVEL) overrides debug ([logging] in /home/you/.config/spice/config.toml)
[analysis]
  max_records = 20000    [survey.inventory.analysis] in /home/you/.config/spice/config.toml
  threads     = 4        [analysis] in /home/you/.config/spice/config.toml

[logging]
  level = "warn"    SPICE_LOGGING_LEVEL

A setting you have not set shows default. Without a configuration file, the first line reads # No configuration file; showing defaults and the environment. Add --group=<name> to show one group only.

If a group name is misspelled, or belongs to a plugin you do not have, the run warns and continues: No command reads [anaylsis] — check the spelling, or the plugin may not be installed.

Shell completion

The installers set up tab completion for spice in Bash, Zsh and PowerShell. The completion script is generated by the installed CLI, so it offers the commands your installation has. Choose your shell above the recording to see how it looks there.

Shell
  1. Type spice and ask the shell for completions. Press Tab twice. Press Tab once.

  2. Zsh lists the top-level commands on the first Tab. On the second it starts inserting them in turn, so config is now on the line. Keep pressing Tab to move through the list, or type a few letters to narrow it.

    Bash lists the top-level commands on the second Tab and leaves the line as it was, ready for you to type the first letters of the one you want.

    PowerShell lists the top-level commands and options on the first Tab. That is its behavior on macOS and Linux; on Windows, Tab instead cycles through the candidates in place.

  3. It works at every level: spice survey followed by Tab offers the survey types.

    The candidates come from spice generate-completion, which reads the installed CLI, so they always match the commands and survey types you have.

    The candidates come from the script the installer generated with spice generate-powershell-completion.

Set it up by hand

The installers do this for you. To do it yourself, for example after an upgrade:

  • Bash. Write the script with spice generate-completion > ~/.spice-completion.bash, and source that file from ~/.bashrc.
  • Zsh. Use the same script, loaded through Bash compatibility. In ~/.zshrc, add autoload -U +X bashcompinit && bashcompinit, then source the file.
  • PowerShell. Write the script with spice generate-powershell-completion > spice-completion.ps1, and dot-source it from your $PROFILE.

CLI reference

This page lists every command and option of spice. For how to use them, start with Inventory surveys; for environment variables and the configuration file, see Configuration.

The CLI prints the same information itself: run spice --help or spice <command> --help, or spice docs --commands for all of it at once.

  1. Start at the top: spice --help lists the top-level commands.
  2. spice --help
    ~ ❯ spice --help
    Usage: spice [-hV] [--config=FILE] [COMMAND]
    Spice Labs CLI
          --config=FILE   TOML configuration file. Defaults to the standard config
                            location.
      -h, --help          Show this help message and exit.
      -V, --version       Print version information and exit.
    Commands:
      survey  Survey software artifacts
      pass    Spice Pass utilities
      docs    Show the user guide, or print the help for every command when this
                build has no guide.
      config  Inspect the configuration this run would use
    
    Examples:
      spice survey inventory my-app ./build/libs
      spice survey inventory my-app ./app.jar --no-upload --output ./out
      spice survey runtime my-app --jfr -- java -jar app.jar
      spice pass decode
    
    Run 'spice <command> --help' for details on each subcommand.
    

    The main ones are survey, which runs a survey, and config, which explains configuration. pass works with your Spice Pass. docs prints the help for every command. Plugins, when installed, add their commands here as well.

  3. spice survey --help
    ~ ❯ spice survey --help
    Usage: spice survey [-hV] [COMMAND]
    Survey software artifacts
      -h, --help      Show this help message and exit.
      -V, --version   Print version information and exit.
    Commands:
      inventory  Survey artifact inventory and upload ADGs to Spice Labs
      runtime    Survey runtime crypto usage via JFR instrumentation
    
    Examples:
      spice survey inventory my-app ./build/libs
      spice survey inventory my-app docker://nginx:1.27
      spice survey runtime my-app --jfr -- java -jar app.jar
    
    Run 'spice survey <type> --help' for per-subcommand details.
    

    spice survey --help lists the survey types, each with a one-line summary, followed by examples.

  4. spice survey inventory --help
    ~ ❯ spice survey inventory --help
    Usage: spice survey inventory [OPTIONS] <subject> <input>
           spice survey inventory [OPTIONS] [<subject>] (docker|oci)://<image>
    Survey artifact inventory and upload ADGs to Spice Labs
          [<subject>]            Label identifying the system being surveyed;
                                   optional before a docker:// or oci:// image,
                                   which defaults it to the image's repository name
          [<input>]              Path to artifacts (directory or single file), or
                                   docker://<image> or oci://<image> for a
                                   container image in a registry
          --analysis-args=<goatRodeoArgsRaw>[,<goatRodeoArgsRaw>...]
                                 Additional analysis args in key=value format
          --chunk-size=<chunkSizeMB>
                                 Target chunk size in MB for uploads (default: 64)
      -h, --help                 Show this help message and exit.
          --log-file=<logFile>   Path to log file (output appended to both console
                                   and file)
          --log-level=<logLevel> Log level: debug|info|warn|error (default: info)
          --max-records=<maxRecords>
                                 Max records to process per batch (default: 5000)
          --no-upload            Survey only, skip upload
          --output=<output>      Output directory for survey results
          --tag-json=<tagJson>   Additional JSON metadata for tags
          --threads=<threads>    Number of threads to use (default: half of
                                   available CPU cores)
          --upload-args=<gingerArgsRaw>[,<gingerArgsRaw>...]
                                 Additional upload args in key=value format
          --upload-only          Upload previously-generated ADGs (skip survey)
      -V, --version              Print version information and exit.
    
    Examples:
      # Survey a directory of artifacts and upload
      spice survey inventory my-app ./build/libs
    
      # Survey a container image from a registry; the subject defaults to the
      # repository name (here ghcr.io/acme/web)
      spice survey inventory docker://ghcr.io/acme/web:2.4.1
      spice survey inventory web-store oci://ghcr.io/acme/web:2.4.1
    
      # Survey a single file, skip upload, write output to ./out
      spice survey inventory my-app ./app.jar --no-upload --output ./out
    
      # Attach JSON tag metadata
      spice survey inventory my-app ./dist --tag-json='{"env":"prod"}'
    
      # Upload previously-surveyed ADGs
      spice survey inventory my-app ./out --upload-only
    
    SPICE_PASS must be set in the environment for upload.
    

    Every survey type has its own --help with the full option list. spice survey inventory --help shows the arguments an inventory survey takes and every option, with its default.

Commands

CommandWhat it does
spice survey inventorySurvey files, folders and archives
spice survey inventory docker://<image>Survey a container image straight from its registry (docker:// or oci://)
spice survey runtimeRecord the cryptography a running Java application uses
spice survey inventory --upload-only, --upload-args, --chunk-sizeUpload inventory survey results to Topographer
spice survey inventory docker://<image> --upload-args, --chunk-sizeUpload image survey results to Topographer
spice survey runtime --chunk-sizeUpload runtime survey results to Topographer
spice pass decodeShow what your credential holds
spice config explainShow every setting a run would use and where each came from
spice docs --commands, --jsonPrint the help for every command, or the commands as JSON
spice --versionPrint the version and, where a license applies, whether it is valid
spice generate-completionPrint the tab completion script (generate-powershell-completion for PowerShell)

Global options

These belong to spice itself, so they go before the subcommand.

OptionDescription
--config=FILEUse this TOML configuration file instead of the one found at the standard locations. See Configuration file.
-h, --helpShow help and exit. Every command accepts it.
-V, --versionPrint the CLI version and the commit it was built from, and exit. Through the wrapper, it also prints the wrapper script’s hash. Every command accepts it.

spice survey inventory

Available in:
  • Surveyor CLI
spice survey inventory [options] <subject> <input>
spice survey inventory [options] [<subject>] docker://<image>

Surveys artifacts and uploads the results to Spice Labs as encrypted Artifact Dependency Graphs (ADGs). SPICE_PASS must be set to upload.

Argument or optionDescriptionDefault
<subject>Label identifying the system being surveyed. Required for a path; optional before an imageFor an image, its repository name without tag or digest
<input>A folder (not empty) or a single file, or docker://<image> (or oci://<image>) for a container image in a registry. Required.
--output=<dir>Folder for the results. Each run writes to <dir>/surveyor/survey-<random-id>/.A folder inside the container, discarded after the run
--tag-json=<json>Your own metadata for the survey, as a JSON objectNone
--threads=<n>Number of analysis threads, 1 or moreHalf your CPU cores
--max-records=<n>Records processed per batch5000
--log-level=<level>error, warn, info, debug or traceinfo
--log-file=<path>Append everything the run prints to this file on your machine, without color codesNone
--analysis-args=<key=value>[,...]Extra settings passed to the analysis engineNone

These control the upload:

Available in:
  • Surveyor CLI
OptionDescriptionDefault
--no-uploadSurvey only, skip upload. No credential needed.Off
--upload-onlyUpload a previous run’s results without surveying again. <input> is that run’s survey-<random-id> folder. Not with --no-upload or an image.Off
--chunk-size=<MB>Target upload chunk size in MBChosen by Spice Labs
--upload-args=<key=value>[,...]Extra settings passed to the upload stepNone

The help text shows (default: 64) for --chunk-size, but when you leave the option unset, the CLI sends no chunk size and Spice Labs chooses one.

The help lists debug|info|warn|error for --log-level; trace is accepted too. Change --analysis-args only when Spice Labs support asks you to.

Most of these options also have a configuration file key and an environment variable, such as [analysis] threads and SPICE_ANALYSIS_THREADS. See One setting, three names.

Container images

Available in:
  • Surveyor CLI
spice survey inventory [options] [<subject>] docker://<image>

With docker://<image> as the input, the CLI pulls the image from its registry with oras, which is built into the CLI’s container, so there is no docker pull or tar export. It surveys the image’s contents and handles the result like any inventory survey. oci://<image> means the same thing. The image is name[:tag][@digest]; a bare name such as nginx is expanded to docker.io/library/nginx:latest.

Without a subject, the survey is labeled with the image’s repository name, without its tag or digest: docker://ghcr.io/acme/web:2.4.1 becomes ghcr.io/acme/web and docker://nginx:1.27 becomes nginx, so every version of an image lands on one subject. While the survey runs, the image is downloaded to a temporary folder, under --output when you set it, and removed afterwards.

All the options above apply, except --upload-only. See Image surveys.

An image name without the prefix, such as nginx:1.27, is read as a path; when no such file exists, the CLI says to use docker://nginx:1.27. spice survey image <image>, the older form, still runs but is hidden from the help, prints a notice naming the new form, and will be removed.

spice survey runtime

Available in:
  • Surveyor CLI
spice survey runtime [options] <subject> --jfr -- <command...>

Runs <command> with Java Flight Recorder instrumentation, then analyzes the recordings and uploads the results. Everything after -- is the command to run. See Runtime surveys.

Argument or optionDescriptionDefault
<subject>Label identifying the system being surveyed. Required.
--jfrUse Java Flight Recorder instrumentation. Required.
--anchor=<path>The jar, war or ear this survey is of. It is fingerprinted so the survey can be correlated with an inventory survey that indexed it, producing a combined CBOM.None
--native-onlyRecord only the JDK’s built-in security events, without the Spice Labs agentOff
--keep-recordingKeep the .jfr files after the runOff
--output=<dir>Folder for the working files~/.spicelabs/runtime-survey
OptionDescriptionDefault
--no-uploadAnalyze locally and print a summary, don’t uploadOff
--log-level=<level>error, warn, info, debug or trace. Applied only in JVM mode, when running without Docker.info
--chunk-size=<MB>Target upload chunk size in MB. Applied only in JVM mode, when running without Docker.Chosen by Spice Labs

The wrapper runs your command on your machine and uses the container only to prepare and analyze. --log-file works too.

spice pass decode

Available in:
  • Surveyor CLI
spice pass decode

Decodes and displays the Spice Pass in SPICE_PASS.

It prints:

  • A first line naming the credential and its source, such as Spice Pass (from SPICE_PASS).
  • JWT Header: the signing algorithm and type.
  • Claims: a table with the columns Name, Claim and Value. Times are shown as numbers with a readable date beside them.
  • Status: Valid (expires in ...), EXPIRED or No expiration.

The claims it can show, in this order:

LabelClaimLabelClaim
Token Typex-typeOrganization IDx-uuid-org
Token Versionx-versionUser IDx-uuid-user
JWT IDjtiProject IDx-uuid-project
Issued AtiatDemo Projectdemo
Expires AtexpUpload Serverx-upload-server
Not BeforenbfChallengex-challenge
IssuerissArtifact Cutoffx-cutoff
SubjectsubLicensed Featuresx-features
AudienceaudLicensed Editionx-edition

Any other claim is shown with its claim name as the label. A public key in the credential is printed as a separate Public Key block. If Artifact Cutoff is present, inventory surveys leave out artifacts published after that date: see Artifact cutoff.

spice config explain

Available in:
  • Surveyor CLI
spice config explain [--group=GROUP] [COMMAND...]

Shows every setting and where its value came from: a default, a group in the configuration file, the environment or an option. COMMAND is the command to explain, such as survey inventory; without it, every command’s settings are shown. --group restricts the output to one group, such as analysis. See Check what a run will use.

spice docs

Available in:
  • Surveyor CLI
spice docs [--commands | --json]

Prints the help for every command, one after another. --json prints the commands and their options as JSON instead, for tools and AI agents; the same JSON is attached to each CLI release as cli-docs.json. --commands prints the help listing explicitly.

Tab completion

Available in:
  • Surveyor CLI

The installer sets up tab completion for you. To generate it yourself:

# Bash and Zsh, for the current shell
source <(spice generate-completion)

In PowerShell, spice generate-powershell-completion prints the equivalent script. See Shell completion.

Exit status

spice exits with 0 when the command succeeds. On an error it prints the reason and exits with a non-zero status. The survey commands follow an error with Use --help for usage information. A runtime survey exits with your command’s exit code when that command failed, and otherwise with the survey’s own status. See Troubleshooting for the messages.

Supported file types

A survey fingerprints every file in its input, whatever the type. The formats below are the ones it also opens, so it can survey what is inside them, or recognizes as packages. Containers nest: a jar inside a tarball inside a disk image is opened all the way down.

Archives and containers

CategoryFormatsExamples
ZIP-family archivesZIP, JAR, WAR, EAR and other Java archives, Android APKapp.zip, myapp.jar, webapp.war, app.ear, app.apk
Container imagesdocker save tarballs, OCI image layoutsmyimage.tar (with manifest.json), a folder with oci-layout, index.json and blobs/
Tar and other archivestar, cpio, arbackup.tar, initrd.cpio, libfoo.a
Compressed filesgzip, bzip2, xz, lzma, zstddata.tar.gz, logs.tar.bz2, archive.xz, payload.zst
OS packagesRPM, Debian, Arch Linux (pacman), Alpine, FreeBSD and OpenBSD packagesnginx-1.24.0-1.el9.x86_64.rpm, curl_8.5.0_amd64.deb, musl-1.2.5-r0.apk
ISO 9660 imagesISO disc imagesubuntu-24.04-live-server-amd64.iso
Disk imagesqcow2, VMDK, VHD, VHDX, VDI, raw, AMI, Google Cloud imagesdisk.qcow2, vm.vmdk, machine.vhdx, os.vdi, disk.raw, gcp-image.tar.gz
File systems in disk imagesext2, ext3, ext4, FAT32, exFAT, NTFS, XFS, Btrfs, SquashFS, HFS+, APFS, behind MBR or GPT partition tables and LVMan ext4 partition inside a .qcow2, a SquashFS root file system in a firmware image
Firmware and binary containersLinux kernel images, U-Boot FIT images, device tree blobs, ELF, Raspberry Pi firmware, Android boot images, WIM, DMGzImage, fitImage, bcm2711-rpi-4-b.dtb, boot.img, install.wim, app.dmg

Compressed files are decompressed first, and the result is then checked against the other formats. A disk image is read through every file system on it, including those in LVM volumes.

Packages

Besides opening files, a survey identifies the packages they belong to:

EcosystemWhat it readsExamples
JavaJars and other Java archives, with their Maven metadatacommons-codec-1.17.0.jar
.NETManaged assembliesSystem.Data.dll, MyApp.exe
Installed OS packagesThe package databases inside container images and file systemsDebian, RPM and Alpine packages in an image
LockfilesDeclared dependencies, such as npm, cargo and Python requirementspackage-lock.json, Cargo.lock, requirements.txt
GoModules built into Go binariesa compiled Go service
Language package archivesnpm, PyPI, Go modules, crates.io, RubyGems, Packagist, Conda, CocoaPods, CPAN, Hex and LuaRocks packageslodash-4.17.21.tgz, requests-2.32.3-py3-none-any.whl, serde-1.0.200.crate, rails-7.1.3.gem

Troubleshooting

Find the message spice printed, or the symptom that matches, and follow the fix. The headings quote each message without the symbol printed before it; <path> and similar stand for the value in your message.

For more detail on any run, add --log-level=debug and run it again, and add --log-file=spice.log to save a copy of the output. Messages marked JVM mode appear only when you run the CLI without Docker, in JVM mode (SPICE_LABS_CLI_USE_JVM=1). On Windows, the wrapper’s own messages use [X], [!] and [*] in place of the symbols, and a few differ slightly in wording.

Setup and Docker

Docker is not installed or not in PATH

The CLI runs in Docker by default. Install Docker from docs.docker.com/get-docker, make sure it is running, and open a new terminal. On Windows, install Docker Desktop and start it before you run spice. If you cannot use Docker, see JVM mode.

Docker on this machine runs Windows containers.

The CLI runs in a Linux container, and this machine’s Docker runs only Windows containers. In Docker Desktop, right-click the Docker icon and choose Switch to Linux containers, then run spice again. Windows Server’s Docker Engine cannot run Linux containers; use a machine whose Docker can.

Failed to pull <image>, then Image <image> not found locally either.

spice could not download the CLI image and has no local copy. Check that:

  • Your machine can reach Docker Hub, or the registry you use.
  • If you set SPICE_IMAGE or SPICE_IMAGE_TAG, that image and tag exist. A tag must be in SPICE_IMAGE itself when SPICE_IMAGE is set: see Pin the CLI version.
  • If you used --features, your machine has access to that product’s private image.

If you see Failed to pull <image> followed by Using local copy., the run continues with the image you already have.

A newer version of this script is available. Run:

Your wrapper script is older than the latest release. Run the install command it prints, or see Install the Surveyor CLI.

The shell cannot find spice

  • Open a new terminal after installing.
  • Check that the install folder is on your PATH: ~/.local/bin on macOS and Linux, %USERPROFILE%\.spice\bin on Windows. See Set your PATH and Spice Pass.

Missing: <jar>

JVM mode. There is no CLI jar at the path in SPICE_LABS_CLI_JAR. Point it at your jar, or unset SPICE_LABS_CLI_USE_JVM to run in Docker.

Spice Pass

SPICE_PASS must be set via SPICE_PASS env var for upload. Use --no-upload to skip upload.

An inventory or image survey needs your Spice Pass to upload. Generate one and set SPICE_PASS, or add --no-upload to survey locally. A runtime survey reports the same problem as SPICE_PASS not set, or in JVM mode as SPICE_PASS must be set for upload. Use --no-upload to run locally.

The upload fails

  • Run spice pass decode and check the Status line. If it says EXPIRED, generate a new Spice Pass.
  • Check that Project ID is the project you expect. A Spice Pass works for one project only.
  • Check that SPICE_PASS holds the whole pass, with no extra spaces or line breaks.
  • Check your network connection and that your machine can reach the Upload Server shown by spice pass decode, then run again.

Inventory and image surveys

Input path does not exist: <path> or Input directory is empty: <path>

Check the <input> argument of spice survey inventory. Relative paths are resolved from your current folder, and a folder must contain at least one file.

Cannot use both --no-upload and --upload-only

Pick one. Use --no-upload to survey without uploading, and --upload-only to upload the results of an earlier run.

--tag-json is not valid JSON or --tag-json must be a JSON object

The value must be a JSON object such as {"env":"dev"}. On Windows PowerShell 5.1, assign the JSON to a variable first, as the message suggests. See Tag a survey with metadata.

--threads must be at least 1, got: <n>

Use a whole number of 1 or more, or leave --threads off to use half your CPU cores.

Failed to pull image (<image>), oras exited <n>:

spice could not download the image you asked it to survey. The lines after the message are the download tool’s own output. Check the image name and tag, and for a private registry run docker login <registry> first. See Survey a private image.

The survey covered fewer artifacts than expected

If you are using a trial or demo Spice Pass, it may carry an artifact cutoff. Look for Ignoring artifacts published after <date> in the output, or run spice pass decode and look for Artifact Cutoff. See Artifact cutoff.

The local results are missing

Without --output, results are written inside the CLI’s container and discarded when the run ends. Run again with --output ./spice-results and look inside spice-results/surveyor/survey-<random-id>/.

Runtime surveys

No command specified after --

Put -- between the spice options and your command, for example spice survey runtime payments-api --jfr -- java -jar app.jar. In JVM mode the message is No command specified. Use -- to separate the command to execute.

No subject specified

Add a subject label before --, for example spice survey runtime payments-api --jfr -- mvn test.

Missing required option: '--jfr'

JVM mode. Add --jfr. Include it in every runtime survey, in Docker mode too.

No JFR recordings found in <folder>

Your command ran but produced no recordings. In JVM mode the message is No JFR recordings found. The target application may not have produced any. Check that:

  • The command starts a Java process. A script that launches Java counts.
  • The application exits normally after doing real work, so the recording is written.
  • Your command’s output shows no Flight Recorder start-up errors.

Target command exited with code <n>. Still collecting recordings.

Your command failed, for example with a failing test. The survey continues with whatever was recorded and then exits with your command’s exit code.

JDK <n> is not supported by the JFR parser. JDK 11+ is required for the CLI to parse JFR recordings.

JVM mode. Run the application on JDK 11 or later.

Could not download probe config. Using native-only mode.

spice could not fetch the agent’s probe configuration, so it recorded the JDK’s built-in security events only. The download needs your Spice Pass: set SPICE_PASS, check your network connection, and run again for full detail. To skip the download on purpose, add --native-only. In JVM mode the message is Failed to download probe config. Falling back to native-only mode.

No --anchor given; this survey will not correlate into a combined CBOM.

The survey still runs, but it cannot be combined with an inventory survey. Add --anchor=<path-to-jar>. See Anchor the survey to an artifact.

Total recording size exceeds 1GB. This may indicate excessive instrumentation.

JVM mode. The run was very long or recorded a lot. Survey a shorter run of the parts of the application you care about.

Configuration

No command reads [<group>] — check the spelling, or the plugin may not be installed

A group name in your configuration file is misspelled, or belongs to a plugin you do not have. The run continues without it. Fix the name and check with spice config explain.

[analysis] unknown key: <key>

A key in the [analysis] group is misspelled or not supported. See Settings for the keys.

[logging] level must be one of error, warn, info, debug, trace, got: <value>

Set level in [logging] to one of the values listed.

[logging] file was set in <source>, but it can only be given as --log-file

The log file can only be set with --log-file on the command line. Remove file from the group named in the message, or SPICE_LOGGING_FILE from your environment.

A setting is not taking effect

Run spice config explain <command>, for example spice config explain survey inventory, to see the value each setting will use and where it came from. Options beat environment variables, which beat the configuration file. In Docker mode, SPICE_<GROUP>_<KEY> variables do not reach the CLI unless you pass them through SPICE_DOCKER_FLAGS: see Which value wins.