Sémantique d'exécution, contraintes et sécurité

Cette page résume comment un Script se comporte à l'exécution (ordre, transactions, erreurs, verrouillage), à quelles contraintes statiques il est soumis à l'enregistrement et son modèle de sécurité. Pour la syntaxe, consultez le Catalogue des Statement et les Expressions de valeur ; pour les combinaisons concrètes, consultez le Cookbook.

Ordre d'exécution

  • Les statements s'exécutent séquentiellement de haut en bas. Lorsque l'exécution atteint un Return, elle se termine à ce point.
  • L'exécution se déroule en ligne, sur le chemin qui traite la requête d'appel. La réponse de l'appel est le résultat de l'exécution (pour la forme de la réponse, voir Requête et réponse dans l'aperçu de Script), et le temps alloué à une exécution est traité plus bas dans Budget de temps.

Sémantique d'exécution

Guard (conditions préalables)

Il n'existe pas de Statement guard dédié. On l'exprime avec If et then:[Return]. En cas de violation de la condition, il renvoie un résultat et n'exécute pas les Statement suivants (un Script sans guard est bien entendu également possible).

{ "type": "If", "condition": { "<": [ "{ /wallet/fields/balance/en-US }", "{ /payload/fields/cost }" ] },
  "then": [ { "type": "Return", "value": { "ok": false, "reason": "insufficient credit" }, "statusCode": 402 } ] }

Sans transaction et compensation best-effort

Un Script n'est pas une transaction. En cas d'échec, le moteur tente de compenser (compensation) le travail effectué jusque-là et renvoie la cause de l'erreur, mais avec les limites suivantes (assumées par conception).

  • Annuler une suppression crée un nouveau sys.id, de sorte que les références qui pointaient dessus se brisent.
  • Les effets externes (Http) sont irréversibles (un appel déjà parti, ainsi que sa facturation, ne peuvent pas être annulés).
  • Il arrive que la compensation ne s'exécute pas du tout, laissant subsister un état non compensé.

Si vous avez besoin d'une véritable atomicité, écrivez la compensation dans le Script vous-même ou placez les opérations irréversibles (les appels externes, etc.) tout à la fin. L'ordre le plus dangereux est celui qui « s'enchaîne jusqu'au bout mais ne peut pas être annulé, tout en paraissant sûr ».

Verrouillage optimiste

La contention d'update/patch se maîtrise avec le version de ResourceUpdate et ResourcePatch. Si l'on fournit version (une expression de valeur, Int), la mise à jour n'a lieu que si elle correspond au sys.version actuel de la cible ; une non-correspondance avorte avec une erreur de conflit de version (gérable localement avec Try/catch). Si on l'omet, c'est du last-write-wins sans vérification. En général, on lit d'abord avec ResourceRead ou ResourceFind et on transmet ce sys.version (voir CAS de verrouillage optimiste dans le Cookbook).

Écritures sur origin

Les écritures s'appliquent toujours sur l'origin (draft), et l'exposition en delivery (CDA/ACDA) se contrôle avec publish (le publish de ResourceCreate/ResourceUpdate/ResourcePatch, ou ResourcePublish/ResourceUnpublish).

Qu'est-ce qui constitue un échec

Si un Statement échoue en cours d'exécution, l'exécution s'interrompt à cet endroit, à moins qu'un Try ne prenne en charge cet échec. Le moteur tente alors d'annuler le travail effectué jusque-là. Cette annulation a des limites, détaillées dans Sans transaction et compensation best-effort.

Si le Statement en échec se trouve dans un Try, cet échec peut être traité dans catch. Dans un catch, on référence le contenu de l'échec ({ message }) via /error. Le Statement où l'échec s'est produit n'y figure pas.

Les cas suivants sont traités comme des échecs.

Un Return n'est pas un échec. Il termine normalement l'exécution de façon anticipée : il ne passe donc pas dans catch.

Les deux façons dont Http échoue

Un échec de Http se répartit en deux cas, selon qu'il est traité ou non comme une réponse de status. Cette différence détermine si retry et ignoreStatusCode s'appliquent.

CatégorieTraité comme une réponse de statusÉchec immédiat
Cas concernésL'API cible répond avec un status supérieur ou égal à 400, le délai est dépassé (status 504), la connexion à l'API cible a échoué ou la réponse n'a pas pu être lue (status 502), le corps de réponse dépasse 10MiB (status 502)responseType vaut "Json" mais le corps d'une réponse de succès n'est pas du JSON, le fichier à envoyer dépasse la limite de téléchargement, l'URL du fichier répond avec un status autre que 2xx ou la connexion à l'URL du fichier est impossible, la valeur d'une part a un format invalide
retryRéessaie le nombre de fois indiquéNe réessaie pas
ignoreStatusCode: trueNe le considère pas comme un échec et lie { status, body } comme résultatNe s'applique pas ; traité comme un échec
Try/catchPeut être traité dans catchPeut être traité dans catch

Les conditions d'échec pendant l'envoi de fichier sont détaillées dans Envoyer un fichier comme corps.

L'agrégation côté serveur se limite au décompte

Le décompte, c'est ResourceCount qui l'effectue côté serveur. Comme il ne va pas lire les éléments, il n'est pas soumis au plafond du nombre d'éléments traités.

Pour sum et group-by, il n'existe pas d'opération serveur dédiée. Une telle agrégation doit se calculer soi-même en parcourant avec ResourceForEach et en utilisant SetVar et JsonLogic ; on est donc lié au plafond du nombre d'éléments traités (inadapté pour agréger des millions d'enregistrements). Si seul le décompte est nécessaire, on ne parcourt pas : on utilise ResourceCount.

