Référence du Langage

Guide complet de la syntaxe Rego et des fonctionnalités du langage pour écrire des politiques

Les politiques sont écrites en Rego, un langage de politique déclaratif conçu pour exprimer des décisions complexes de contrôle d'accès. Contrairement aux langages impératifs où vous décrivez comment calculer un résultat, Rego vous permet de décrire quelles conditions doivent déclencher une décision de politique. Cette page couvre toute la syntaxe et les fonctionnalités du langage supportées dans 256 Blocks.

Structure de Politique

Chaque politique que vous écrivez est automatiquement enveloppée avec le code passe-partout nécessaire par 256 Blocks. Cela signifie que vous pouvez vous concentrer uniquement sur l'écriture de vos règles sans vous soucier des déclarations de package ou des valeurs par défaut.

Toutes les politiques :

  • Sont automatiquement enveloppées avec la déclaration package nécessaire
  • Ont un default deny := false prédéfini (autoriser par défaut)
  • Ont un default denyGasSponsor := false prédéfini (sponsoriser par défaut)
  • Peuvent seulement définir des règles, pas remplacer les valeurs par défaut

Syntaxe de Règle de Base

Les règles sont les blocs de construction des politiques. Une règle consiste en un en-tête (le nom de la règle, ex : deny ou denyGasSponsor) et un corps (les conditions). Lorsque toutes les conditions du corps sont vraies, la règle s'évalue à true.

Exemple

# Basic structure: rule_name if { conditions }
deny if {
    input.usd_value > 10000
}

Conditions Multiples (Logique AND)

Lorsque vous incluez plusieurs conditions dans le même corps de règle, TOUTES les conditions doivent être vraies pour que la règle se déclenche. Chaque condition est implicitement jointe avec AND.

Exemple

# Both conditions must be true to deny
deny if {
    input.chain == "ethereum"
    input.usd_value > 1000
}

Règles Multiples (Logique OR)

Lorsque vous définissez plusieurs règles avec le même nom, N'IMPORTE quelle règle correspondante déclenchera la politique. Cela fournit une logique OR entre les règles.

Exemple

# Either condition triggers denial
deny if {
    input.chain == "ethereum"
}
 
deny if {
    input.usd_value > 10000
}

Combinaison AND et OR

Vous pouvez combiner les deux modèles pour une logique complexe. Chaque corps de règle utilise la logique AND en interne, tandis que plusieurs règles fournissent la logique OR entre elles.

Exemple

# Deny if: (ethereum AND high-value) OR (any chain AND blocked country)
deny if {
    input.chain == "ethereum"
    input.usd_value > 5000
}
 
deny if {
    input.source_country in {"KP", "IR", "CU"}
}

Attribution de Variable

Utilisez l'opérateur := pour attribuer des valeurs aux variables. Les variables rendent vos politiques plus lisibles et maintenables en donnant des noms significatifs aux valeurs et en permettant la réutilisation.

Variables au Niveau de la Politique

Les variables définies en dehors des corps de règle agissent comme des constantes qui peuvent être référencées par plusieurs règles. Utilisez-les pour les seuils, les listes blanches et les listes noires.

Exemple

# Policy-level constants - defined once, used everywhere
max_transaction_value := 50000
blocked_countries := {"KP", "IR", "CU", "SY"}
approved_senders := {"0x742d35cc...", "0xa0b86991..."}
 
deny if {
    input.usd_value > max_transaction_value
}
 
deny if {
    input.source_country in blocked_countries
}
 
deny if {
    not input.from_address in approved_senders
}

Variables Locales

Les variables définies à l'intérieur d'un corps de règle sont locales à cette règle. Utilisez-les pour des calculs intermédiaires ou pour améliorer la lisibilité.

Exemple

deny if {
    # Calculate with a safety margin
    value_with_buffer := input.usd_value * 1.15
    value_with_buffer > 10000
}
 
deny if {
    # Estimate gas cost in wei
    gas_cost := to_number(input.gas_limit) * to_number(input.max_fee_per_gas)
    gas_cost > 1000000000000000000  # 1 ETH in wei
}

