Skip to content

CEL rule expressions

The CEL when and selector expressions in config documents: which kinds take them, where each is evaluated, what happens when one cannot be, every variable per context, the functions, the limits and examples.

Checked against config-schemas@v1.18.0

CEL, the Common Expression Language, is how a config document writes a condition the typed fields cannot. A when field holds one expression that must return bool. One Go package, github.com/vulnetix/config-schemas/cel, compiles and evaluates every expression, in the config engine and in each service that runs the rules, and all of them run the same golden test vectors, so a rule gives the same answer wherever it runs.

when: severity == 'critical' && (kev || reachable)

Which kinds take CEL

13 fields in 8 of the 59 kinds take an expression. They are listed in each schema’s x-vulnetix.celFields, with the context the expression is compiled in. The other 51 kinds have none.

Kind Field Context Status
AiFirewallPolicy spec.guardrails[].when request Applied by the engine
ComplianceTarget spec.crypto.allow cbom Applied by the engine
ComplianceTarget spec.crypto.appliesTo cbom Applied by the engine
DetectionRuleFeed spec.selector.when cve Applied by the engine
JailPolicy spec.rules[].when finding Applied by the engine
PackageList spec.entries[].when package Applied by the engine
RiskStrategy spec.rules[].when finding Applied by the engine
SsvcPolicy spec.exploitation.active finding Applied by the engine
SsvcPolicy spec.exploitation.poc finding Applied by the engine
SsvcPolicy spec.automatable finding Applied by the engine
SsvcPolicy spec.technicalImpact finding Applied by the engine
SsvcPolicy spec.overrides[].when finding Applied by the engine
Suppression spec.when finding Applied by the engine

Each context has its own variables, listed below. A variable from another context is a type error. The event context is defined in the package, for Software Factory trigger conditions, but no released kind has a field in it: FactoryTrigger conditions are typed fields.

Where each expression is evaluated

The engine type-checks every expression when it plans a document, with the same package that evaluates it, so a stored expression normally compiles at run time too. Where it is then evaluated, and what happens when it cannot be, differs by kind:

Kind and field Evaluated When the expression cannot be evaluated
AiFirewallPolicy spec.guardrails[].when by the AI firewall gateway, for each request The rule is skipped, named in the decision’s skipped list, and the gateway logs it.
ComplianceTarget spec.crypto.allow, spec.crypto.appliesTo by the Vulnetix site API at every run of the target, once for each component of the newest CBOM of each repository in scope (at most 20000 components) Fails closed for crypto.allow: a component it cannot be evaluated for is a violation, because an unassessed algorithm must not pass a policy. A crypto.appliesTo that fails leaves the component in scope.
DetectionRuleFeed spec.selector.when by the Vulnetix site API at every publish of the feed, once for each candidate rule and CVE The pair does not match. When every pair fails, the publish is refused.
JailPolicy spec.rules[].when by the jail evaluator in the VDB API, which vulnetix jail and vulnetix scan --jail call, and by the Software Factory gate node for its COUNT rules In the VDB API a rule whose when does not compile, or uses a variable its rule kind lacks, is skipped with a warning, and a fact the expression errors on makes the rule indeterminate (vulnetix jail exits 3). In the factory gate the rule fails closed: it breaches, labelled “when could not be evaluated”.
PackageList spec.entries[].when by the package firewall proxy, for each requested version, in evaluate() The entry is skipped and the proxy logs it.
RiskStrategy spec.rules[].when by the ranking ladder in the Vulnetix site API, over the tenant’s open findings (at most 5000, most severe first) Fails open. A rule that does not compile matches nothing and is logged. A finding the expression errors on does not match.
SsvcPolicy spec.exploitation.active, spec.exploitation.poc, spec.automatable, spec.technicalImpact, spec.overrides[].when by the SSVC decision in the Vulnetix site API, on every decision and summary (the summary covers at most 5000 open findings, most severe first, cached for 60 seconds), and by the VDB API for the CLI scan and the remediation plan The decision point takes its lower value and the decision is still made. An override that fails does not hold.
Suppression spec.when by the suppression engine, over the findings a rule’s anchors have already matched Fails open. A finding the expression errors on is not suppressed.

JailPolicy

Jail evaluates when over the facts it already holds, and those do not carry every finding variable. A rule is skipped with a warning when its when does not compile, or names a variable the facts of its rule kind lack. Skipping reports a rule that is not running, rather than counting against a zero value and showing a green gate on missing evidence.