Pas d'attente ni de délai

Un Script n'a pas de Statement Delay. Un Script s'exécute une seule fois puis se termine, et il n'attend ni ne sonde en interne la fin d'un job externe.

Contraintes statiques (validées à l'enregistrement)

Les points suivants sont vérifiés au moment où l'on enregistre un Script (création/modification). En cas de violation, l'enregistrement est refusé (échec au moment de l'enregistrement, pas à l'exécution). Quelle violation entraîne quel code de refus est traité dans Erreurs.

ContrainteValeur
Maximum d'appels externes par définition (Http, EmailSend)Selon le plan (voir Tarifs)
Maximum d'éléments traités par ResourceForEach (en l'absence de limit déclaré, parcourt jusqu'à cette valeur ; échec s'il reste des correspondances à ce plafond)10 000
Maximum de SetVar par définition (imbriqués inclus)10
Maximum de Cache par définition (imbriqués inclus, toutes opérations confondues)5. Au-delà, enregistrement refusé
Un Cache dans le bloc d'un Loop ou d'un ResourceForEachEnregistrement refusé
Cache.keyLittéral uniquement, 128 caractères au maximum. Une expression de valeur fait refuser l'enregistrement
Cache.ttlEntre 1 et 30 secondes ; en son absence, 5 secondes. Hors de cet intervalle, enregistrement refusé
Maximum total de Statement par définition (imbriqués inclus)Selon le plan (voir Tarifs)
Plafond de Http.retry2
Champs de corps de requête d'un Http (body, urlBody, multipartBody)Un seul des trois. En indiquer deux ou plus fait refuser l'enregistrement
Nombre de parts de Http.multipartBodyAu moins 1. Vide, l'enregistrement est refusé
value et url d'une part de multipartBodyExactement l'un des deux. Indiquer les deux ou aucun fait refuser l'enregistrement
fileName d'une part de multipartBodyUniquement sur une part qui indique url. L'indiquer sans url fait refuser l'enregistrement
Longueur de Regex.pattern128 caractères
Maximum de secrets par définition20
key de secrets1 à 64 caractères, lettres latines, chiffres, _ et - uniquement. Deux key identiques font refuser l'enregistrement
value de secrets1 à 4 096 caractères. En dehors de cet intervalle, enregistrement refusé
Référence { /secrets… }Exactement /secrets/<key déclaré>. Sinon, enregistrement refusé
Statement qui crée ou supprime un ServiceUserEnregistrement refusé. Seuls les trois Statement de lecture ainsi que ResourceUpdate et ResourcePatch acceptent cette ressource
Si anonymousCallEnabled vaut true, le createdBy: ":self" de whereEnregistrement refusé
transformations d'une instruction d'ingestion Media (Transformation de fichier)Tableau uniquement. Le type de chaque élément est PdfWatermark, et color est au format #RRGGBB. Pour text, toute la chaîne écrite (chemins des { /pointer } compris) doit tenir sur une seule ligne de caractères autorisés. Sinon, enregistrement refusé
Longueur du text littéral de PdfWatermark1 à 64 caractères. En dehors de cet intervalle, enregistrement refusé. Un text contenant un { /pointer } n'est pas vérifié à l'enregistrement, mais à l'exécution, sur la valeur résolue

