Surveyor IT Pro Documentation
How to install and run the spice command-line tool, with recorded sessions
of the real thing. Everything on this page works offline.
Your first offline survey
This walkthrough takes Surveyor IT Pro from a machine that is set up to its first results, without anything leaving the machine. Everything it produces is written to a folder you choose; there is no account to sign in to and nothing to upload.
Before you start
Follow Air-gapped setup, then check that spice runs and the license is valid:
spice --version
The last line should read license: valid until <date>. If it does not, see Spice License.
Make a working folder and copy into it the files to survey, such as a release archive, a build output folder or a few jars. Run every command below from that folder: the wrapper makes it visible to the CLI’s container.
mkdir first-survey && cd first-survey
mkdir artifacts
cp /path/to/payments-api.jar artifacts/New-Item -ItemType Directory first-survey, first-survey\artifacts | Out-Null
Set-Location first-survey
Copy-Item C:\path\to\payments-api.jar artifacts\Survey the folder
An inventory survey maps every file in the folder: the packages they belong to and the cryptography they contain.
spice survey inventory payments-api ./artifacts --output ./spice-resultspayments-api is the subject: the name you give this application, the same on every run. The run logs its progress and ends with Done with run. Always pass --output: every survey here runs locally, and without --output the results stay inside the CLI’s container and are discarded when the run ends.
The results are in a new folder for this run:
spice-results/
surveyor/
survey-<random-id>/
survey/ the Artifact Dependency Graphs (ADGs)
Build a CBOM
A registry sweep builds a CBOM for every package version in a repository or a folder. To sweep the artifacts folder, create registry.toml in the working folder:
[[repositories]]
id = "first-survey"
format = "local"
path = "artifacts"
Then list what is there, and build the CBOMs:
spice registry discover --config registry.toml --output discovery.toml
spice registry cbom --process --config registry.toml --discovery discovery.toml --output cboms
Each file in artifacts gets a folder under cboms/, holding a cbom folder with the CBOM of the cryptographic material found, such as certificates, keys and algorithms, in CycloneDX JSON.
Each folder also gets cbom.json, which ranks the cryptography found for post-quantum readiness
and names where in the code it is called.
Next steps
Air-gapped setup
Surveyor IT Pro runs entirely on your machine: it uploads nothing
and checks its license offline. This page sets it up on a machine with no network access. You
carry three things to that machine from one that has access: the Docker image, the spice wrapper
script, and your Spice License.
What you need
- Docker on the machine that runs the surveys: Docker Engine on Linux, or Docker Desktop on Windows or macOS. On Windows, Docker Desktop must run Linux containers, its default.
- The image. Spice Labs arranges access to it with you, either as access to pull it from the registry or as an image file.
- The
spicewrapper:spicefor Linux and macOS,spice.ps1for Windows, from the Surveyor CLI releases. Download it on a machine with access and copy it across. - A Spice License, issued to your organization by Spice Labs. See Spice License.
Bring the image across
If you received an image file, skip to loading it. Otherwise, on a machine that can reach the registry, pull the image and save it to a file. Use the tag Spice Labs gave you:
docker pull ghcr.io/spice-labs-inc/spice-labs-cli-itpro:<tag>
docker save -o spice-surveyor.tar ghcr.io/spice-labs-inc/spice-labs-cli-itpro:<tag>docker pull ghcr.io/spice-labs-inc/spice-labs-cli-itpro:<tag>
docker save -o spice-surveyor.tar ghcr.io/spice-labs-inc/spice-labs-cli-itpro:<tag>Copy spice-surveyor.tar to the air-gapped machine and load it:
docker load -i spice-surveyor.tar
docker load prints the image’s name and tag, such as Loaded image: ghcr.io/spice-labs-inc/spice-labs-cli-<name>:<tag>. You need that name in the next step. docker image ls lists it again.
Install the wrapper
The installer downloads the wrapper from the internet, so on an air-gapped machine put the script in place yourself, as the installer would.
mkdir -p ~/.local/bin
install -m 755 spice ~/.local/bin/spiceNew-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.spice\bin" | Out-Null
Copy-Item .\spice.ps1 "$env:USERPROFILE\.spice\bin\spice.ps1"
Unblock-File "$env:USERPROFILE\.spice\bin\spice.ps1"
Set-Content -Path "$env:USERPROFILE\.spice\bin\spice.cmd" -Value "@echo off`npowershell -ExecutionPolicy Bypass -File `"$env:USERPROFILE\.spice\bin\spice.ps1`" %*"Then make sure the folder is on your PATH: ~/.local/bin on Linux and macOS, %USERPROFILE%\.spice\bin on Windows. On Windows, add it once for your user account and open a new PowerShell window:
[Environment]::SetEnvironmentVariable("Path", "$([Environment]::GetEnvironmentVariable('Path', 'User'));$env:USERPROFILE\.spice\bin", "User")
Point the wrapper at the image
Tell the wrapper which image to run, and that it must never try to pull it. Use the name and tag docker load printed:
export SPICE_IMAGE="ghcr.io/spice-labs-inc/spice-labs-cli-<name>:<tag>"
export SPICE_LABS_CLI_SKIP_PULL=1$env:SPICE_IMAGE = "ghcr.io/spice-labs-inc/spice-labs-cli-<name>:<tag>"
$env:SPICE_LABS_CLI_SKIP_PULL = "1"SPICE_IMAGE is used exactly as written, so include the tag. Without SPICE_LABS_CLI_SKIP_PULL=1, every run first tries to pull the image, fails with Failed to pull, and goes on with Using local copy. Put both lines in your shell’s startup file, or on Windows store them for your user account as shown for PATH, so every terminal has them.
Set your Spice License
export SPICE_LICENSE=$(cat spicelicense.txt)$env:SPICE_LICENSE = (Get-Content -Raw .\spicelicense.txt).Trim()See Spice License for keeping it in a file, setting it for every terminal, and renewing it.
Check the setup
spice --version
It prints the wrapper script’s hash (script version <hash>, or Powershell Script hash and the hash on Windows), the CLI version, the commit it was built from, the product with its features, and last the license:
license: valid until 1 March 2027, 00:00 UTC
If the last line says license: none (...), the reason is in the parentheses: see Troubleshooting. Then list the commands this product has:
spice --help
Prove it needs no network
To show that a run reaches nothing, cut the container off from every network with SPICE_DOCKER_NETWORK=none. This works for anything that reads only local files: an inventory survey of a folder, or a registry sweep of a folder of files. A sweep of an artifact repository needs a route to that repository, so leave the setting off for it.
export SPICE_DOCKER_NETWORK=none$env:SPICE_DOCKER_NETWORK = "none"Spice License
A Spice License lets Surveyor IT Pro run. Spice Labs issues it
to your organization; it names the product and the features it grants, and it expires on a set
date. spice checks it on your machine against a key built into the image, offline: the check
never contacts a server, and you need no Spice Labs account.
Every command checks the license before it does any work, except spice pass decode, spice config explain, tab completion and --help, which run without one.
Get a license
Spice Labs issues Spice Licenses; contact Spice Labs for one, or for a new one when yours nears its expiry date. You receive it as a single line of text, usually in a file.
Set it
Keep the license in a file with restricted permissions, or in your secrets manager, and load it into the SPICE_LICENSE environment variable from there rather than typing it:
export SPICE_LICENSE=$(cat spicelicense.txt)$env:SPICE_LICENSE = (Get-Content -Raw .\spicelicense.txt).Trim()That sets it for the current terminal. To set it for every new terminal, add the same line to your shell’s startup file (such as ~/.bashrc or ~/.zshrc), or on Windows store it for your user account and open a new PowerShell window:
[Environment]::SetEnvironmentVariable("SPICE_LICENSE", (Get-Content -Raw .\spicelicense.txt).Trim(), "User")
The wrapper passes SPICE_LICENSE into the CLI’s container and trims stray spaces and line breaks from it.
Check it
spice --version ends with one line saying whether the license is valid, without running anything:
license: valid until 1 March 2027, 00:00 UTC
When it is not, the line gives the reason, as in license: none (Your Spice License expired on 1 March 2026, 00:00 UTC.).
For the whole license, run spice pass decode. It runs even when the license is not valid, and shows the licensed features (Licensed Features), what it was issued for (Licensed Edition), when it expires (Expires At), any Artifact Cutoff, and a License: line saying whether it is valid for this product.
Renew it
Within 30 days of the expiry date, every run warns you:
⚠️ Your Spice License expires on 1 March 2027, 00:00 UTC; contact Spice Labs for a new one before then.
Ask Spice Labs for a new license before then, and set SPICE_LICENSE to it. After the expiry date, every command except the ones above stops with Your Spice License expired on <date>.
When spice refuses to run
spice stops before doing any work and prints one line saying why, followed by what to do. Every message, and its fix, is in Troubleshooting.
Inventory surveys
- Surveyor IT Pro
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 written to a folder you choose as Artifact Dependency Graphs (ADGs). Nothing is uploaded.
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.tararchive, adocker savetarball, a disk image and so on. See Supported file types.
# Survey a build output folder and keep the results in ./spice-results
spice survey inventory payments-api ./build/libs --output ./spice-results
# Survey a single archive
spice survey inventory payments-api ./dist/payments-api.tar --output ./spice-resultsEvery survey here runs locally, so pass --output on every run: without it, the results stay inside the container and are discarded when the run ends. See Keep the results.
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-apiorcustomer-portal. - The same name on every run, from every machine and pipeline that surveys that application.
payments-apiandpayments_apiare 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-jsoninstead:
spice survey inventory payments-api ./build/libs --tag-json='{"version":"2.3.0","branch":"main"}'
Keep the results
Pass --output, so the results land in a folder you choose. --no-upload is accepted and changes nothing here:
spice survey inventory payments-api ./build/libs --no-upload --output ./spice-results
This example surveys a small project directory,
my-app, and keeps the results on disk with--no-uploadand--output.ls my-app~ ❯ ls my-app Sample.java readme.txtThe 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.
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.8.6 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 multi-thread consumer loop 1 at PT0.857955208S INFO Finished processing 2, vertices 14 at PT0.057242946S INFO Writing 0 Package URLs INFO Post-sort at PT0.008920594S INFO Post CBOR cache at PT0.027894505S INFO Wrote 14 entries in PT0.069111271S INFO Total build time for survey PT0.128088998S, write took PT0.07051468S INFO Done with runThe 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
infolevel of detail, which the example also sets explicitly;--log-levelchanges it.find out -maxdepth 2 | head -20~ ❯ find out -maxdepth 2 | head -20 out out/surveyor out/surveyor/survey-1242916983054718201The results are written under the
--outputdirectory, insurveyor/survey-<id>. Everything the survey produced is in that directory; nothing leaves the machine.
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
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
| Option | What it controls | Default |
|---|---|---|
--threads | Number of analysis threads (1 or more) | Half your CPU cores |
--max-records | Records processed per batch | 5000 |
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 License can carry an artifact cutoff: a date after which published artifacts are left out of the survey, together with anything that contains them. A license without one surveys 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.
Image surveys
- Surveyor IT Pro
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).
Run a survey
spice survey inventory [<subject>] docker://<image>
<image>is the image reference, in the formname[:tag][@digest].oci://<image>means the same asdocker://<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 web-frontend docker://registry.example.internal/web-frontend:2.3.0 --output ./spice-resultsThe image must come from a registry this machine can reach, such as a mirror inside your network. Nothing is uploaded, so pass --output on every run; see Keep the results.
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 type | spice surveys | Default subject |
|---|---|---|
docker://nginx | docker.io/library/nginx:latest | nginx |
docker://nginx:1.27 | docker.io/library/nginx:1.27 | nginx |
docker://myorg/app | docker.io/myorg/app:latest | myorg/app |
docker://ghcr.io/myorg/app:2.3.0 | Exactly what you typed | ghcr.io/myorg/app |
docker://ubuntu@sha256:<digest> | That exact image digest | ubuntu |
docker://registry.example.internal:5000/team/app:1.0 | Exactly what you typed | registry.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
Keep the results
Every image survey here runs locally. Pass --output, so the results land in a folder you choose:
spice survey inventory web-frontend docker://nginx:1.27 --no-upload --output ./spice-results
--no-upload is accepted and changes nothing here.
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.
Other options
Image surveys accept the same options as other inventory surveys: --tag-json, --threads, --max-records, --log-level, --log-file and --analysis-args. See Inventory surveys for how to use them.
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
- Surveyor IT Pro
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.--jfrselects JDK Flight Recorder instrumentation. Always include it.--separates thespiceoptions 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.
What happens during a run
spiceprepares a working folder with the recording settings.- It runs your command on your own machine, not in a container, with recording turned on.
- When your command exits, it analyzes the recordings and prints a summary.
Nothing is uploaded, and no results file is written: the summary is the result. Add --keep-recording to keep the raw .jfr recordings; see Keep the recordings.
Pass --native-only on every run. The Spice Labs agent needs a probe configuration that comes from Spice Labs, so without --native-only the run tries to fetch it, cannot, and falls back to native-only recording with the warning Could not download probe config. Using native-only mode.
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.
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.
Keep the recordings
| Goal | Add |
|---|---|
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.
Registry sweeps and CBOMs
- Surveyor IT Pro
A registry sweep starts from the artifacts your builds already publish. Point it at an artifact repository, such as Artifactory or Nexus, or at a folder of files, and it lists every package version there. Then it downloads each version, maps every file inside it, and writes a CBOM (a cryptographic bill of materials) for it, on this machine. No team has to change its build pipeline, and the sweep remembers what it has done, so the next run builds only the versions that are new.
Nothing is uploaded: the CBOMs are written to a folder on this machine and nowhere else. The repository must be reachable from this machine, such as one inside your network, or you sweep a folder of files.
A sweep takes three steps:
- Write a registry configuration file that says where the artifacts are.
- Run
spice registry discoverto list the package versions into a discovery file, and edit it to choose what to build. - Run
spice registry cbom --processto build the CBOMs.
Run every command from one folder that holds the configuration file, the discovery file and the output. The wrapper makes that folder, and every file you name on the command line, visible to the CLI’s container; paths inside the configuration file are read relative to that folder.
Write a registry configuration file
The file is TOML. Each [[repositories]] table is one repository: its format (the package type), the server’s url, the repository’s name on that server, and which product serves it. For a Maven repository on Sonatype Nexus:
[[repositories]]
id = "corp-maven" # your name for it, used in output
format = "maven"
url = "https://nexus.example.internal"
repository = "maven-releases"
[repositories.host]
kind = "nexus"
[repositories.host.credential]
type = "basic"
username = "survey-bot"
password = { file = "nexus-password.txt" }
Save it as registry.toml. The password is read from nexus-password.txt in the same folder, so the configuration file holds no secret. A secret can also be written in the file as a plain string, which is simplest to test with but is then in the file for anyone who can read it.
For JFrog Artifactory, url includes the context path, and Artifactory also accepts a bearer token:
[[repositories]]
id = "corp-libs"
format = "maven"
url = "https://artifactory.example.internal/artifactory"
repository = "libs-release-local"
[repositories.host]
kind = "artifactory"
[repositories.host.credential]
type = "bearer"
token = { file = "artifactory-token.txt" }
format can be maven, npm, pypi, nuget, helm, rubygems, cargo, apt, rpm, conda and others; kind can be nexus, artifactory, gitlab, standard (any server that speaks only the format’s own protocol) and others. A repository that needs no sign-in leaves out the credential table. Add one [[repositories]] table for each repository to sweep.
Sweep a folder of files
To sweep files you already have, such as firmware images, device images or compiled binaries copied from elsewhere, use format = "local" with a path:
[[repositories]]
id = "device-images"
format = "local"
path = "artifacts"
Every file under artifacts/ is a package with one version, named by the first twelve hex digits of its SHA-256. Keep the folder inside the one you run spice from.
Discover what is there
spice registry discover --config registry.toml --output discovery.toml
This lists every package and its versions into discovery.toml. Without --output, the list is printed instead; add --max 20 to try a few packages first. The discovery file is a snapshot: run discover again to refresh it.
To choose what to build, edit the rules near the top of the file. Each pattern is matched against the package URL (such as pkg:maven/com.example/payments-api); with no rules, everything is built:
[[include]]
pattern = "pkg:maven/com.example/"
[[exclude]]
pattern = "-test"
Do not edit the package list below the rules; discover rewrites it.
Build the CBOMs
spice registry cbom --process --config registry.toml --discovery discovery.toml --output cboms
For each selected version, this downloads the artifacts from the repository, maps every file inside them, and writes the results to cboms/<namespace>/<name>/<version>/. Each version’s folder holds a cbom folder with the CBOM of the cryptographic material found, such as certificates, keys and algorithms, in CycloneDX JSON, beside the inventory of every file.
- Surveyor IT Pro
Each version’s folder also gets cbom.json: a CBOM that ranks the cryptography found for
post-quantum readiness, using the complete cryptographic algorithm catalog built into the image,
and names where in the code it is called.
When the run ends, it prints a summary: how many packages it processed, how many artifacts it downloaded, how many CBOM files it wrote, and any errors. --threads 4 processes four versions at once.
Run it again
The sweep keeps track of every version it has processed, in a state folder it creates beside the configuration file. Run the same --process command again after discover has found new versions, and it builds only those. To see or reset what it remembers:
# List the versions already processed
spice registry cbom --config registry.toml --export-processed
# Forget one package, or everything, so the next --process builds it again
spice registry cbom --config registry.toml --reset --purl pkg:maven/com.example/payments-api
spice registry cbom --config registry.toml --reset
spice registry status --config registry.toml summarizes what the sweeps have done so far.
On Windows
The commands are the same in PowerShell. Run them from the folder that holds registry.toml, with Docker Desktop running:
spice registry discover --config registry.toml --output discovery.toml
spice registry cbom --process --config registry.toml --discovery discovery.toml --output cboms
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_LICENSE holds your Spice License, which every run needs; see Spice License. It has no configuration file setting.
Host environment variables
The wrapper reads these on your machine before the CLI starts.
| Variable | Default | What it does |
|---|---|---|
SPICE_IMAGE | spicelabs/spice-labs-cli | The CLI image to run. When set, it is used exactly as written, including any tag. |
SPICE_IMAGE_TAG | latest | The image tag. Used only when SPICE_IMAGE is not set. |
SPICE_LABS_CLI_SKIP_PULL | 0 | 1 skips pulling the image and the wrapper’s update check. The image must already be on the machine. |
SPICE_DOCKER_NETWORK | host | The network the CLI’s container uses. none cuts it off from the network. |
SPICE_DOCKER_FLAGS | none | Extra options added to the docker run command, separated by spaces. Not applied to runtime surveys. |
DOCKER_CONFIG | ~/.docker | The Docker configuration folder whose registry credentials image surveys use, mounted read-only. |
SPICE_LABS_JVM_ARGS | -XX:MaxRAMPercentage=75 | Options for the JVM that runs the CLI. It is passed into the container when you set it. |
The wrapper also takes a --features option before the command: --features it, --features itpro or --features otpro runs ghcr.io/spice-labs-inc/spice-labs-cli-it, -itpro or -otpro
(tag latest) when SPICE_IMAGE is not set. The option is not passed on to the CLI.
Run the image you were given
Set SPICE_IMAGE to the image exactly as it is on this machine, tag included, and SPICE_LABS_CLI_SKIP_PULL=1 so the wrapper never tries to pull it. SPICE_IMAGE takes priority over everything else that picks an image. See Air-gapped setup.
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
| Platform | Location, first match wins |
|---|---|
| Any | The 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"
| Group | Keys |
|---|---|
analysis | threads (default: half your CPU cores), max_records (default: 5000) |
upload | target_chunk_size (MB), encrypt_only, skip_key, comment, bundle_format_version |
logging | level: 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:
| Form | Shape | Example |
|---|---|---|
| Configuration key | snake_case in a group | [analysis] max_records |
| Option | kebab-case | --max-records |
| Environment variable | SPICE_<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_FLAGSthe 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.
Type
spiceand ask the shell for completions. Press Tab twice. Press Tab once.Zsh lists the top-level commands on the first Tab. On the second it starts inserting them in turn, so
configis 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.
It works at every level:
spice surveyfollowed 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, addautoload -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.
- Start at the top:
spice --helplists the top-level commands. spice --help~ ❯ spice --help Usage: spice [-hV] [--config=FILE] [COMMAND] Spice Labs CLI: Surveyor IT Pro --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 registry Bulk-survey an artifact registry over time (allspice) 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, andconfig, which explains configuration.docsprints the help for every command. Plugins, when installed, add their commands here as well.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 image Survey an OCI or Docker image pulled by name Examples: spice survey inventory my-app ./build/libs spice survey image my-app nginx spice survey runtime my-app --jfr -- java -jar app.jar Run 'spice survey <type> --help' for per-subcommand details.spice survey --helplists the survey types, each with a one-line summary, followed by examples.spice survey inventory --help~ ❯ spice survey inventory --help Usage: spice survey inventory [-hV] [--no-upload] [--log-file=<logFile>] [--log-level=<logLevel>] [--max-records=<maxRecords>] [--output=<output>] [--tag-json=<tagJson>] [--threads=<threads>] [--analysis-args=<goatRodeoArgsRaw>[, <goatRodeoArgsRaw>...]]... <subject> <input> Survey artifact inventory and upload ADGs to Spice Labs <subject> Label identifying the system being surveyed <input> Path to artifacts (directory or single file) --analysis-args=<goatRodeoArgsRaw>[,<goatRodeoArgsRaw>...] Additional analysis args in key=value format -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) -V, --version Print version information and exit. Examples: # Survey a directory of artifacts and upload spice survey inventory my-app ./build/libs # 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_PASS must be set in the environment for upload.Every survey type has its own
--helpwith the full option list.spice survey inventory --helpshows the arguments an inventory survey takes and every option, with its default.
Commands
| Command | What it does |
|---|---|
spice survey inventory | Survey files, folders and archivesAlways runs locally; pass --output to keep the results |
spice survey inventory docker://<image> | Survey a container image straight from its registry (docker:// or oci://)Always runs locally; pass --output to keep the results |
spice survey runtime | Record the cryptography a running Java application usesPrints a summary; nothing is uploaded |
spice registry discover --output, --max | List the packages and versions in an artifact repository or a folder |
spice registry cbom --process, --discovery, --output, --threads, --reset, --export-processed | Build a CBOM of every package version a discovery file selects, on this machine |
spice registry cbom | Rank the cryptography in each CBOM for post-quantum readiness, with call sites |
spice registry status | Summarize what the registry runs have done |
spice pass decode | Show what your credential holds |
spice config explain | Show every setting a run would use and where each came from |
spice docs --commands, --json | Print the help for every command, or the commands as JSONNeeds a valid Spice License |
spice --version | Print the version and, where a license applies, whether it is validIncludes a license line |
spice generate-completion | Print the tab completion script (generate-powershell-completion for PowerShell) |
Global options
These belong to spice itself, so they go before the subcommand.
| Option | Description |
|---|---|
--config=FILE | Use this TOML configuration file instead of the one found at the standard locations. See Configuration file. |
-h, --help | Show help and exit. Every command accepts it. |
-V, --version | Print 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. |
--version also names the product and its features, and ends with a license line: license: valid until <date>, or license: none (<reason>). It is the quickest way to check a license; see
Spice License.
The wrapper also takes --features it, --features itpro or --features otpro before the
command, to choose the image to run when SPICE_IMAGE is not set. See
Configuration.
spice survey inventory
- Surveyor IT Pro
spice survey inventory [options] <subject> <input>
spice survey inventory [options] [<subject>] docker://<image>Surveys artifacts and writes the results as Artifact Dependency Graphs (ADGs) to the --output
folder. Nothing is uploaded, and every run surveys locally, so pass --output on every run:
without it the results are discarded when the run ends.
| Argument or option | Description | Default |
|---|---|---|
<subject> | Label identifying the system being surveyed. Required for a path; optional before an image | For 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 object | None |
--threads=<n> | Number of analysis threads, 1 or more | Half your CPU cores |
--max-records=<n> | Records processed per batch | 5000 |
--log-level=<level> | error, warn, info, debug or trace | info |
--log-file=<path> | Append everything the run prints to this file on your machine, without color codes | None |
--analysis-args=<key=value>[,...] | Extra settings passed to the analysis engine | None |
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
- Surveyor IT Pro
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. As with any inventory survey, pass --output on every run. 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
- Surveyor IT Pro
spice survey runtime [options] <subject> --jfr -- <command...>Runs <command> with Java Flight Recorder instrumentation, then analyzes the recordings and prints a summary. Nothing is uploaded and no results file is written; add --keep-recording to keep the raw recordings. Everything after -- is the command to run. See Runtime surveys.
| Argument or option | Description | Default |
|---|---|---|
<subject> | Label identifying the system being surveyed. Required. | |
--jfr | Use 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-only | Record only the JDK’s built-in security events, without the Spice Labs agent | Off |
--keep-recording | Keep the .jfr files after the run | Off |
--output=<dir> | Folder for the working files | ~/.spicelabs/runtime-survey |
The wrapper runs your command on your machine and uses the container only to prepare and analyze. --log-file works too.
spice registry
- Surveyor IT Pro
Sweeps an artifact repository, or a folder of files, and builds CBOMs of what it holds. The settings (which repository, how to sign in to it) come from a registry configuration file that each command names with --config. See Registry sweeps and CBOMs for a walkthrough and the file’s format.
Every registry command takes:
| Option | Description |
|---|---|
--config=FILE | The registry configuration file |
--json | Machine-readable output |
This --config comes after registry <command>. The global --config, before registry, names spice’s own configuration file, which is a different file.
spice registry discover
spice registry discover --config=FILE [--output=FILE] [--max=N] [--json]Lists the packages and versions in the repository. With --output, writes them to a discovery file instead: TOML, or JSON when the name ends in .json. --max caps how many packages are listed.
spice registry cbom
- Surveyor IT Pro
spice registry cbom --config=FILE --process --discovery=FILE --output=DIR [--threads=N]
spice registry cbom --config=FILE --export-processed
spice registry cbom --config=FILE --reset [--purl=PURL]Builds a CBOM of every package version the discovery file selects, on this machine. Nothing is uploaded.
| Option | Description |
|---|---|
--process | Download and analyze every selected version that has not been processed yet |
--discovery=FILE | The discovery file. Required with --process. |
--output=DIR | Where the CBOMs go, one folder per package version. Required with --process. |
--threads=N | How many package versions to process at once |
--export-processed | List the versions already processed |
--reset | Forget what has been processed, so the next --process starts again |
--purl=PURL | With --reset, forget only this package |
- Surveyor IT Pro
Each version’s folder also gets a cbom.json that ranks the cryptography found for post-quantum
readiness and names where it is called. The built-in algorithm catalog is used; --rogues=FILE
names a different one, only when Spice Labs support gives you one.
spice registry run surveys and uploads, so it is refused here with 'registry run' uploads survey results to the platform, which this build does not do. Use spice registry cbom --process instead.
spice registry status
- Surveyor IT Pro
spice registry status --config=FILE [--json]Summarizes what the registry runs have done so far.
spice pass decode
- Surveyor IT Pro
spice pass decode
Decodes and displays the Spice License in SPICE_LICENSE.
It prints:
- A first line naming the credential and its source, such as
Spice License (from.SPICE_LICENSE) - 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 ...),EXPIREDorNo expiration.
For a Spice License, a License: line says whether it is valid for this product.
The claims it can show, in this order:
| Label | Claim | Label | Claim |
|---|---|---|---|
| Token Type | x-type | Organization ID | x-uuid-org |
| Token Version | x-version | User ID | x-uuid-user |
| JWT ID | jti | Project ID | x-uuid-project |
| Issued At | iat | Demo Project | demo |
| Expires At | exp | Upload Server | x-upload-server |
| Not Before | nbf | Challenge | x-challenge |
| Issuer | iss | Artifact Cutoff | x-cutoff |
| Subject | sub | Licensed Features | x-features |
| Audience | aud | Licensed Edition | x-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
- Surveyor IT Pro
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
- Surveyor IT Pro
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.
spice docs needs a valid Spice License, like every command except spice pass decode, spice config explain and tab completion.
Tab completion
- Surveyor IT Pro
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
| Category | Formats | Examples |
|---|---|---|
| ZIP-family archives | ZIP, JAR, WAR, EAR and other Java archives, Android APK | app.zip, myapp.jar, webapp.war, app.ear, app.apk |
| Container images | docker save tarballs, OCI image layouts | myimage.tar (with manifest.json), a folder with oci-layout, index.json and blobs/ |
| Tar and other archives | tar, cpio, ar | backup.tar, initrd.cpio, libfoo.a |
| Compressed files | gzip, bzip2, xz, lzma, zstd | data.tar.gz, logs.tar.bz2, archive.xz, payload.zst |
| OS packages | RPM, Debian, Arch Linux (pacman), Alpine, FreeBSD and OpenBSD packages | nginx-1.24.0-1.el9.x86_64.rpm, curl_8.5.0_amd64.deb, musl-1.2.5-r0.apk |
| ISO 9660 images | ISO disc images | ubuntu-24.04-live-server-amd64.iso |
| Disk images | qcow2, VMDK, VHD, VHDX, VDI, raw, AMI, Google Cloud images | disk.qcow2, vm.vmdk, machine.vhdx, os.vdi, disk.raw, gcp-image.tar.gz |
| File systems in disk images | ext2, ext3, ext4, FAT32, exFAT, NTFS, XFS, Btrfs, SquashFS, HFS+, APFS, behind MBR or GPT partition tables and LVM | an ext4 partition inside a .qcow2, a SquashFS root file system in a firmware image |
| Firmware and binary containers | Linux kernel images, U-Boot FIT images, device tree blobs, ELF, Raspberry Pi firmware, Android boot images, WIM, DMG | zImage, 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:
| Ecosystem | What it reads | Examples |
|---|---|---|
| Java | Jars and other Java archives, with their Maven metadata | commons-codec-1.17.0.jar |
| .NET | Managed assemblies | System.Data.dll, MyApp.exe |
| Installed OS packages | The package databases inside container images and file systems | Debian, RPM and Alpine packages in an image |
| Lockfiles | Declared dependencies, such as npm, cargo and Python requirements | package-lock.json, Cargo.lock, requirements.txt |
| Go | Modules built into Go binaries | a compiled Go service |
| Language package archives | npm, PyPI, Go modules, crates.io, RubyGems, Packagist, Conda, CocoaPods, CPAN, Hex and LuaRocks packages | lodash-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. 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.
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_IMAGEorSPICE_IMAGE_TAG, that image and tag exist. A tag must be inSPICE_IMAGEitself whenSPICE_IMAGEis set: see Air-gapped setup. - 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.
On a machine with no network, set SPICE_LABS_CLI_SKIP_PULL=1 so the wrapper uses the image
already loaded and never tries to pull it.
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/binon macOS and Linux,%USERPROFILE%\.spice\binon Windows.
Spice License
Every command except spice pass decode, spice config explain and tab completion checks the Spice License first, and stops with one of these messages when it cannot run. <product> is the product’s name and <date> a date and time in UTC. See Spice License for how to set and check one.
The <product> edition requires a Spice License.
SPICE_LICENSE is not set, or is empty, in this terminal. Set it to the Spice License issued to your organization and run again.
SPICE_LICENSE holds a Spice Pass (<type>), but the <product> edition needs a Spice License.
The variable holds a credential for uploading to a hosted project, which this product cannot use. Ask Spice Labs for a Spice License.
SPICE_LICENSE is not a Spice License: <reason>
The value is not a license at all, often because it was cut short when it was copied. Set it again from the file you received, with no extra spaces or line breaks.
SPICE_LICENSE was not signed by the key this build of <product> trusts.
The license was changed after it was issued, or was issued for a different build. Ask Spice Labs for a license for the image you run.
Your Spice License expired on <date>.
Ask Spice Labs for a new license, then set SPICE_LICENSE to it.
Your Spice License is not valid until <date>.
The license starts later than this machine’s clock reads; the next line of the message shows the clock. On an isolated machine the clock is often wrong: set it correctly and run again.
Your Spice License does not cover the <product> edition: it lacks <features>.
The license was issued for a different product. The next line lists what it covers. Run the product the license covers, or ask Spice Labs to extend it.
Your Spice License expires on <date>; contact Spice Labs for a new one before then.
A warning, not an error: the run continues. It appears on every run in the last 30 days of the license. Ask Spice Labs for a new license before the date.
This build of <product> is missing its licensing key
The image itself is faulty, which nothing you set can fix. Send the output of spice --version to Spice Labs support.
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
Your Spice License 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>/.
Registry sweeps
--config is required, or repositories in the host's configuration
Name your registry configuration file with --config, after registry <command>. See Registry sweeps and CBOMs.
--discovery is required for --process or --output is required for --process
spice registry cbom --process needs both: the discovery file that selects what to build, and the folder the CBOMs go to.
Discovery file not found: <path>
Run spice registry discover --output first, and run spice from the folder that holds the discovery file, or give its full path.
no action: use --process, --reset or --export-processed
spice registry cbom needs one of those three options.
No packages to process
The discovery file’s include and exclude rules select nothing. Loosen them, or run spice registry discover --output again.
All <n> package(s) already processed
Every version the discovery file selects already has its CBOM. To build them again, run spice registry cbom --reset first, or --reset --purl=<purl> for one package.
'registry run' uploads survey results to the platform, which this build does not do.
Use spice registry cbom --process to build the CBOMs on this machine.
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.
Expected on this machine: the probe configuration comes from Spice Labs, so the run records the
JDK’s built-in security events only. Add --native-only to every runtime survey to skip the
attempt.
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.