lint:packages — variables/schémas incorrects non détectés à la validation #7

Closed
opened 2026-06-10 18:47:29 +02:00 by xmortelette · 1 comment

Contexte

Plusieurs cas où lint:packages valide un package (Package xxx is valid) alors que son schéma d'options ou un template référence des variables qui ne se résolvent jamais correctement à l'exécution.


1. Option object avec properties.*.default — silencieusement ignorée

Un package déclarait :

solver_settings:
  type: object
  description: Solvers settings
  properties:
    ingress_class:
      type: string
      default: traefik

Convention réellement supportée (format à plat) :

solver_settings:
  type: object
  default:
    ingress_class: traefik

Avec le schéma properties.*.default, les valeurs par défaut ne sont jamais appliquées : au rendu du template, values.solver_settings.ingress_class est absent et casse en mode strict, même quand le test fournit explicitement la valeur dans values:.

Suggestion : lint:packages devrait détecter/avertir sur l'usage de properties: dans une option type: object (motif non supporté par le moteur de fusion d'options), ou la doc devrait explicitement interdire ce style JSON-Schema imbriqué.


2. Variable absente du contexte de rendu dans un partial Handlebars

Un partial référençait {{ instance.package.jukebox }}, mais ce chemin n'existe pas dans le contexte passé par safe_apply (seuls name, namespace, category, pck, options sont fournis comme params). Résultat : échecs SystemInstance-* (Failed to access variable in strict mode Some("instance.package.jukebox")).

lint:templates/lint:rhai ne croisent pas les variables référencées dans un partial Handlebars avec les params réellement fournis par les appels Rhai qui le rendent — ce qui aurait permis de détecter ce chemin mort avant l'exécution des tests.


3. Accès à context.namespace depuis un package type: system

let replicas = if context.namespace.ha { 2 } else { 1 };

context.namespace n'existe que pour les packages tenant/service. Pour un package type: system, context.namespace vaut (), et l'accès .ha casse avec Unknown property 'ha' - a getter is not registered for type '()'.

Ni lint:rhai ni lint:packages ne vérifient la cohérence entre metadata.type du package et les chemins de contexte (context.namespace, context.tenant, …) utilisés dans ses scripts.


4. Le pipeline CI ne fait jamais échouer le job sur des assertions de test en échec

La commande agent package test retourne toujours un code de sortie 0 — y compris quand des assertions Test/TestSet échouent ([FAIL] ... no objects matched selector, 0/1 match, expected exactly 1, etc.). Le || exit 1 du script ne se déclenche que si l'agent plante (erreur Rhai, parsing), jamais sur un résultat de type Results: 8 passed, 6 failed, 14 total.

Conséquence concrète : un pipeline peut passer "Success" alors que le widget "Test summary" de la MR affiche de nombreux échecs réels — rendant le badge vert trompeur et masquant les régressions silencieuses.

Suggestion : faire échouer lint:packages/lint:templates dès qu'un Test/TestSet contient une assertion en échec — par ex. en parsant le résumé Results: N passed, M failed, T total et en faisant un exit 1 si M > 0.


Suggestion générale

Ces cas partagent un point commun : le linter valide la forme YAML/Rhai mais ne détecte pas qu'une variable référencée dans un template/script ne sera jamais peuplée à l'exécution. Une passe de lint capable de croiser "variables référencées" ↔ "variables garanties par le contexte du type de package + les params/options fournis" éviterait ces régressions silencieuses.

