Open-source project
electron/sheriff avatar
electron/sheriff

electron/sheriff: Automated Permission Enforcement for GitHub, Slack, and GSuite

Controls and monitors organization permissions across GitHub, Slack and GSuite. Built with ❤️ by The Electron Team

153 stars17 forksTypeScriptMIT

At a glance

What is it?
Sheriff is a Node.js bot that reads a YAML file to control permissions across GitHub, Slack, Heroku, and GSuite, and monitors GitHub for suspicious activity such as new deploy keys with write access or deletion of protected branches. It runs as a Heroku app with a cron job that enforces configuration every ten minutes.
Who is it for?
Sheriff is the right tool for a GitHub organization that already runs on Heroku and wants permission changes to flow through a version-controlled YAML file rather than manual UI clicks. It is not suited to organizations without Heroku access, since the deployment model is tightly coupled to that platform, and not suited to teams that want real-time blocking rather than post-hoc alerting.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What Sheriff Does and Who Uses It

Sheriff is an internal tool from the Electron project, designed for GitHub organization administrators who want to manage permissions declaratively. Instead of clicking through GitHub's settings UI, an administrator writes a `config.yaml` file in a private `.permissions` repository, and Sheriff reads that file on a ten-minute cron cycle to enforce the declared state.

The tool covers four platforms: GitHub (the primary use case), Slack (optional), Heroku (optional), and GSuite (optional). On GitHub it manages team membership, repository access levels, branch protection, wiki settings, and GitHub Actions approval rules. It also monitors the organization for suspicious activity: new deploy keys with write access, deletion of tags, and deletion of release branches all trigger a notification to a configured Slack channel.

The Electron team uses Sheriff in production and the repository is the canonical source. It is not published to npm as a ready-made package; adopters clone and deploy it themselves.

Three Core Components: Webhook, GitHub App, and Cron Job

Sheriff has three independent components that must all be configured and running together.

The webhook component is a Node.js HTTP server that listens for events from GitHub. Start it with:

bash
npm start

This starts the webhook server that handles incoming GitHub event payloads. After deploying, the administrator creates an organization-wide webhook in GitHub pointing to the server's URL, sets the content type to `application/json`, generates a shared secret, and selects "Send me everything" for which events to receive.

The GitHub App component is a separate GitHub App installation. Sheriff requires it to manage GitHub resources. The app needs the following OAuth scopes:

code
Org:
administration:write
contents:read
metadata:read

Repo:
members:write
actions:write        # only if you use `vouched_ci`
pull_requests:read   # only if you use `vouched_ci`

After creating the app, the administrator downloads a private key and converts it to the format expected by Octokit using a utility from the `@electron/github-app-auth` package. The converted credentials go into the `SHERIFF_GITHUB_APP_CREDS` environment variable.

The cron job component is the actual permissions enforcement run. It reads `config.yaml` from the `.permissions` repository and reconciles the live state of the organization against the declaration. Run it with:

bash
node lib/permissions/run.js --do-it-for-real-this-time

Omitting the `--do-it-for-real-this-time` flag causes Sheriff to perform a dry run, printing what it would do without making any changes. On Heroku, the Heroku Scheduler add-on triggers this command every ten minutes.

The Permissions YAML File

All of Sheriff's access control state lives in a `config.yaml` file stored in a `.permissions` repository within the target GitHub organization. The README recommends keeping that repository private, though a public configuration is also possible. The file begins with organization-level defaults and then lists teams:

yaml
organization: <name of github org>
repository_defaults:
  has_wiki: <boolean>
teams:
  - name: <team name>
    members:
      - list
      - of
      - gh_usernames
    maintainers:
      - list

Teams defined here are shared across GitHub, Slack, and GSuite when those plugins are enabled. A team member in this file becomes a member of the corresponding GitHub team, Slack user group, and Google Group simultaneously.

The file also supports per-repository settings such as branch protection rules, whether external contributors need CI approval before their Actions runs execute, and which named collaborators have access to specific repositories. The README describes the `vouched_ci` list, which extends the trust grant to specific GitHub accounts for CI runs without requiring a full team membership. The full schema is documented in the README under the Permissions File section, and the `.permissions` repository must have a `config.yaml` at the top level for Sheriff to function at all.

Environment Variables and Deployment Configuration

