Skip to main content

Using the CLI

Just looking for the code?
Modsurfer CLI is open-source, checkout the code on GitHub.

Modsurfer CLI is used to interact with the HTTP API or validate modules offline.

Download

Modsurfer CLI can be downloaded via:

  • the latest GitHub Release
  • the GitHub container registry (for Docker environments)
    • docker pull ghcr.io/dylibso/modsurfer:latest

Usage Overview

$ modsurfer -h
Usage: modsurfer [COMMAND]

Commands:
create Create a new entry for a module.
delete Delete a module and its versions.
get Get a module by its ID.
list List all modules, paginated by the `offset` and `limit` parameters or their defaults.
search Search for modules matching optional parameters.
validate Validate a module using a module checkfile.
yank Mark a module version as yanked (unavailable).
audit Return a list of modules which violate requirements in the provided checkfile.
generate Generate a starter checkfile from the given module.
help Print this message or the help of the given subcommand(s)

Options:
-h, --help Print help
-V, --version Print version

Environment Variables

Modsurfer CLI defaults can be overridden using environment variables. The following are available to use:

Variable NameDescriptionDefault Value
MODSURFER_BASE_URLUsed to connect to the Modsurfer HTTP API.http://localhost:1739
MODSURFER_RISK_LOWDefines the maximum value of the low risk cyclomatic complexity score used in validation.2500
MODSURFER_RISK_MEDIUMDefines the maximum value of the medium risk cyclomatic complexity score used in validation.50000
MODSURFER_RISK_HIGHDefines the maximum value of the high risk cyclomatic complexity score used in validation.4_294_967_295

Commands

Output Format

modsurfer get --id 1 --output-format=json

NOTE: for commands that print some output related to your modules, you can optionally pass an --output-format=json argument to override the default "table" output with JSON. This can be useful if you're using Modsurfer CLI within a script or pipeline.


create

Create a new entry for a module.

$ modsurfer create
modsurfer create -p path/to/module.wasm -l s3://where/module/lives/module.wasm \
-m user_id=12345 -m other=something

create options

-p, --path <path>                    a path on disk to a valid WebAssembly module
-m, --metadata <metadata> a repeatable key=value metadata entry, to add arbitrary context to a module
-l, --location <location> a valid URL to where this module should be located
-c, --check <check> a path on disk to a YAML checkfile which declares validation requirements
--output-format <output-format> set the output format of any command, supports `json` or `table` (default)
-h, --help Print help

You can provide metadata which is arbitrary key=value records. These will be indexed and searchable so you can tag and retrieve modules based on reference data according to your needs.

Validation

Validation can be run prior to creating a module in Modsurfer by passing another optional argument, -c with the path to a checkfile (e.g. mod.yaml). If validation fails, the module will not be inserted into Modsurfer and the failing properties will be printed to stdout along with some context:

┌────────┬──────────────────────────────────────────────────┬──────────┬──────────┬───────────────────┬────────────┐
│ Status │ Property │ Expected │ Actual │ Classification │ Severity │
╞════════╪══════════════════════════════════════════════════╪══════════╪══════════╪═══════════════════╪════════════╡
│ FAIL │ allow_wasi │ false │ true │ ABI Compatibility │ |||||||||| │
├────────┼──────────────────────────────────────────────────┼──────────┼──────────┼───────────────────┼────────────┤
│ FAIL │ complexity.max_risk │ <= low │ medium │ Resource Limit │ | │
├────────┼──────────────────────────────────────────────────┼──────────┼──────────┼───────────────────┼────────────┤
│ FAIL │ exports.exclude.main │ excluded │ included │ Security │ ||||| │
├────────┼──────────────────────────────────────────────────┼──────────┼──────────┼───────────────────┼────────────┤
│ FAIL │ exports.include.bar │ included │ excluded │ ABI Compatibility │ |||||||||| │
├────────┼──────────────────────────────────────────────────┼──────────┼──────────┼───────────────────┼────────────┤
│ FAIL │ exports.max │ <= 100 │ 151 │ Security │ |||||| │
├────────┼──────────────────────────────────────────────────┼──────────┼──────────┼───────────────────┼────────────┤
│ FAIL │ imports.include.http_get │ included │ excluded │ ABI Compatibility │ |||||||| │
├────────┼──────────────────────────────────────────────────┼──────────┼──────────┼───────────────────┼────────────┤
│ FAIL │ imports.include.log_message │ included │ excluded │ ABI Compatibility │ |||||||| │
├────────┼──────────────────────────────────────────────────┼──────────┼──────────┼───────────────────┼────────────┤
│ FAIL │ imports.namespace.exclude.wasi_snapshot_preview1 │ excluded │ included │ ABI Compatibility │ |||||||||| │
├────────┼──────────────────────────────────────────────────┼──────────┼──────────┼───────────────────┼────────────┤
│ FAIL │ imports.namespace.include.env │ included │ excluded │ ABI Compatibility │ |||||||| │
├────────┼──────────────────────────────────────────────────┼──────────┼──────────┼───────────────────┼────────────┤
│ FAIL │ size.max │ <= 4MB │ 4.4 MiB │ Resource Limit │ | │
└────────┴──────────────────────────────────────────────────┴──────────┴──────────┴───────────────────┴────────────┘

