Skip to content

Ownership Policy Reference

Ownership policies assign findings to teams or individuals. This determines who sees the finding in their dashboard and who is assigned when tickets are generated.


Package

package mayo.ownership

Required output

Variable Type Description
owner string Team ID or user ID to assign the finding to

Optional outputs:

Variable Type Description
owner_type string "team" or "user" (default: "team")
reason string Explanation of the assignment

Input schema

{
  "finding": {
    "id": "string",
    "title": "string",
    "severity": "string",
    "scanner": "string",
    "scanner_type": "string",
    "file_path": "string",
    "package": "string",
    "asset": {
      "name": "string",
      "source": "string",
      "full_name": "string"
    },
    "project": {
      "id": "string",
      "name": "string"
    }
  },
  "teams": [
    {
      "id": "string",
      "name": "string",
      "slug": "string",
      "members": ["user_id_1", "user_id_2"]
    }
  ],
  "users": [
    {
      "id": "string",
      "email": "string",
      "name": "string"
    }
  ],
  "organization": {
    "id": "string",
    "name": "string"
  }
}

Examples

Assign by file path

package mayo.ownership

import rego.v1

# Frontend team owns frontend code
owner := "team_frontend" if {
    some prefix in ["src/components/", "src/pages/", "src/styles/"]
    startswith(input.finding.file_path, prefix)
}

# Backend team owns API code
owner := "team_backend" if {
    some prefix in ["src/api/", "src/services/", "src/models/"]
    startswith(input.finding.file_path, prefix)
}

# Infrastructure team owns IaC
owner := "team_infra" if {
    some ext in [".tf", ".yml", ".yaml"]
    endswith(input.finding.file_path, ext)
    input.finding.scanner_type == "iac"
}

Assign by asset (repository)

package mayo.ownership

import rego.v1

# Map repositories to teams
repo_owners := {
    "acme/payments-api": "team_payments",
    "acme/auth-service": "team_identity",
    "acme/mobile-app": "team_mobile",
    "acme/infrastructure": "team_platform"
}

owner := repo_owners[input.finding.asset.full_name]

Assign by scanner type

package mayo.ownership

import rego.v1

# Security team handles secret findings
owner := "team_security" if {
    input.finding.scanner_type == "secret"
}

# DevOps team handles container findings
owner := "team_devops" if {
    input.finding.scanner_type == "container"
}

# Default to the project team
default owner := "team_engineering"

CODEOWNERS-style assignment

package mayo.ownership

import rego.v1

# Mimic GitHub CODEOWNERS patterns
owner := "team_auth" if {
    startswith(input.finding.file_path, "src/auth/")
}

owner := "team_billing" if {
    startswith(input.finding.file_path, "src/billing/")
}

owner := "user_alice" if {
    input.finding.file_path == "src/core/crypto.go"
}

owner_type := "user" if {
    input.finding.file_path == "src/core/crypto.go"
}

default owner := "team_engineering"
default owner_type := "team"

Evaluation behavior

  • Ownership policies run after triage on accepted findings.
  • If no ownership policy matches, the finding is assigned to the project default owner.
  • Ownership can be manually overridden in the UI at any time.
  • Re-running ownership evaluation (via Re-evaluate button) will overwrite manual assignments unless the finding is locked.

Integration with ticketing

When tickets are generated, the owner output determines the Jira assignee:

  • If owner is a team, Mayo ASPM uses the team's Jira assignment rule (round-robin, team lead, or unassigned).
  • If owner is a user, that user is assigned directly (their Mayo ASPM profile must have a linked Jira account).

Tips

  1. Start with repository-level ownership — it's the simplest and covers most cases.
  2. Layer file-path rules on top — for monorepos where different teams own different directories.
  3. Use default — always have a fallback owner so no finding is unassigned.
  4. Keep teams updated — ownership policies reference team IDs; ensure your team list is current.

Next steps