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

This commit is contained in:
StellaOps Bot
2025-11-26 20:23:28 +02:00
parent 4831c7fcb0
commit d63af51f84
139 changed files with 8010 additions and 2795 deletions

View File

@@ -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 (Sprint20).
> **Audience:** Policy authors, reviewers, and tooling engineers building lint/compile flows for the Policy Engine v2 rollout (Sprint20).
> **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 StellaOps 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` (01), `reachability.state` (`reachable|unreachable|unknown`), `reachability.score` (01), `entropy_penalty` (00.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).*