Opérateurs de Comparaison

Rego fournit des opérateurs de comparaison standard pour évaluer les conditions. Ceux-ci fonctionnent avec les chaînes, les nombres et d'autres types comparables.

OpérateurDescriptionExemple
==Égal àinput.chain == "ethereum"
!=Différent deinput.chain != "polygon"
>Supérieur àinput.usd_value > 1000
>=Supérieur ou égal àinput.usd_value >= 1000
<Inférieur àinput.usd_value < 100
<=Inférieur ou égal àinput.usd_value <= 100

Exemple

# Block high-value transactions on expensive chains
deny if {
    input.chain == "ethereum"
    input.usd_value >= 5000
}
 
# Block transactions below a minimum value (potential spam)
deny if {
    input.usd_value != null
    input.usd_value < 1
}

Opérateurs Arithmétiques

Vous pouvez effectuer des calculs arithmétiques dans vos conditions de politique. Cela est utile pour calculer des seuils, appliquer des multiplicateurs ou combiner des valeurs.

OpérateurDescriptionExemple
+Additioninput.usd_value + 100
-Soustractioninput.usd_value - fees
*Multiplicationinput.usd_value * 1.1
/Divisioninput.usd_value / 2
%Modulo (reste)input.gas_limit % 1000

Exemple

# Apply a 10% buffer when checking limits
deny if {
    input.usd_value * 1.1 > 10000
}
 
# Block if combined value exceeds threshold
deny if {
    total := input.usd_value + 500  # Add estimated fees
    total > 5000
}

Opérateurs Logiques

Au-delà du AND implicite (conditions multiples) et du OR (règles multiples), Rego fournit des opérateurs logiques explicites pour des expressions plus complexes.

L'Opérateur not

Utilisez not pour nier une condition. Cela est particulièrement utile pour les modèles de liste blanche où vous souhaitez refuser tout ce qui n'est PAS dans un ensemble autorisé.

Exemple

# Only allow specific chains (deny everything else)
allowed_chains := {"polygon", "base", "arbitrum"}
 
deny if {
    not input.chain in allowed_chains
}

Exemple : Combinaison avec d'Autres Conditions

# Deny if NOT a read-only method AND value is high
deny if {
    not input.rpc_method in {"eth_call", "eth_getBalance"}
    input.usd_value > 1000
}

Règles d'Aide

Au-delà de deny et denyGasSponsor, vous pouvez définir vos propres règles personnalisées pour organiser une logique complexe. Les règles d'aide agissent comme des blocs de construction réutilisables qui rendent vos politiques plus lisibles et maintenables.

Une règle d'aide est simplement une condition nommée qui s'évalue à true lorsque son corps correspond. Vous pouvez ensuite référencer ces règles dans vos règles deny ou denyGasSponsor, y compris avec l'opérateur not pour les nier.

Exemple

# Define a helper rule to check if request is from a trusted source
is_trusted if {
    input.source_country in {"US", "GB", "DE"}
    input.source_ip in {"203.0.113.10", "203.0.113.11"}
}
 
# Define another helper for high-risk transactions
is_high_risk if {
    input.usd_value > 10000
}
 
is_high_risk if {
    input.source_country in {"RU", "CN"}
}
 
# Use helper rules in deny conditions
deny if {
    not is_trusted
    is_high_risk
}

Les règles d'aide sont particulièrement utiles pour :

  • Réutilisabilité : Définissez une condition une fois, utilisez-la dans plusieurs règles
  • Lisibilité : Donnez des noms significatifs aux conditions complexes
  • Négation : Utilisez not pour vérifier quand une condition n'est PAS remplie
  • Organisation : Décomposez les politiques complexes en composants logiques

Opérations sur les Chaînes

Les chaînes sont des séquences de caractères entre guillemets doubles (""). La plupart des champs d'entrée comme input.chain, input.rpc_method et les adresses sont des chaînes. Rego fournit plusieurs fonctions intégrées pour travailler avec les chaînes, essentielles pour la correspondance de modèles sur les adresses, les noms de méthodes et autres champs de texte.

