up
Some checks failed
api-governance / spectral-lint (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
oas-ci / oas-validate (push) Has been cancelled
SDK Publish & Sign / sdk-publish (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Policy Simulation / policy-simulate (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled
Some checks failed
api-governance / spectral-lint (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
oas-ci / oas-validate (push) Has been cancelled
SDK Publish & Sign / sdk-publish (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Policy Simulation / policy-simulate (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
# Stella Policy DSL (`stella-dsl@1`)
|
||||
|
||||
> **Audience:** Policy authors, reviewers, and tooling engineers building lint/compile flows for the Policy Engine v2 rollout (Sprint 20).
|
||||
> **Audience:** Policy authors, reviewers, and tooling engineers building lint/compile flows for the Policy Engine v2 rollout (Sprint 20).
|
||||
> **Imposed rule:** Policies that alter reachability or trust weighting must run in shadow mode first with coverage fixtures; promotion to active is blocked until shadow + coverage gates pass.
|
||||
|
||||
This document specifies the `stella-dsl@1` grammar, semantics, and guardrails used by Stella Ops to transform SBOM facts, Concelier advisories, and Excititor VEX statements into effective findings. Use it with the [Policy Engine Overview](overview.md) for architectural context and the upcoming lifecycle/run guides for operational workflows.
|
||||
|
||||
@@ -14,6 +15,7 @@ This document specifies the `stella-dsl@1` grammar, semantics, and guardrails us
|
||||
- **Lean authoring:** Common precedence, severity, and suppression patterns are first-class.
|
||||
- **Offline-friendly:** Grammar and built-ins avoid cloud dependencies, run the same in sealed deployments.
|
||||
- **Reachability-aware:** Policies can consume reachability lattice states (`ReachState`) and evidence scores to drive VEX gates (`not_affected`, `under_investigation`, `affected`).
|
||||
- **Signal-first:** Trust, reachability, entropy, and uncertainty signals are first-class so explain traces stay reproducible.
|
||||
|
||||
---
|
||||
|
||||
@@ -40,14 +42,26 @@ policy "Default Org Policy" syntax "stella-dsl@1" {
|
||||
}
|
||||
}
|
||||
|
||||
rule vex_precedence priority 10 {
|
||||
when vex.any(status in ["not_affected","fixed"])
|
||||
and vex.justification in ["component_not_present","vulnerable_code_not_present"]
|
||||
then status := vex.status
|
||||
because "Strong vendor justification prevails";
|
||||
}
|
||||
}
|
||||
```
|
||||
rule vex_precedence priority 10 {
|
||||
when vex.any(status in ["not_affected","fixed"])
|
||||
and vex.justification in ["component_not_present","vulnerable_code_not_present"]
|
||||
then status := vex.status
|
||||
because "Strong vendor justification prevails";
|
||||
}
|
||||
|
||||
rule reachability_gate priority 20 {
|
||||
when telemetry.reachability.state == "reachable" and telemetry.reachability.score >= 0.6
|
||||
then status := "affected"
|
||||
because "Runtime/graph evidence shows reachable code path";
|
||||
}
|
||||
|
||||
rule trust_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";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
High-level layout:
|
||||
|
||||
@@ -127,9 +141,10 @@ annotate = "annotate", identifier, ":=", expression, ";" ;
|
||||
|
||||
Notes:
|
||||
|
||||
- `helper` is reserved for shared calculcations (not yet implemented in `@1`).
|
||||
- `else` branch executes only if `when` predicates evaluate truthy **and** no prior rule earlier in priority handled the tuple.
|
||||
- Semicolons inside rule bodies are optional when each clause is on its own line; the compiler emits canonical semicolons in IR.
|
||||
- `helper` is reserved for shared calculcations (not yet implemented in `@1`).
|
||||
- `else` branch executes only if `when` predicates evaluate truthy **and** no prior rule earlier in priority handled the tuple.
|
||||
- Semicolons inside rule bodies are optional when each clause is on its own line; the compiler emits canonical semicolons in IR.
|
||||
- `settings.shadow = true` enables shadow-mode evaluation (findings recorded but not enforced). Promotion gates require at least one shadow run with coverage fixtures.
|
||||
|
||||
---
|
||||
|
||||
@@ -146,6 +161,7 @@ Within predicates and actions you may reference the following namespaces:
|
||||
| `run` | `policyId`, `policyVersion`, `tenant`, `timestamp` | Metadata for explain annotations. |
|
||||
| `env` | Arbitrary key/value pairs injected per run (e.g., `environment`, `runtime`). |
|
||||
| `telemetry` | Optional reachability signals. Example fields: `telemetry.reachability.state`, `telemetry.reachability.score`, `telemetry.reachability.policyVersion`. Missing fields evaluate to `unknown`. |
|
||||
| `signals` | Normalised signal dictionary: `trust_score` (0–1), `reachability.state` (`reachable|unreachable|unknown`), `reachability.score` (0–1), `entropy_penalty` (0–0.3), `uncertainty.level` (`U1`–`U3`), `runtime_hits` (bool). |
|
||||
| `secret` | `findings`, `bundle`, helper predicates | Populated when the Secrets Analyzer runs. Exposes masked leak findings and bundle metadata for policy decisions. |
|
||||
| `profile.<name>` | Values computed inside profile blocks (maps, scalars). |
|
||||
|
||||
@@ -162,8 +178,9 @@ Missing fields evaluate to `null`, which is falsey in boolean context and propag
|
||||
| `normalize_cvss(advisory)` | `Advisory → SeverityScalar` | Parses `advisory.content.raw` for CVSS data; falls back to policy maps. |
|
||||
| `cvss(score, vector)` | `double × string → SeverityScalar` | Constructs a severity object manually. |
|
||||
| `severity_band(value)` | `string → SeverityBand` | Normalises strings like `"critical"`, `"medium"`. |
|
||||
| `risk_score(base, modifiers...)` | Variadic | Multiplies numeric modifiers (severity × trust × reachability). |
|
||||
| `vex.any(predicate)` | `(Statement → bool) → bool` | `true` if any statement satisfies predicate. |
|
||||
| `risk_score(base, modifiers...)` | Variadic | Multiplies numeric modifiers (severity × trust × reachability). |
|
||||
| `reach_state(state)` | `string → ReachState` | Normalises reachability state strings (`reachable`, `unreachable`, `unknown`). |
|
||||
| `vex.any(predicate)` | `(Statement → bool) → bool` | `true` if any statement satisfies predicate. |
|
||||
| `vex.all(predicate)` | `(Statement → bool) → bool` | `true` if all statements satisfy predicate. |
|
||||
| `vex.latest()` | `→ Statement` | Lexicographically newest statement. |
|
||||
| `advisory.has_tag(tag)` | `string → bool` | Checks advisory metadata tags. |
|
||||
@@ -252,16 +269,30 @@ rule vex_strong_claim priority 5 {
|
||||
}
|
||||
```
|
||||
|
||||
### 9.3 Environment-Specific Escalation
|
||||
### 9.3 Environment-Specific Escalation
|
||||
|
||||
```dsl
|
||||
rule internet_exposed_guard {
|
||||
when env.exposure == "internet"
|
||||
and severity.normalized >= "High"
|
||||
then escalate to severity_band("Critical")
|
||||
because "Internet-exposed assets require critical posture";
|
||||
}
|
||||
```
|
||||
rule internet_exposed_guard {
|
||||
when env.exposure == "internet"
|
||||
and severity.normalized >= "High"
|
||||
then escalate to severity_band("Critical")
|
||||
because "Internet-exposed assets require critical posture";
|
||||
}
|
||||
```
|
||||
|
||||
### 9.4 Shadow mode & coverage
|
||||
|
||||
- Enable `settings { shadow = true; }` for new policies or major changes. Findings are recorded but not enforced.
|
||||
- Provide coverage fixtures under `tests/policy/<policyId>/cases/*.json`; run `stella policy test` locally and in CI. Coverage results must be attached on submission.
|
||||
- Promotion to active is blocked until shadow runs + coverage gates pass (see lifecycle §3).
|
||||
|
||||
### 9.5 Authoring workflow (quick checklist)
|
||||
|
||||
1. Write/update policy with shadow enabled.
|
||||
2. Add/refresh coverage fixtures; run `stella policy test`.
|
||||
3. `stella policy lint` and `stella policy simulate --fixtures ...` with expected signals (trust_score, reachability, entropy_penalty) noted in comments.
|
||||
4. Submit with attachments: lint, simulate diff, coverage results.
|
||||
5. After approval, disable shadow and promote; retain fixtures for regression tests.
|
||||
|
||||
### 9.4 Anti-pattern (flagged by linter)
|
||||
|
||||
@@ -318,4 +349,4 @@ rule catch_all {
|
||||
|
||||
---
|
||||
|
||||
*Last updated: 2025-11-05 (Sprint 21).*
|
||||
*Last updated: 2025-11-26 (Sprint 0401).*
|
||||
|
||||
Reference in New Issue
Block a user