Skip to content

Latest commit

 

History

History
155 lines (128 loc) · 3.5 KB

File metadata and controls

155 lines (128 loc) · 3.5 KB
id MDS040
name recipe-safety
status ready
description Validate each build.recipes command for shell-safety at lint time; the rule never executes any binary.
category directive
nature structure
maintainability
markdownlint
rumdl
mado
panache
obsidian-linter
gomarklint

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