mdsmith
Esc
    v0.52.0 GitHub
    MDS040 directive ready

    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:

    1. Non-emptycommand must have at least one token.
    2. No shell interpreter — the first token must not be sh, bash, zsh, ksh, fish, /bin/sh, /bin/bash, or similar.
    3. No shell operators in static parts — tokens that are not purely a single {param} placeholder must not contain &&, ||, ;, |, >, <, >>, 2>, `, $(, or ${.
    4. 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.
    5. No .. in executable — the first token must not contain a .. path component.
    6. No reserved param namesinputs and outputs are the collective argv placeholders expanded from the directive’s inputs: / outputs: lists. A recipe must not declare either in params.required or params.optional.
    7. No unused params (warning, not error) — every entry in params.required and params.optional must be referenced by at least one {param} token in command.

    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: "![{alt}]({output})"
          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