Résumé

  • Le projet JMAP Enhanced Result References permet d’alimenter une propriété, un correctif ou un filtre avec des valeurs sélectionnées dans la réponse d’une méthode précédente.
  • Une sélection réussie et un type JSON correct prouvent un acheminement technique, non la provenance, l’actualité ni le droit de transférer la donnée vers un autre public.

Le PDF figurait dans un message réservé à un petit groupe juridique. Une première méthode avait renvoyé la structure du courriel et les métadonnées de ses pièces jointes. Une référence de résultat a choisi le blobId correspondant, puis une méthode ultérieure l’a placé dans une fiche accessible à une équipe beaucoup plus large.

Chaque contrôle local semblait rassurant. L’utilisateur pouvait lire le message. Le chemin pointait vers un nœud existant. La valeur était bien une chaîne. Le service pouvait modifier la fiche. Le résultat final était donc techniquement cohérent. Il n’était pas pour autant légitime.

Le droit de lire une source et le droit d’écrire une destination ne s’additionnent pas automatiquement pour former un droit de publication. C’est précisément le genre de distinction que les couches d’intégration ont tendance à effacer lorsqu’un identifiant voyage sans son contexte.

La révision 02 de JMAP Enhanced Result References est datée du 21 juin 2026 et expire le 23 décembre 2026. À la date de recherche, il s’agit d’un Internet-Draft actif du groupe de travail JMAP, engagé sur la voie Standards Track. Ce n’est ni une RFC définitive, ni une attestation de mise en œuvre, ni une mesure d’adoption.

Le texte étend un mécanisme déjà présent dans RFC 8620. Dans une requête JMAP comportant plusieurs appels, une méthode ultérieure peut désigner une réponse antérieure par resultOf et name, puis y sélectionner une valeur avec path. Le projet rend cette référence utilisable dans les propriétés d’un /set, dans les valeurs d’un PatchObject et dans les FilterCondition d’un /query. Il propose aussi JSON Path, de manière optionnelle, en plus de JSON Pointer.

Ce dispositif évite un aller-retour client entre deux opérations liées. Il ne donne pas à la donnée sélectionnée une autorité qu’elle n’avait pas à la source.

La trajectoire d’une valeur compte autant que sa forme

Un journal qui ne conserve que l’objet final peut montrer que la fiche contient désormais l’identifiant du PDF. Il ne peut pas répondre aux questions décisives : quel appel a produit cet identifiant, quel sélecteur l’a retenu, sous quelle identité, avec quelles permissions et pour quelle destination ?

Le projet rend la trajectoire techniquement explicite. Une référence contient l’appel d’origine, le nom de la méthode et le chemin. Cette information devrait devenir une provenance d’exécution, et non disparaître dès que la valeur est copiée.

Il faut toutefois choisir les mots avec rigueur. Cette provenance prouve qu’une valeur vient de telle réponse JMAP. Elle ne prouve pas que le contenu sous-jacent est authentique, que la réponse était encore fraîche, ni que la source avait mandat pour gouverner l’opération suivante. Un blobId rattache une opération à un objet du serveur ; il ne transporte pas à lui seul la politique de diffusion de cet objet.

La meilleure piste d’audit relie donc deux contextes. Du côté source : compte, principal, méthode, réponse, visibilité et expression de sélection. Du côté destination : propriété ou filtre, type attendu, public prévu, contrôle d’autorisation et effet produit. Sans ce pont, une organisation saura que la copie a eu lieu, mais pas pourquoi elle était permise.

JSON Pointer et JSON Path ne prennent pas de décision éditoriale

JSON Pointer suit une route structurelle précise. JSON Path peut filtrer, parcourir récursivement et produire zéro, un ou plusieurs nœuds. Cette expressivité est utile lorsque la réponse antérieure contient une collection dont il faut extraire certains éléments.

