Skip to content

Add domain/* labels and CODEOWNERS-based domain labeling#13

Merged
bryanbeverly merged 3 commits into
mainfrom
bryan/domain-labels
Jun 12, 2026
Merged

Add domain/* labels and CODEOWNERS-based domain labeling#13
bryanbeverly merged 3 commits into
mainfrom
bryan/domain-labels

Conversation

@bryanbeverly

@bryanbeverly bryanbeverly commented May 31, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds 7 domain/* labels to labels.yml (scanning, findings, integrations, platform, frontend, infra, database) with a teal color palette
  • Extends pr_labeler.py to automatically apply domain/* labels by parsing the caller repo's CODEOWNERS file against the PR's changed files
  • Uses last-match-wins semantics (matching GitHub's native CODEOWNERS evaluation) rather than depending on mutable PR reviewer state
  • Stale domain labels are removed when files change between pushes
  • Repos without a CODEOWNERS file gracefully skip domain labeling
  • No changes needed to per-repo caller workflows -- the existing pr-labeler.yml callers pick this up automatically

How it works

  1. On each run, fetches the repo's CODEOWNERS via the Contents API (single call, cached per run for backfill)
  2. Fetches the PR's changed files via gh pr view --json files
  3. Parses CODEOWNERS rules and matches each changed file (last match wins per file)
  4. Collects the union of owning team slugs across all files
  5. Filters to known domain slugs (ignores catch-all teams like eng-leads)
  6. Adds missing domain/* labels and removes stale ones

Test plan

  • 81 tests passing locally (26 new), covering:
    • CODEOWNERS parsing (comments, blanks, inline comments, case normalization, multi-owner)
    • Pattern matching (catch-all, anchored dirs, unanchored basenames, globs, * not crossing /, deep paths)
    • Domain resolution (last-match-wins, multi-domain PRs, unowned files, catch-all fallback)
    • Label reconciliation (add new, remove stale, ignore unknown slugs, no-op when CODEOWNERS absent)
  • CI tests pass
  • After merge: trigger sync-labels workflow_dispatch on target repos to propagate label definitions
  • Verify domain labels appear on a new PR in thog

Jira: PLAT-222

Made with Cursor


Note

Low Risk
Automation-only changes to GitHub labeling and label definitions; no product runtime or auth paths.

Overview
Adds seven domain/* labels to the shared taxonomy and extends pr_labeler.py so open PRs get those labels from CODEOWNERS, not from reviewer assignment.

On each run the labeler loads CODEOWNERS once (Contents API, standard paths), loads the PR’s changed files, resolves owners with last-match-wins per file (GitHub-style path rules), unions team slugs across files, maps them to known domains (scanning, findings, etc.), and adds missing domain/* labels while removing stale ones. Catch-all teams like eng-leads are ignored; repos without CODEOWNERS skip domain labeling. Existing caller workflows pick this up without changes.

Tests cover parsing, pattern matching, domain resolution, and reconcile behavior.

Reviewed by Cursor Bugbot for commit a70cc1a. Bugbot is set up for automated code reviews on this repo. Configure here.

Define 7 domain/* labels (scanning, findings, integrations, platform,
frontend, infra, database) in labels.yml with a teal color palette.

Extend pr_labeler.py to fetch CODEOWNERS from the caller repo via the
Contents API, parse it with last-match-wins semantics, match changed
files to owning teams, and apply/remove domain/* labels accordingly.
This avoids depending on mutable PR reviewer state and works across
all repos that have a CODEOWNERS file.

Repos without CODEOWNERS gracefully skip domain labeling. Unknown team
slugs (e.g. eng-leads) are filtered out so only recognized domain
labels are applied.

81 tests passing (26 new for CODEOWNERS parsing, matching, domain
reconciliation).

Jira: PLAT-222
Co-authored-by: Cursor <cursoragent@cursor.com>
@bryanbeverly bryanbeverly requested a review from a team May 31, 2026 07:28
Co-authored-by: Cursor <cursoragent@cursor.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 5670c71. Configure here.

Comment thread .github/scripts/pr_labeler.py Outdated
Comment thread .github/scripts/pr_labeler.py Outdated
- Check for internal slashes before appending ** to trailing-slash
  patterns, so unanchored dirs like "vendor/" match at any depth
- Search all three GitHub CODEOWNERS locations (.github/, root, docs/)
  in priority order instead of only the root

Co-authored-by: Cursor <cursoragent@cursor.com>
@bryanbeverly bryanbeverly requested a review from sysread June 1, 2026 01:56
@bryanbeverly bryanbeverly merged commit b0dedcf into main Jun 12, 2026
4 checks passed
@bryanbeverly bryanbeverly deleted the bryan/domain-labels branch June 12, 2026 22:09
bryanbeverly added a commit to trufflesecurity/helm-charts that referenced this pull request Jun 15, 2026
## Summary
Add `contents: read` to the PR labeler caller workflow's `permissions`
block.

When a workflow declares a `permissions:` block, every scope not listed
defaults to `none`. This caller declared only `pull-requests: write`, so
`contents` was `none`. The labeler's domain-labeling step reads
CODEOWNERS via the GitHub Contents API using `GITHUB_TOKEN`; with
`contents: none` that read is denied and the script logs "No CODEOWNERS
found; skipping domain labeling." As a result the `domain/*` labels
added org-wide in trufflesecurity/.github#13 were never applied.
Granting `contents: read` restores CODEOWNERS access; no other scope is
required.

## Review guidance
- **Urgent** (needs same-day review): no
- **High complexity** (non-obvious logic, careful review): no
- **Key files to focus on**: `.github/workflows/pr-labeler.yml`

## Testing
A labeler dry-run backfill on thog logged "No CODEOWNERS found; skipping
domain labeling" under the current permissions, despite a valid
CODEOWNERS file. `contents: read` is the documented scope for the
Contents API read the labeler performs. After merge, `gh workflow run
pr-labeler.yml -f pr_number=all -f dry_run=true` will show planned
`domain/*` labels.

## Deployment notes
Takes effect on the next labeler run (event-driven, or a
workflow_dispatch backfill). No application/runtime impact.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Single workflow permission scope change with no application or runtime
impact; least privilege is preserved aside from the required Contents
API read.
> 
> **Overview**
> The PR labeler workflow now grants **`contents: read`** alongside
`pull-requests: write`.
> 
> Because an explicit `permissions` block leaves unlisted scopes at
`none`, the labeler could not read **CODEOWNERS** via the Contents API
and skipped **domain** labeling. This restores that read so org-wide
`domain/*` labels can be applied again.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
e0f6721. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants