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¶
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
owneris a team, Mayo ASPM uses the team's Jira assignment rule (round-robin, team lead, or unassigned). - If
owneris a user, that user is assigned directly (their Mayo ASPM profile must have a linked Jira account).
Tips¶
- Start with repository-level ownership — it's the simplest and covers most cases.
- Layer file-path rules on top — for monorepos where different teams own different directories.
- Use
default— always have a fallback owner so no finding is unassigned. - Keep teams updated — ownership policies reference team IDs; ensure your team list is current.
Next steps¶
- Project policies — map assets to projects
- Policy scoping — scope ownership policies per project
- Connecting Jira — ticket assignment integration