FonctionDescriptionRetourne
contains(string, substring)Vérifie si la chaîne contient une sous-chaîneboolean
startswith(string, prefix)Vérifie si la chaîne commence par un préfixeboolean
endswith(string, suffix)Vérifie si la chaîne se termine par un suffixeboolean
lower(string)Convertir en minusculesstring
upper(string)Convertir en majusculesstring
substring(string, start, length)Extraire une portion de chaînestring
sprintf(format, values)Formater la chaîne avec des valeursstring

Exemple

# Block any method containing "sign" (covers eth_sign, personal_sign, etc.)
deny if {
    contains(input.rpc_method, "sign")
}
 
# Block addresses starting with known malicious prefix
deny if {
    startswith(lower(input.to_address), "0x000000000000000000000000000000000000dead")
}
 
# Block debug and admin methods
deny if {
    startswith(input.rpc_method, "debug_")
}
 
deny if {
    startswith(input.rpc_method, "admin_")
}

Opérations sur les Tableaux

Les tableaux sont des listes ordonnées de valeurs, définis avec des crochets []. Contrairement aux ensembles, les tableaux préservent l'ordre des éléments et peuvent contenir des doublons. Vous travaillerez fréquemment avec des tableaux dans les politiques, en particulier input.contract_addresses qui contient toutes les adresses de contrats impliquées dans une demande.

# Array syntax
my_array := ["first", "second", "third"]

Rego fournit plusieurs façons d'inspecter et de travailler avec les tableaux.

FonctionDescriptionRetourne
count(array)Nombre d'élémentsnumber
array[index]Accéder à l'élément par index (base 0)element
value in arrayVérifier si la valeur existe dans le tableauboolean

Exemple

# Limit the number of contracts in a single request
deny if {
    count(input.contract_addresses) > 10
}
 
# Check if a specific address is in the contract list
deny if {
    "0xbanned..." in input.contract_addresses
}
 
# Access specific array elements
deny if {
    count(input.contract_addresses) > 0
    first_contract := input.contract_addresses[0]
    startswith(first_contract, "0xdead")
}

Test d'Appartenance

Le test d'appartenance est l'une des opérations les plus courantes dans les politiques. Vous l'utiliserez pour vérifier si les valeurs appartiennent à des listes blanches, des listes noires ou d'autres collections de valeurs autorisées.

Ensembles

Les ensembles sont des collections non ordonnées de valeurs uniques, définis avec des accolades {}. Utilisez l'opérateur in pour tester si une valeur existe dans un ensemble.

# Set syntax
my_set := {"value1", "value2", "value3"}

Les ensembles sont optimisés pour un test d'appartenance rapide, ce qui les rend idéaux pour les listes blanches et noires.

Exemple

# Block requests from sanctioned countries
blocked_countries := {"KP", "IR", "CU", "SY", "RU"}
 
deny if {
    input.source_country in blocked_countries
}
 
# Only allow specific chains
allowed_chains := {"polygon", "base", "arbitrum"}
 
deny if {
    not input.chain in allowed_chains
}

Ensembles Inline vs Nommés

Vous pouvez définir des ensembles en ligne dans les règles ou comme variables nommées au niveau de la politique. Les ensembles nommés améliorent la lisibilité et permettent la réutilisation dans plusieurs règles.

Exemple

# Inline set - good for simple, one-off checks
deny if {
    input.rpc_method in {"eth_sign", "personal_sign", "eth_signTypedData"}
}
 
# Named set - better for reusability and readability
approved_contracts := {
    "0xdac17f958d2ee523a2206206994597c13d831ec7",  # USDT
    "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",  # USDC
    "0x6b175474e89094c44da98b954eedeac495271d0f"   # DAI
}
 
deny if {
    some addr in input.contract_addresses
    not addr in approved_contracts
}

Itération avec some

Le mot-clé some vous permet d'itérer sur des collections et de vérifier les conditions pour chaque élément. Ceci est essentiel lorsque vous travaillez avec des tableaux comme input.contract_addresses.

