Skip to content

feat: reject conflicting permission entries at load/save time; document GLOB semantics#218

Merged
coopernetes merged 1 commit into
mainfrom
feat/permission-conflict-check
May 5, 2026
Merged

feat: reject conflicting permission entries at load/save time; document GLOB semantics#218
coopernetes merged 1 commit into
mainfrom
feat/permission-conflict-check

Conversation

@coopernetes
Copy link
Copy Markdown
Member

Summary

  • RepoPermissionService.findConflict(): detects overlapping paths for the same username+provider — exact string equality, or one path's GLOB/REGEX pattern matches the other path string as a literal (covers LITERAL-vs-GLOB, LITERAL-vs-REGEX, GLOB-vs-GLOB subset cases)
  • seedFromConfig: throws IllegalStateException on first conflict, failing startup loudly rather than silently evaluating in undefined order
  • PermissionController.add: returns 400 with the conflicting path before saving, blocking new conflicts via the dashboard API
  • CONFIG-vs-DB conflicts are checked (not just within each source)
  • Comprehensive GLOB behaviour tests: * vs **, hyphenated names, path separator crossing, wildcard owner/repo patterns, ? single-char matching
  • CONFIGURATION.md: new GLOB semantics table + conflict detection note in the permissions section

Test plan

  • All existing permission tests still pass
  • New conflict tests: exact duplicate, glob-overlaps-literal (both directions), glob-subset, different user/provider do not conflict
  • seedFromConfig throws on both CONFIG-vs-CONFIG and CONFIG-vs-DB conflicts
  • Controller returns 400 on conflict, does not call save
  • jacocoTestCoverageVerification passes

closes #215

@coopernetes coopernetes force-pushed the feat/permission-conflict-check branch from 9ab7bcd to 3b52e88 Compare May 5, 2026 14:49
…nt GLOB semantics

Add conflict detection to RepoPermissionService.findConflict(): two permissions
conflict when they share the same username+provider, their paths overlap, AND
their operations affect the same permission check. SELF_CERTIFY is evaluated by
isBypassReviewAllowed() independently, so PUSH_AND_REVIEW + SELF_CERTIFY on the
same path coexist without conflict — both entries are required for a trusted
committer configuration.

Path overlap uses a practical heuristic: exact path string equality, or one
path's GLOB/REGEX pattern matches the other path string as a literal. Covers
LITERAL-vs-GLOB, LITERAL-vs-REGEX, and GLOB-vs-GLOB subset cases.

- seedFromConfig: throws IllegalStateException on first conflict, failing startup
  loudly rather than allowing silent wrong behaviour
- PermissionController.add: returns 400 with the conflicting path before saving
- CONFIG-vs-DB conflicts are checked (not just within each source)

Also adds comprehensive GLOB behaviour tests documenting * vs ** semantics,
hyphenated names, path separator crossing, wildcard owner/repo patterns, and ?
single-character matching. Updates CONFIGURATION.md with a GLOB semantics table,
a conflict detection note, real-world permission examples, and real-world URL rule
examples (including a note clarifying that owners/names use OR logic and slugs
are needed for AND conditions).

closes #215

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coopernetes coopernetes force-pushed the feat/permission-conflict-check branch from 3b52e88 to 3119340 Compare May 5, 2026 15:01
@coopernetes coopernetes enabled auto-merge May 5, 2026 15:36
@coopernetes coopernetes merged commit b4d193a into main May 5, 2026
21 of 24 checks passed
@coopernetes coopernetes deleted the feat/permission-conflict-check branch May 5, 2026 15:39
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.

feat: reject conflicting repo permission entries at load/save time

1 participant