CEL Context Reference This page documents every variable available in PolicyGate CEL expressions. The context is built fresh on every evaluation using live CRD data.
Root Variables Variable Type Description bundle map The Bundle being promoted schedule map Current time context environment map The target environment upstream map Per-environment soak data from upstream metrics map MetricCheck results from the same namespace
bundle.* Field Type Example When populated bundle.type string "image" Always bundle.version string "1.29.0" Always; derived from image tag or configRef bundle.upstreamSoakMinutes int 45 After any upstream environment is Verified; max across all envs bundle.provenance.author string "engineer@co.com" When Bundle was created with provenance.author bundle.provenance.commitSHA string "abc123def" When Bundle was created with provenance.commitSHA bundle.provenance.ciRunURL string "https://github.com/..." When Bundle was created with provenance.ciRunURL bundle.intent.targetEnvironment string "prod" When Bundle has spec.intent.targetEnvironment set bundle.metadata.annotations map {"team": "platform"} Available via bundle.metadata.annotations["key"]
Bundle examples # Block bots from promoting to prod
bundle.provenance.author != "dependabot[bot]"
# Require upstream soak (convenience shorthand — max across all upstream envs)
bundle.upstreamSoakMinutes >= 30
# Block hotfix bundles from skipping gates
bundle.metadata.annotations["release-type"] != "hotfix"
# Check intent
bundle.intent.targetEnvironment == "prod"
schedule.* Field Type Example Notes schedule.isWeekend bool false true on Saturday or Sunday (UTC) schedule.hour int 14 Hour of day in UTC (0–23) schedule.dayOfWeek string "Monday" Full weekday name (Monday, Tuesday, ..., Sunday)
Schedule examples # Block weekend deploys
!schedule.isWeekend
# Block deploys outside business hours (9am–5pm UTC Mon–Fri)
!schedule.isWeekend && schedule.hour >= 9 && schedule.hour < 17
# Block Monday morning deploys (risky after weekend)
schedule.dayOfWeek != "Monday" || schedule.hour >= 10
# Allow only Friday deploys (release day)
schedule.dayOfWeek == "Friday"
environment.* Field Type Example Notes environment.name string "prod" The target environment this gate is evaluating for
Environment examples # Block bots on prod only (allow on staging)
environment.name != "prod" || bundle.provenance.author != "dependabot[bot]"
upstream.* The upstream map contains per-environment data for all environments that have been promoted upstream of the current gate's environment. Keys are environment names.
Field Type Example Notes upstream.<envName>.soakMinutes int 42 Minutes since the Bundle was Verified in that environment
Only populated for environments that have status Verified in Bundle.status.environments.
Upstream examples # Require 30 minutes of soak in uat before prod
upstream.uat.soakMinutes >= 30
# Require soak in both staging regions
upstream["staging-us"].soakMinutes >= 15 && upstream["staging-eu"].soakMinutes >= 15
# Convenience: use bundle.upstreamSoakMinutes for max across all upstream envs
bundle.upstreamSoakMinutes >= 30
metrics.* The metrics map contains one entry per MetricCheck CRD in the same namespace as the gate. Keys are MetricCheck names.
Field Type Example Notes metrics.<name>.value string "0.005" Last queried metric value (as string) metrics.<name>.result string "pass" "pass" or "fail" — result of the MetricCheck threshold
Populated when a MetricCheck CRD with the given name exists in the gate's namespace and has been evaluated by the MetricCheckReconciler.
Metrics examples # Block if error rate MetricCheck is failing
metrics["error-rate"].result == "pass"
# Check raw value (convert string → float via standard CEL)
double(metrics["p99-latency"].value) < 500.0
# Allow if no MetricCheck exists (graceful degradation)
!has(metrics.error_rate) || metrics["error-rate"].result == "pass"
Extended CEL Functions (kro library) kardinal uses the kro CEL library for all gate evaluation. These functions are available in addition to standard CEL:
JSON Function Signature Example json.marshal (dyn) → string json.marshal(bundle.provenance) json.unmarshal (string) → dyn json.unmarshal(bundle.metadata.annotations["config"]).featureFlags.darkMode
Maps Function Signature Example .merge() map.merge(map) → map environment.labels.merge({"region": "us-east-1"})
Note : merge is a member function called on a map: map1.merge(map2). The namespace-style maps.merge(map1, map2) is incorrect and produces "undeclared reference" errors.
Lists Function Signature Example lists.setAtIndex (list, int, dyn) → list lists.setAtIndex(myList, 0, "new-value") lists.insertAtIndex (list, int, dyn) → list lists.insertAtIndex(myList, 0, "prepend") lists.removeAtIndex (list, int) → list lists.removeAtIndex(myList, 0)
Random (deterministic) Function Signature Example random.seededInt (int, int, int) → int random.seededInt(0, 100, bundle.version.hashCode()) < 10
String extensions Standard cel-go/ext string functions are available:
Method Example .format(args) "Bundle %s promoted".format([bundle.version]) .lowerAscii() bundle.provenance.author.lowerAscii().contains("bot")
Complete Expression Examples # No weekend deploys
!schedule.isWeekend
# Business hours only (Mon–Fri 9am–5pm UTC)
!schedule.isWeekend && schedule.hour >= 9 && schedule.hour < 17
# Require 30-minute UAT soak
upstream.uat.soakMinutes >= 30
# Block bots on prod
bundle.provenance.author != "dependabot[bot]"
# Require low error rate from Prometheus MetricCheck
metrics["error-rate"].result == "pass"
# Hotfix bypass: hotfix bundles skip soak requirement
bundle.metadata.annotations["release-type"] == "hotfix" || bundle.upstreamSoakMinutes >= 30
# Multi-condition prod gate
!schedule.isWeekend &&
schedule.hour >= 9 && schedule.hour < 17 &&
upstream.uat.soakMinutes >= 30 &&
metrics["error-rate"].result == "pass"
Simulating Expressions Use kardinal policy simulate to evaluate an expression against the current context without creating a real Bundle:
kardinal policy simulate \
--pipeline my-app \
--env prod \
--time "Saturday 3pm"
# RESULT: BLOCKED
# no-weekend-deploys: !schedule.isWeekend evaluated to false (isWeekend=true)
kardinal policy simulate \
--pipeline my-app \
--env prod \
--time "Tuesday 10am"
# RESULT: ALLOWED
# no-weekend-deploys: !schedule.isWeekend evaluated to true
Testing Expressions Validate CEL syntax and semantics before deploying:
kardinal policy test --file my-gate.yaml
# PASS: expression "!schedule.isWeekend && upstream.uat.soakMinutes >= 30" is valid CEL
See Also April 13, 2026 April 13, 2026