Itération de Base

Utilisez some pour vérifier si N'IMPORTE quel élément d'une collection correspond à une condition.

Exemple

# Deny if ANY contract address is in the blocklist
blocked_contracts := {"0xbanned1...", "0xbanned2..."}
 
deny if {
    some addr in input.contract_addresses
    addr in blocked_contracts
}

Itération avec Index

Vous pouvez également accéder à l'index de chaque élément pendant l'itération.

Exemple

# Check conditions on specific positions
deny if {
    some i, addr in input.contract_addresses
    i == 0  # First contract only
    startswith(addr, "0x000")
}

Exemple : Trouver N'importe quelle Correspondance

# Deny if any contract starts with a suspicious prefix
deny if {
    some addr in input.contract_addresses
    startswith(lower(addr), "0x000000000000000000000000")
}
 
# Deny if any contract is not in the approved list
approved := {"0xusdt...", "0xusdc...", "0xdai..."}
 
deny if {
    some addr in input.contract_addresses
    not addr in approved
}

Itération avec every

Alors que some vérifie si N'IMPORTE quel élément correspond, every exige que TOUS les éléments correspondent à une condition. Ceci est utile pour s'assurer que des collections entières répondent à vos critères.

Exemple

# Deny only if ALL contracts are from a suspicious set
# (unlikely to be legitimate if every address is suspicious)
suspicious_prefixes := {"0x0000000000000000"}
 
deny if {
    count(input.contract_addresses) > 0
    every addr in input.contract_addresses {
        some prefix in suspicious_prefixes
        startswith(addr, prefix)
    }
}

Exemple : Modèles de Validation

# Ensure all contracts are from approved list (inverse of some/not)
approved_contracts := {"0xusdt...", "0xusdc...", "0xdai..."}
 
# This denies if ANY contract is not approved
deny if {
    some addr in input.contract_addresses
    not addr in approved_contracts
}
 
# Equivalent using every (deny if NOT every contract is approved)
deny if {
    count(input.contract_addresses) > 0
    not every addr in input.contract_addresses {
        addr in approved_contracts
    }
}

Compréhensions

Les compréhensions vous permettent de créer de nouvelles collections en transformant ou en filtrant celles existantes. Elles sont utiles pour extraire des valeurs spécifiques ou construire des ensembles de données dérivés.

Compréhension de Tableau

Créer un nouveau tableau à partir d'éléments qui correspondent à certains critères.

Exemple

# Extract all contract addresses that start with a specific prefix
matching_contracts := [addr |
    some addr in input.contract_addresses
    startswith(addr, "0xa")
]
 
deny if {
    count(matching_contracts) > 3
}

Compréhension d'Ensemble

Créer un ensemble de valeurs uniques.

Exemple

# Get unique prefixes from all contract addresses
contract_prefixes := {substring(addr, 0, 6) |
    some addr in input.contract_addresses
}
 
# Deny if there are too many different contract prefixes (suspicious)
deny if {
    count(contract_prefixes) > 5
}

Else Conditionnel

Le mot-clé else vous permet de définir des valeurs de secours lorsque les conditions ne sont pas remplies. Ceci est utile pour calculer des valeurs dérivées qui varient en fonction de l'entrée.

Exemple

# Assign risk level based on transaction value
risk_level := "critical" if {
    input.usd_value > 100000
} else := "high" if {
    input.usd_value > 10000
} else := "medium" if {
    input.usd_value > 1000
} else := "low"
 
# Use the computed risk level in deny rules
deny if {
    risk_level == "critical"
}
 
denyGasSponsor if {
    risk_level in {"high", "critical"}
}

Exemple : Seuils Spécifiques aux Chaînes

# Different limits for different chains
chain_limit := 1000 if {
    input.chain == "ethereum"
} else := 5000 if {
    input.chain == "polygon"
} else := 10000
 
deny if {
    input.usd_value > chain_limit
}
Référence du Langage | 256 Blocks