Skip to main content

A deterministic pre-deployment infrastructure governance engine

Project description

ObsidianWall Verdict

Pre-deployment infrastructure governance. Evaluate Terraform plans against governance policies before deployment executes — catching budget overruns, policy violations, and compliance failures before they become incidents.

CI Python 3.11+ License: Apache 2.0 obsidianwall.com


What it does

Verdict sits between terraform plan and terraform apply. It takes a Terraform plan and a policy file, evaluates the plan deterministically against your governance policies, and produces a decision — with a full audit trail, risk score, stakeholder notifications, and explainability built in.

$ verdict evaluate \
    --plan  terraform_plan.json \
    --policy policies/cost/basic_budget.yaml \
    --role  engineer

  policy       basic_budget_verdict
  condition    budget_check                    ✗ FAILED
  expression   (current_spend + estimated_cost) <= budget.amount
  evaluated    (0 + 100) <= 50  →  false

  risk score   75 / 100  (critical)
  findings     cost_analysis: 2   topology: 1
  notified     budget_owner (email)   engineering_lead (slack)

  decision     DENY_WITH_OVERRIDE
  override     budget_owner may authorize
  decision_id  abc3a13b-83d5-4fad-87d8

✗ Deployment blocked by governance policy.

No AI guessing. No approximations. Every decision is deterministic, reproducible, and attributable to a human-authored policy.


Quickstart

Install

pip install obsidianwall-verdict

Write a policy

# policies/cost/budget.yaml
apiVersion: obsidianwall.io/v1
kind: Policy

metadata:
  name: team_budget
  version: "0.1"
  owner: your-team

spec:
  inputs:
    - estimated_cost
    - current_spend

  parameters:
    budget:
      amount: 5000
      period: monthly
      flexibility: soft

  conditions:
    - id: budget_check
      expression: "(current_spend + estimated_cost) <= budget.amount"
      description: "Monthly spend must not exceed budget"

  decision:
    allow: ALLOW
    deny:  DENY_WITH_OVERRIDE
    warn:  ALLOW_WITH_NOTIFICATION

  governance:
    severity: medium
    notifications:
      - role: budget_owner
        channel: email
      - role: engineering_lead
        channel: slack

  override:
    roles:
      - budget_owner
    requires_approval: false

Evaluate a plan

# Generate your Terraform plan
terraform plan -out=tfplan
terraform show -json tfplan > terraform_plan.json

# Run governance evaluation
verdict evaluate \
  --plan   terraform_plan.json \
  --policy policies/cost/budget.yaml \
  --role   engineer

Verdict returns exit code 0 on ALLOW and non-zero on DENY, blocking CI/CD pipelines automatically.


Commands

verdict evaluate

Evaluate a Terraform plan against a governance policy.

verdict evaluate \
  --plan          terraform_plan.json \
  --policy        policies/cost/budget.yaml \
  --role          engineer \
  --current-spend 30.0
Flag Description
--plan Path to Terraform plan JSON
--policy Path to policy YAML file
--role Role of the user triggering the deployment
--current-spend Spend already incurred this month (default: 0.0)
--pricing table (default, offline) or live (Azure Retail API)
--region Cloud region for live pricing (default: eastus)
--output Path to write the audit artifact (default: output/result.json)

verdict validate

Check that a policy file is valid before using it in an evaluation. Useful when writing new policies — catches schema errors immediately without needing a plan file.

verdict validate --policy policies/cost/budget.yaml

Returns a JSON object with status: valid or status: invalid and the error if the policy fails validation.


verdict test

Assert that a Terraform plan produces a specific governance decision. This is the policy regression testing command — use it to verify your policies behave correctly and catch regressions when policies change.

verdict test \
  --plan   terraform_plan.json \
  --policy policies/cost/budget.yaml \
  --expect DENY_WITH_OVERRIDE
  ✅ Test passed

  Policy:   policies/cost/budget.yaml
  Plan:     terraform_plan.json
  Expected: DENY_WITH_OVERRIDE
  Actual:   DENY_WITH_OVERRIDE

If the decision does not match, Verdict tells you what failed and why:

  ✗ Test failed

  Policy:   policies/cost/budget.yaml
  Plan:     terraform_plan.json
  Expected: DENY
  Actual:   DENY_WITH_OVERRIDE

  Risk score:  75/100
  Severity:    critical

  Failed conditions:
    ✗ budget_check
Flag Description
--plan Path to Terraform plan JSON
--policy Path to policy YAML file
--expect Expected decision (see governance decisions table)
--role Role of the user (default: engineer)
--verbose Show full evaluation output on failure

Exit codes: 0 pass, 1 fail, 2 evaluation error.


verdict audit