Rule kind Variables when may use
VULN id, severity, cvss, kev, malicious, reachable, fixAvailability, direct, purl, ecosystem, labels, owner, criticality, now
EOL id, severity, eol, direct, purl, ecosystem, labels, owner, criticality, now
HYGIENE id, severity, cvss, labels, owner, criticality, now
GOAL id, labels, owner, criticality, now

labels, owner and criticality come from the asset record of the repository being assessed (RepositorySettings), and are empty for a repository with no record. epss, exploitMaturity, cwe and internetExposed are not available to jail rules. An expression over one of them type-checks, so plan accepts it, and the rule is then skipped with a warning when the gate runs. A fact the expression errors on is not counted, and the rule then reports indeterminate: vulnetix jail exits 3, which is neither a pass nor a breach.

The factory gate

A Software Factory gate node applies a JailPolicy to a scan’s findings. A COUNT rule with when counts only the scan’s finding items (at most 200, from scan/findings.json) at or above its severity floor for which the condition holds. Items carry id, severity, kind, KEV and package, and repo, labels, owner and criticality come from the run’s repository, so other finding variables read as zero values. The gate fails closed: when the condition cannot be evaluated, or when the scan kept fewer items than it found and the partial count does not already breach a GT or GTE threshold, the rule breaches and its label says why. A rule with onBreach: warn never breaches.

RiskStrategy

The ranking ladder is a SQL CASE and cannot run CEL, so each CEL rule is evaluated in Go over the tenant’s open findings, most severe first, at most 5000, and the result is cached for 60 seconds. A finding past the cap matches no CEL rule and falls to the rules after it, which is logged. A rule that does not compile matches nothing and is logged. A finding the expression errors on does not match: the rule fails open. labels, owner and criticality are filled from each finding’s repository asset record; when the records cannot be read, a rule over them matches nothing and the failure is logged.

Suppression

The suppression engine matches a rule’s anchors first, then asks which of the matched findings the when holds for, over the same facts the ranking ladder reads. An expression that errors on a finding does not select it, so the finding is not suppressed: the rule fails open, because an unevaluable condition never suppresses anything. The asset variables (labels, owner, criticality) are filled the same way as for the ranking ladder.

PackageList

The package firewall evaluates an entry’s when in evaluate() for the requested version. An entry with no when always applies. A conditional entry applies when its expression holds. An expression that fails to evaluate is logged and the entry skipped, so a broken condition neither blocks nor waives more than was declared.

The proxy has the version’s advisory signals (malware, CVSS, EPSS, CESS, KEV, EOL, exploit maturity, bad actor) but not its publish time or version lag, so ageDays reads -1 and versionLag reads 0. A conditional entry is judged only where the proxy has the version’s signals. The whole-package gates, the cooldown and version-lag waivers, the bad-actor waiver and deny injection for versions with no signal row skip it. A conditional allow entry still lets an allowlist_only package through to per-version filtering. Entries are stored in PackageFirewallListEntry.expr, which needs saas migration 20261225000000_firewall_rule_expr: until it runs, an apply that sets a when is refused with the migration’s name.

AiFirewallPolicy

The AI firewall gateway evaluates a guardrail’s when over the request: its provider, model and client, and the tools, MCP servers and skills it declares. A tool shown being invoked in replayed history is not on offer, so it does not count. A guardrail with no when always applies. A rule whose when fails to evaluate is skipped, named in the decision’s skipped list, and logged: the gateway does not block or flag on a condition it could not judge. Each list is bounded at 256 entries, and a larger request is judged on the first 256.

A guardrail of rule type expression takes no pattern: its when is its whole match, it blocks or flags, and it is judged on the capability plane with the tool, MCP server, skill and client lists before content is scanned. Guardrails are stored in AiFirewallGuardrail.expr, from the same migration as package list entries.

SsvcPolicy

The SSVC decision evaluates the policy’s expressions over the finding, with the repository’s asset record, whenever a decision or the summary is read, and the VDB API does the same for each vulnerability of a CLI scan and for the remediation plan when the tenant has stored a policy. An expression that fails to evaluate holds for nothing: the decision point takes its lower value (not exploited, not automatable, partial impact) and the decision is still made. An override whose when fails does not hold, so the table’s outcome stands. The summary decides at most 5000 open findings, most severe first, and is cached for 60 seconds per policy.

DetectionRuleFeed

