# YAML

## Vad det är

YAML är ett textformat för strukturerade data som markerar strukturen med indrag, kolon och
bindestreck i stället för klamrar och citattecken, och det är därför det brukar väljas för
konfiguration som människor skriver och granskar för hand. Namnet är en rekursiv akronym, ”YAML
Ain't Markup Language”. Filerna slutar på `.yaml` eller `.yml`, och RFC 9512, som publicerades i
februari 2024, registrerade medietypen `application/yaml` och angav `.yaml` som föredragen
filändelse.

Under den sparsamma interpunktionen finns en liten datamodell. Den består av mappningar, som parar
ihop nycklar med värden, sekvenser, som är ordnade listor, och skalärer: strängar, tal, booleska
värden och null. Runt den modellen lägger språket till det som en människa som redigerar en fil vill
ha: kommentarer som börjar med `#`, blockskalärer som behåller radbrytningar med `|` eller viker
ihop dem med `>`, flera dokument i en fil åtskilda av `---`, ankare och alias (`&name` och `*name`)
som låter ett värde återanvändas på andra ställen, och taggar som anger en typ rakt ut.

Det första ramverket för YAML skrevs i Perl 2001. Version 1.1 av specifikationen följde 2005, och
version 1.2 kom 2009 med huvudsyftet att göra YAML till en strikt övermängd av JSON, och med många
av de äldre reglerna för implicita typer borttagna. Revision 1.2.2, som publicerades i oktober 2021,
rättade fel och förtydligade formuleringar utan att ändra språket. Mycket programvara läser ändå
fortfarande enligt de äldre reglerna: dokumentationen för Ansible noterar att PyYAML och libyaml
implementerar YAML 1.1.

YAML står alltså mellan två grannar. JSON är en strikt delmängd av YAML, kortfattad och entydig,
gjord för att program ska utbyta data. TOML är ett plattare konfigurationsformat där varje sträng
står inom citattecken, så att ett värdes typ aldrig gissas. YAML erbjuder mer än båda, och den extra
friheten är just där problemen kommer ifrån.

## Varför det spelar roll

Det verkliga valet är vilket format en fil ska få när människor kommer att underhålla den i flera
år: beskrivningar av driftsättningar, flödesdefinitioner för CI, serverkonfiguration. Playbooks i
Ansible är YAML, och det är konfigurationsfilerna för många andra infrastrukturverktyg också, så för
mycket av det arbetet är beslutet redan fattat högre upp i kedjan, och det som återstår att bestämma
är hur strikt filen ska skrivas.

Argumentet för YAML är läsbarheten. En granskare kan läsa en diff av det utan att räkna klamrar, en
kommentar kan förklara varför ett värde är som det är, och ett skript eller ett certifikat på flera
rader får plats i en blockskalär utan att något behöver escapas. Mot det står att blanktecken bär
betydelse, så att en nyckel som är indragen två mellanslag för långt kan hamna i en annan mappning
medan filen ändå går att tolka. Tabbar är helt förbjudna för indrag. Värden utan citattecken får sin
typ av hur de stavas, och stavningsreglerna skiljer sig mellan 1.1 och 1.2. Mallar lägger till en
andra syntax ovanpå: i Ansible måste ett värde som börjar med `{{` stå inom citattecken, annars tar
tolken det för en mappning.

Det som avgör beslutet är hur filen ska kontrolleras. YAML med ett lintverktyg och en vana att sätta
strängar inom citattecken är ett bekvämt format för konfiguration som ett team redigerar
tillsammans. YAML utan någotdera är ett format där en giltig fil kan säga något annat än vad
författaren menade. För data som skickas mellan program är JSON det säkrare standardvalet, och för
en kort inställningsfil med få nivåer av nästling är TOML enklare.

## Så ser det ut i praktiken

Hela företagets egen IT-miljö, server för server, från webbnärvaron och git-forgen till databasen,
säkerhetskopiorna, e-posttransporten och DNS, är deklarerad i YAML:
[19 playbooks och 34 roller för Ansible, 12 065 rader sammanlagt](/sv/portfolio/built-the-companys-infrastructure-as-code-108/).
Sammansättningen är data snarare än flaggor. Varje server tillhör en nivågrupp, och gruppens
YAML-variabler listar de roller som servern får, så en provisioneringskörning behöver inga argument
för att föra varje server till det tillstånd som dess grupp deklarerar. Det är YAML som språk för
deklarerat tillstånd, och framgången kontrolleras i stället för att antas, eftersom en konvergerad
server måste rapportera noll ändringar. Priset för det är fart: varje ändring tar längre tid än att
redigera en fil på servern skulle ta, och eftersom en konvergering som bara tillämpas till hälften
är värre än en som vägrar körs numera en preflight-play framför den.