Review governance decisions recorded over time. Verdict stores a local history of every evaluation when telemetry is enabled, and verdict audit turns that history into a governance report.

Enable telemetry first:

export OW_TELEMETRY_ENABLED=true

Run the audit:

verdict audit
────────────────────────────────────────────────────────────────────────
  ObsidianWall Verdict — Governance Audit
────────────────────────────────────────────────────────────────────────

  Total evaluations:  12
  Allowed:            4
  Denied:             8  (66.7%)

────────────────────────────────────────────────────────────────────────
  Domain Risk Scores  (average across recorded decisions)
────────────────────────────────────────────────────────────────────────
  Cost                      [██████░░░░░░]   50.0/100  medium
  Network / Topology        [███░░░░░░░░░]   25.0/100  low
  Architecture              [░░░░░░░░░░░░]    0.0/100  informational
  Utilization               [░░░░░░░░░░░░]    0.0/100  informational

────────────────────────────────────────────────────────────────────────
  Why Decisions Were Made
────────────────────────────────────────────────────────────────────────

  Failed conditions  (why deployments were DENIED)
  Condition                                 Failures    Rate
  ────────────────────────────────────────  ────────  ──────
  budget_check                                     8   66.7%

────────────────────────────────────────────────────────────────────────
  Policy Effectiveness
────────────────────────────────────────────────────────────────────────
  Policy                    Evals  Denied  Overrides  Override%   Deny%
  basic_budget_verdict         12       8          2      25.0%   66.7%

Add --insights to get a governance interpretation:

verdict audit --insights

This adds two sections at the end — Governance Insights (what patterns the data shows) and Recommendations (what to do about them):

────────────────────────────────────────────────────────────────────────
  Governance Insights
────────────────────────────────────────────────────────────────────────
  ⚠  'basic_budget_verdict' has a 25.0% override rate.
     Policy may not reflect deployment reality.
  ℹ  Cost is the highest risk domain (avg score: 50/100).
  ℹ  'budget_check' is the most frequently failed condition
     (8 failures, 66.7% of evaluations).

────────────────────────────────────────────────────────────────────────
  Recommendations
────────────────────────────────────────────────────────────────────────
  1. Review 'basic_budget_verdict' threshold — consider whether
     the policy limit reflects realistic deployment patterns.
  2. Review Cost governance policies.
     This domain is driving the most aggregate risk.
  3. Review 'budget_check' condition — it is responsible for
     66.7% of all denials.
Flag Description
--insights Include governance insights and recommendations
--policy Filter to a specific policy name
--limit Number of recent decisions to show (default: 50)
--format table (default) or json

Decision history is stored locally at ~/.obsidianwall/decisions.db. Nothing leaves your machine. Remote telemetry is not implemented yet — that is planned for v0.5.0 with explicit opt-in.


GitHub Actions

Add Verdict as a governance gate in your CI/CD pipeline:

# .github/workflows/governance.yml
name: Infrastructure Governance

on:
  pull_request:
    paths: ["**.tf", "**.tfvars"]

jobs:
  governance:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@9f698171ed81b15d1823a05fc7211befd50c8ae0  # v6.0.3

      - name: Generate Terraform plan
        run: |
          terraform init
          terraform plan -out=tfplan
          terraform show -json tfplan > terraform_plan.json

      - name: ObsidianWall Verdict
        id: verdict
        uses: obsidianwall/obsidianwall-verdict@main
        with:
          plan:         terraform_plan.json
          policy:       policies/cost/budget.yaml
          role:         engineer
          fail_on_deny: "true"

      - name: Governance outcome
        if: always()
        run: |
          echo "Decision:   ${{ steps.verdict.outputs.decision }}"
          echo "Risk score: ${{ steps.verdict.outputs.risk_score }}/100"
          echo "Severity:   ${{ steps.verdict.outputs.effective_severity }}"

Action outputs

Output Description
decision ALLOW / ALLOW_WITH_NOTIFICATION / ALLOW_WITH_APPROVAL_REQUIRED / DENY_WITH_OVERRIDE / DENY
conditions_passed true or false
risk_score Integer 0–100
effective_severity informational / low / medium / high / critical
decision_id UUID for audit trail correlation

How it works

Terraform plan
      ↓
Translation Layer     Parses plan, estimates cost
      ↓
Policy loader         Loads and validates the policy YAML
      ↓
Runtime normalizer    Flattens policy parameters into evaluation context
      ↓
Condition evaluator   Evaluates each condition deterministically
      ↓
Analyzer framework    Cost, topology, architecture, utilization analysis
      ↓
Risk scorer           Aggregates findings into risk score (0–100)
      ↓
Decision resolver     5-level governance decision with override routing
      ↓