The selector is evaluated at every publish, from the console or the engine. The candidates are the newest 5000 generated rules of the feed’s format: virtual patches for a block-lane format, countermeasures for a detect-lane one. Each rule is evaluated once per CVE it was written for, and selected when the condition holds for any of them. A rule with no CVE is evaluated once with an empty id and zero scores. A pair the expression errors on does not match; when every pair fails, the publish is refused. The published file holds the explicit entries first, then each selected rule not already among them, up to 500. Selected rules are never written as entries, so the next publish picks up new rules and new KEV listings without an edit to the feed.

How an expression is checked

When What happens
POST /config/validate The schema checks that the field is a string of 1 to 4096 characters.
Plan The expression is compiled and type-checked in its context. A failure is a blocking condition, invalid_cel, that names the rule and the position, and blocks the plan. The worst-case cost is estimated with every string and list at its bound, and an expression over the limit is refused.
Evaluation An input past a variable’s bound is refused, and evaluation that goes past the cost limit stops.

Comparisons between int and double are allowed, so cvss >= 7 type-checks. Equality between them is not: write cvss == 7.0. The cel-go extension libraries (strings, math, lists) are not loaded.

Error codes

Code When
length The expression is longer than the limit.
syntax It does not parse.
type It does not type-check: an unknown variable, a variable from another context, or a comparison between the wrong types.
result_type It type-checks to something other than bool.
cost Its estimated cost at compile time, or its actual cost at evaluation, exceeds the limit.
context An unknown context, or an input of the wrong context.
input The input exceeds a variable’s bound.
eval Evaluation failed, for example an invalid purl passed to matchesPurl.

The codes are stable; the messages are not. Line and column are counted from 1.

Variables, functions and limits

The tables below are generated from the CEL environments themselves (go run ./cmd/celdoc in config-schemas). The top-level names are the variables: write severity, not finding.severity. Variables marked Derived are computed from the others. now is the time of evaluation unless the caller fixes it.

Context finding

Variable Type Bound Description
id string 256 chars The advisory identifier, such as CVE-2024-3094 or a GHSA ID.
aliases list(string) 64 items of 256 chars Other identifiers the advisory is known by.
severity string 64 chars Lower case: critical, high, medium, low, or empty when unknown.
cvss double CVSS base score, 0 to 10. 0 when unscored.
epss double EPSS probability, 0 to 1.
epssPercentile double EPSS percentile, 0 to 1.
kev bool Listed in any known-exploited catalogue: CISA KEV, VulnCheck KEV or EU KEV.
exploitMaturity string 64 chars The highest exploit tier, as the CLI --exploits gate grades it: poc, active, weaponized, or empty when none is known.
exploitCount int Number of public exploits known.
reachability string 64 chars Lower case reachability verdict: direct, transitive, semantic, unreachable, or empty when not assessed.
reachable bool Derived. True when reachability is direct, transitive or semantic, the same set the findings page counts as reachable.
internetExposed bool The package is observed on internet-facing infrastructure.
eol bool The package version is end of life.
malicious bool The package is known malware.
fixAvailability string 64 chars available, partial, no_fix, or empty when unknown.
direct bool The package is a direct dependency, not a transitive one.
purl string 2048 chars Package URL of the affected package, with version.
ecosystem string 64 chars Package ecosystem, such as npm, pypi, golang, maven.
cwe list(string) 64 items of 64 chars CWE identifiers, upper case with prefix: CWE-79.
repo string 512 chars Repository full name, owner/name.
branch string 512 chars Branch the finding was scanned on.
path string 1024 chars File the finding came from, such as the manifest or lock file, relative to the repository root.
labels map(string, string) 50 keys, keys and values of 256 chars The key/value labels of the repository the finding is in, as set on the repository’s asset record or in a RepositorySettings document: labels['tier'] == 'prod'. Empty when the repository has none, and in a runtime that does not know the repository’s asset record, so 'tier' in labels is false there.
owner string 512 chars Who owns the repository: a team name, a user name or an email address, as set on its asset record. Empty when none is set.
criticality string 64 chars How much the business depends on the repository: low, medium, high or critical. Empty when none is set, so criticality in ['high', 'critical'] is false for an unclassified repository.
now timestamp The time of evaluation. Callers may fix it; otherwise it is the clock when Eval runs.

Context package

