Writing a recipe¶
A recipe says how to build the target. Without one, the tool tries to detect the build from the repository layout, which works for many projects but not for all of them.
The file¶
.verdis/recipe.yml in the root of the repository.
language: c
build:
system: cmake
flags: [asan, ubsan]
steps:
- cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
- cmake --build build -j
env:
CFLAGS: -fsanitize=address,undefined
run:
workdir: /work
default_timeout: 30s
repeat: 3
The fields¶
| Field | Meaning |
|---|---|
language |
c, cpp, python, node, go, rust, java, docker or unknown. |
build.system |
cmake, make, autotools, pip, npm, go, cargo, gradle or docker. |
build.flags |
the sanitizers to enable: asan, ubsan, tsan, msan, race. |
build.steps |
the commands to run, in order. |
build.env |
environment variables for the build. |
build.image |
a pinned image, by digest. |
run.workdir |
the workdir inside the sandbox. |
run.default_timeout |
how long a single run may take. |
run.repeat |
how many times the PoC is run, to detect flakiness. |
Instrumented builds¶
Use them. A crash that is only visible under a sanitizer is the difference
between REPRODUCED and NOT_REPRODUCED.
- C and C++ —
flags: [asan, ubsan]. The detector adds-fsanitize=address,undefined -fno-omit-frame-pointerfor you. - Go —
flags: [race]. The detector addsgo build -race ./.... - Everything else — assertion-enabled builds.
What the tool detects on its own¶
| The repository has | The tool builds with |
|---|---|
Dockerfile |
Docker mode |
CMakeLists.txt |
CMake with ASan and UBSan |
Makefile |
make with ASan and UBSan |
configure.ac or configure |
autotools with ASan and UBSan |
go.mod |
go build -race ./... |
pyproject.toml or setup.py |
pip install . |
package.json |
npm install --ignore-scripts |
Cargo.toml |
cargo build --release |
pom.xml or build.gradle |
gradle build -x test |
Detection is a starting point. When it is wrong, write the recipe.
The two phases¶
The build stage may reach an allowlisted mirror, because dependencies have to come from somewhere. The run stage never does. If your build needs something unusual, vendor it and add a recipe step that uses the vendored copy.
Checking a recipe¶
verdis recipe init
verdis recipe validate
validate checks that the file parses and reports what it found. It does
not build anything; the real test is a triage run.