Explainability        Reasoning chain, trace graph, remediation steps
      ↓
Notification manifest Stakeholder routing — never dispatched automatically
      ↓
Audit artifact        Immutable JSON record of the complete evaluation

Every stage is deterministic. Analyzers are advisory — they inform the risk score but never override the condition evaluation. The condition evaluation alone determines the governance decision.


Enforcement modes

Mode How What it blocks
CI/CD pipeline GitHub Actions with fail_on_deny: true terraform apply never runs on DENY
IAM access controls Azure Entra ID / AWS IAM restricts engineer credentials to read-only Direct deployment from local machines impossible
Standalone manual Run verdict evaluate before terraform apply Governance guidance, audit trail, budget owner notification

For hard technical enforcement, integrate Verdict into your CI/CD pipeline and restrict cloud credentials so only the pipeline's service principal can apply infrastructure. Engineers with read-only credentials cannot deploy directly even if they skip Verdict locally.


Governance decisions

Decision Meaning
ALLOW All conditions passed. Deployment authorized.
ALLOW_WITH_NOTIFICATION Conditions passed but stakeholders are notified.
ALLOW_WITH_APPROVAL_REQUIRED Conditions passed but formal approval is required.
DENY_WITH_OVERRIDE Conditions failed. An authorized role may override.
DENY Conditions failed. No override permitted. Hard block.

Policy DSL

Policies are YAML files that define governance constraints for an infrastructure change. The schema is versioned and validated on load.

Policy structure

apiVersion: obsidianwall.io/v1     Protocol version
kind: Policy                        Always Policy for now

metadata:
  name:        string               Policy identifier
  version:     string               Semver string
  owner:       string               Responsible team
  description: string               Optional description

spec:
  inputs:      list[string]         Runtime context keys required
  parameters:  dict                 Policy parameters (flattened at runtime)
  conditions:  list[Condition]      Evaluated deterministically
  decision:    Decision             allow / deny / warn mappings
  governance:  GovernanceConfig     Severity, notifications, approvals
  override:    Override             Roles and approval requirements
  actions:     list[Action]         notify / log actions

Governance domains

Policies declare which governance domain they enforce. Verdict validates conditions against the declared domain and rejects mismatches.

Domain What it governs
cost Budget spend enforcement
security Security posture — open ingress, public storage, encryption
compliance Tagging, naming, regulatory requirements
resource_limits Instance counts, GPU limits, sizing
network Network topology, segmentation, public exposure
identity IAM, MFA, privileged access
data_governance PII handling, encryption, data residency
resilience Availability, DR, replica counts
ai_governance AI system controls, model provenance, GPU workloads
composite Coordinates multiple domains in one policy

Composite policies

A composite policy governs multiple domains simultaneously and produces a single governance decision. Every domain used must be declared explicitly — Verdict enforces this and rejects any condition that references an undeclared domain.

spec:
  policy_type: composite
  governance_domains:
    - cost
    - security
    - compliance

Condition expressions

conditions:
  - id: budget_check
    expression: "(current_spend + estimated_cost) <= budget.amount"
    description: "Monthly spend must not exceed budget"

  - id: no_open_ingress
    expression: "open_ingress_rules <= security.max_open_ingress_rules"
    description: "No unrestricted inbound rules permitted"

Supported operators: <=, >=, <, >, == Supported arithmetic: + Context resolution: dot-notation for nested parameters (budget.amount)


Audit artifact

Every evaluation produces a complete audit artifact:

{
  "decision_id":        "abc3a13b-83d5-4fad-87d8-bbe77e4b8075",
  "timestamp":          "2026-05-20T04:05:28Z",
  "policy":             "basic_budget_verdict",
  "decision":           "DENY_WITH_OVERRIDE",
  "override_possible":  true,
  "override_required":  false,
  "conditions_passed":  false,
  "effective_severity": "critical",
  "risk_summary": {
    "overall_risk_score":    75,
    "risk_severity":         "critical",
    "highest_risk_analyzer": "cost_analysis",
    "total_findings":        3
  },
  "trace": [...],
  "explanation": {
    "governance_reasoning": {...},
    "policy_reasoning":     {...},
    "trace_graph":          {...}
  },
  "notification_manifest": {...}
}

The artifact is written to output/result.json and printed to stdout. It is suitable for storage in an audit log, S3 bucket, or compliance system.


Doctrine

AI may advise.
AI may explain.
AI may optimize.
AI may correlate.
AI may recommend.

AI may NOT authoritatively govern.

Every governance decision in ObsidianWall Verdict is produced by deterministic evaluation of human-authored policy conditions — never by a probabilistic model.

