Open-source project
repository-settings/app avatar
repository-settings/app

Repository Settings app: repository configuration reviewed through a pull request

Pull Requests for GitHub repository settings

1,061 stars189 forksJavaScriptISC

At a glance

What is it?
The Repository Settings app is a GitHub App that syncs repository settings declared in .github/settings.yml back to GitHub, turning branch protection, labels and similar configuration into a pull request that reviewers can see. It is hosted on GitHub.com or self-hosted, and the README is unusually direct about the privilege escalation its design creates.
Who is it for?
The Repository Settings app suits a team that has decided repository configuration should live in the repository and be changed through review, because a settings file diff is something everyone can read and a settings screen click is not. It is the wrong tool if the settings in question are not expressible in the file, and it is the wrong choice for a repository where collaborators you do not fully trust can push, since the app turns push access into admin access by design.
Can I use it commercially?
Yes. ISC 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 last received commits 1 day ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

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

Editorial analysis

Configuration as a diff instead of a settings screen

The Repository Settings app syncs repository settings defined in .github/settings.yml to GitHub, enabling Pull Requests for repository settings.

That sentence is the entire product. GitHub's own repository settings are a web form whose state lives on GitHub's servers, is not versioned, and is changed by whoever happens to have administrative permission at the time. This app inverts that: the desired state is a YAML file committed to the repository, and the app reads it and applies it.

The consequence is that a configuration change becomes a pull request. A reviewer sees a diff of the YAML, comments on it, and merges it. The app then reconciles GitHub's actual settings with the file. When somebody asks why branch protection was changed, the answer is a commit rather than an audit log entry.

The mechanism has an obvious prerequisite: the app has to be installed as a GitHub App on the repositories it manages, and the README is explicit that to gain the benefits of the Repository Settings app, it will need to be installed as a GitHub App on your repositories.

The author is Brandon Keepers, the license is ISC, and the topics list names github-app and probot-app, so this is a Probot application.

The two install routes are the first decision. A hosted version is provided for use with GitHub.com, and you can install the app on your repositories or your entire organization. If you would prefer to self-host your own instance, the README points at the self-hosting documentation.

The privilege escalation, stated by the project itself

The security implications section is the most valuable part of the README, and it is worth quoting because it is unusual for a project to advertise its own risk in those terms.

The note says this app inherently escalates anyone with push permissions to the admin role, since they can push config settings to the default branch, which will be synced. Use caution when merging PRs and adding collaborators.

Think about what that means mechanically. Administrative permission on a GitHub repository controls branch protection, the ability to bypass it, the list of people who can push, and other settings that determine who can change what. The app makes the contents of the default branch authoritative for those settings. Anyone who can push to the default branch can therefore change administrative settings, by opening a pull request that changes .github/settings.yml.

So the app converts push access into admin access. That is a genuine escalation, and it is a consequence of the design rather than a flaw in the implementation.

The README offers a mitigation, and it is the standard one. One way to preserve admin and push permissions is to use the GitHub CodeOwners feature to set one or more administrative users as the code owner of the .github/settings.yml file, and turn on require code owner review for the default branch.

The mitigation has a cost the README also states: requiring code owner review for the entire branch means every change needs an administrator's approval, not just changes to the settings file. That is a significant slowdown for a busy repository, and it is the trade you are choosing between a fast branch and a protected one.

A Probot app with a small dependency set

The package.json describes a compact application with four runtime dependencies.

json
"dependencies": {
  "deep-equal": "2.2.3",
  "deepmerge": "4.3.1",
  "js-yaml": "4.3.2",
  "probot": "14.3.2"
}

probot at 14.3.2 is the framework, and it is the piece that provides the GitHub App plumbing, webhook handling and the authentication flow that a GitHub App needs. js-yaml parses the settings file. deepmerge and deep-equal are the other two, and they are the interesting ones: deepmerge is what combines a settings file with inherited or defaulted values, and deep-equal is what lets the app decide whether the current GitHub state already matches the desired state, so it can skip a redundant API call.

Together those two suggest the sync model. The app does not blindly write every setting on every push. It computes the difference and applies only what changed, which matters because a naive implementation would fight with settings that people changed by hand in the GitHub UI, and the difference would be silently reverted on the next commit.

The package is ESM, with type set to module and main and exports both pointing at ./index.js. The version field reads 0.0.0-semantically-released, which is the placeholder semantic-release uses, since the actual version is derived from the git tag at release time.

The repository layout matches the shape of a GitHub App: an api/ directory, a lib/ directory for the library code, a script/ directory, a test/ directory, an index.js at the root, and app.json, which is the manifest GitHub reads when you create the app. The .env.example gives the three settings a local run needs: APP_ID for the GitHub App, WEBHOOK_SECRET, and a commented WEBHOOK_PROXY_URL pointing at smee.io, the service that tunnels webhooks to a local machine during development.

