Files
git.stella-ops.org/docs/modules/policy/dsl-grammar-specification.md

284 lines
6.3 KiB
Markdown

# Stella Policy DSL Grammar Specification
**Version**: stella-dsl@1.0
**Status**: Implemented
**Last Updated**: 2026-02-15
## Overview
The Stella Policy DSL is a domain-specific language for defining release policies that control software deployment decisions. Policies are evaluated against signal contexts to produce deterministic verdicts.
## File Extension
Policy files use the `.stella` extension.
## Lexical Structure
### Comments
```
// Single-line comment
/*
* Multi-line comment
*/
```
### Keywords
Reserved keywords (case-sensitive):
| Keyword | Description |
|---------|-------------|
| `policy` | Policy declaration |
| `syntax` | Syntax version declaration |
| `metadata` | Policy metadata block |
| `settings` | Policy settings block |
| `profile` | Profile declaration |
| `rule` | Rule declaration |
| `when` | Rule condition |
| `then` | Rule action (condition true) |
| `else` | Rule action (condition false) |
| `and` | Logical AND |
| `or` | Logical OR |
| `not` | Logical NOT |
| `true` | Boolean true |
| `false` | Boolean false |
| `null` | Null literal |
| `in` | Membership operator |
| `map` | Map literal |
| `env` | Environment binding |
### Operators
| Operator | Description |
|----------|-------------|
| `==` | Equality |
| `!=` | Inequality |
| `<` | Less than |
| `<=` | Less than or equal |
| `>` | Greater than |
| `>=` | Greater than or equal |
| `:=` | Definition |
| `=>` | Arrow (lambda/map) |
| `.` | Member access |
| `,` | Separator |
| `:` | Key-value separator |
| `=` | Assignment |
### Literals
#### Strings
```
"hello world"
"escaped \"quotes\""
```
#### Numbers
```
42
3.14
-1
0.5
```
#### Booleans
```
true
false
```
#### Arrays
```
[1, 2, 3]
["a", "b", "c"]
```
### Identifiers
Identifiers start with a letter or underscore, followed by letters, digits, or underscores:
```
identifier
_private
signal_name
cvss_score
```
## Grammar (EBNF)
```ebnf
document = policy-header "{" body "}" ;
policy-header = "policy" string-literal "syntax" string-literal ;
body = { metadata-block | settings-block | profile | rule } ;
metadata-block = "metadata" "{" { key-value } "}" ;
settings-block = "settings" "{" { key-value } "}" ;
key-value = identifier ":" literal ;
profile = "profile" identifier "{" { profile-item } "}" ;
profile-item = map-item | env-item | scalar-item ;
map-item = "map" identifier "=>" expression ;
env-item = "env" identifier "=>" string-literal ;
scalar-item = identifier ":=" expression ;
rule = "rule" identifier [ "(" priority ")" ] "{" rule-body "}" ;
priority = number-literal ;
rule-body = when-clause then-clause [ else-clause ] ;
when-clause = "when" expression ;
then-clause = "then" "{" { action } "}" ;
else-clause = "else" "{" { action } "}" ;
action = action-name [ "(" { argument } ")" ] ;
action-name = identifier ;
argument = expression | key-value ;
expression = or-expression ;
or-expression = and-expression { "or" and-expression } ;
and-expression = unary-expression { "and" unary-expression } ;
unary-expression = [ "not" ] primary-expression ;
primary-expression = literal
| identifier
| member-access
| "(" expression ")"
| comparison ;
comparison = primary-expression comparison-op primary-expression ;
comparison-op = "==" | "!=" | "<" | "<=" | ">" | ">=" | "in" ;
member-access = identifier { "." identifier } ;
literal = string-literal
| number-literal
| boolean-literal
| array-literal
| null-literal ;
string-literal = '"' { character } '"' ;
number-literal = [ "-" | "+" ] digit { digit } [ "." digit { digit } ] ;
boolean-literal = "true" | "false" ;
array-literal = "[" [ expression { "," expression } ] "]" ;
null-literal = "null" ;
```
## Example Policy
```stella
policy "Production Release Policy" syntax "stella-dsl@1" {
metadata {
author: "security-team@example.com"
version: "1.2.0"
description: "Governs production releases"
}
settings {
default_action: "block"
audit_mode: false
}
profile production {
env target => "prod"
map severity_threshold := 7.0
}
rule critical_cve_block (100) {
when cvss.score >= 9.0 and cve.reachable == true
then {
block("Critical CVE is reachable")
notify("security-oncall")
}
}
rule high_cve_warn (50) {
when cvss.score >= 7.0 and cvss.score < 9.0
then {
warn("High severity CVE detected")
}
else {
allow()
}
}
rule sbom_required (80) {
when not sbom.present
then {
block("SBOM attestation required")
}
}
}
```
## Signal Context
Policies are evaluated against a signal context containing runtime values:
| Signal | Type | Description |
|--------|------|-------------|
| `cvss.score` | number | CVSS score of vulnerability |
| `cve.reachable` | boolean | Whether CVE is reachable |
| `cve.id` | string | CVE identifier |
| `sbom.present` | boolean | SBOM attestation exists |
| `sbom.format` | string | SBOM format (cyclonedx, spdx) |
| `artifact.digest` | string | Artifact content digest |
| `artifact.tag` | string | Container image tag |
| `environment` | string | Target environment |
| `attestation.signed` | boolean | Has signed attestation |
## Compilation
The DSL compiles to a content-addressed IR (Intermediate Representation):
1. **Tokenize**: Source → Token stream
2. **Parse**: Tokens → AST
3. **Compile**: AST → PolicyIrDocument
4. **Serialize**: IR → Canonical JSON
5. **Hash**: JSON → SHA-256 checksum
The checksum provides deterministic policy identity for audit and replay.
## CLI Commands
```bash
# Lint a policy file
stella policy lint policy.stella
# Compile to IR JSON
stella policy compile policy.stella --output policy.ir.json
# Get deterministic checksum
stella policy compile policy.stella --checksum-only
# Simulate with signals
stella policy simulate policy.stella --signals context.json
```
## See Also
- [Policy Module Architecture](architecture.md)
- [PolicyDsl Implementation](../../../src/Policy/StellaOps.PolicyDsl/)
- [Signal Context Reference](signal-context-reference.md)