Le projet définit ensuite comment la cardinalité devient une valeur de destination. Pour une propriété primitive ou un objet unique, un nœud donne une valeur, zéro donne null et plusieurs provoquent invalidResultReference. Pour un tableau, zéro donne [] et plusieurs nœuds deviennent un tableau dans l’ordre de la liste JSON Path. Pour une map, zéro donne {} et un seul objet conforme peut être accepté.

Ces règles empêchent les serveurs de choisir chacun leur comportement. Elles ne disent pas ce que signifie le vide. null peut effacer une valeur, signifier une absence ou être refusé plus tard. [] peut vouloir dire qu’aucun destinataire n’a été trouvé ou demander de retirer tous les destinataires. {} peut signifier qu’aucune option n’est fournie ou qu’il faut remplacer toutes les options par un ensemble vide.

L’application qui connaît la propriété doit décider si zéro résultat constitue une observation acceptable, une instruction de suppression ou un motif d’arrêt. Laisser le résolveur générique décider reviendrait à faire d’une convention de forme une politique métier.

La cardinalité protège aussi contre une autre facilité dangereuse : choisir arbitrairement le premier résultat lorsque plusieurs nœuds alimentent une propriété scalaire. L’erreur invalidResultReference conserve le fait que les preuves étaient ambiguës. Le « premier » n’est pas nécessairement le meilleur, le plus récent ni le plus autorisé.

Le bon type peut encore désigner le mauvais monde

Après la résolution, la méthode valide le type attendu. Dans /set, une incompatibilité devient invalidProperties. Dans /query, elle devient invalidArguments. Le projet avertit contre les conversions implicites : une chaîne ne doit pas devenir un nombre ou un booléen simplement pour franchir le contrôle.

Cette discipline protège la signification. Convertir "01" en 1 peut transformer un identifiant en quantité. Transformer un objet en texte peut masquer sa structure et contourner un contrat. Le refus montre que les données disponibles ne satisfont pas l’interface déclarée ; la coercition fabrique une compatibilité.

Mais un type exact ne suffit pas. Deux comptes peuvent employer des identifiants de boîte aux lettres de même forme. Une chaîne extraite d’un compte A peut être syntaxiquement parfaite dans un filtre appliqué au compte B tout en désignant un espace sans rapport. Une liste de destinataires peut être bien formée et avoir été constituée pour une finalité incompatible avec la nouvelle action.

Il faut donc distinguer validation de forme, validation de domaine et autorisation. La première appartient au contrat de méthode. La deuxième vérifie que la valeur se rapporte au bon compte, au bon tenant ou au bon objet. La troisième détermine si ce principal peut utiliser cette donnée pour cet effet. Fusionner ces contrôles dans un seul voyant vert rend l’audit flatteur et peu fiable.

Une couche intermédiaire peut être volontairement ignorante

Le projet prévoit qu’une couche syntaxique intermédiaire puisse résoudre les chemins sur du JSON opaque. Elle n’a pas besoin de connaître les types de méthode, les propriétés ni leur sémantique. La couche d’exécution applique ensuite les règles de type propres à la destination.

C’est une bonne architecture. Une passerelle peut fournir une fonction commune de résolution sans embarquer toute la logique des applications. C’est également une limite de preuve. La passerelle peut certifier que l’expression a produit trois nœuds. Elle ne peut pas certifier que ces trois nœuds représentent les personnes qui doivent recevoir le dossier.

La doctrine de couche mince de Heng Lu aide à préserver cette honnêteté. La coordination gagne en légitimité lorsqu’elle résout un problème borné sans annexer le pouvoir de décider. Le résolveur transporte une valeur. La méthode accepte ou refuse un argument typé. Le mandat de publier, de partager ou d’effacer reste ailleurs.

Cette séparation doit apparaître dans les tableaux de bord. Une métrique « référence réussie » ne devrait jamais être présentée comme « transfert approuvé ». La première décrit une opération de données ; la seconde suppose une règle institutionnelle, un principal et un public.