Two test suites, one for units and one for the whole app

The test scripts show a project that takes its integration behaviour seriously.

The unit tests run with NODE_OPTIONS=--experimental-vm-modules and NODE_NO_WARNINGS=1 against test/unit/, which is the standard way to get Jest to load ES modules in a package with type set to module.

The integration tests are the more interesting part. They run through cucumber-js against test/integration, with source maps enabled and DEBUG set to any, and they come in profiles: a base profile run with the noWip profile, a wip profile for work in progress, a focus profile, and debug variants of both.

Running a GitHub App end to end means driving a real webhook, so a behaviour-first test suite with a separate profile for work in progress is the right shape. The profile split also lets a contributor land a partly finished feature without breaking the main integration run, which is a courtesy to reviewers.

The lint story is unusually broad. There is prettier-standard for JavaScript formatting, lockfile-lint against package-lock.json with the npm type, validating HTTPS and allowing only the npm host, ls-engines for the Node engine requirements, npm ls to verify the peer dependency tree, and publint with the strict flag to validate the package's publishing metadata.

That last one is a sign of care. publint in strict mode catches the class of mistake where a package publishes fine but the exported entry points do not resolve for consumers, and it is the sort of check that only appears in packages whose author has shipped enough versions to have hit the problem.

The docs are generated with remark, through the generate:md script and a .remarkrc.json, and the @form8ion/remark-preset plugin is in the dev dependencies. The test script runs lint and test in parallel using npm-run-all with printed labels.

Version 5.x, with the deployment handled by Vercel

The release history shows v5.0.14 from 2026-08-29, v5.0.13 from 2026-08-03 and v5.0.12 from 2026-06-30, and the last push was on 2026-10-14, so the tree is being worked on.

The 5.x line with a patch version in the teens is a mature project, and the release pattern of small patch releases every few weeks is consistent with an application that is deployed frequently and adjusted in response to GitHub API changes.

The hosted version runs on Vercel, which the README records with a powered by Vercel badge. That is a deliberate choice for a GitHub App: the app is a webhook receiver, so it has to be reachable from the internet, and it is otherwise stateless apart from its configuration, so a serverless platform fits without any infrastructure work.

The .nvmrc file at the root pins the Node version, and the ls-engines lint check verifies that the declared engine matches, so the runtime is consistent between local development and the hosted deployment.

The Renovate badge shows that dependency updates are automated, with a .renovaterc.json at the root holding the configuration, which is standard for an application with a handful of runtime dependencies and a long tail of dev dependencies. There is also an .editorconfig, a .prettierignore, a .git-blame-ignore-revs file for bulk formatting commits, and an .idea/ directory, which suggests at least one contributor works in IntelliJ.

The licence is ISC, which is short and permissive, appropriate for an application most people will run hosted rather than vendor.

Editorial conclusion

The Repository Settings app suits a team that has decided repository configuration should live in the repository and be changed through review, because a settings file diff is something everyone can read and a settings screen click is not. It is the wrong tool if the settings in question are not expressible in the file, and it is the wrong choice for a repository where collaborators you do not fully trust can push, since the app turns push access into admin access by design. Before you install it, read the security implications section and set up the CodeOwners pattern the README describes for .github/settings.yml, because the app itself states that it escalates anyone with push permissions to the admin role.

Frequently asked questions

What does the Repository Settings app do?

It syncs repository settings defined in .github/settings.yml to GitHub, which means configuration changes are made through pull requests rather than through the GitHub settings interface, and the desired state lives in version control.

How do I install the Repository Settings app?

As a GitHub App. There is a hosted version for use with GitHub.com that you can install on individual repositories or a whole organization, and the README points at the self-hosting documentation if you would rather run your own instance.

What is the security risk of using the Repository Settings app?

The README states that the app inherently escalates anyone with push permissions to the admin role, since they can push config settings to the default branch which will be synced. It recommends using CodeOwners to make administrators the code owner of .github/settings.yml and requiring code owner review on the default branch.

What framework is the Repository Settings app built on?

Probot, pinned at 14.3.2, with js-yaml to parse the settings file and deepmerge and deep-equal for combining and comparing configuration values. The package is ESM and is published as @repository-settings/app.

How is the Repository Settings app tested?

Unit tests run with Jest against test/unit/, and integration tests run with cucumber-js against test/integration, with separate profiles for base, wip and focus runs and source maps enabled.

Official sources

  1. License: ISC
  2. Project website
  3. README
  4. Releases
  5. repository-settings/app on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/repository-settings-app.svg)](https://hysenlabs.com/projects/repository-settings-app)

Was this useful?