MDS040: recipe-safety
Validate each build.recipes command for shell-safety at lint time; the rule never executes any binary.
# What it detects
MDS040 validates the command field of every recipe in
build.recipes. It applies seven checks:
- Non-empty —
commandmust have at least one token. - No shell interpreter — the first token must not be
sh,bash,zsh,ksh,fish,/bin/sh,/bin/bash, or similar. - No shell operators in static parts — tokens that are
not purely a single
{param}placeholder must not contain&&,||,;,|,>,<,>>,2>,`,$(, or${. - No fused placeholders — a token containing two
adjacent
{param}patterns (e.g.{a}{b}) is rejected; the resulting concatenation at build time could produce unexpected values. - No
..in executable — the first token must not contain a..path component. - No reserved param names —
inputsandoutputsare the collective argv placeholders expanded from the directive’sinputs:/outputs:lists. A recipe must not declare either inparams.requiredorparams.optional. - No unused params (warning, not error) — every entry
in
params.requiredandparams.optionalmust be referenced by at least one{param}token incommand.
The collective placeholders {outputs} and {inputs} carry
the directive’s output and input lists. Use them directly in
command; do not declare them as named params.
# Config
build.recipes is declared in the top-level build: section
of .mdsmith.yml:
build:
base-url: ""
recipes:
mermaid:
command: "mmdc -i {input} -o {output}"
body-template: ""
params:
required: [input]
optional: [output]MDS040 is enabled by default and configured implicitly from
build:. To disable:
rules:
recipe-safety: false# Examples
# Good
build:
recipes:
mermaid:
command: "mmdc -i {input} -o {output}"
params:
required: [input]
optional: [output]# Bad — shell interpreter
build:
recipes:
audit:
command: "bash audit.sh"MDS040 reports: recipe "audit": command uses shell interpreter "bash" — use the direct binary
# Bad — shell operator
build:
recipes:
build:
command: "make all && make install"MDS040 reports: recipe "build": command contains shell operator "&&" — use a wrapper script
# Bad — fused placeholders
build:
recipes:
render:
command: "tool {a}{b}"
params:
required: [a, b]MDS040 reports: recipe "render": command contains fused placeholders "{a}{b}" — separate with a delimiter
# Bad — reserved param name
build:
recipes:
render:
command: "mmdc -i {input} -o {outputs}"
params:
required: [input, outputs]MDS040 reports: recipe "render": reserved parameter name "outputs" must not be declared in params
# Meta-Information
- ID: MDS040
- Name:
recipe-safety - Status: ready
- Default: enabled
- Fixable: no
- Implementation: source
- Category: directive