Le cache doit se souvenir des permissions

Le résultat d’un chemin semble facile à mettre en cache : même réponse, même expression, même valeur. Pourtant, la validité d’une réutilisation dépend parfois d’éléments absents du JSON. Un membre peut perdre l’accès à un espace privé entre la première résolution et la suivante. Le nœud existe toujours, mais son droit d’être utilisé a changé.

Le projet impose de ne jamais partager ces caches entre utilisateurs ou contextes de sécurité et demande leur invalidation lorsque les contrôles d’accès évoluent. Une clé robuste doit lier le principal, le compte, l’état pertinent des permissions et, si nécessaire, le contexte de destination. Un cache qui ne connaît que le corps de réponse et l’expression peut restituer une vérité structurelle devenue interdite.

Il faut aussi surveiller les canaux temporels. La différence entre une réponse issue du cache et une évaluation complète peut révéler l’existence d’une donnée ou d’un chemin dans un autre contexte. L’isolation ne se limite donc pas aux octets retournés.

Un journal utile distingue une sélection fraîche d’une réutilisation. Il indique l’époque d’autorisation associée à l’entrée et la raison pour laquelle elle restait valable. « Cache hit » est une information de performance, pas une preuve de permission.

L’expression consomme une ressource gouvernée

JSON Path sait filtrer et descendre récursivement. Sur une grande réponse, une expression peut produire une liste immense ou demander beaucoup de calcul. Des références imbriquées peuvent recopier des structures complexes. La séquentialité des appels empêche une boucle directe simple, mais pas une demande pathologique.

Les serveurs doivent limiter la complexité des expressions, le temps d’évaluation, la taille des listes de nœuds, le nombre de références et leur profondeur cumulée. Lorsqu’une limite est atteinte, le rejet doit rester visible. Tronquer silencieusement une liste pour sauver la requête changerait le jeu de données tout en laissant croire que la sélection complète a réussi.

Le parseur JSON Path fait lui aussi partie de la surface de sécurité. Bibliothèque maintenue, correctifs, isolation et tests de limites ne sont pas des détails d’implémentation lorsqu’une expression non fiable peut commander une traversée récursive.

Le même principe vaut pour les filtres. Une FilterCondition peut recevoir dynamiquement un identifiant sélectionné auparavant. Le type peut être correct, mais la portée du filtre peut devenir beaucoup plus large que prévu. Les opérateurs doivent observer non seulement le coût du sélecteur, mais aussi l’ampleur de la requête qu’il alimente.

Conserver ce que le succès ne prouve pas

Une référence résolue prouve qu’un appel antérieur a été trouvé et qu’un chemin a été évalué. La règle de cardinalité prouve comment les nœuds ont été façonnés. La validation prouve une conformité au type JSON. L’autorisation de la méthode prouve que l’écriture ou la requête était permise dans son propre périmètre.

Aucune de ces propositions, isolément, ne prouve la provenance métier, l’actualité, la compatibilité des finalités ni le droit de déplacer la donnée d’un public à l’autre. Le système fiable conserve ces affirmations négatives au lieu de les faire disparaître derrière la réponse finale.

Les tests doivent donc inclure la fuite plausible, pas seulement le chemin heureux. Sélectionner un document privé et tenter de l’insérer dans un objet public. Réutiliser une résolution après changement d’ACL. Fournir plusieurs résultats à une propriété scalaire. Comparer un pointeur absent à un wildcard sans résultat. Tester null, [] et {} sur des destinations dont les conséquences diffèrent. Puis vérifier que l’audit reconstruit chaque transfert.

Le PDF privé n’a pas été exposé parce que JMAP avait mal lu le chemin. Il l’a été parce qu’une chaîne de contrôles locaux a été prise pour une autorité globale. Les références enrichies rendent le flux plus puissant. Elles rendent donc la frontière entre transport et mandat encore plus importante à nommer.

Sources