# Stella Policy Language (SPL) v1 > **Status:** Draft (2025-11) > **Imposed rule:** SPL packs must pass lint, simulate, shadow, and coverage gates before activation; IR hashes must be attested when published. This document defines the SPL v1 language: syntax, semantics, JSON schema, and examples used by the Policy Engine. ## 1. Syntax summary - File-level directive: `policy "" syntax "stella-dsl@1" { ... }` - Blocks: `metadata`, `profile {}`, `settings {}`, `rule [priority n] { when ... then ... because "..." }` - No loops, no network/clock access; pure, deterministic evaluation. ## 2. JSON Schema (canonical IR) ```jsonc { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Stella Policy Language v1", "type": "object", "required": ["policyId", "syntax", "rules"], "properties": { "policyId": {"type": "string"}, "syntax": {"const": "stella-dsl@1"}, "metadata": {"type": "object"}, "settings": { "type": "object", "properties": { "shadow": {"type": "boolean"}, "default_status": {"type": "string"} } }, "profiles": { "type": "object", "additionalProperties": { "type": "object", "properties": { "maps": {"type": "object"}, "env": {"type": "object"}, "scalars": {"type": "object"} } } }, "rules": { "type": "array", "items": { "type": "object", "required": ["name", "when", "then"], "properties": { "name": {"type": "string"}, "priority": {"type": "integer", "minimum": 0}, "when": {"type": "object"}, "then": {"type": "array"}, "else": {"type": "array"}, "because": {"type": "string"} } } } } } ``` Notes: - The compiler emits canonical IR JSON sorted by keys; hashing uses this canonical form. - `when` and actions are expressed as AST nodes; see engine schema for exact shape. ## 3. Built-in functions (v1) - `normalize_cvss`, `cvss`, `severity_band`, `risk_score`, `reach_state`, `exists`, `coalesce`, `percent_of`, `lowercase`. - VEX helpers: `vex.any`, `vex.all`, `vex.latest`. - Secrets helpers: `secret.hasFinding`, `secret.match.count`, `secret.bundle.version`, `secret.mask.applied`, `secret.path.allowlist`. - Signals: access via `signals.trust_score`, `signals.reachability.state/score`, `signals.entropy_penalty`, `signals.uncertainty.level`, `signals.runtime_hits`. ## 4. Data namespaces - `sbom`, `advisory`, `vex`, `run`, `env`, `telemetry`, `signals`, `secret`, `profile.*`. - Missing fields evaluate to `null/unknown`; comparisons must handle `unknown` explicitly. ## 5. Examples ### 5.1 Reachability-aware gate ```dsl rule reachability_gate priority 20 { when signals.reachability.state == "reachable" and signals.reachability.score >= 0.6 then status := "affected" because "Runtime/graph evidence shows reachable code path"; } ``` ### 5.2 Trust/entropy penalty ```dsl rule trust_entropy_penalty priority 30 { when signals.trust_score < 0.4 or signals.entropy_penalty > 0.2 then severity := severity_band("critical") because "Low trust score or high entropy"; } ``` ### 5.3 Shadow mode on ```dsl settings { shadow = true } ``` ## 6. Authoring workflow (quick) 1. Write/update SPL with shadow enabled; add coverage fixtures. 2. Run `stella policy lint`, `stella policy simulate`, and `stella policy test`. 3. Attach artefacts to submission; ensure determinism twin-run passes in CI. 4. Publish with DSSE attestation (IR hash + metadata) and promote to environments. ## 7. Compatibility - SPL v1 aligns with `stella-dsl@1` grammar. Future SPL versions will be additive; declare `syntax` explicitly. ## 8. References - `docs/policy/dsl.md` - `docs/policy/lifecycle.md` - `docs/policy/architecture.md` - `docs/policy/overview.md`