## Contexte Plusieurs cas où `lint:packages` valide un package (`Package xxx is valid`) alors que son schéma d'options ou un template référence des variables qui ne se résolvent jamais correctement à l'exécution. --- ## 1. Option `object` avec `properties.*.default` — silencieusement ignorée Un package déclarait : ```yaml solver_settings: type: object description: Solvers settings properties: ingress_class: type: string default: traefik ``` Convention réellement supportée (format à plat) : ```yaml solver_settings: type: object default: ingress_class: traefik ``` Avec le schéma `properties.*.default`, les valeurs par défaut ne sont **jamais appliquées** : au rendu du template, `values.solver_settings.ingress_class` est absent et casse en mode strict, même quand le test fournit explicitement la valeur dans `values:`. **Suggestion** : `lint:packages` devrait détecter/avertir sur l'usage de `properties:` dans une option `type: object` (motif non supporté par le moteur de fusion d'options), ou la doc devrait explicitement interdire ce style JSON-Schema imbriqué. --- ## 2. Variable absente du contexte de rendu dans un partial Handlebars Un partial référençait `{{ instance.package.jukebox }}`, mais ce chemin n'existe pas dans le contexte passé par `safe_apply` (seuls `name`, `namespace`, `category`, `pck`, `options` sont fournis comme `params`). Résultat : échecs `SystemInstance-*` (`Failed to access variable in strict mode Some("instance.package.jukebox")`). `lint:templates`/`lint:rhai` ne croisent pas les variables référencées dans un partial Handlebars avec les `params` réellement fournis par les appels Rhai qui le rendent — ce qui aurait permis de détecter ce chemin mort avant l'exécution des tests. --- ## 3. Accès à `context.namespace` depuis un package `type: system` ```rhai let replicas = if context.namespace.ha { 2 } else { 1 }; ``` `context.namespace` n'existe que pour les packages `tenant`/`service`. Pour un package `type: system`, `context.namespace` vaut `()`, et l'accès `.ha` casse avec `Unknown property 'ha' - a getter is not registered for type '()'`. Ni `lint:rhai` ni `lint:packages` ne vérifient la cohérence entre `metadata.type` du package et les chemins de contexte (`context.namespace`, `context.tenant`, …) utilisés dans ses scripts. --- ## 4. Le pipeline CI ne fait jamais échouer le job sur des assertions de test en échec La commande `agent package test` retourne toujours un code de sortie 0 — y compris quand des assertions `Test`/`TestSet` échouent (`[FAIL] ... no objects matched selector`, `0/1 match, expected exactly 1`, etc.). Le `|| exit 1` du script ne se déclenche que si l'agent plante (erreur Rhai, parsing), jamais sur un résultat de type `Results: 8 passed, 6 failed, 14 total`. Conséquence concrète : un pipeline peut passer "Success" alors que le widget "Test summary" de la MR affiche de nombreux échecs réels — rendant le badge vert trompeur et masquant les régressions silencieuses. **Suggestion** : faire échouer `lint:packages`/`lint:templates` dès qu'un `Test`/`TestSet` contient une assertion en échec — par ex. en parsant le résumé `Results: N passed, M failed, T total` et en faisant un `exit 1` si `M > 0`. --- ## Suggestion générale Ces cas partagent un point commun : le linter valide la *forme* YAML/Rhai mais ne détecte pas qu'une variable référencée dans un template/script ne sera jamais peuplée à l'exécution. Une passe de lint capable de croiser "variables référencées" ↔ "variables garanties par le contexte du type de package + les `params`/`options` fournis" éviterait ces régressions silencieuses.
Author

Traité dans la PR upstream : https://github.com/sebt3/vynil/pull/227

Points adressés (3/4) :

  • #4agent package test retournait toujours exit 0 même quand des assertions échouaient. Corrigé : retourne désormais exit 1 (TestFailure) si total_failed > 0.
  • #1type: object avec properties.*.default (JSON Schema imbriqué) silencieusement accepté par lint:packages. Ajout du finding package/object-properties-unsupported (Warn).
  • #3context.namespace / context.tenant dans un package type: system non détecté par lint:rhai. Étendu check_wrong_package_type pour détecter ces accès de propriété (l'AST Rhai 1.25 est associatif à droite : context.namespace.haDot(Variable("context"), Dot(Property("namespace"), Property("ha")))).

Point hors scope (#2) — Croisement variables partials Handlebars ↔ params passés par les appelants Rhai : refactoring plus conséquent, à traiter séparément.

Traité dans la PR upstream : https://github.com/sebt3/vynil/pull/227 **Points adressés (3/4) :** - **#4** — `agent package test` retournait toujours exit 0 même quand des assertions échouaient. Corrigé : retourne désormais exit 1 (`TestFailure`) si `total_failed > 0`. - **#1** — `type: object` avec `properties.*.default` (JSON Schema imbriqué) silencieusement accepté par `lint:packages`. Ajout du finding `package/object-properties-unsupported` (Warn). - **#3** — `context.namespace` / `context.tenant` dans un package `type: system` non détecté par `lint:rhai`. Étendu `check_wrong_package_type` pour détecter ces accès de propriété (l'AST Rhai 1.25 est associatif à droite : `context.namespace.ha` → `Dot(Variable("context"), Dot(Property("namespace"), Property("ha")))`). **Point hors scope (#2)** — Croisement variables partials Handlebars ↔ `params` passés par les appelants Rhai : refactoring plus conséquent, à traiter séparément.
xmortelette added the Kind/Bug
Priority
Medium
3
labels 2026-06-11 09:43:27 +02:00
Sign in to join this conversation.