Ticket Guardrails
Enforce ticket hygiene across your organization. Verify PRs reference valid issue tracker tickets, check ticket status and type, enforce a specific tracker, and detect ticket reuse across multiple PRs. Works with Jira by default; other issue trackers require a compatible ticket collector.
ticket to your lunar-config.yml:uses: github://earthly/lunar-lib/policies/ticket@v1.0.0
Included Guardrails
This policy includes 6 guardrails that enforce standards for your devex build and ci.
ticket-present
Ensures PRs reference an issue tracker ticket in the title.
ticket-valid
Ensures the referenced ticket exists and is valid in the issue tracker.
ticket-source
Ensures the ticket comes from an approved issue tracker.
ticket-status
Ensures the ticket is in an acceptable workflow status.
ticket-type
Ensures the ticket is an acceptable issue type.
ticket-reuse
Prevents teams from recycling the same ticket across too many PRs.
How Guardrails Fit into Lunar
Lunar guardrails define your engineering standards as code. They evaluate data collected by integrations and produce pass/fail checks with actionable feedback.
Policies support gradual enforcement—from silent scoring to blocking PRs or deployments—letting you roll out standards at your own pace without disrupting existing workflows.
Learn How Lunar Works →Required Integrations
This policy evaluates data gathered by one or more of the following integration(s).
Make sure to enable them in your lunar-config.yml.
Configuration
Configure this policy in your lunar-config.yml.
Inputs
| Input | Required | Default | Description |
|---|---|---|---|
allowed_sources
|
Required | — | Comma-separated list of allowed ticket sources (e.g. "jira,linear"). Empty = any. |
allowed_statuses
|
Required | — | Comma-separated list of allowed ticket statuses (empty = any) |
disallowed_statuses
|
Required | — | Comma-separated list of disallowed ticket statuses (empty = none) |
allowed_types
|
Required | — | Comma-separated list of allowed issue types (empty = any) |
max_ticket_reuse
|
Optional |
3
|
Maximum number of other PRs allowed to reference the same ticket |
Documentation
View on GitHubTicket Guardrails
Enforce issue tracker ticket hygiene across your organization's pull requests. Works with any issue tracker (Jira, Linear, GitHub Issues, etc.).
Overview
This policy verifies that PRs reference valid tickets, checks ticket status and type, enforces a specific issue tracker, and detects ticket reuse across multiple PRs. It helps teams maintain traceability between code changes and project management.
Policies
This plugin provides the following policies (use include to select a subset):
| Policy | Description | Failure Meaning |
|---|---|---|
ticket-present |
PRs must reference a ticket | No ticket ID found in PR title |
ticket-valid |
Referenced ticket must exist | Ticket ID was parsed but doesn't exist in the issue tracker |
ticket-source |
Ticket must come from an approved tracker | Ticket source not in allowed list |
ticket-status |
Ticket must be in an acceptable status | Ticket status is disallowed or not in allowed list |
ticket-type |
Ticket must be an acceptable issue type | Issue type not in allowed list |
ticket-reuse |
Same ticket can't be reused too many times | Ticket used in more PRs than the configured limit |
Required Data
This policy reads from the following Component JSON paths:
| Path | Type | Description |
|---|---|---|
.vcs.pr.ticket.id |
string | Ticket ID extracted from PR title |
.vcs.pr.ticket.source |
string | Issue tracker name (e.g. "jira", "linear") |
.vcs.pr.ticket.valid |
boolean | Whether ticket exists in the tracker |
.vcs.pr.ticket.status |
string | Ticket workflow status |
.vcs.pr.ticket.type |
string | Issue type (e.g. Story, Bug) |
.vcs.pr.ticket.reuse_count |
number | Count of other PRs using same ticket |
Installation
Add to your lunar-config.yml:
policies:
- uses: github://earthly/lunar-lib/policies/ticket
on: ["domain:your-domain"]
enforcement: report-pr
with:
allowed_sources: "jira"
disallowed_statuses: "Done,Closed"
max_ticket_reuse: "3"
Examples
Passing — Valid ticket with acceptable status
{
"vcs": {
"pr": {
"ticket": {
"id": "ENG-456",
"source": "jira",
"url": "https://acme.atlassian.net/browse/ENG-456",
"valid": true,
"status": "In Progress",
"type": "Story",
"summary": "Add payment validation",
"assignee": "jane@acme.com",
"reuse_count": 0
}
}
}
}
Failing — No ticket in PR title
{}
Failure message: "PR does not reference a ticket. Include a ticket ID in the PR title (e.g. [ABC-123])."
Remediation
When this policy fails, you can resolve it by:
- ticket-present: Add a ticket reference to your PR title (e.g.
ABC-123 Your PR description) - ticket-valid: Verify the ticket ID exists in the issue tracker
- ticket-source: Use the approved issue tracker for your organization
- ticket-status: Move the ticket to an acceptable status before opening the PR
- ticket-type: Use an acceptable issue type (e.g. Story, Bug, Task)
- ticket-reuse: Create a new ticket for this work instead of reusing an existing one
Open Source
This policy is open source and available on GitHub. Contribute improvements, report issues, or fork it for your own use.
Common Use Cases
Explore how individual guardrails work with specific integrations.
Ready to Automate Your Standards?
See how Lunar can turn your engineering wiki, compliance docs, or postmortem action items into automated guardrails with our 100+ built-in guardrails.