sonde.yaml
Project file: environments, variables and secrets files, defaults
Owner: this file (internal/config). sonde.yaml is the only
project file Sonde reads on its own; it selects environments for a test run
and nothing else. It never widens file access and never changes what a
request file can read or write — that stays a CLI-only concern
(--file-root).
sonde.yaml sits inside the repository being tested, so it is untrusted
input (see docs/architecture.md §9): a CLI flag always overrides
anything it sets.
Schema
version: 1
environments:
local:
variables:
base_url: http://localhost:8080
retries: 3
strict: true
extra: null
variables_files:
- env/local.vars
secrets_files:
- env/local.secrets
secrets:
- api_token
staging:
variables:
base_url: https://staging.example.internal
defaults:
env: local
jobs: 4
openapi:
spec: openapi.yaml
server: http://localhost:3000/v1
strict: false
exclude_operations: ["GET /health"]
exclude_files: ["legacy/**/*.hurl"]-
version(required): must be1. Any other value, or a missing key, is an error. -
environments(optional): a map from environment name to:variables(optional): a map of name to value. A value is a plain YAML scalar — string, boolean, number ornull— typed the same way a--variableor variables-file entry is (internal/config/value.go). Lists and nested maps are rejected.variables_files(optional): paths to variables files, in the existingname=valueformat (internal/config/properties.go), applied in order aftervariables(a name in a later file wins).secrets_files(optional): paths to secrets files, same format, loaded as secrets (redacted), same rules as--secrets-file: a name already defined by an earlier secrets source is an error.secrets(optional): the names of the secrets the environment needs, committed withsonde.yamlwhile their values stay in the secrets files, kept out of git (add*.secretsto.gitignore). A name is listed once and is a variable name ([A-Za-z0-9_][A-Za-z0-9_.-]*). Withsecretsset, asecrets_filesentry that does not exist (a fresh clone) is no error: each listed name may come from any secret source instead (CI:SONDE_SECRET_<name>). A run of the environment in which a listed name is set by none of them fails before any request, naming each missing secret and where to set it:sonde.yaml: environment local: secret api_token not set: add it to env/local.secrets, or set SONDE_SECRET_api_token. Withoutsecrets, a missing secrets file stays an error.
-
defaults(optional):env: the environment used when neither--envnorSONDE_ENVis set.jobs: the default--jobsvalue when the flag is not given; an integer from0(unset) to64. An untrustedsonde.yamlcannot size a run's parallelism (and so its goroutines, HTTP clients and file descriptors) beyond that cap.
-
openapi(optional): validates every response of the project's files against an OpenAPI contract (see guides/openapi.md).spec(required): the OpenAPI file, a relative path inside thesonde.yamldirectory. A remote (http(s)://) spec cannot be set here: remote fetching is enabled only on the command line (--openapi URL --openapi-allow-remote).server: a base URL replacing the spec'sserversfor matching request URLs, like--openapi-server.strict: a request no operation matches fails (exit 4), like--openapi-strict; by default it is a warning.exclude_operations: operations never validated,METHOD /pathwith the path as written in the spec (GET /pets/{petId}). A method the spec does not document on a documented path can be excluded too (DELETE /pets/{petId}), which silences its unmatched warning (or strict failure).exclude_files: globs of request files never validated, relative to thesonde.yamldirectory;**matches any number of directories.
Command line flags win over these keys one by one (
--openapireplacesspec); the exclusions still apply.
Any other top-level or nested key is an error naming the offending line.
There is no file_root key and no way to set report options or inline
secret values — those stay CLI-only. A sonde.yaml file is exactly one
YAML document (a second ----separated document is an error) and at most
1 MiB; the same 1 MiB cap and "must be a regular file" rule apply to every
variables_files/secrets_files entry it references (a FIFO or other
special file is rejected rather than read, since reading one with no
writer would hang the run).
Precedence
sonde.yaml variables and secrets sit at the lowest precedence, below
every CLI and environment-variable source (docs/architecture.md §5,
"Variable precedence"):
sonde.yamlenvironment:variables, thenvariables_filesHURL_VARIABLE_*/SONDE_VARIABLE_*env vars--variables-file- data row (
--data) --variable- entry
[Options] variable: - captures during the run
Secrets follow the same shape: sonde.yaml secrets_files is the lowest
secret source, below HURL_SECRET_*/SONDE_SECRET_*, --secrets-file,
--secret, --data-secret columns and redact captures. A name defined
twice inside sonde.yaml itself (the same name in two secrets_files
entries) is still an error, exactly like a duplicate anywhere else. Once
resolved, though, a sonde.yaml secret is a plain lowest-precedence
default: the same name from any of those higher sources silently overrides
it, with no error — it is only a duplicate among HURL_SECRET_*/
SONDE_SECRET_*, --secrets-file and --secret themselves (which have no
config-file role to sit below) that is still rejected.
Environment selection, highest precedence first:
--env NAMESONDE_ENVenvironment variabledefaults.env
An --env/SONDE_ENV/defaults.env value that names an environment not
present in sonde.yaml is an error listing the environments that do exist;
the CLI exits with status 1. No environment selected (none of the three set,
and environments is absent or unused) is not an error: a run simply has no
sonde.yaml variables or secrets.
The same distinction applies when a file has no sonde.yaml above it at
all (and no --config override): an explicit --env NAME is then an error
(status 1, naming the file and the environment) — there is no project file
for it to select an environment from. SONDE_ENV alone, with no --env,
is silently ignored in that case instead: it only ever selects an
environment where a sonde.yaml actually exists to apply it to.
Discovery
For each input file, Sonde looks for sonde.yaml in that file's directory,
then its parent, and so on, stopping at the first one found. Different
input files in the same run may resolve to different sonde.yaml files
this way; each directory's answer is cached for the run so the walk
happens once per directory.
The walk is bounded, not open-ended up to the filesystem root, so a file placed somewhere Sonde does not control cannot configure a run it was never meant to:
- It stops at the first directory containing a
.gitentry (a directory for a normal checkout, a file for a worktree or submodule) — that directory's ownsonde.yamlis still eligible, but nothing above the repository being tested is considered. A run outside any repository has no such boundary short of the filesystem root. - On Unix, a candidate
sonde.yamlnot owned by the user running Sonde, or writable by group or others, is treated as absent (with a recorded warning) rather than used: it cannot be trusted to be the project's own file even if it happens to be found. This check does not exist on Windows, whose permission model does not express it the same way.
Neither restriction applies to --config FILE (a trusted, CLI-given
path): it overrides discovery entirely, is used for every input, and does
not have to be named sonde.yaml.
When input files resolve to different sonde.yaml files this way, each
file's own variables/secrets still apply only to that file's job. The
one setting that isn't per-file is defaults.jobs, since --jobs picks a
single worker count for the whole run: Sonde uses whichever project's
defaults.jobs it discovers first, in input-file order, and does not
merge or compare it against any other project's value. Give every
sonde.yaml in a multi-project run the same defaults.jobs (or none at
all, relying on --jobs) to avoid depending on that order.
File access
Every path in variables_files and secrets_files is resolved relative to
the directory containing that sonde.yaml file, through a sandbox rooted
there (internal/sandbox). A path that is absolute, that escapes that
directory with .., or that reaches outside it through a symbolic link is
rejected. sonde.yaml cannot reference anything outside its own directory,
and it has no key to change that (no file_root). Each referenced file
must also be a regular file no larger than 1 MiB (see Schema); a FIFO or a
directory is rejected before it is ever opened for reading, and the size
check happens before the content is used.