Files
git.stella-ops.org/docs/modules/advisory-ai/guides/policy-studio-api.md

14 KiB
Raw Blame History

Policy Studio API and Rule Syntax

Sprint: SPRINT_20251226_017_AI_policy_copilot Task: POLICY-26

This guide documents the Policy Studio API for AI-powered policy authoring, converting natural language to lattice rules.

Overview

Policy Studio enables:

  1. Natural Language → Policy Intent: Parse human intent from plain English
  2. Intent → Lattice Rules: Generate K4 lattice-compatible rules
  3. Validation: Detect conflicts, unreachable conditions, loops
  4. Test Synthesis: Auto-generate test cases for policy validation
  5. Compilation: Bundle rules into signed, versioned policy packages

API Endpoints

Parse Natural Language

Convert natural language to structured policy intent.

POST /api/v1/policy/studio/parse
Content-Type: application/json

{
  "input": "Block all critical vulnerabilities in production services unless they have a vendor VEX stating not affected",
  "scope": "production"
}

Response:

{
  "intent": {
    "intentId": "intent-20251226-001",
    "intentType": "OverrideRule",
    "originalInput": "Block all critical vulnerabilities in production services unless they have a vendor VEX stating not affected",
    "conditions": [
      {
        "field": "severity",
        "operator": "equals",
        "value": "critical",
        "connector": "and"
      },
      {
        "field": "scope",
        "operator": "equals",
        "value": "production",
        "connector": "and"
      },
      {
        "field": "has_vex",
        "operator": "equals",
        "value": false,
        "connector": null
      }
    ],
    "actions": [
      {
        "actionType": "set_verdict",
        "parameters": {
          "verdict": "block",
          "reason": "Critical vulnerability without VEX exception"
        }
      }
    ],
    "scope": "production",
    "scopeId": null,
    "priority": 100,
    "confidence": 0.92,
    "alternatives": null,
    "clarifyingQuestions": null
  },
  "success": true,
  "modelId": "claude-sonnet-4-20250514",
  "parsedAt": "2025-12-26T10:30:00Z"
}

Clarifying Questions

When intent is ambiguous, the API returns clarifying questions:

{
  "intent": {
    "intentId": "intent-20251226-002",
    "intentType": "ThresholdRule",
    "confidence": 0.65,
    "clarifyingQuestions": [
      "Should this rule apply to all environments or just production?",
      "What should happen when the threshold is exceeded: block or escalate?"
    ],
    "alternatives": [
      { "...alternative interpretation 1..." },
      { "...alternative interpretation 2..." }
    ]
  },
  "success": true
}

Generate Rules

Convert policy intent to K4 lattice rules.

POST /api/v1/policy/studio/generate
Content-Type: application/json

{
  "intentId": "intent-20251226-001"
}

Response:

{
  "rules": [
    {
      "ruleId": "rule-20251226-001",
      "name": "block-critical-no-vex",
      "description": "Block critical vulnerabilities in production without VEX exception",
      "latticeExpression": "Present ∧ ¬Mitigated ∧ severity=critical ∧ scope=production → Block",
      "conditions": [
        { "field": "severity", "operator": "equals", "value": "critical" },
        { "field": "scope", "operator": "equals", "value": "production" },
        { "field": "has_vex", "operator": "equals", "value": false }
      ],
      "disposition": "Block",
      "priority": 100,
      "scope": "production",
      "enabled": true
    }
  ],
  "success": true,
  "warnings": [],
  "intentId": "intent-20251226-001",
  "generatedAt": "2025-12-26T10:30:00Z"
}

Validate Rules

Check rules for conflicts and issues.

POST /api/v1/policy/studio/validate
Content-Type: application/json

{
  "rules": [
    { "ruleId": "rule-20251226-001", "..." },
    { "ruleId": "rule-20251226-002", "..." }
  ],
  "existingRuleIds": ["rule-existing-001", "rule-existing-002"]
}

Response:

{
  "valid": false,
  "conflicts": [
    {
      "ruleId1": "rule-20251226-001",
      "ruleId2": "rule-existing-002",
      "description": "Both rules match critical vulnerabilities but produce different dispositions (Block vs Allow)",
      "suggestedResolution": "Add priority ordering or more specific conditions to disambiguate",
      "severity": "error"
    }
  ],
  "unreachableConditions": [
    "Rule rule-20251226-002 condition 'severity=low AND severity=high' is always false"
  ],
  "potentialLoops": [],
  "coverage": 0.85
}

Compile Policy Bundle

Bundle validated rules into a signed policy package.

