Skip to content

Commit

Permalink
release: v0.0.8 (#37)
Browse files Browse the repository at this point in the history
* chore: bump cli version

* chore: update README

* chore: update CLI readme with diff command

* fix: update cfg for necessary application types
  • Loading branch information
nilslice authored Apr 26, 2023
1 parent f94ec0d commit c61d702
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 36 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 44 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,33 +57,47 @@ validate:
# will run properly in any host environment
imports:
include:
- http_get
# ensure these named functions are in the imports of this module
- log_message
- proc_exit

# further specify the function beyond its name
- namespace: env
name: http_get
params: [I32, I32]
results: [I32]
exclude:
- fd_write
namespace:
include:
- env
exclude:
# phasing out old APIs? exclude these from acceptable namespaces/module names
- some_future_deprecated_module_name
# phasing out old APIs? exclude the from acceptable namespaces/module names
- wasi_snapshot_preview1

exports:
# only want exactly 2 functions exported: `_start` and `bar` for the host to call:
max: 2
# secure your modules by ensuring that there is no superfluous functionality hidden inside a binary
max: 100
include:
- _start
- bar
- name: bar
params: []
results: [I32, I32, I32, I32]
# and/or ensuring no unwanted functions to be exported.
exclude:
- main
- name: init
results: []
- foo

# use a human-readable module size to prevent overly large binaries from running in your environment
size:
max: 4MB
# our Cyclomatic Complexity analysis can help prevent risk of CPU exhaustion from deteriorating your user experience and slowing down your system

# our Cyclomatic Complexity analysis can help prevent risk of CPU exhaustion from deteriorating
# your user experience and slowing down your system
# (override these low, medium, high optional values with environment variables $MODSURFER_RISK_{LOW,MEDIUM,HIGH})
complexity:
max_risk: low

Expand All @@ -92,18 +106,30 @@ validate:
You can also point to a remote check file to track up-to-date requirements:
```yaml
validate:
url: https://raw.githubusercontent.com/extism/extism/main/mod.yaml
url: https://raw.githubusercontent.com/fermyon/spin/main/tools/modsurfer/http/mod.yaml
```
### Usage
To run validation, you can use our [GitHub Action](https://github.com/dylibso/modsurfer-validate-action), or call the `validate` command directly:
Modsurfer runs validation tests on compiled .wasm binaries. It uses a "checkfile" to compare with the
contents of a .wasm binary. The `modsurfer` CLI provides [a number of commands](https://dev.dylib.so/docs/modsurfer/cli#commands)
to create and use a checkfile, as well as to interact as a client to a remote service that stores
and organizes your WebAssembly modules available over HTTP (via [this `protobuf` API](./proto/v1/api.proto)).

##### To create a "checkfile" (passed to `-c`), run the `generate` command:

```
modsurfer generate -p path/to/my.wasm -o mod.yaml
```
> **NOTE:** this checkfile will be very restrictive, and you likely want to edit it to fit less (or more) restricted environments.
##### To run validation, you can use our [GitHub Action](https://github.com/dylibso/modsurfer-validate-action), or call the `validate` command directly:
```
modsurfer validate -p path/to/my.wasm -c path/to/mod.yaml
```
If any of the expectations declared in your checkfile are invalid, Modsurfer will report them:
If any of the restrictions or expectations declared in your checkfile are not satisfied, Modsurfer will report them:
```
┌────────┬──────────────────────────────────────────────────┬──────────┬──────────┬───────────────────┬────────────┐
Expand All @@ -130,22 +156,28 @@ If any of the expectations declared in your checkfile are invalid, Modsurfer wil
│ FAIL │ size.max │ <= 4MB │ 4.4 MiB │ Resource Limit │ | │
└────────┴──────────────────────────────────────────────────┴──────────┴──────────┴───────────────────┴────────────┘
```
> **NOTE**: convert this table into JSON with the `--output-format json` option, supported by the `validate` command and many others.
Find more information about the CLI in its dedicated [README](./cli/README.md), or download the tool and run `modsurfer -h`.
### Testing the CLI
### Validating platform-specific compatibility
Before running or integrating a WebAssembly module on your platform (Emscripten, Extism, Fastly, Shopify, Spin, Suborbital, wasmCloud, Workers)
#### Contributing
##### Testing the CLI
From the root of the repo, run the following to see a basic validation report:
- `make test-cli`
- `make empty-cli`
- `make unknown-cli`
`test/` contains a `mod.yaml`, which declares expected properties of a WebAssembly module, as well as a `spidermonkey.wasm` file to use as example input to use for the validation.
`wasm/` contains a set of WebAssembly binaries downloaded from the [`wapm`](https://wapm.io) package manager used for analysis and testing.
---
## `proto`
### `proto` Protobuf definitions and libraries
This directory contains the Protobuf definitions for the types used in the API. Messages have various levels of documentation as well as endpoints if they are request types. Use the `api.proto` to generate a language client if you'd like to interact with Modsurfer API programmatically from your application.
2 changes: 1 addition & 1 deletion cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "modsurfer-cli"
version = "0.0.6"
version = "0.0.8"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
8 changes: 6 additions & 2 deletions cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ Commands:
Return a list of modules which violate requirements in the provided checkfile.
generate
Generate a starter checkfile from the given module.
diff
Compare two modules
help
Print this message or the help of the given subcommand(s)

Expand Down Expand Up @@ -57,9 +59,9 @@ modsurfer get --id 4 | jq . | ...

modsurfer create \
-p my.wasm \
-c mod.yaml \
-c mod.yaml \ # optional - validate before creating an entry in Modsurfer
-l file:///wasm/my.wasm \
-m userid=12234 -m app=33
-m userid=12234 -m app=33 # optional - associate searchable key-value metadata with a module

modsurfer delete --id 3 --id 4 --id 5

Expand All @@ -71,6 +73,8 @@ modsurfer search --function-name _start --module-name env --source-language Rust

modsurfer generare -p spidermonkey.wasm -o mod.yaml

modsurfer diff a.wasm b.wasm # or diff using Modsurfer module IDs

modsurfer audit --outcome pass -c mod.yaml
```

Expand Down
1 change: 0 additions & 1 deletion convert/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ mod types;

pub use types::{Order, Pagination, Sort, SortField};

#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
#[cfg(feature = "api")]
pub use types::{Audit, AuditOutcome, Search};

Expand Down
26 changes: 7 additions & 19 deletions convert/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
#[cfg(feature = "api")]
use chrono::Utc;
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
#[cfg(feature = "api")]

use modsurfer_module::{Export, Import, SourceLanguage};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -53,7 +52,6 @@ pub struct Sort {
pub field: SortField,
}

#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
#[cfg(feature = "api")]
#[derive(Default)]
pub struct Search {
Expand All @@ -65,22 +63,24 @@ pub struct Search {
pub function_name: Option<String>,
pub module_name: Option<String>,
pub source_language: Option<SourceLanguage>,
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
pub inserted_after: Option<chrono::DateTime<Utc>>,
#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
pub inserted_after: Option<u64>,
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
pub inserted_before: Option<chrono::DateTime<Utc>>,
#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
pub inserted_before: Option<u64>,
pub strings: Option<Vec<String>>,
pub sort: Option<Sort>,
}

#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
#[cfg(feature = "api")]
#[derive(Debug, Clone)]
pub enum AuditOutcome {
Pass,
Fail,
}

#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
#[cfg(feature = "api")]
impl std::fmt::Display for AuditOutcome {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expand All @@ -90,16 +90,12 @@ impl std::fmt::Display for AuditOutcome {
}
}

#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
#[cfg(feature = "api")]
impl From<&std::ffi::OsStr> for AuditOutcome {
fn from(value: &std::ffi::OsStr) -> Self {
value.to_str().unwrap_or_else(|| "fail").to_string().into()
}
}

#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
#[cfg(feature = "api")]
impl From<String> for AuditOutcome {
fn from(value: String) -> Self {
match value.to_lowercase().as_str() {
Expand All @@ -109,25 +105,19 @@ impl From<String> for AuditOutcome {
}
}

#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
#[cfg(feature = "api")]
#[derive(Debug)]
pub struct Audit {
pub page: Pagination,
pub outcome: AuditOutcome,
pub checkfile: Vec<u8>,
}

#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
#[cfg(feature = "api")]
impl Default for AuditOutcome {
fn default() -> Self {
AuditOutcome::Fail
}
}

#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
#[cfg(feature = "api")]
impl From<modsurfer_proto_v1::api::AuditOutcome> for AuditOutcome {
fn from(outcome: modsurfer_proto_v1::api::AuditOutcome) -> AuditOutcome {
match outcome {
Expand All @@ -137,8 +127,6 @@ impl From<modsurfer_proto_v1::api::AuditOutcome> for AuditOutcome {
}
}

#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
#[cfg(feature = "api")]
impl From<AuditOutcome> for modsurfer_proto_v1::api::AuditOutcome {
fn from(outcome: AuditOutcome) -> Self {
match outcome {
Expand Down

0 comments on commit c61d702

Please sign in to comment.