Skip to content

fix(rulesets): ignore omitted parameters that hold the GitHub default - #1103

Open
lmbaschiera wants to merge 2 commits into
github-community-projects:main-enterprisefrom
lmbaschiera:lmbaschiera/ruleset-param-defaults
Open

lmbaschiera wants to merge 2 commits into
github-community-projects:main-enterprisefrom
lmbaschiera:lmbaschiera/ruleset-param-defaults

Conversation

@lmbaschiera

@lmbaschiera lmbaschiera commented Oct 5, 2026 •

Copy link
Copy Markdown

Problem

When a ruleset is written without some rule parameters, GitHub fills them in and returns them on every GET:

Rule Parameter Value GitHub fills in
pull_request required_reviewers []
pull_request require_extra_approval_for_unattributed_changes true
required_status_checks do_not_enforce_on_create false
pull_request dismissal_restriction { enabled: false, allowed_actors: [] }

dismissal_restriction was added at review: another 3.0.0 user saw GitHub fill it in on 27 pull_request rules. The orgs we observed don't return it.

compareDeep counts any parameters key that's present in GitHub and missing from config as a deletion; only allowed_merge_methods is exempt, via PARAM_DELETION_IGNORE. So a config that never declared these parameters reports Changes found on every sync, and every ruleset with a pull_request or required_status_checks rule is PUT on every cycle.

We hit this upgrading to 3.0.0. A NOP full sync planned a PUT of every such org ruleset on every cycle, even though the PUT bodies matched the live rulesets apart from these defaults. The defaults were confirmed against rulesets that safe-settings itself had written without these keys: they read back with exactly the values above.

Fix

Skip the deletion only when GitHub's value equals the default (PARAM_DELETION_DEFAULTS, compared with the existing stableStringify). Omitting a parameter that GitHub holds at a different value is still a deletion. That keeps the existing required_reviewers removal detection intact (Ruleset Compare detects required_reviewers removal without bypass_actors churn), which is why these keys aren't simply added to PARAM_DELETION_IGNORE.

Tests

Two new cases in test/unit/lib/mergeDeep.test.js:

  • No churn on defaults: a ruleset whose live pull_request and required_status_checks rules carry the defaults, compared with a config that omits them, reports no changes. This fails before the fix.
  • Non-defaults still detected: the same comparison with require_extra_approval_for_unattributed_changes: false and do_not_enforce_on_create: true in GitHub still reports both as deletions.

npm run test:unit passes (1006 tests), and the changed lines are clean under eslint and standard.

🤖 Generated with Claude Code

When a ruleset is written without some rule parameters, GitHub fills
them in: required_reviewers: [] and
require_extra_approval_for_unattributed_changes: true on pull_request,
and do_not_enforce_on_create: false on required_status_checks.
compareDeep counts any parameter that is present in GitHub and missing
from config as a deletion, so a config that never declared these
reports changes on every sync and every ruleset with those rules is
PUT each cycle.

Skip the deletion only when GitHub's value equals that default.
Omitting a parameter that GitHub holds at a different value is still a
deletion, so removing real required_reviewers from config is still
detected.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@lmbaschiera
lmbaschiera force-pushed the lmbaschiera/ruleset-param-defaults branch from d364a9a to 002df69 Compare October 5, 2026 19:18
@tdabasinskas

tdabasinskas commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

We hit the same thing upgrading to 3.0.0. Could you add dismissal_restriction to PARAM_DELETION_DEFAULTS? GitHub fills it in on pull_request rules when config omits it:

dismissal_restriction: { enabled: false, allowed_actors: [] }

Our NOP plan reports it as a deletion on number of pull_request rules across multiple repos, next to the required_reviewers and require_extra_approval_for_unattributed_changes rows this PR already handles. Every deleted value in our plan is one of these defaults, so with this entry added our plan has no ruleset changes left.

…ault

GitHub fills in dismissal_restriction: { enabled: false,
allowed_actors: [] } on pull_request rules when config omits it,
reported on github-community-projects#1103 for 27 rules in another org. Add it to
PARAM_DELETION_DEFAULTS so that value is not planned as a deletion.
A restriction that is enabled or lists actors is still a deletion.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@lmbaschiera

Copy link
Copy Markdown
Author

I've added dismissal_restriction to the defaults in 44df697, with test coverage both ways: left out of config at { enabled: false, allowed_actors: [] }, it no longer shows up as a change. If a rule actually restricts dismissals, it's still flagged.

I couldn't verify the default on our side, though. None of our rulesets return dismissal_restriction at all, so I went with the value from your plan. It matches the published schema, and since only an exact match is skipped, the worst case if GitHub ever fills in something different is that it gets reported as a deletion, the same as before this PR.

This branch has not been deployed

No deployments
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.

2 participants