yaml-pro

YAML authoring and processing — gotchas, validation, and safe loading — use when writing configs or parsing YAML.

SKILL.md

GitHub

Overview

YAML is the config language of the DevOps world — readable, but full of footguns (the infamous no → false, octal surprises, billion-laughs attacks). This skill covers writing safe, predictable YAML and parsing it defensively in code.

When to use

  • Authoring configs (CI pipelines, Kubernetes manifests, app settings)
  • Designing YAML-based file formats or DSLs
  • Parsing YAML safely in applications (avoiding deserialization attacks)
  • Templating YAML (anchors, merge keys, and when to avoid them)
  • Validating YAML configs with schemas in CI

Core concepts

Quote defensively. YAML's implicit typing converts unquoted yes/no/on/off, 0o17-style numbers, and version-like strings (3.10 → 3.1). Quote strings that could be misinterpreted — especially versions, identifiers with leading zeros ("007"), and anything resembling a boolean. Explicit is better than clever.

Safe loading only. Never use a full YAML loader on untrusted input — it can instantiate arbitrary objects (the classic deserialization attack). Always use the safe loader, which handles only plain scalars, lists, and maps. This is non-negotiable for any YAML from users or networks.

Anchors and merge keys: use sparingly. &anchor / *alias / <<: *merge reduce duplication in hand-written configs, but they complicate programmatic processing and confuse newcomers. Fine for small DRY wins; for heavy reuse, prefer a templating layer or config generation in code.

Schema-validate configs. JSON Schema validates YAML too (YAML is a superset of JSON). Validate CI configs, app settings, and manifests against a schema in CI — catching a typo'd key at commit time beats debugging a silent misconfig in production.

Multi-document files. --- separates documents in one stream; some tools read only the first. Know whether your consumer handles multi-doc files before relying on them.

Practical workflow

  1. Start from a known-good example for the target system; adapt minimally rather than writing from memory.
  2. Quote aggressively: versions, booleans-as-strings, leading-zero numbers, and any value where the type matters downstream.
  3. Keep nesting shallow (3–4 levels max); deep nesting is hard to read and easy to mis-indent — refactor into flatter structures or multiple files.
  4. Validate in CI: schema check + a dry-run/parse of the consuming tool (e.g. kubectl --dry-run, CI config linter) on every change.
  5. In code, always safe-load; convert to typed config objects with defaults and validation immediately after parsing — don't pass raw dicts around.
  6. Document the config: a commented example file or schema with descriptions is worth more than a wiki page nobody updates.

Common pitfalls

  • The Norway problem: no/yes/on/off becoming booleans — quote country codes and string flags.
  • Tabs for indentation — forbidden in YAML; use spaces, consistently (2 is the convention).
  • Version 3.10 parsed as float 3.1 — quote versions, always.
  • Merge-key surprises: <<: *base silently overrides in non-obvious order with multiple merges; prefer explicit keys for critical settings.
  • Giant YAML files generated by tools — split into multiple files with clear naming; 2000-line YAML is unreviewable.
  • Secrets in YAML committed to git — configs get committed; secrets don't belong in them. Reference secret stores via placeholders resolved at deploy time.