Variable Type Bound Description
purl string 2048 chars Package URL of the requested version.
ecosystem string 64 chars Package ecosystem, such as npm, pypi, golang, maven.
name string 512 chars Package name as the ecosystem writes it: @acme/tool, github.com/acme/tool, com.acme:tool.
version string 256 chars Requested version.
published timestamp When the version was published. The zero timestamp when unknown.
ageDays int Derived. Whole days from published to now. -1 when the publish time is unknown, so a cooldown rule never reads an unknown age as new.
versionLag int How many releases are newer than this version. 0 for the newest, or when the lag is unknown.
malware bool The version is known malware.
cvss double Highest CVSS base score across the version’s advisories.
epss double Highest EPSS probability across the version’s advisories.
cess double Highest Coalition ESS score across the version’s advisories.
kev bool An advisory for the version is in a known-exploited catalogue.
eol bool The version is end of life.
exploitMaturity string 64 chars poc, active, weaponized, or empty when no exploit is known.
badActor bool The publisher is a known bad actor.
now timestamp The time of evaluation. Callers may fix it; otherwise it is the clock when Eval runs.

Context request

Variable Type Bound Description
provider string 256 chars Provider slug, such as anthropic or openai.
model string 256 chars Model slug as requested.
client string 256 chars Calling client’s name, such as claude-code or codex.
tools list(string) 512 items of 256 chars Tool names the request declares or calls, including flattened MCP tools such as mcp__github__create_issue.
mcpServers list(string) 128 items of 256 chars Labels of the remote MCP servers the request wires in.
skills list(string) 256 items of 256 chars Skill names the request offers.
now timestamp The time of evaluation. Callers may fix it; otherwise it is the clock when Eval runs.

Context event

Variable Type Bound Description
event string 64 chars Trigger event name, such as pull_request.opened or push.
base string 64 chars The event name before the first dot, such as pull_request. Derived from event when not sent.
action string 64 chars The event name after the first dot, such as opened. Empty for push.
repo string 512 chars owner/name on github.com, host/owner/name on other forges.
number int Pull request or issue number, 0 when there is none.
subject string 256 chars What the delivery is about: pr:7, issue:12, release:v1.2.3, or empty.
ref string 512 chars The pushed ref, for push.
headBranch string 512 chars Branch the change is on.
baseBranch string 512 chars Pull request target branch; the pushed branch for push.
defaultBranch string 512 chars Repository default branch.
author string 256 chars Pull request author, pusher, comment author or run actor.
authorType string 64 chars user or bot.
sender string 256 chars The delivery’s sender.
senderType string 64 chars user or bot.
labels list(string) 100 items of 256 chars Labels on the pull request or issue.
draft bool The pull request is a draft.
origin string 64 chars same_repo or fork. An empty origin reads as same_repo.
conclusion string 64 chars Conclusion of a check run, check suite or workflow run, or a deployment state: success, failure, cancelled and so on.
reviewState string 64 chars approved, changes_requested, dismissed or commented on pull_request_review.
paths list(string) 1000 items of 1024 chars Paths a push added, modified or removed. A caller with more than the bound sends the first 1000 and sets pathsTruncated.
pathsTruncated bool paths is partial.
deleted bool The push deleted its ref.
severity string 64 chars Lower case alert severity on dependabot_alert, code_scanning_alert and posture_finding.
environment string 512 chars Deployment environment on deployment_status.
packageType string 64 chars Published package type on registry_package: container, npm, maven and so on.
properties map(string, list(string)) 100 keys, 50 items each, of 256 chars Repository custom property values, by property name.
now timestamp The time of evaluation. Callers may fix it; otherwise it is the clock when Eval runs.

Context cve

Variable Type Bound Description
id string 256 chars CVE identifier.
cvss double CVSS base score, 0 to 10. 0 when unscored.
epss double EPSS probability, 0 to 1.
kev bool Listed in a known-exploited catalogue.
published timestamp When the CVE was published. The zero timestamp when unknown.
kind string 64 chars Rule format: SNORT, SURICATA, MODSECURITY, NGINX, AWS_WAF, CLOUDFLARE_WAF, REGEX_L7, SIGMA, YARA, STIX, OPENIOC.
confidence string 64 chars Confidence in the rule: HIGH, MEDIUM, LOW, or empty.
falsePositiveRisk string 64 chars HIGH, MEDIUM, LOW, or empty.
now timestamp The time of evaluation. Callers may fix it; otherwise it is the clock when Eval runs.

Context cbom

