Skip to content

Getting Started with Policies

This guide walks you through creating your first OPA policy in Mayo ASPM. By the end, you will have a working triage policy that automatically suppresses low-value findings.


Prerequisites

  • A Mayo ASPM account with admin or policy-editor role
  • At least one completed scan with findings (so you have data to test against)

Step 1 — Open the policy editor

  1. Navigate to Policies in the left sidebar.
  2. Click New Policy.
  3. Select the policy kind: Triage.
  4. Give your policy a name, e.g., suppress-info-findings.

You'll see a split-screen editor with:

  • Left panel — Rego code editor with syntax highlighting
  • Right panel — input preview and evaluation output

Step 2 — Write your first rule

Replace the template code with:

package mayo.triage

import rego.v1

# Suppress all informational findings
decision := "reject" if {
    input.finding.severity == "info"
}

This policy tells Mayo ASPM: for any finding with severity info, the triage decision is reject (suppress it).

What is import rego.v1?

Mayo ASPM uses Rego v1 syntax, which requires explicit imports and uses := for assignment. The import rego.v1 statement enables v1 features like the if keyword and in operator.


Step 3 — Test in the playground

  1. Click Test in Playground (or navigate to Policies > Playground).
  2. The left panel shows your Rego code.
  3. The middle panel shows a sample input object. Modify the severity to test:
{
  "finding": {
    "id": "f_test123",
    "severity": "info",
    "scanner": "semgrep",
    "rule_id": "javascript.express.best-practice",
    "title": "Express best practice suggestion",
    "file_path": "src/app.js"
  }
}
  1. Click Evaluate.
  2. The right panel shows the output:
{
  "decision": "reject"
}
  1. Change the severity to critical and evaluate again — the output should be empty (no decision), meaning the finding passes through without a triage decision.

Step 4 — Add more rules

Expand your policy with additional rules:

package mayo.triage

import rego.v1

# Suppress informational findings
decision := "reject" if {
    input.finding.severity == "info"
}

# Auto-accept critical CVEs
decision := "accept" if {
    input.finding.severity == "critical"
    input.finding.cve_id != ""
}

# Suppress findings in test directories
decision := "reject" if {
    contains(input.finding.file_path, "/test/")
}

# Suppress findings in vendor directories
decision := "reject" if {
    contains(input.finding.file_path, "/vendor/")
}

Rule conflicts

If multiple rules in the same policy produce different decisions for the same finding, OPA will raise a conflict error. Design your rules so they are mutually exclusive, or use the default keyword for fallback behavior.


Step 5 — Activate the policy

  1. Return to the policy editor.
  2. Review your code one final time.
  3. Click Save & Activate.

The policy is now active and will evaluate against all new findings as they arrive.

Tip

To test without affecting real data, save the policy as inactive first. Use the playground to verify behavior, then activate when ready.


Step 6 — Verify it's working

  1. Trigger a new scan (or wait for the next scheduled scan).
  2. Navigate to Findings and filter by status: Suppressed.
  3. You should see informational findings that were auto-suppressed by your policy.
  4. Each suppressed finding shows the policy that made the decision.

Understanding the input object

Every policy kind receives an input object with context about what's being evaluated. For triage policies, the input looks like:

{
  "finding": {
    "id": "f_abc123",
    "title": "SQL Injection in query builder",
    "severity": "high",
    "scanner": "semgrep",
    "rule_id": "java.lang.security.audit.sqli",
    "file_path": "src/main/java/com/example/Query.java",
    "line_number": 42,
    "cve_id": "",
    "package": "",
    "asset": {
      "name": "backend-api",
      "source": "github",
      "full_name": "acme/backend-api"
    },
    "project": {
      "name": "backend",
      "id": "proj_xyz"
    }
  },
  "organization": {
    "id": "org_abc",
    "name": "Acme Corp"
  }
}

See the Rego guide for complete input documentation for all policy kinds.


Common starter policies

Suppress low-severity findings older than 90 days

decision := "reject" if {
    input.finding.severity == "low"
    input.finding.age_days > 90
}

Accept CISA KEV findings

decision := "accept" if {
    input.finding.cve_id in data.kev_list
}

Defer medium findings for manual review

decision := "defer" if {
    input.finding.severity == "medium"
}

Next steps