Sheriff reads its configuration from environment variables, listed in `.env.example`. Several are required before the tool will start. `PERMISSIONS_FILE_ORG` must contain the name of the GitHub organization where the `.permissions` repository lives. `GITHUB_WEBHOOK_SECRET` must match the secret set in the GitHub webhook. `SLACK_TOKEN` and `SLACK_WEBHOOK_URL` are both required even if the Slack plugin is not enabled, since Sheriff posts permission change notifications and security alerts to Slack by default.

`SHERIFF_HOST_URL` is the fully qualified URL of the deployed webhook server. `SHERIFF_GITHUB_APP_CREDS` holds the converted private key for the GitHub App. Optional variables include `SHERIFF_IMPORTANT_BRANCH` (a regular expression for branches whose deletion should trigger an alert), `SHERIFF_PLUGINS` (a comma-separated list enabling the `gsuite` and `slack` plugins), and GSuite credentials if that plugin is active.

For Docker-based deployment, the Makefile includes targets for building and running the image:

bash
docker build -t electron/sheriff .
docker run --rm -p 8080:8080 --env-file .env electron/sheriff

These targets are defined in the repository's Makefile alongside separate targets for running the permissions job and the generate command inside a container.

What Sheriff Monitors and When It Alerts

The monitoring aspect of Sheriff is distinct from the enforcement aspect. The cron job enforces the declared YAML state by making changes. The webhook server, running continuously, monitors for unexpected events that happen outside the YAML configuration.

Alerts are sent to the designated Slack channel when: a new deploy key with write access is added to a repository; a tag is deleted; a branch matching `SHERIFF_IMPORTANT_BRANCH` is deleted; or any permission setting is updated by the cron job. The alert channel provides a real-time record of every permission change Sheriff makes, as well as any out-of-band changes that could indicate compromised credentials or a repository being used in an unexpected way.

This is a notification-and-audit model, not a blocking model. If a repository administrator manually adds a deploy key outside of the YAML configuration, Sheriff will alert on it but the key will remain in place until the next cron run reconciles the configuration. Organizations that require every permission change to be blocked at the point of the GitHub API call would need a different architecture.

Limitations and the Alternative of Native GitHub Controls

Sheriff has several constraints that matter before committing to it. First, the deployment guide is written for Heroku, and while alternative deployment strategies are mentioned as possible, there is no documentation for them. Teams without Heroku accounts, or those prohibited from using it by policy, face an undocumented path.

Second, the tool has no GitHub releases and is not versioned as a public package. Adopters run directly from the repository, which means updates require pulling the latest commit and rebuilding. There is no changelog in the repository to consult before updating.

Third, the Slack integration is effectively required: several environment variables for Slack are marked required in the configuration table even when the Slack plugin is disabled. Organizations that do not use Slack or cannot create Slack apps face a configuration gap.

The natural alternative for teams that do not need the automation layer is GitHub's built-in organization settings, combined with protected branch rules and CODEOWNERS files for code review requirements. GitHub's native controls lack the cross-platform synchronization to Slack user groups and Google Groups that Sheriff provides, but they require no infrastructure to maintain and no ongoing Heroku costs.

Editorial conclusion

Sheriff is the right tool for a GitHub organization that already runs on Heroku and wants permission changes to flow through a version-controlled YAML file rather than manual UI clicks. It is not suited to organizations without Heroku access, since the deployment model is tightly coupled to that platform, and not suited to teams that want real-time blocking rather than post-hoc alerting. Before adopting it, confirm that the GitHub App configuration and all required environment variables in `.env.example` can be set in your deployment environment.

Frequently asked questions

How does electron/sheriff differ from simply using GitHub's organization settings?

Sheriff stores permission declarations in a version-controlled YAML file and enforces them on a ten-minute cron cycle, so every change is auditable in git history. GitHub's built-in organization settings are applied manually through the web UI with no automatic enforcement. Sheriff also synchronizes team membership to Slack user groups and Google Groups, which GitHub's native settings do not cover.

Can electron/sheriff be deployed somewhere other than Heroku?

The README states that alternative deployment strategies are possible but the documentation covers only Heroku. The Makefile includes Docker build and run targets, so a Docker-based deployment is one option, but there is no step-by-step guide for non-Heroku environments.

What happens if someone adds a GitHub deploy key outside of the YAML config?

The webhook server detects the new key and sends an alert to the configured Slack channel, since any new deploy key with write access is treated as a suspicious event. The key is not automatically removed; it remains until the cron job next reconciles the YAML configuration, which runs every ten minutes by default.

Official sources

  1. Official README
  2. Project repository