Variable Type Bound Description
name string 512 chars The component’s name as the inventory records it: AES-256-GCM, RSA-2048, ML-KEM-768, a certificate subject, or a library name.
category string 64 chars algorithm, certificate, key or library.
assetType string 64 chars The CycloneDX cryptographic asset type: algorithm, certificate, related-crypto-material, or empty for a library.
oid string 256 chars The algorithm’s OID, such as 2.16.840.1.101.3.4.1.46, or empty when unknown.
primitive string 64 chars The CycloneDX cryptographic primitive: ae, block-cipher, stream-cipher, hash, mac, kdf, drbg, signature, pke, kem, key-agree, xof, combiner, other, or empty.
parameterSetIdentifier string 256 chars The parameter set: a key size such as 256, a curve such as P-256, or a named set such as ML-DSA-65. Empty when none.
classicalSecurityLevel int Classical security strength in bits. 0 when unknown.
nistQuantumSecurityLevel int The NIST post-quantum security category, 1 to 5 (6 for a hybrid that meets the highest). 0 when the algorithm offers none, or when unknown.
pqcStatus string 64 chars quantum-safe, quantum-vulnerable, deprecated, hybrid, or empty when not assessed.
quantumSafe bool Derived. True when pqcStatus is quantum-safe or hybrid, the set the Crypto Inventory counts as safe.
deprecated bool Derived. True when pqcStatus is deprecated.
standards map(string, string) 20 keys, keys and values of 256 chars Each standards body’s verdict on the algorithm, by body: standards['NIST'] is approved, deprecated, disallowed and so on. The bodies the catalogue knows include NIST, BSI and CNSA 2.0. Empty for a component with none.
provider string 512 chars The library or implementation that provides it, such as openssl or golang.org/x/crypto.
purl string 2048 chars Package URL of the providing library, when known.
confidence string 64 chars How sure the detection is: high, medium, low, or empty.
repo string 512 chars Repository full name, owner/name, of the scan the component was found in.
branch string 512 chars Branch of that scan.
now timestamp The time of evaluation. Callers may fix it; otherwise it is the clock when Eval runs.

Functions

Available in every context, alongside the CEL standard library.