Les limites fixes du tableau ci-dessus sont des valeurs fixées par la plateforme : elles sont identiques quel que soit le plan. En revanche, le nombre total de Statement et le nombre d'appels externes par définition sont des limites propres au plan. Comme ces deux-là ne sont pas des erreurs de validation mais des limites de plan, un dépassement fait refuser l'enregistrement ou la modification pour dépassement de la limite du plan (une même définition est admise sur un plan supérieur) et se débloque par une montée en gamme de plan. Les valeurs par plan figurent dans Tarifs.

L'ingestion de fichier Media, contrairement aux appels externes comme Http et EmailSend, ne compte pas dans le plafond d'appels externes par définition.

ResourceForEach étant un Statement composite qui possède des enfants, il ne compte pas lui-même dans le nombre d'appels externes. Ce sont les Statement d'appel externe (Http, EmailSend) à l'intérieur de onEach qui sont comptés (comptés pour 1 statiquement, mais réellement exécutés à chaque élément lors du parcours). onEach peut contenir des appels externes ou l'ingestion de fichier Media, tout comme le body d'un Loop. Le nombre de tours qu'une itération effectue réellement n'entre pas dans ce comptage : il entre en revanche, sous forme de multiplication, dans le Budget de temps ci-dessous.

Limites de longueur des valeurs (à l'exécution)

Les Statement de signature et de traitement de texte, ainsi que Cache, ont une limite sur la taille des valeurs qu'ils manipulent. Il s'agit de la longueur de la valeur résolue de l'expression, et non de la longueur de l'expression (les seize caractères de { /rawPayload } peuvent désigner plusieurs dizaines de KB) : la vérification a donc lieu pendant l'exécution et non à l'enregistrement.

CibleLimiteEn cas de dépassement
Le value de Signature65 536 caractèresCe Statement échoue (status 422)
Le value de Hash128 caractèresCe Statement échoue (status 422)
Le value de Regex10 240 caractères (10KiB)Ce Statement échoue (status 400)
Le value de Cache10 240 octets (10KiB)Ce Statement échoue (status 422)
  • Tous quatre se comportent comme les autres échecs d'exécution : ils se traitent localement avec Try/catch.
  • La limite de Signature est calée sur la taille des corps que les fournisseurs envoient réellement (un événement de paiement fait quelques KB, un webhook de commande atteint plusieurs dizaines de KB). Celle de Hash est bien plus étroite, car c'est l'emplacement où l'on concatène quelques champs.
  • Les 128 caractères de Regex.pattern relèvent de la vérification à l'enregistrement des contraintes statiques ci-dessus. Cette longueur n'est pas un dispositif contre l'emballement ((a+)+$ est dangereux avec six caractères seulement). Ce qui empêche l'emballement, c'est la règle qui n'autorise le motif qu'en littéral et le budget de temps ci-dessous ; la longueur ne promet rien de plus qu'une taille qu'un humain peut lire et relire.

Budget de temps (à l'exécution)

Le temps alloué à une exécution est de 180 secondes au maximum. Le temps réellement alloué dépend de la définition du Script (et aussi du plan lorsqu'il envoie des fichiers) : c'est la base de 30 secondes à laquelle s'ajoute le temps que les appels externes peuvent utiliser.

Ce budget s'applique à l'exécution entière. Indépendamment de cela, une requête Http doit se terminer dans le timeoutMs de cette requête.

Base de 30 secondes

Toutes les opérations qui ne sont pas des appels externes, comme la lecture et l'écriture de ressources ou la réception et le traitement d'un fichier Media, sont traitées dans ces 30 secondes. Un Script sans appel externe se voit allouer 30 secondes.

Temps ajouté par Statement

Les temps des Statement placés en séquence s'additionnent tous.

StatementTemps ajouté
HttptimeoutMs (30 secondes s'il n'est pas indiqué). Si des fichiers sont envoyés, on ajoute pour chaque fichier le temps de téléchargement (tableau ci-dessous), et si retry est indiqué, on multiplie le tout par le nombre de tentatives (1 + retry)
EmailSendtimeoutMs (10 secondes s'il n'est pas indiqué). Comme il ne réessaie pas, on ne l'ajoute qu'une seule fois
IfLe temps de la plus longue des deux branches then et else
ParallelLe temps de la plus longue des branches
TryLa somme des temps de body, catch et finally
LoopLe temps de body multiplié par maxIterations (10 000 s'il n'est pas indiqué)
ResourceForEachLe temps de onEach multiplié par limit (10 000 s'il n'est pas indiqué)
Les autres Statement (ceux qui ne contiennent pas d'autre Statement)Rien n'est ajouté. Ils sont traités dans la base de 30 secondes

S'il n'y a pas d'appel externe dans une itération, le temps ajouté reste 0 même multiplié par le nombre d'itérations. Une telle itération doit donc se terminer dans la base de 30 secondes.

Temps de téléchargement par fichier

PlanTemps de téléchargement
FreeEnviron 5,2 secondes
BasicEnviron 10,5 secondes
ProEnviron 10,5 secondes
EnterpriseEnviron 107,4 secondes

Cette valeur correspond au temps nécessaire pour recevoir, à 10 000 000 octets par seconde, la quantité fixée par la limite de téléchargement du plan.

Exemple de calcul

Sur le plan Pro, un Script qui appelle une fois un Http (timeoutMs de 30 secondes, retry de 1) envoyant deux photos se calcule comme suit.

  • Http : (30 secondes + 10,5 secondes × 2) × 2 = environ 102 secondes
  • Exécution entière : 30 secondes + 102 secondes = environ 132 secondes

Comme 132 secondes restent sous les 180 secondes, ce Script se voit allouer 132 secondes.

Au-delà de 180 secondes

Même si la valeur calculée dépasse 180 secondes, le Script est enregistré et exécuté. Toutefois, lorsque l'exécution atteint 180 secondes, elle s'interrompt à ce moment-là.

Limites de quantité par plan

Le nombre de Script par Organization est limité selon le plan.

PlanNombre de Script
Free10
Basic30
Pro100
EnterpriseIllimité

Indépendamment de cela, le nombre de Statement et le nombre d'appels externes (Http, EmailSend) qu'une définition de Script peut contenir sont eux aussi limités selon le plan. Lors de l'enregistrement ou de la modification d'une définition, un dépassement de la limite de ce plan est refusé ; pour les valeurs précises, consultez Tarifs.

Lorsque la limite est atteinte, la création d'un nouveau Script est refusée.

Taille de téléchargement de fichier Http

Lorsque Http récupère depuis une URL un fichier à envoyer comme corps de requête (urlBody, part url de multipartBody), la taille pouvant être reçue par URL de fichier est limitée selon le plan. C'est le plan de l'Organization à laquelle appartient le Space propriétaire de ce Script qui s'applique.

PlanTaille maximale par URL de fichier
Free50MiB
Basic100MiB
Pro100MiB
Enterprise1GiB
  • La limite s'applique séparément à chaque URL. S'il y a plusieurs parts url, chaque fichier doit respecter cette limite.
  • Si l'on tente d'envoyer un fichier qui dépasse la limite, ce Http échoue (voir Les deux façons dont Http échoue).
  • Cette limite sert aussi de base au temps de téléchargement ajouté au Budget de temps.

Modèle de sécurité

secrets

Les valeurs secrètes comme une clé d'API externe, la clé secrète d'un prestataire de paiement (PG), une clé de signature de webhook ou une valeur d'authentification Basic … calculée à l'avance ne s'écrivent pas telles quelles dans un Statement. On les déclare dans les secrets de la définition, et un Statement les lit via { /secrets/<key> }. Les clés de test publiées se placent au même endroit. Ainsi, au passage à la clé réelle, on laisse les Statement tels quels et il suffit de changer la valeur dans secrets.

"secrets": [
  { "key": "LLM_API_KEY",            "value": "sk-...",    "description": "Clé d'API pour les appels LLM" },
  { "key": "WEBHOOK_SIGNING_SECRET", "value": "whsec_...", "description": "" }
],
"statements": [
  { "type": "Http", "method": "POST", "url": "https://api.openai.com/v1/chat/completions",
    "headers": [ { "key": "Authorization", "value": "Bearer { /secrets/LLM_API_KEY }" } ],
    "body": { /* ... */ }, "name": "llm" }
]
ChampObligatoireRègle
keyObligatoireDe 1 à 64 caractères, uniquement des lettres latines, des chiffres, _ et -. Il doit être unique au sein d'un même Script.
valueObligatoireUne chaîne de 1 à 4 096 caractères. C'est une valeur statique qui n'est pas interprétée comme un modèle : un { /… } placé à l'intérieur est utilisé tel quel, caractère pour caractère.
descriptionObligatoireLa description de l'usage, de 0 à 128 caractères. La chaîne vide "" est également acceptée.
  • Stockage : WEEGLOO chiffre le value et le stocke en toute sécurité. Un Statement lit la valeur d'origine via { /secrets/<key> }.
  • Consultation : dans les réponses d'API qui renvoient le Script (consultation, création, modification), le value est renvoyé avec sa valeur d'origine. La valeur est visible pour les rôles capables de lire ce Script : restreignez donc la permission de lecture. Un membre (ServiceUser) ne peut pas lire la définition d'un Script (la consultation et la rédaction sont réservées à CMA, et ACMA n'a pas d'API Script).
  • Modification : la modification complète (PUT) remplace la définition entière. Si on l'envoie sans secrets, les valeurs secrètes déclarées sont supprimées, et si un Statement y fait encore référence via { /secrets/… }, l'enregistrement est refusé. Envoyez donc secrets à chaque modification. Il suffit de renvoyer telles quelles les valeurs de la réponse de consultation.
  • La valeur pendant l'exécution : c'est le Statement qui décide de ce que devient la valeur lue. Renvoyée par Return, elle reste dans la réponse d'exécution et dans le ScriptLog ; placée dans SetVar, Cache ou un Content, elle y reste avec sa valeur d'origine. N'envoyez une valeur secrète qu'à l'API externe qui en a besoin.
  • App Bundle : lorsqu'un Script est empaqueté dans un App Bundle, le value de secrets est masqué en ******, tandis que key et description sont inclus tels quels. Un Script créé en installant cet App Bundle a ses valeurs secrètes à ****** : c'est à celui qui l'installe d'y saisir les valeurs réelles pour que les Statement qui les lisent fonctionnent. Les valeurs écrites hors de secrets (les en-têtes de Http, le secret de Signature, etc.) ne sont pas masquées et sont incluses telles quelles.

Un Script peut contenir jusqu'à 20 secrets. Les règles de pointer sont traitées dans /secrets des Expressions de valeur.

Identité d'exécution et autorisation

  • Identité d'exécution : pendant l'exécution, toute opération de ressource est effectuée sous l'identité de l'utilisateur qui a appelé /execute. Le createdBy/updatedBy de toute ressource créée ou modifiée est l'appelant, et une portée createdBy: ":self" se résout elle aussi par rapport à l'appelant. L'appel anonyme fait exception. Une exécution arrivée par /execute/anonymous n'a pas d'appelant : les deux se résolvent donc par rapport à l'auteur (voir Appel anonyme).
  • Il y a deux limites d'autorisation, et à l'exécution, le moteur ne revérifie pas les permissions de ressource à chaque Statement.
    1. Au moment de la rédaction (enregistrement) : lors de l'enregistrement d'un Script, on vérifie si l'auteur possède réellement les permissions de ressource et d'action qu'utilisent ses Statement. S'il en manque ne serait-ce qu'une, l'enregistrement est refusé. Autrement dit, un Script contenant une opération non autorisée n'est jamais enregistré au départ. Tout Statement qui désigne une ressource subit cette vérification, qu'il s'agisse d'un leaf ou d'un ResourceForEach qui possède un bloc. Une définition déjà enregistrée est revérifiée lors de sa modification : après une révocation de permission, il n'est donc plus possible de la corriger et de l'enregistrer.
      • L'annuaire des membres (ServiceUser) est vérifié sur l'axe des paramètres et non sur les mappages de permissions. Pour écrire resource: "ServiceUser" dans les trois Statement de lecture ainsi que dans ResourceUpdate et ResourcePatch, le settings du SpaceRole de l'auteur doit contenir SETTING_SERVICE_LOGIN (ou SETTING_ALL) (voir le settings de SpaceRole). C'est que l'annuaire des membres est, sur tous les autres chemins également, une ressource que gouvernent les paramètres du Space.
      • Aucun rôle ne permet d'enregistrer un Statement qui crée ou supprime un membre. Comme un Script ne peut ni créer ni supprimer un membre, le refus n'est pas un manque de permission (403) mais un Statement mal écrit (400). Ce n'est donc pas une lacune qu'on pourrait combler en ajoutant une permission. Les seules modifications autorisées sont le roleOverride et le enableLogin de ResourceUpdate et ResourcePatch (voir Manipuler l'annuaire des membres).
    2. Au moment de l'appel (/execute) : on ne vérifie que la permission Execute de Script de l'appelant. Sans elle, le résultat est 403. Une fois qu'elle est validée, les permissions de ressource par Statement ne sont pas revérifiées à l'exécution ; l'exécution se poursuit. C'est le même principe que le droit d'exécuter une fonction en programmation. Si l'on a le droit d'exécuter la fonction, on ne redemande pas la permission de chaque opération individuelle qu'elle contient. Le chemin d'appel anonyme n'a pas cette vérification. C'est qu'il n'y a pas d'appelant à vérifier : ouvrir ce chemin équivaut donc à publier un Script sans authentification.
  • Blocage de l'appel direct (directCallEnabled) : si le directCallEnabled d'un Script vaut false, l'appel direct à /execute lui-même est refusé. Cette barrière s'applique une fois la vérification de la permission Execute franchie, si bien que le blocage a lieu même lorsque l'on possède la permission Execute. Un appelant qui n'a pas cette permission reçoit un 403 avant d'atteindre cette barrière. Cette barrière n'existant que sur cet endpoint, l'action de liaison (script) d'un Webhook et un Scheduler l'exécutent tel quel. La valeur par défaut est true (appel direct autorisé).
  • Appel anonyme (anonymousCallEnabled) : la valeur par défaut est false. En la passant à true, ce Script et lui seul s'exécute aussi par un chemin dédié sans authentification (/execute/anonymous), et l'identité d'exécution est alors non pas l'appelant mais l'auteur. Des deux limites ci-dessus, la vérification au moment de l'appel (la permission Execute) est absente de ce chemin : l'authentification effective est donc assurée par le Script lui-même (la vérification de signature de la requête reçue). Les conditions pour l'activer et les règles d'enregistrement sont traitées dans Appel anonyme.
  • Portée de propriété : dans un filtre where, createdBy: ":self" signifie « uniquement ce qu'a créé l'appelant actuel » (par exemple, ne consulter que son propre portefeuille). Ce filtre est inutilisable dans un Script qui autorise l'appel anonyme. Faute d'appelant, il se résout sur l'auteur, si bien que le sens même de portée de propriété ne tient plus.
  • Permissions déléguées (prudence à la rédaction) : en combinant les deux limites ci-dessus, exécuter un Script revient à agir avec les permissions de l'auteur déléguées. L'appelant n'a besoin que de Execute, et les Statement à l'intérieur du Script s'exécutent tels quels dans le périmètre pour lequel l'auteur a été autorisé au moment de l'enregistrement. Par conséquent, une opération de ressource que l'appelant ne pourrait pas effectuer lui-même peut tout de même se produire à travers le Script. Comme les permissions accordées à l'auteur constituent la portée effective de ce Script, il convient de définir avec soin les opérations que l'on place dans un Script.

Liste de contrôle récapitulative

Avant d'enregistrer, vérifiez les points suivants.

  • Si l'appel anonyme (anonymousCallEnabled) est activé, where ne contient pas createdBy: ":self" et le Statement qui vérifie la requête reçue (Signature, etc.) est placé tout au début.
  • Le nombre d'appels externes (Http, EmailSend) et le nombre total de Statement restent dans la limite du plan, il y a au maximum 10 SetVar et au maximum 5 Cache.
  • Si l'on a utilisé Cache, le key a été écrit en littéral et le Statement n'a été placé ni dans un Loop ni dans un ResourceForEach.
  • Si l'on parcourt un grand ensemble avec ResourceForEach, on a déclaré un limit ou vérifié que la taille permet d'aller au bout.
  • Si l'on a placé une itération (Loop, ResourceForEach), on a vérifié qu'elle entre sous forme de multiplication dans le Budget de temps (sans appel externe, la limite est le budget de base de 30 secondes).
  • Les valeurs secrètes comme une clé d'API externe ou une clé de signature ont été déclarées dans secrets et lues via { /secrets/<key> }. Aucune valeur secrète n'est écrite telle quelle dans un Statement.
  • Si l'on enregistre par une modification complète (PUT), secrets a été envoyé en même temps.
  • Le message utilisé pour la vérification de signature a été pris sur { /rawPayload } et non sur /payload.
  • S'il y a un Statement qui manipule un membre (ServiceUser), l'auteur possède SETTING_SERVICE_LOGIN et aucun Statement ne crée ni ne supprime cette ressource.
  • Les opérations irréversibles (les appels externes) ont été placées le plus tard possible.
  • Si l'on envoie un fichier avec Http, un seul champ de corps de requête (body, urlBody, multipartBody) a été indiqué, et l'on a vérifié que chaque fichier respecte la limite de téléchargement par plan.
  • Si la contention d'update/patch est une préoccupation, on utilise le version de ResourceUpdate ou ResourcePatch.
  • Pour renvoyer un résultat, Return.value a été spécifié.

Erreurs

Ce sont les codes qui surviennent lorsque l'enregistrement est refusé parce que la forme de la définition enfreint une contrainte statique. Les codes qui sanctionnent une infraction aux règles des expressions de valeur figurent dans Erreurs des Expressions de valeur, et les codes qui surviennent lors de l'appel ou de la suppression dans Erreurs de Ressource Script et endpoints. Pour les codes communs à toutes les ressources, consultez Erreurs communes.

CodeCondition
WGL400066Une définition contient plus de cinq Statement Cache.
WGL400068Un Statement Cache a été placé dans le bloc d'un Loop ou d'un ResourceForEach.
WGL400067Le key d'un Statement Cache porte une référence { /pointer } au lieu d'un littéral.
WGL400065Le ttl d'un Statement Cache sort de l'intervalle autorisé.
WGL400063Un Statement Cache porte un champ qui ne correspond pas à son action (un ttl sur Get, un defaultValue sur Set).
WGL400060Le resource d'un ResourceCreate, d'un ResourceDelete ou d'un Statement de publication ou d'archivage porte "ServiceUser". L'annuaire des membres n'est accepté que par les trois Statement de consultation ainsi que ResourceUpdate et ResourcePatch.
WGL400077Le resource d'un ResourceCount porte une ressource qui ne peut pas être comptée. Les Media et l'annuaire des membres (ServiceUser) ne se comptent pas.
WGL400037Un EmailSend porte à la fois to et toServiceUser, ou les laisse tous deux vides. On en écrit exactement un.
WGL400054Le total des destinataires d'un EmailSend (to 1 personne + cc + bcc) dépasse 50.
WGL400039Le timeoutMs d'un EmailSend dépasse le plafond.
WGL400101Un EmailSend porte à la fois body et templateBody, ou les laisse tous deux vides. On en écrit exactement un.
WGL400102Le templateBody.source d'un EmailSend n'est pas un pointeur unique désignant un Content lu par un ResourceRead ou un ResourceFind de ce Script. La présence de tout autre caractère avant ou après le pointeur entraîne aussi le refus.
WGL400061Dans un Script qui autorise l'appel anonyme (anonymousCallEnabled), le where d'un Statement de lecture porte createdBy: ":self".
WGL400023Une définition contient plus de dix Statement SetVar.
WGL400026Le retry d'un Statement Http dépasse la limite supérieure de 2.
WGL400087Un Http porte deux champs de corps de requête ou plus (body, urlBody, multipartBody).
WGL400088Le multipartBody d'un Http ne contient aucune part.
WGL400089Une part de multipartBody porte à la fois value et url, ou ne porte ni l'un ni l'autre.
WGL400090Une part de multipartBody porte un fileName sans url.
WGL400036Un ResourceForEach dépasse la limite supérieure du nombre d'éléments traitables.
WGL400094Plusieurs entrées de secrets utilisent le même key.
WGL400095Une définition contient plus de 20 secrets.
WGL400086Le value d'une entrée de secrets sort de l'intervalle de 1 à 4 096 caractères. L'erreur ne contient pas le value.
WGL400086Le text d'un PdfWatermark sans { /pointer } sort de l'intervalle de 1 à 64 caractères.
WGL400096Les transformations d'une instruction d'ingestion Media ne sont pas un tableau, le type d'un élément n'est pas PdfWatermark, un PdfWatermark n'a pas de text ou son text est un objet ou un tableau, color n'est pas au format #RRGGBB, ou le text tel qu'il est écrit contient un caractère non autorisé ou un saut de ligne.
WGL429005Le nombre total de Statement d'une définition dépasse la limite du plan.
WGL429006Le nombre d'appels externes (Http, EmailSend) d'une définition dépasse la limite du plan.
WGL403015L'auteur ne possède pas les permissions de ressource et d'action qu'utilisent les Statement de la définition. Même lorsque la permission existe, l'enregistrement est refusé si l'autorisation porte un filtre contentType, createdBy ou tag. L'autorisation doit être inconditionnelle. La seule exception est le Create de Content : dans ce cas, une autorisation limitée à une portée contentType est également acceptée, et cette portée est comparée au contentType indiqué dans le Statement (le Create de Media ne bénéficie pas de cette exception). Ce code survient aussi lorsque le resource d'un Statement de lecture porte "ServiceUser" alors que l'auteur n'a pas SETTING_SERVICE_LOGIN.