Decisions are reproducible, explainable, and attributable to a named policy and a named human who wrote it.

This is not an anti-AI position. The analyzer framework, recommendation engine, and explainability pipeline all use intelligence to inform the governance process. The boundary is authority: intelligence informs, policy governs.


Architecture

Verdict is the first executable of the ObsidianWall programmable assurance platform.

┌─────────────────────────────────────────────────────┐
│  Open Governance Core  (this repo — open source)    │
│                                                     │
│  engine/       deterministic evaluation pipeline    │
│  schemas/      policy DSL and typed contracts       │
│  context/      Translation Layer (plan parsing)     │
│  telemetry/    local decision history (SQLite)      │
│  audit/        structured audit logging             │
│  cli/          command-line interface               │
└─────────────────────────────────────────────────────┘
         ↓ telemetry (opt-in, local SQLite)
┌─────────────────────────────────────────────────────┐
│  Intelligence Layer  (future — private)             │
│                                                     │
│  Derived optimization intelligence                  │
│  Workload pattern recognition                       │
│  Pricing behavior intelligence                      │
│  Predictive governance scoring                      │
└─────────────────────────────────────────────────────┘
         ↓ enterprise workflows
┌─────────────────────────────────────────────────────┐
│  Platform Layer  (future — paid)                    │
│                                                     │
│  Hosted policy management                           │
│  Approval workflow persistence                      │
│  Governance dashboards                              │
│  RBAC, SSO, multi-tenant                            │
│  Compliance exports                                 │
└─────────────────────────────────────────────────────┘

Telemetry

Telemetry is opt-in and disabled by default. When enabled, Verdict records governance decisions to a local SQLite database at ~/.obsidianwall/decisions.db. Nothing is sent anywhere remotely.

export OW_TELEMETRY_ENABLED=true

What is stored:

  • Decision outcomes, risk scores, policy names
  • Which conditions passed and which failed
  • Override and approval events

What is never stored:

  • Plan contents or resource configurations
  • Cost amounts or budget values
  • Resource names or identifiers
  • Organization or team identifiers

Telemetry powers verdict audit. Without it, verdict audit has no data to read. Remote telemetry with explicit opt-in is planned for v0.5.0.


Development

Requirements: Python 3.11+, Git

git clone https://github.com/obsidianwall/obsidianwall-verdict
cd obsidianwall-verdict
pip install -e ".[dev]"

# Run the full test suite
pytest tests/ -v

# Run a sample evaluation
verdict evaluate \
  --plan   samples/terraform_plan.json \
  --policy policies/cost/basic_budget.yaml \
  --role   engineer

Test suite: 101 tests — unit, integration, and pipeline.

pytest tests/unit/        # unit tests
pytest tests/integration/ # integration tests
pytest tests/             # full suite

Policy examples are in policies/ organized by governance domain:

policies/
  cost/           budget enforcement
  security/       security posture
  compliance/     tagging and regulatory
  network/        topology and exposure
  identity/       IAM and Zero Trust
  ai_governance/  AI system controls
  composite/      multi-domain coordination

License

Verdict is released under the Apache License 2.0.

Free to use, modify, and distribute for any purpose — commercial or non-commercial. Attribution required.

Built on ObsidianWall — the programmable assurance platform. obsidianwall.com


Built by

Aisha I. — obsidianwall.com

"Organizations that design for programmable assurance now will not need to retrofit later."

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

obsidianwall_verdict-0.4.0.tar.gz (104.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

obsidianwall_verdict-0.4.0-py3-none-any.whl (123.7 kB view details)

Uploaded Python 3

File details

Details for the file obsidianwall_verdict-0.4.0.tar.gz.

File metadata

  • Download URL: obsidianwall_verdict-0.4.0.tar.gz
  • Upload date:
  • Size: 104.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for obsidianwall_verdict-0.4.0.tar.gz
Algorithm Hash digest
SHA256 9d3c16d2742d99271afe75078b683c05d406249f4594fc8fbc8c3fa69be03b3c
MD5 9f05a83add3419c14cd184eb94fe5ab4
BLAKE2b-256 5811db16dd2753835dbda545cf8ad87c262211393ae9a094546e3f9439014b2f

See more details on using hashes here.

File details

Details for the file obsidianwall_verdict-0.4.0-py3-none-any.whl.

File metadata

File hashes

Hashes for obsidianwall_verdict-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 62b0c617b65d3b8b9ed9e51a8f9cad72db9dc04cfb4e66553145f174ffadb793
MD5 a769da6518604f26d31c4bf4c31b7e60
BLAKE2b-256 c7ba82df46b04d7f3c0aa2b91ecb5f3fc25247c9ff7256a88e227bc2b5330569

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page