feat: chatops_repo restriction — keep slash commands off public repos#32
Merged
Conversation
## Why
ChatOps commands (/configure-repo, /sync-all-repos, /review-pr, etc.) are
currently honoured from any repo where Temper is installed. Even with
allowed_command_users restricting *who* can trigger them, the bot's "Working
on it…" replies and any error responses are public — sitting in whichever
public repo the maintainer happened to comment in.
For an org running an org-wide config sweep (especially the upcoming
/sync-all-repos that migrates every repo to Repository Rulesets + applies
config changes via PR), the user wants the trigger and the bot's response
trail to stay in a private admin repo.
## What
Opt-in `chatops_repo:` config section:
chatops_repo:
enabled: false
repo: pulseengine/temper-ops
When `enabled: true`, the issue_comment.created handler silently ignores
any comment starting with `/` UNLESS it's posted in `repo`. The check fires
*before* command extraction, so:
- no log line emitted
- no comment posted back
- no public footprint at all
Non-command comments (no leading `/`) are unaffected — handler proceeds
through the existing no-op path. Commands posted in the designated repo
work exactly as before.
## Operational pattern this unlocks
1. Create `pulseengine/temper-ops` as a **private** repo
2. Install Temper on it
3. Set `chatops_repo.enabled: true` and `repo: pulseengine/temper-ops` in
`config.local.yml`
4. Trigger /sync-all-repos, /configure-repo, etc. from there
5. The bot's "Working on it…" + result replies all land in the private
repo. Configuration PRs the bot opens against public repos are still
public — that's the intentional asymmetry: trigger private, application
public, audit trail intact.
## Test plan
- [x] All 792 tests pass (was 788; +4 covering: command honoured from admin
repo, command silently ignored from public repo, non-command comments
unaffected, legacy default still honours every repo)
- [x] eslint clean
- [ ] After deploy: enable chatops_repo, comment /configure-repo on any
public pulseengine repo — should be a complete no-op (no working
comment, no error). Comment from temper-ops — should work normally.
## Risk & rollout
- Risk: low. Opt-in via config; default behaviour unchanged.
- Rollout: self-update on merge.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
ChatOps commands are currently honoured from any installed repo. Even with `allowed_command_users` restricting who can trigger, the bot's "Working on it…" + result replies are public — landing in whichever public repo the maintainer commented in. For an org-wide sweep (`/sync-all-repos` migrating every repo to Repository Rulesets + applying config via PR), trigger + response trail should stay in a private admin repo.
What
Opt-in `chatops_repo:` section. When `enabled: true`, the `issue_comment.created` handler silently ignores any comment starting with `/` UNLESS posted in `repo`. Check fires before command extraction → no log, no comment, no public footprint.
Non-command comments (no leading `/`) unaffected. Commands in the designated repo work exactly as before.
Operational pattern unlocked
Test plan
Risk & rollout
🤖 Generated with Claude Code