Enforce owner allowlist at the writ-core mutation boundary

Merged
RM
1mo ago
+4332-2482

User description

Summary

Restores the owner allowlist as a real writ-core policy gate after the Python layer was removed.

  • New OwnerAllowlist reader for WRIT_ALLOWED_OWNERS, legacy WH_ALLOWED_OWNERS, and explicit --allowed-owners / API args.
  • Empty or unset lists deny owner-taking operations rather than permitting them (OWNER_NOT_ALLOWED, exit 2).
  • Enforcement runs before worktree mutation and before spawning gh.
  • gh -R / --repo parsing covers the pflag spellings gh 2.x actually accepts (-R=, attached -Rvalue, clustered -wR), plus GH_REPO.
  • Owner comparison uses the same identity parser as github_repo_slugs_match, so Acme/Repo and github.com/acme/repo cannot diverge.
  • The four documentation sites drop their not-enforced qualifiers in this PR.

Issue

Fixes #146
Linear: https://linear.app/rpd-34/issue/RM-983/enforce-owner-allowlist-has-no-enforcement-after-the-python-removal

Test plan

  • Local gates from README.md (cargo fmt --all -- --check, cargo clippy --workspace --all-targets -- -D warnings, cargo test --workspace)
  • CI on PR

Notes for review

  • Independent review flagged -R= / attached / clustered -R as an authorization bypass of the new gate; those spellings are now parsed and tested.
  • Codacy: .codacy.yml now excludes git_safe/** (replacing stale git_safe.rs glob) to match pre-split policy.
  • CodeScene: delta gate still fails on new git_safe/* module health scores; structural refactor or CodeScene suppress may be needed if the gate does not clear on Codacy-only fix.
  • Agent: Cursor Grok 4.6

Linear Issue: RM-983

Open in Web Open in Cursor 

Summary by cubic

Restores the owner allowlist as a real writ-core policy gate, fixing #146 (Linear RM-983) where the allowlist had no reader after the Python layer was removed. Out-of-scope owners are now rejected before they can create worktrees or run repository-targeting gh commands.

  • OwnerAllowlist reads WRIT_ALLOWED_OWNERS, legacy WH_ALLOWED_OWNERS, and explicit --allowed-owners / API args; empty or unset lists deny with OWNER_NOT_ALLOWED (exit 2).
  • Enforcement runs before worktree mutation or gh spawning and covers all -R / --repo spellings, GH_REPO, and positional repo, clone, and PR-URL targets.
  • Owner comparison uses the same normalization as github_repo_slugs_match, and filesystem origins that masquerade as GitHub owners are rejected.
  • Worktree create binds the caller-supplied owner to the repository's verified origin owner; GH_REPO applies only to repository-context gh commands, and the selected repo is pinned after origin binding so a permit wait can't retarget gh.
  • Documentation now describes allowlisting as enforced, and Codacy complexity exclusions follow the git_safe module split (git_safe/**).

Migration

  • Operators must configure the allowlist (env var or --allowed-owners) or worktree create and gh commands with repo selectors will fail.

CodeAnt-AI Description

Enforce configured repository-owner access at the writ-core mutation boundary

What Changed

  • Worktree creation now rejects empty, unset, or unauthorized owner lists before creating branches or worktrees.
  • gh repository targets are checked against the configured owners, including explicit and clustered -R/--repo forms, repository operands, URLs, and applicable GH_REPO values.
  • Requested worktree owners and mutating gh repository targets must match the verified GitHub origin, preventing local repositories from being relabeled or commands from targeting another repository.
  • Added --allowed-owners, support for WRIT_ALLOWED_OWNERS and legacy WH_ALLOWED_OWNERS, stable OWNER_NOT_ALLOWED errors, and fail-closed handling for ambiguous gh arguments.
  • Updated documentation to identify owner allowlist checks as enforced and added regression coverage for denied operations and selector bypasses.

Impact

βœ… Unauthorized worktree creation blocked
βœ… Fewer cross-repository mutation risks
βœ… Clearer OWNER_NOT_ALLOWED failures

πŸ’‘ Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.