Tolv tusen rader YAML behöver en maskin som läser dem innan en människa gör det.
[YAML är ett av språken som en kvalitetsgrind med 22 lintverktyg kontrollerar](/sv/portfolio/built-a-22-linter-commit-gate-127/),
tillsammans med HTML, CSS, JavaScript, Python, Markdown och shell. Grinden saknar varningsnivå, så
varje diagnostik stoppar committen, och undertryckningar direkt i koden är helt förbjudna: en
kommentar som ignorerar en regel eller ett direktiv som stänger av den är ingen nödutgång. För YAML
spelar det roll, eftersom de flesta av fällorna nedan är helt giltig syntax, och bara en regel som
vägrar dem fångar dem innan de når en server.

## Var det går fel

Fällorna nedan har en sak gemensamt: filen tolkas utan fel och betyder något annat.

**En landskod blir false.** Enligt reglerna i YAML 1.1 är `yes`, `no`, `on`, `off`, `y` och `n` utan
citattecken, i flera varianter av versaler och gemener, booleska värden. Kärnschemat i YAML 1.2
behåller bara `true` och `false`, i tre skrivsätt, och RFC 9512 varnar för att en tolk som följer
den äldre syntaxen kan läsa `{insecure: n}` som false i stället för som bokstaven n. En lista över
nordiska länder visar problemet:

```yaml
countries:
    - DK
    - SE
    - NO # YAML 1.1 reads this as false
```

Sätt citattecken kring varje sträng som kan läsas som något annat, skriv booleska värden bara som
`true` och `false`, och låt ett lintverktyg upprätthålla båda.

**Ett versionsnummer tappar en siffra.** Tal utan citattecken konverteras, så `version: 1.10` kommer
fram som flyttalet `1.1`, och enligt reglerna i 1.1 markerar en inledande nolla ett oktalt tal, så
en kod skriven som `010` blir 8. Dokumentationen för Ansible uppmanar sina användare att sätta
citattecken kring en version som `"1.0"` av just det skälet. Sätt citattecken kring identifierare,
koder och versioner, som är strängar som råkar innehålla siffror.

**En nyckel hamnar under fel förälder.** Indraget avgör vilken mappning en nyckel hör till, så en
rad som flyttas två mellanslag flyttar en inställning någon annanstans utan något fel.
Specifikationen kräver också att varje nyckel i en mappning är unik, och en upprepad nyckel långt
ned i ett långt block är lätt att missa vid granskning, så yamllint har en regel för vart och ett av
de två misstagen. Kör det innan filen används.

**Att ladda en fil kör kod.** Taggar kan namnge språkspecifika typer, och en laddare som respekterar
dem konstruerar vilket objekt filen än ber om. Dokumentationen för PyYAML säger att dess
fullständiga `yaml.load` är lika kraftfull som `pickle.load` och kan anropa vilken Python-funktion
som helst, och hänvisar till `yaml.safe_load`, som bara känner igen standardtaggar. RFC 9512 begär
att kodkörning i deserialiserare ska vara avstängd som standard. Använd den säkra laddaren för varje
fil som inte kom från ditt eget repo.

**En kort fil fyller minnet.** Ankare och alias gör ett YAML-dokument till en graf snarare än ett
träd. När varje ankare upprepar det föregående två gånger fördubblar varje ny rad storleken, så
trettio korta rader beskriver mer än en miljard strängar när ett program går igenom resultatet som
ett vanligt träd. RFC 9512 kallar det exponentiell dataexpansion, attacken billion laughs, och möter
det med processorer som begränsar rekursionsdjupet för ankare. Ta bara emot YAML utifrån genom en
sådan processor, och testa gränsen mot den tolk som faktiskt används.

## Läs mer

- [YAML 1.2.2 specification](https://yaml.org/spec/1.2.2/) — själva språket, inklusive kärnschemat
  som avgör hur värden utan citattecken får sin typ.
- [RFC 9512: YAML Media Type](https://www.rfc-editor.org/rfc/rfc9512) — registreringen av
  `application/yaml`, med säkerhetsanteckningar om booleska värden, kodkörning och expansion av
  alias.
- [YAML specification changes](https://yaml.org/spec/1.2.2/ext/changes/) — vad varje revision
  ändrade, från 1.2.1 till 1.2.2.
- [Ansible: YAML Syntax](https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html)
  — den delmängd som Ansible använder, med dess fällor kring citattecken.
- [yamllint rules](https://yamllint.readthedocs.io/en/stable/rules.html) — kontrollerna för
  sanningsvärden (truthy), dubblerade nycklar, oktala tal och indrag.
- [PyYAML documentation](https://pyyaml.org/wiki/PyYAMLDocumentation) — skillnaden mellan `load` och
  `safe_load`, med bibliotekets egna ord.

<https://engineer.company/sv/glossary/yaml/>
