Documentation
Surveyor OT Pro 1f21c27

Surveyor OT 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 OT 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\

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.

Next steps

Air-gapped setup

Surveyor OT 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 spice wrapper: spice for Linux and macOS, spice.ps1 for 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-otpro:<tag>
docker save -o spice-surveyor.tar ghcr.io/spice-labs-inc/spice-labs-cli-otpro:<tag>
docker pull ghcr.io/spice-labs-inc/spice-labs-cli-otpro:<tag>
docker save -o spice-surveyor.tar ghcr.io/spice-labs-inc/spice-labs-cli-otpro:<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/spice
New-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 OT 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.

Registry sweeps and CBOMs

Available in:
  • Surveyor OT 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:

  1. Write a registry configuration file that says where the artifacts are.
  2. Run spice registry discover to list the package versions into a discovery file, and edit it to choose what to build.
  3. Run spice registry cbom --process to 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.

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.

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.

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

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.

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 Registry sweeps and CBOMs; 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.

Commands

CommandWhat it does
spice registry discover --output, --maxList the packages and versions in an artifact repository or a folder
spice registry cbom --process, --discovery, --output, --threads, --reset, --export-processedBuild a CBOM of every package version a discovery file selects, on this machine
spice registry statusSummarize what the registry runs have done
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 JSONNeeds a valid Spice License
spice --versionPrint the version and, where a license applies, whether it is validIncludes a license line
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.

--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 registry

Available in:
  • Surveyor OT 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:

OptionDescription
--config=FILEThe registry configuration file
--jsonMachine-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

Available in:
  • Surveyor OT 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.

OptionDescription
--processDownload and analyze every selected version that has not been processed yet
--discovery=FILEThe discovery file. Required with --process.
--output=DIRWhere the CBOMs go, one folder per package version. Required with --process.
--threads=NHow many package versions to process at once
--export-processedList the versions already processed
--resetForget what has been processed, so the next --process starts again
--purl=PURLWith --reset, forget only this package

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

Available in:
  • Surveyor OT Pro
spice registry status --config=FILE [--json]

Summarizes what the registry runs have done so far.

spice pass decode

Available in:
  • Surveyor OT 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 ...), EXPIRED or No expiration.

For a Spice License, a License: line says whether it is valid for this product.

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 OT 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

Available in:
  • Surveyor OT Pro
Needs a valid Spice License
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

Available in:
  • Surveyor OT 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

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. 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_IMAGE or SPICE_IMAGE_TAG, that image and tag exist. A tag must be in SPICE_IMAGE itself when SPICE_IMAGE is 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/bin on macOS and Linux, %USERPROFILE%\.spice\bin on 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.

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.

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.