For an example mod.yaml, please see the validate command docs below.


delete

Delete a module and its versions.

$ modsurfer delete
# any number of --id arguments can be provided
modsurfer delete --id 1 --id 2 --id 3

delete options

--id <id>                        the numeric ID of a module entry in Modsurfer
--output-format <output-format> set the output format of any command, supports `json` or `table` (default)
-h, --help Print help

get

Get a module by its ID.

$ modsurfer get
modsurfer get --id 1

get options

--id <id>                        the numeric ID of a module entry in Modsurfer
--output-format <output-format> set the output format of any command, supports `json` or `table` (default)
-h, --help Print help

list

List all modules, paginated by the offset and limit parameters or their defaults.

$ modsurfer list
# by default, offset=0 and limit=50
modsurfer list --offset 1 --limit 20

list options

List all modules, paginated by the `offset` and `limit` parameters or their defaults.

Usage: modsurfer list [OPTIONS]

Options:
--offset <offset> the pagination offset by which modules are listed [default: 0]
--limit <limit> the maximum number of modules in a list of results [default: 50]
--output-format <output-format> set the output format of any command, supports `json` or `table` (default)
-h, --help Print help

Search for modules matching optional parameters.

$ modsurfer search
# find all modules that reference `fd_write` and are written in Rust
modsurfer search --function-name fd_write --source-language Rust

search options