POST /api/v1/policy/studio/compile
Content-Type: application/json

{
  "rules": [
    { "ruleId": "rule-20251226-001", "..." }
  ],
  "bundleName": "production-security-policy",
  "version": "1.0.0",
  "sign": true
}

Response:

{
  "bundleId": "bundle-20251226-001",
  "bundleName": "production-security-policy",
  "version": "1.0.0",
  "ruleCount": 5,
  "digest": "sha256:bundledigest...",
  "signed": true,
  "signatureKeyId": "stellaops-policy-signer-2025",
  "compiledAt": "2025-12-26T10:30:00Z",
  "downloadUrl": "/api/v1/policy/bundle/bundle-20251226-001"
}

Policy Intent Types

Type Description Example
OverrideRule Override default verdict "Block all critical CVEs"
EscalationRule Escalate findings "Escalate CVSS ≥9.0 to security team"
ExceptionCondition Bypass rules "Except internal-only services"
MergePrecedence Priority ordering "VEX takes precedence over CVSS"
ThresholdRule Automatic thresholds "Allow max 10 high-severity per service"
ScopeRestriction Scope limits "Only apply to production"

Rule Syntax

Lattice Expression Format

Rules use K4 lattice logic:

<atoms> → <disposition>

Security Atoms

Atom Meaning
Present Vulnerability is present in artifact
Applies Vulnerability applies to this context
Reachable Vulnerable code is reachable
Mitigated Mitigation exists (VEX, WAF, etc.)
Fixed Fix is available
Misattributed False positive

Operators

Operator Symbol Example
AND Present ∧ Reachable
OR Fixed Mitigated
NOT ¬ ¬Mitigated
Implies Present → Block

Dispositions

Disposition Meaning
Block Fail the build/gate
Warn Warning only
Allow Pass with no action
Review Require human review
Escalate Escalate to security team

Examples

# Block critical unmitigated vulnerabilities
Present ∧ Reachable ∧ ¬Mitigated ∧ severity=critical → Block

# Allow if vendor says not affected
Present ∧ Mitigated ∧ vex_status=not_affected → Allow

# Escalate CVSS ≥9.0
Present ∧ cvss_score>=9.0 → Escalate

# Warn on high severity with fix available
Present ∧ severity=high ∧ Fixed → Warn

Condition Fields

Field Type Values
severity string critical, high, medium, low, none
cvss_score number 0.0 - 10.0
reachable boolean true, false
has_vex boolean true, false
vex_status string not_affected, affected, fixed, under_investigation
has_fix boolean true, false
fix_version string Version string
scope string production, staging, development
age_days number Days since disclosure
exploit_available boolean true, false
in_kev boolean In CISA KEV catalog

Condition Operators

Operator Description Example
equals Exact match severity equals critical
not_equals Not equal scope not_equals development
greater_than Greater than cvss_score greater_than 7.0
less_than Less than age_days less_than 30
greater_or_equal cvss_score greater_or_equal 9.0
less_or_equal cvss_score less_or_equal 3.9
contains String contains component contains lodash
in In list severity in [critical, high]
not_in Not in list scope not_in [development, test]

Test Case Format

Generated Test Cases

Policy Studio auto-generates test cases:

{
  "testCases": [
    {
      "testId": "test-001",
      "type": "positive",
      "description": "Critical unmitigated vulnerability should be blocked",
      "input": {
        "severity": "critical",
        "reachable": true,
        "has_vex": false,
        "scope": "production"
      },
      "expectedDisposition": "Block",
      "matchedRuleId": "rule-20251226-001"
    },
    {
      "testId": "test-002",
      "type": "negative",
      "description": "Critical vulnerability with VEX should not match block rule",
      "input": {
        "severity": "critical",
        "reachable": true,
        "has_vex": true,
        "vex_status": "not_affected",
        "scope": "production"
      },
      "expectedDisposition": "Allow",
      "shouldNotMatch": "rule-20251226-001"
    },
    {
      "testId": "test-003",
      "type": "boundary",
      "description": "CVSS exactly at threshold",
      "input": {
        "cvss_score": 9.0,
        "severity": "critical"
      },
      "expectedDisposition": "Escalate"
    },
    {
      "testId": "test-004",
      "type": "conflict",
      "description": "Input matching multiple conflicting rules",
      "input": {
        "severity": "high",
        "reachable": true,
        "has_fix": true
      },
      "possibleDispositions": ["Warn", "Block"],
      "conflictingRules": ["rule-001", "rule-002"]
    }
  ]
}

Test Types