Function Description
string.glob(pattern string) bool Glob match over the whole string. * is any run of characters except /, ** is any run including /, **/ is zero or more directories, ? is one character except /. Everything else is literal. The same dialect as factory trigger conditions.
string.matchesPurl(pattern string) bool Package URL match. The pattern is a purl: without a version it matches every version, with one it matches that version only. A pattern whose name ends in /* or :* matches every package under that namespace, as package firewall allow entries do: pkg:npm/@acme/* covers pkg:npm/@acme/tool@1.0.0 but not pkg:npm/@acme-evil/tool. Qualifiers and subpaths are ignored. Names compare as written. An invalid purl or pattern is an evaluation error.
semverCompare(a string, b string) int -1, 0 or 1 as a is lower than, equal to or higher than b in semantic version order. Precedence follows SemVer 2.0.0: pre-releases rank below the release and build metadata is ignored. A leading v is optional; the shorthands 1 and 1.2 are not versions. A value that is not a semantic version is an evaluation error; guard with isSemver.
isSemver(v string) bool Whether v is a semantic version, with or without a leading v.

When a rule cannot be evaluated

The library reports a compile or evaluation error and nothing more. What a rule does with it differs by runtime. The factory gate and a cryptography policy fail closed; every other rule fails open or is skipped.

Runtime Field On an error
Jail (vdb-api) JailPolicy rule when Does not fail closed. A rule whose when does not compile, or uses a finding variable the facts of its rule kind do not carry yet, is skipped with a warning and does not run. A fact the expression fails on leaves the rule indeterminate, so the verdict is indeterminate and the CLI exits 3; a breached rule elsewhere still wins, with exit 1.
Factory gate (vdb-site) JailPolicy rule when, in a workflow gate node The only runtime that fails closed. A when that does not compile or fails on a finding makes the rule breach, and its label says it could not be evaluated. So does a scan that kept fewer findings than it found, unless the count over the kept ones already breaches. A rule with onBreach: WARN does not fail the gate.
Risk prioritisation (vdb-site) RiskStrategy rule when Fails open. A finding the expression fails on does not match. A rule that does not compile is logged and matches nothing.
Suppression Suppression when Fails open. A finding the expression fails on is not suppressed. A rule whose expression cannot be evaluated covers nothing in that run and the error is logged; every other rule applies as usual.
Package firewall PackageList entry when The entry is skipped and the error is logged: a deny entry does not block and an allow entry does not waive, so a broken condition neither blocks nor waives more than was declared.
SSVC decision (vdb-site) SsvcPolicy decision point expressions and overrides[].when The decision point takes its lower value (not exploited, not automatable, partial impact) and the decision is still made. An override that fails does not hold.
Cryptography policy (vdb-site) ComplianceTarget crypto.allow and crypto.appliesTo Fails closed for allow: a component the expression cannot be evaluated for is reported as a violation, because an unassessed algorithm must not pass a policy. An appliesTo that fails leaves the component in scope.
AI firewall AiFirewallPolicy rule when The rule is skipped and named in the decision’s skipped list with the error. The gateway does not block or flag on a condition it could not evaluate.

Cost and length limits

Limit Value
Expression length 4096 bytes
Estimated cost, checked at plan 1000000
Actual cost, checked at evaluation 1000000

The estimate assumes every string and list is at its bound in the tables above, and evaluation refuses an input past a bound, so an expression that passes plan cannot exceed the limit when it runs. A single exists or all over a list is well inside it; a comprehension nested inside another over the same list usually is not.

Examples

Every expression below is in a released example, and a test in config-schemas compiles each one in its context.

Kind Context Expression
AiFirewallPolicy request client == 'codex'
AiFirewallPolicy request 'filesystem' in mcpServers && tools.exists(t, t.startsWith('mcp__filesystem__write'))
ComplianceTarget cbom quantumSafe || (primitive in ['block-cipher', 'hash', 'mac'] && classicalSecurityLevel >= 128)
ComplianceTarget cbom category == 'algorithm' && confidence != 'low'
DetectionRuleFeed cve kind == 'SURICATA' && (kev || epss >= 0.5) && cvss >= 7.0 && falsePositiveRisk != 'HIGH' && now - published < duration('8760h')
DetectionRuleFeed cve kev && confidence == 'HIGH' && kind == 'SIGMA'
JailPolicy finding fixAvailability == 'available' && (kev || epss >= 0.1)
JailPolicy finding epss >= 0.1
PackageList package !malware && !badActor
PackageList package cvss < 9.0 && !kev
PackageList package ageDays < 3 || versionLag > 5
RiskStrategy finding reachable && (epss >= 0.2 || exploitMaturity == 'active')
RiskStrategy finding reachable && epss >= 0.2
SsvcPolicy finding kev || exploitMaturity in ['active', 'weaponized']
SsvcPolicy finding exploitMaturity == 'poc' || exploitCount > 0
SsvcPolicy finding cvss >= 9.0 || epss >= 0.5
SsvcPolicy finding [no, yes]
SsvcPolicy finding cvss >= 9.0 || malicious
SsvcPolicy finding [total]
SsvcPolicy finding labels['pci'] == 'in-scope' && severity in ['critical', 'high']
SsvcPolicy finding !reachable && fixAvailability == 'no_fix'
Suppression finding severity != 'critical' && !kev && repo == 'acme/storefront'
Suppression finding !internetExposed

A few more. Each compiles in the context named.

# finding: glob matches the whole string; * stops at /, ** does not
when: path.glob('services/**/package.json')

# finding: matchesPurl takes a purl pattern; a name ending /* covers a namespace
when: purl.matchesPurl('pkg:npm/@acme/*')

# finding: the repository's asset record (RepositorySettings labels, owner, criticality)
when: criticality in ['high', 'critical'] && labels['tier'] == 'prod'

# package: guard with isSemver before comparing
when: isSemver(version) && semverCompare(version, '2.0.0') < 0

# request: lists take exists, all and in
when: "'filesystem' in mcpServers && tools.exists(t, t.startsWith('mcp__filesystem__write'))"
Edit this pageSources: config-schemas/cel/README.md, config-schemas/cel/variables.go, config-schemas/cel/functions.go, config-schemas/cel/cost.go, config-schemas/cmd/celdoc/main.go, vdb-site/api/internal/handler/risk_cel.go, vdb-site/api/internal/handler/factory_engine_node_gate.go, vdb-site/api/internal/handler/detection_rule_feeds_selector.go, vdb-api/internal/handler/jail_when.go, vdb-api/internal/handler/jail_eval.go, package-firewall/internal/policy/condition.go, ai-firewall/internal/policy/expr.go
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.