--function-name <function-name>
adds a search parameter to match on `function-name
--module-name <module-name>
adds a search parameter to match on `module-name`
--source-language <source-language>
adds a search parameter to match on `source-language`
--hash <hash>
adds a search parameter to match on `hash`
--text <text>
adds a search parameter to match on `strings` extracted from a module
--offset <offset>
the pagination offset by which modules are listed [default: 0]
--limit <limit>
the maximum number of modules in a list of results [default: 50]
--output-format <output-format>
set the output format of any command, supports `json` or `table` (default)
-h, --help
Print help

validate

Validate a module using a module checkfile.

$ modsurfer validate
modsurfer validate -p spidermonkey.wasm -c mod.yaml

Checkfile

An example mod.yaml checkfile can include these properties and values:

mod.yaml
validate:
# can also point to a remote checkfile to track up-to-date requirements:
# url: https://raw.githubusercontent.com/extism/extism/main/mod.yaml

# mandate that WASI support is allowed or not
allow_wasi: false
# define requirements for existence (or non-existence) of a module's import functions
imports:
include:
# specify the function and its signature, optionally scoping it to a particular module name / namespace
- name: http_get
namespace: env
params:
- I32
- I32
results:
- I32
# or, simply use the function name
- log_message
- proc_exit
exclude:
- fd_write
# declare module-wide requirements for existence (or non-existence) of imports from modules / namespaces
namespace:
include:
- env
exclude:
- some_future_deprecated_module_name
- wasi_snapshot_preview1
# define requirements for existence (or non-existence) of a module's export functions
exports:
# set a threshold for maximum number of exports
max: 2
include:
- name: _start
params: []
results: []
- name: bar
params:
- I32
- I32
results:
- I32
exclude:
- main
- foo
# restrict binary size of a module (supports suffixes listed here: https://docs.rs/parse-size/1.0.0/parse_size/index.html)
size:
max: 4MB
# restrict WASM code complexity to a risk profile (low, medium, high) based on Cyclomatic Complexity analysis
complexity:
max_risk: low

validate options

-p, --path <path>                    a path on disk to a valid WebAssembly module
-c, --check <check> a path on disk to a YAML file which declares validation requirements [default: mod.yaml]
--output-format <output-format> set the output format of any command, supports `json` or `table` (default)
-h, --help Print help

If validation fails, the module will not be inserted into Modsurfer and the failing properties will be printed to stdout along with some context:

┌────────┬──────────────────────────────────────────────────┬──────────┬──────────┬───────────────────┬────────────┐
│ Status │ Property │ Expected │ Actual │ Classification │ Severity │
╞════════╪══════════════════════════════════════════════════╪══════════╪══════════╪═══════════════════╪════════════╡
│ FAIL │ allow_wasi │ false │ true │ ABI Compatibility │ |||||||||| │
├────────┼──────────────────────────────────────────────────┼──────────┼──────────┼───────────────────┼────────────┤
│ FAIL │ complexity.max_risk │ <= low │ medium │ Resource Limit │ | │
├────────┼──────────────────────────────────────────────────┼──────────┼──────────┼───────────────────┼────────────┤
│ FAIL │ exports.exclude.main │ excluded │ included │ Security │ ||||| │
├────────┼──────────────────────────────────────────────────┼──────────┼──────────┼───────────────────┼────────────┤
│ FAIL │ exports.include.bar │ included │ excluded │ ABI Compatibility │ |||||||||| │
├────────┼──────────────────────────────────────────────────┼──────────┼──────────┼───────────────────┼────────────┤
│ FAIL │ exports.max │ <= 100 │ 151 │ Security │ |||||| │
├────────┼──────────────────────────────────────────────────┼──────────┼──────────┼───────────────────┼────────────┤
│ FAIL │ imports.include.http_get │ included │ excluded │ ABI Compatibility │ |||||||| │
├────────┼──────────────────────────────────────────────────┼──────────┼──────────┼───────────────────┼────────────┤
│ FAIL │ imports.include.log_message │ included │ excluded │ ABI Compatibility │ |||||||| │
├────────┼──────────────────────────────────────────────────┼──────────┼──────────┼───────────────────┼────────────┤
│ FAIL │ imports.namespace.exclude.wasi_snapshot_preview1 │ excluded │ included │ ABI Compatibility │ |||||||||| │
├────────┼──────────────────────────────────────────────────┼──────────┼──────────┼───────────────────┼────────────┤
│ FAIL │ imports.namespace.include.env │ included │ excluded │ ABI Compatibility │ |||||||| │
├────────┼──────────────────────────────────────────────────┼──────────┼──────────┼───────────────────┼────────────┤
│ FAIL │ size.max │ <= 4MB │ 4.4 MiB │ Resource Limit │ | │
└────────┴──────────────────────────────────────────────────┴──────────┴──────────┴───────────────────┴────────────┘

yank

Mark a module version as yanked (unavailable).

NOTE: This command is not yet supported. Please contact [email protected] for more information.

$ modsurfer yank
modsurfer yank --id 1 --version 0.2.1

yank options

--id <id>                        the numeric ID of a module entry in Modsurfer
--version <version> the version of a module entry in Modsurfer (if no version exists, this command has no effect)
--output-format <output-format> set the output format of any command, supports `json` or `table` (default)
-h, --help Print help

audit

Return a list of modules which violate requirements in the provided checkfile.

NOTE: results are paginated, and by default limited to 50. Pass the --limit and --offset parameters to adjust this based on needs.

$ modsurfer audit
modsurfer audit --outcome fail -c mod.yaml

audit options

--outcome <outcome>              which type of expected outcome the audit should verify ('pass' or 'fail') [default: fail]
-c, --check <check> a path on disk to a YAML file which declares validation requirements [default: mod.yaml]
--offset <offset> the pagination offset by which modules are listed [default: 0]
--limit <limit> the maximum number of modules in a list of results [default: 50]
--output-format <output-format> set the output format of any command, supports `json` or `table` (default)
-h, --help Print help

generate

Generate a starter checkfile from the given module.

$ modsurfer generate
modsurfer generate -p spidermonkey.wasm -o mod.yaml

generate options

-p, --path <path>      a path on disk to a valid WebAssembly module
-o, --output <output> a path on disk to write a generated YAML checkfile [default: mod.yaml]
-h, --help Print help

help

Print this message or the help of the given subcommand(s).