Type Purpose Auto-Generated
positive Should match rule and produce expected disposition Yes
negative Should NOT match rule (boundary conditions) Yes
boundary Edge cases at thresholds Yes
conflict Triggers multiple rules Yes
manual User-defined custom cases No

Natural Language Examples

Override Rules

Input: "Block all critical vulnerabilities"
→ Present ∧ severity=critical → Block

Input: "Allow vulnerabilities with VEX not_affected status"
→ Present ∧ vex_status=not_affected → Allow

Input: "Block exploitable vulnerabilities older than 30 days"
→ Present ∧ exploit_available=true ∧ age_days>30 → Block

Escalation Rules

Input: "Escalate anything in the KEV catalog to security team"
→ Present ∧ in_kev=true → Escalate

Input: "Escalate CVSS 9.0 or above"
→ Present ∧ cvss_score>=9.0 → Escalate

Exception Conditions

Input: "Except for development environments"
→ Adds: ∧ scope!=development to existing rules

Input: "Unless there's a VEX from the vendor"
→ Adds: ∧ ¬(has_vex=true ∧ vex_status=not_affected)

Threshold Rules

Input: "Allow maximum 5 high-severity vulnerabilities per service"
→ Creates threshold counter with Block when exceeded

CLI Commands

# Parse natural language
stella policy parse "Block all critical CVEs in production"

# Generate rules from intent
stella policy generate intent-20251226-001

# Validate rules
stella policy validate rules.yaml

# Run test cases
stella policy test rules.yaml --cases tests.yaml

# Compile bundle
stella policy compile rules.yaml \
  --name production-policy \
  --version 1.0.0 \
  --sign

# Apply policy
stella policy apply bundle-20251226-001.tar.gz

Configuration

policyStudio:
  # Maximum conditions per rule
  maxConditionsPerRule: 10

  # Auto-generate test cases
  autoGenerateTests: true

  # Test case types to generate
  testTypes:
    - positive
    - negative
    - boundary
    - conflict

  # Minimum test coverage
  minTestCoverage: 0.80

  # Require human approval for production policies
  requireApproval:
    production: true
    staging: false
    development: false

  # Number of approvers required
  requiredApprovers: 2

  # Sign compiled bundles
  signBundles: true

Policy Bundle Format

Compiled policy bundles are tar.gz archives:

production-policy-1.0.0.tar.gz
├── manifest.json          # Bundle metadata
├── rules/
│   ├── rule-001.yaml      # Individual rule files
│   ├── rule-002.yaml
│   └── ...
├── tests/
│   ├── test-001.yaml      # Test cases
│   └── ...
├── signature.dsse.json    # DSSE signature
└── checksums.sha256       # File checksums

Manifest Schema

{
  "bundleId": "bundle-20251226-001",
  "bundleName": "production-security-policy",
  "version": "1.0.0",
  "createdAt": "2025-12-26T10:30:00Z",
  "createdBy": "policy-studio",
  "rules": [
    {
      "ruleId": "rule-001",
      "name": "block-critical",
      "file": "rules/rule-001.yaml"
    }
  ],
  "testCount": 15,
  "coverage": 0.92,
  "signed": true,
  "signatureKeyId": "stellaops-policy-signer-2025"
}

Attestation Format

Policy drafts are attested using DSSE:

{
  "_type": "https://stellaops.org/attestation/policy-draft/v1",
  "bundleId": "bundle-20251226-001",
  "bundleName": "production-security-policy",
  "version": "1.0.0",
  "authority": "Validated",
  "rules": {
    "count": 5,
    "ruleIds": ["rule-001", "rule-002", "..."]
  },
  "validation": {
    "valid": true,
    "conflictCount": 0,
    "testsPassed": 15,
    "coverage": 0.92
  },
  "model": {
    "modelId": "claude-sonnet-4-20250514",
    "parseConfidence": 0.95
  },
  "createdAt": "2025-12-26T10:30:00Z"
}

Error Handling

Parse Errors

{
  "success": false,
  "error": "ambiguous_intent",
  "message": "Could not determine whether 'block' means verdict or action",
  "suggestions": [
    "Try: 'Set verdict to block for critical vulnerabilities'",
    "Try: 'Fail the build for critical vulnerabilities'"
  ]
}

Validation Errors

{
  "valid": false,
  "conflicts": [
    {
      "severity": "error",
      "description": "Rule A and Rule B have contradicting dispositions for the same conditions"
    }
  ]
}

Compilation Errors

{
  "success": false,
  "error": "compilation_failed",
  "message": "Cannot compile bundle with unresolved conflicts",
  "unresolvedConflicts": 2
}