Spec couche 1 — Format de source air-config (grammaire, design)
Spécification technique — Version 0.1 (design ; décision #1 d’air-config validée :
format maison minimal, hand-rolled, zéro-dép, fuzzé). Couche 1. Companion de
air-config.md.
Objet
Définit la grammaire du format de source qu’air-config-compile parse, valide
contre un schéma Cap’n Proto (ADR-040), et compile en artefact binaire (ADR-033). C’est
la forme canonique éditée par l’humain/le technicien (versionnable, diffable,
greppable) — pas la forme runtime.
Principes de conception (et pourquoi)
- Schema-directed (l’idée maîtresse). Le schéma Cap’n Proto connaît les types. Le parseur ne fait donc aucune inférence de type : il lit des lexèmes et le compilateur les valide/convertit selon le type attendu par le schéma. Cela élimine d’un coup la classe d’ambiguïtés de TOML/YAML (dates, types inférés) → grammaire régulière, petite, fuzzable.
- Familier mais maison. Surface inspirée de TOML (sections,
clé = valeur, tableaux) → l’admin reconnaît ; mais sous-ensemble strict hand-rollé (pas de dépendancetoml/serde), sans les pièges de TOML (cf. exclusions §4). - Défensif (Principe 3). UTF-8 validé, slicing borné
get(), bornes anti-DoS (taille document, profondeur d’imbrication, longueur de ligne), arithmétiquechecked_*(entiers validés vs le type cible du schéma → rejet d’overflow), aucun panic sur octets arbitraires (fuzzé). - Déterministe (ADR-025). L’ordre des clés dans la source n’affecte pas l’artefact (encodage canonique Cap’n Proto) → même source ⇒ artefact bit-pour-bit.
- Diagnostics qualité compilateur : ligne/colonne, type attendu (issu du schéma),
suggestion (
did-you-meansur clés/valeurs d’enum).
Section 1 — Lexique
- Commentaire :
#jusqu’à fin de ligne. - Identifiant (clé, nom de section, valeur d’enum) :
[A-Za-z][A-Za-z0-9_-]*. - Fin de ligne :
\n(les\rfinaux tolérés). Encodage UTF-8 obligatoire (sinon erreur de lexing, pas de panic). - Espaces : insignifiants hors chaînes.
- Bornes (valeurs par défaut, configurables, anti-DoS) : document ≤ N Mio, ligne ≤ 64 Kio, profondeur de sections ≤ 32, longueur de tableau ≤ N. Dépassement → erreur diagnostiquée.
Section 2 — Structure
# En-tête OBLIGATOIRE : quel schéma + version cette source cible (évolution, ADR-040)
schema = "air.network@1"
# Affectation simple (clé = valeur)
ipv6_first = true
# Section = struct imbriqué du schéma ; chemin pointé autorisé
[resolver]
timeout_ms = 5000
servers = ["2001:db8::1", "192.0.2.1"]
[resolver.cache] # sous-struct (chemin pointé)
max_entries = 100_000
# Tableau de structs (liste de structs du schéma) — double crochet
[[rules]]
name = "allow-dns"
action = allow # valeur d'enum (identifiant nu, validé vs le schéma)
[[rules]]
name = "deny-all"
action = deny
- En-tête
schema = "domaine@version": obligatoire, première directive signifiante. Détermine le schéma de validation + la version (compat avant/arrière). [section]↔ struct/sous-struct (chemin pointé[a.b]).[[liste]]↔List(Struct)(chaque bloc = un élément).clé = valeur↔ champ. Champ absent = non défini (défaut du schéma / optionnel).
Section 3 — Valeurs (lexèmes ; types résolus par le schéma)
| Lexème source | Types schéma acceptés (validés par le compilateur) |
|---|---|
true / false | Bool |
123, 0xFF, 1_000, -5 | Int8..64 / UInt8..64 — checked_* vs le type, rejet d’overflow/signe |
1.5, 1e9 | Float32/64 |
"texte\n\u{1F600}" (guillemets, échappements définis) | Text (UTF-8) |
hex:"00ff…" ou b64:"…" | Data (octets bruts) |
nom_nu | valeur d’enum (validée vs les valeurs du schéma ; did-you-mean sinon) |
[ v, v, … ] | List(T) — homogène, T donné par le schéma |
| (absent) | champ optionnel non posé / défaut |
- Échappements de chaîne : ensemble défini et borné (
\n \t \r \" \\ \u{...}) ; tout autre → erreur (pas d’interprétation permissive). - Sucre typé optionnel (à confirmer) : durées (
5s,250ms) et tailles (10MiB) reconnues uniquement si le champ schéma porte l’annotation correspondante → converties en entier par le compilateur. Sinon, entier nu. (Différable si jugé trop large pour v1.)
Section 4 — Exclusions volontaires (anti-pièges TOML, minimalisme)
Pour rester petit, non-ambigu, fuzzable :
- Pas de dates/heures natives (le piège de TOML) → durées via sucre typé ci-dessus.
- Pas de tables inline
{…}→ utiliser des sections. - Pas de tableaux hétérogènes → le schéma impose l’homogénéité.
- Pas d’inférence de type → schema-directed.
- Pas de clés dupliquées (erreur), pas de redéfinition de section.
Section 5 — Sémantique & déterminisme
- Validation en amont (Principe 4) : chaque valeur convertie/validée vers le type
schéma ; champ inconnu → erreur (
did-you-mean) ; champ requis manquant → erreur. - Cascade (XDG, ADR-033) : fusion système < utilisateur au niveau de la source (fusion de documents typés), puis une seule compilation → artefact.
- Déterminisme : l’artefact ne dépend pas de l’ordre des clés/sections de la source
(ordre canonique d’encodage) → repro bit-pour-bit (gate
repro, ADR-025). - Secrets (backend
passwd/shadow, ADR-041) : les valeurs marquées « secret » dans le schéma sont zeroizées dans les tampons du parseur/compilateur après usage, jamais loggées dans les diagnostics (valeur élidée).
Section 6 — Stratégie de test
- Fuzzing obligatoire :
source arbitraire (octets) → parsene panique jamais, ne produit jamais un AST invalide ;source + schéma → compilene panique jamais. - Property-based : ordre des clés indifférent (artefact identique) ; round-trip source→artefact→relecture ; bornes respectées.
- Diagnostics : tests d’erreurs (type incompatible, enum inconnue, champ requis manquant, overflow entier, UTF-8 invalide, profondeur/taille dépassée) → message ligne/colonne correct.
- Conformité : un corpus de sources valides/invalides de référence (par domaine).
Décisions / à confirmer
- Extension de fichier :
.airconf(proposé) — à valider. - Sucre durées/tailles (§3) : inclus v1 ou différé ?
- Multi-lignes de texte (
"""…""") : utile pour certaines valeurs ? (sinon\n). - Inclusion de fichiers (
include) : exclue v1 (surface + risques de cycle) — la cascade XDG couvre la composition.
Travail à reprendre
- Définir les schémas
.capnpdes domaines v1 (cf. backends ADR-041 : resolver/hosts, systemd, passwd) — c’est l’autre pré-requis d’implémentation d’air-config. - Geler la grammaire ci-dessus en BNF complète + table de lexèmes avant codage du parseur.
Licence du document : MPL 2.0
Statut : design v0.1 — grammaire du format de source air-config (maison, schema-directed,
fuzzé). À geler en BNF + définir les schémas .capnp avant implémentation. Bases :
ADR-033 / ADR-040 / ADR-041 + spec air-config.