Repository: hub4j/github-api
Pull request #1897 (2024-07-15 08:52:24)

Add functionality to get active rules for a branch
# Description

Add methods to get all active rules for a branch.

# Before submitting a PR:

- [x] Changes must not break binary backwards compatibility. If you are unclear on how to make the change you think is needed while maintaining backward compatibility, [CONTRIBUTING.md](CONTRIBUTING.md) for details.
- [x] Add JavaDocs and other comments explaining the behavior. 
- [x] When adding or updating methods that fetch entities, add `@link` JavaDoc entries to the relevant documentation on https://docs.github.com/en/rest . 
- [x] Add tests that cover any added or changed code. This generally requires capturing snapshot test data. See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
- [x] Run `mvn -D enable-ci clean install site` locally. If this command doesn't succeed, your change will not pass CI.
- [x] Push your changes to a branch other than `main`. You will create your PR from that branch.

# When creating a PR: 

- [x] Fill in the "Description" above with clear summary of the changes. This includes:
  - [x] If this PR fixes one or more issues, include "Fixes #<issue number>" lines for each issue. 
  - [x] Provide links to relevant documentation on https://docs.github.com/en/rest where possible. If not including links, explain why not.
- [x] All lines of new code should be covered by tests as reported by code coverage. Any lines that are not covered must have PR comments explaining why they cannot be covered. For example, "Reaching this particular exception is hard and is not a particular common scenario."
- [x] Enable "Allow edits from maintainers".


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/hub4j/github-api/pull/1897?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hub4j) Report
Attention: Patch coverage is `92.91339%` with `9 lines` in your changes missing coverage. Please review.
> Project coverage is 81.25%. Comparing base [(`cab9bbb`)](https://app.codecov.io/gh/hub4j/github-api/commit/cab9bbb8cb37599362cb37f0c278ab262298c59b?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hub4j) to head [(`e57d50c`)](https://app.codecov.io/gh/hub4j/github-api/commit/e57d50c15c435fdb725e9220e78734d2f0ea2062?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hub4j).

| [Files](https://app.codecov.io/gh/hub4j/github-api/pull/1897?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hub4j) | Patch % | Lines |
|---|---|---|
| [...main/java/org/kohsuke/github/GHRepositoryRule.java](https://app.codecov.io/gh/hub4j/github-api/pull/1897?src=pr&el=tree&filepath=src%2Fmain%2Fjava%2Forg%2Fkohsuke%2Fgithub%2FGHRepositoryRule.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hub4j#diff-c3JjL21haW4vamF2YS9vcmcva29oc3VrZS9naXRodWIvR0hSZXBvc2l0b3J5UnVsZS5qYXZh) | 92.68% | [8 Missing and 1 partial :warning: ](https://app.codecov.io/gh/hub4j/github-api/pull/1897?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hub4j) |

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff              @@
##               main    #1897      +/-   ##
============================================
+ Coverage     81.05%   81.25%   +0.20%     
- Complexity     2442     2449       +7     
============================================
  Files           237      238       +1     
  Lines          7342     7469     +127     
  Branches        398      399       +1     
============================================
+ Hits           5951     6069     +118     
- Misses         1145     1153       +8     
- Partials        246      247       +1     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/hub4j/github-api/pull/1897?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hub4j).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hub4j).

ihrigb: @bitwiseman I will take care of your suggestions.

As of the Parameter vs. Polymorphism topic I had to thoughts about it as well. The parameter way turned out to be more flexible, if GitHub does any change to the API (not sure, if that would happen with the current version being almost two years old). Using polymorphism would result in weird Java code with `instanceof` stuff and casting types. Happy to discuss this either way.

Patch:
diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java
index e854e618e..9dbbb49eb 100644
--- a/src/main/java/org/kohsuke/github/GHRepository.java
+++ b/src/main/java/org/kohsuke/github/GHRepository.java
@@ -1007,7 +1007,7 @@ public class GHRepository extends GHObject {
 
     /**
      * Lists all
-     * <a href="https://help.github.com/articles/assigning-issues-and-pull-requests-to-other-github-users/">the
+     * <a href= "https://help.github.com/articles/assigning-issues-and-pull-requests-to-other-github-users/">the
      * available assignees</a> to which issues may be assigned.
      *
      * @return the paged iterable
@@ -2222,7 +2222,7 @@ public class GHRepository extends GHObject {
      * @return check runs for given ref
      * @throws IOException
      *             the io exception
-     * @see <a href="https://developer.github.com/v3/checks/runs/#list-check-runs-for-a-specific-ref">List check runs
+     * @see <a href= "https://developer.github.com/v3/checks/runs/#list-check-runs-for-a-specific-ref">List check runs
      *      for a specific ref</a>
      */
     public PagedIterable<GHCheckRun> getCheckRuns(String ref) throws IOException {
@@ -2242,7 +2242,7 @@ public class GHRepository extends GHObject {
      * @return check runs for the given ref
      * @throws IOException
      *             the io exception
-     * @see <a href="https://developer.github.com/v3/checks/runs/#list-check-runs-for-a-specific-ref">List check runs
+     * @see <a href= "https://developer.github.com/v3/checks/runs/#list-check-runs-for-a-specific-ref">List check runs
      *      for a specific ref</a>
      */
     public PagedIterable<GHCheckRun> getCheckRuns(String ref, Map<String, Object> params) throws IOException {
@@ -3568,7 +3568,8 @@ public class GHRepository extends GHObject {
 
         // We don't use the URL provided in the JSON because it is not reliable:
         // 1. There is bug in Push event payloads that returns the wrong url.
-        // For Push event repository records, they take the form "https://github.com/{fullName}".
+        // For Push event repository records, they take the form
+        // "https://github.com/{fullName}".
         // All other occurrences of "url" take the form "https://api.github.com/...".
         // 2. For Installation event payloads, the URL is not provided at all.
 
@@ -3649,6 +3650,23 @@ public class GHRepository extends GHObject {
                 .fetch(GHRepositoryTrafficTopReferralSources[].class));
     }
 
+    /**
+     * Get all active rules that apply to the specified branch
+     * (https://docs.github.com/en/rest/repos/rules?apiVersion=2022-11-28#get-rules-for-a-branch).
+     *
+     * @param branch
+     *            the branch
+     * @return the rules for branch
+     * @throws IOException
+     *             the io exception
+     */
+    public PagedIterable<GHRepositoryRule> listRulesForBranch(String branch) throws IOException {
+        return root().createRequest()
+                .method("GET")
+                .withUrlPath(getApiTailUrl("/rules/branches/" + branch))
+                .toIterable(GHRepositoryRule[].class, null);
+    }
+
     /**
      * A {@link GHRepositoryBuilder} that allows multiple properties to be updated per request.
      *
diff --git a/src/main/java/org/kohsuke/github/GHRepositoryRule.java b/src/main/java/org/kohsuke/github/GHRepositoryRule.java
new file mode 100644
index 000000000..0c1b9c5d5
--- /dev/null
+++ b/src/main/java/org/kohsuke/github/GHRepositoryRule.java
@@ -0,0 +1,610 @@
+package org.kohsuke.github;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonNode;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.kohsuke.github.internal.EnumUtils;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * Represents a repository rule.
+ */
+@SuppressFBWarnings(value = { "UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD" },
+        justification = "JSON API")
+public class GHRepositoryRule extends GitHubInteractiveObject {
+    private String type;
+    private String rulesetSourceType;
+    private String rulesetSource;
+    private long rulesetId;
+    private Map<String, JsonNode> parameters;
+
+    /**
+     * Gets the type.
+     *
+     * @return the type
+     */
+    public Type getType() {
+        return EnumUtils.getEnumOrDefault(Type.class, this.type, Type.UNKNOWN);
+    }
+
+    /**
+     * Gets the ruleset source type.
+     *
+     * @return the ruleset source type
+     */
+    public RulesetSourceType getRulesetSourceType() {
+        return EnumUtils.getEnumOrDefault(RulesetSourceType.class, this.rulesetSourceType, RulesetSourceType.UNKNOWN);
+    }
+
+    /**
+     * Gets the ruleset source.
+     *
+     * @return the ruleset source
+     */
+    public String getRulesetSource() {
+        return this.rulesetSource;
+    }
+
+    /**
+     * Gets the ruleset id.
+     *
+     * @return the ruleset id
+     */
+    public long getRulesetId() {
+        return this.rulesetId;
+    }
+
+    /**
+     * Gets a parameter. ({@link GHRepositoryRule.Parameters Parameters} provides a list of available parameters.)
+     *
+     * @param parameter
+     *            the parameter
+     * @param <T>
+     *            the type of the parameter
+     * @return the parameters
+     * @throws IOException
+     *             if an I/O error occurs
+     */
+    public <T> Optional<T> getParameter(Parameter<T> parameter) throws IOException {
+        if (this.parameters == null) {
+            return Optional.empty();
+        }
+        JsonNode jsonNode = this.parameters.get(parameter.getKey());
+        if (jsonNode == null) {
+            return Optional.empty();
+        }
+        return Optional.ofNullable(parameter.apply(jsonNode, root()));
+    }
+
+    /**
+     * The type of the ruleset.
+     */
+    public static enum Type {
+        /**
+         * unknown
+         */
+        UNKNOWN,
+
+        /**
+         * creation
+         */
+        CREATION,
+
+        /**
+         * update
+         */
+        UPDATE,
+
+        /**
+         * deletion
+         */
+        DELETION,
+
+        /**
+         * required_linear_history
+         */
+        REQUIRED_LINEAR_HISTORY,
+
+        /**
+         * required_deployments
+         */
+        REQUIRED_DEPLOYMENTS,
+
+        /**
+         * required_signatures
+         */
+        REQUIRED_SIGNATURES,
+
+        /**
+         * pull_request
+         */
+        PULL_REQUEST,
+
+        /**
+         * required_status_checks
+         */
+        REQUIRED_STATUS_CHECKS,
+
+        /**
+         * non_fast_forward
+         */
+        NON_FAST_FORWARD,
+
+        /**
+         * commit_message_pattern
+         */
+        COMMIT_MESSAGE_PATTERN,
+
+        /**
+         * commit_author_email_pattern
+         */
+        COMMIT_AUTHOR_EMAIL_PATTERN,
+
+        /**
+         * committer_email_pattern
+         */
+        COMMITTER_EMAIL_PATTERN,
+
+        /**
+         * branch_name_pattern
+         */
+        BRANCH_NAME_PATTERN,
+
+        /**
+         * tag_name_pattern
+         */
+        TAG_NAME_PATTERN,
+
+        /**
+         * workflows
+         */
+        WORKFLOWS,
+
+        /**
+         * code_scanning
+         */
+        CODE_SCANNING
+    }
+
+    /**
+     * The source of the ruleset type.
+     */
+    public enum RulesetSourceType {
+        /**
+         * unknown
+         */
+        UNKNOWN,
+
+        /**
+         * Repository
+         */
+        REPOSITORY,
+
+        /**
+         * Organization
+         */
+        ORGANIZATION
+    }
+
+    /**
+     * Available parameters for a ruleset.
+     */
+    public interface Parameters {
+        /**
+         * update_allows_fetch_and_merge parameter
+         */
+        public static final BooleanParameter UPDATE_ALLOWS_FETCH_AND_MERGE = new BooleanParameter(
+                "update_allows_fetch_and_merge");
+        /**
+         * required_deployment_environments parameter
+         */
+        public static final ListParameter<String> REQUIRED_DEPLOYMENT_ENVIRONMENTS = new ListParameter<String>(
+                "required_deployment_environments") {
+            @Override
+            TypeReference<List<String>> getType() {
+                return new TypeReference<List<String>>() {
+                };
+            }
+        };
+        /**
+         * dismiss_stale_reviews_on_push parameter
+         */
+        public static final BooleanParameter DISMISS_STALE_REVIEWS_ON_PUSH = new BooleanParameter(
+                "dismiss_stale_reviews_on_push");
+        /**
+         * require_code_owner_review parameter
+         */
+        public static final BooleanParameter REQUIRE_CODE_OWNER_REVIEW = new BooleanParameter(
+                "require_code_owner_review");
+        /**
+         * require_last_push_approval parameter
+         */
+        public static final BooleanParameter REQUIRE_LAST_PUSH_APPROVAL = new BooleanParameter(
+                "require_last_push_approval");
+        /**
+         * required_approving_review_count parameter
+         */
+        public static final IntegerParameter REQUIRED_APPROVING_REVIEW_COUNT = new IntegerParameter(
+                "required_approving_review_count");
+        /**
+         * required_review_thread_resolution parameter
+         */
+        public static final BooleanParameter REQUIRED_REVIEW_THREAD_RESOLUTION = new BooleanParameter(
+                "required_review_thread_resolution");
+        /**
+         * required_status_checks parameter
+         */
+        public static final ListParameter<StatusCheckConfiguration> REQUIRED_STATUS_CHECKS = new ListParameter<StatusCheckConfiguration>(
+                "required_status_checks") {
+            @Override
+            TypeReference<List<StatusCheckConfiguration>> getType() {
+                return new TypeReference<List<StatusCheckConfiguration>>() {
+                };
+            }
+        };
+        /**
+         * strict_required_status_checks_policy parameter
+         */
+        public static final BooleanParameter STRICT_REQUIRED_STATUS_CHECKS_POLICY = new BooleanParameter(
+                "strict_required_status_checks_policy");
+        /**
+         * name parameter
+         */
+        public static final StringParameter NAME = new StringParameter("name");
+        /**
+         * negate parameter
+         */
+        public static final BooleanParameter NEGATE = new BooleanParameter("negate");
+        /**
+         * operator parameter
+         */
+        public static final Parameter<Operator> OPERATOR = new Parameter<Operator>("operator") {
+            @Override
+            TypeReference<Operator> getType() {
+                return new TypeReference<Operator>() {
+                };
+            }
+        };
+        /**
+         * regex parameter
+         */
+        public static final StringParameter REGEX = new StringParameter("regex");
+        /**
+         * workflows parameter
+         */
+        public static final ListParameter<WorkflowFileReference> WORKFLOWS = new ListParameter<WorkflowFileReference>(
+                "workflows") {
+            @Override
+            TypeReference<List<WorkflowFileReference>> getType() {
+                return new TypeReference<List<WorkflowFileReference>>() {
+                };
+            }
+        };
+        /**
+         * code_scanning_tools parameter
+         */
+        public static final ListParameter<CodeScanningTool> CODE_SCANNING_TOOLS = new ListParameter<CodeScanningTool>(
+                "code_scanning_tools") {
+            @Override
+            TypeReference<List<CodeScanningTool>> getType() {
+                return new TypeReference<List<CodeScanningTool>>() {
+                };
+            }
+        };
+    }
+
+    /**
+     * Basic parameter for a ruleset.
+     *
+     * @param <T>
+     *            the type of the parameter
+     */
+    public abstract static class Parameter<T> {
+
+        private final String key;
+
+        /**
+         * Get the parameter type reference for type mapping.
+         */
+        abstract TypeReference<T> getType();
+
+        /**
+         * Instantiates a new parameter.
+         *
+         * @param key
+         *            the key
+         */
+        protected Parameter(String key) {
+            this.key = key;
+        }
+
+        /**
+         * Gets the key.
+         *
+         * @return the key
+         */
+        String getKey() {
+            return this.key;
+        }
+
+        T apply(JsonNode jsonNode, GitHub root) throws IOException {
+            if (jsonNode == null) {
+                return null;
+            }
+            return GitHubClient.getMappingObjectReader(root).forType(this.getType()).readValue(jsonNode);
+        }
+    }
+
+    /**
+     * String parameter for a ruleset.
+     */
+    public static class StringParameter extends Parameter<String> {
+        /**
+         * Instantiates a new string parameter.
+         *
+         * @param key
+         *            the key
+         */
+        public StringParameter(String key) {
+            super(key);
+        }
+
+        @Override
+        TypeReference<String> getType() {
+            return new TypeReference<String>() {
+            };
+        }
+    }
+
+    /**
+     * Boolean parameter for a ruleset.
+     */
+    public static class BooleanParameter extends Parameter<Boolean> {
+        /**
+         * Instantiates a new boolean parameter.
+         *
+         * @param key
+         *            the key
+         */
+        public BooleanParameter(String key) {
+            super(key);
+        }
+
+        @Override
+        TypeReference<Boolean> getType() {
+            return new TypeReference<Boolean>() {
+            };
+        }
+    }
+
+    /**
+     * Integer parameter for a ruleset.
+     */
+    public static class IntegerParameter extends Parameter<Integer> {
+        /**
+         * Instantiates a new integer parameter.
+         *
+         * @param key
+         *            the key
+         */
+        public IntegerParameter(String key) {
+            super(key);
+        }
+
+        @Override
+        TypeReference<Integer> getType() {
+            return new TypeReference<Integer>() {
+            };
+        }
+    }
+
+    /**
+     * List parameter for a ruleset.
+     *
+     * @param <T>
+     *            the type of the list
+     */
+    public abstract static class ListParameter<T> extends Parameter<List<T>> {
+        /**
+         * Instantiates a new list parameter.
+         *
+         * @param key
+         *            the key
+         */
+        public ListParameter(String key) {
+            super(key);
+        }
+    }
+
+    /**
+     * Status check configuration parameter.
+     */
+    public static class StatusCheckConfiguration {
+        private String context;
+        private Integer integrationId;
+
+        /**
+         * Gets the context.
+         *
+         * @return the context
+         */
+        public String getContext() {
+            return this.context;
+        }
+
+        /**
+         * Gets the integration id.
+         *
+         * @return the integration id
+         */
+        public Integer getIntegrationId() {
+            return this.integrationId;
+        }
+    }
+
+    /**
+     * Operator parameter.
+     */
+    public static enum Operator {
+        /**
+         * starts_with
+         */
+        STARTS_WITH,
+
+        /**
+         * ends_with
+         */
+        ENDS_WITH,
+
+        /**
+         * contains
+         */
+        CONTAINS,
+
+        /**
+         * regex
+         */
+        REGEX
+    }
+
+    /**
+     * Workflow file reference parameter.
+     */
+    public static class WorkflowFileReference {
+        private String path;
+        private String ref;
+        private long repositoryId;
+        private String sha;
+
+        /**
+         * Gets the path.
+         *
+         * @return the path
+         */
+        public String getPath() {
+            return this.path;
+        }
+
+        /**
+         * Gets the ref.
+         *
+         * @return the ref
+         */
+        public String getRef() {
+            return this.ref;
+        }
+
+        /**
+         * Gets the repository id.
+         *
+         * @return the repository id
+         */
+        public long getRepositoryId() {
+            return this.repositoryId;
+        }
+
+        /**
+         * Gets the sha.
+         *
+         * @return the sha
+         */
+        public String getSha() {
+            return this.sha;
+        }
+    }
+
+    /**
+     * Code scanning tool parameter.
+     */
+    public static class CodeScanningTool {
+        private AlertsThreshold alertsThreshold;
+        private SecurityAlertsThreshold securityAlertsThreshold;
+        private String tool;
+
+        /**
+         * Gets the alerts threshold.
+         *
+         * @return the alerts threshold
+         */
+        public AlertsThreshold getAlertsThreshold() {
+            return this.alertsThreshold;
+        }
+
+        /**
+         * Gets the security alerts threshold.
+         *
+         * @return the security alerts threshold
+         */
+        public SecurityAlertsThreshold getSecurityAlertsThreshold() {
+            return this.securityAlertsThreshold;
+        }
+
+        /**
+         * Gets the tool.
+         *
+         * @return the tool
+         */
+        public String getTool() {
+            return this.tool;
+        }
+    }
+
+    /**
+     * Alerts threshold parameter.
+     */
+    public static enum AlertsThreshold {
+        /**
+         * none
+         */
+        NONE,
+
+        /**
+         * errors
+         */
+        ERRORS,
+
+        /**
+         * errors_and_warnings
+         */
+        ERRORS_AND_WARNINGS,
+
+        /**
+         * all
+         */
+        ALL
+    }
+
+    /**
+     * Security alerts threshold parameter.
+     */
+    public static enum SecurityAlertsThreshold {
+        /**
+         * none
+         */
+        NONE,
+
+        /**
+         * critical
+         */
+        CRITICAL,
+
+        /**
+         * high_or_higher
+         */
+        HIGH_OR_HIGHER,
+
+        /**
+         * medium_or_higher
+         */
+        MEDIUM_OR_HIGHER,
+
+        /**
+         * all
+         */
+        ALL
+    }
+}


Test patch:
diff --git a/src/test/java/org/kohsuke/github/GHRepositoryRuleTest.java b/src/test/java/org/kohsuke/github/GHRepositoryRuleTest.java
new file mode 100644
index 000000000..9f176883e
--- /dev/null
+++ b/src/test/java/org/kohsuke/github/GHRepositoryRuleTest.java
@@ -0,0 +1,107 @@
+package org.kohsuke.github;
+
+import org.junit.Test;
+import org.kohsuke.github.GHRepositoryRule.AlertsThreshold;
+import org.kohsuke.github.GHRepositoryRule.CodeScanningTool;
+import org.kohsuke.github.GHRepositoryRule.Operator;
+import org.kohsuke.github.GHRepositoryRule.Parameter;
+import org.kohsuke.github.GHRepositoryRule.Parameters;
+import org.kohsuke.github.GHRepositoryRule.SecurityAlertsThreshold;
+import org.kohsuke.github.GHRepositoryRule.StatusCheckConfiguration;
+import org.kohsuke.github.GHRepositoryRule.StringParameter;
+import org.kohsuke.github.GHRepositoryRule.WorkflowFileReference;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
+
+/**
+ * Test class for GHRepositoryRule.
+ */
+public class GHRepositoryRuleTest {
+    /**
+     * Test to cover the constructor of the Parameters class.
+     */
+    @Test
+    public void testParameters() {
+        assertThat(Parameters.REQUIRED_DEPLOYMENT_ENVIRONMENTS.getType(), is(notNullValue()));
+        assertThat(Parameters.REQUIRED_STATUS_CHECKS.getType(), is(notNullValue()));
+        assertThat(Parameters.OPERATOR.getType(), is(notNullValue()));
+        assertThat(Parameters.WORKFLOWS.getType(), is(notNullValue()));
+        assertThat(Parameters.CODE_SCANNING_TOOLS.getType(), is(notNullValue()));
+        assertThat(new StringParameter("any").getType(), is(notNullValue()));
+    }
+
+    /**
+     * Tests to cover StatusCheckConfiguration class.
+     */
+    @Test
+    public void testStatusCheckConfiguration() {
+        StatusCheckConfiguration statusCheckConfiguration = new StatusCheckConfiguration();
+        statusCheckConfiguration = new StatusCheckConfiguration();
+        assertThat(statusCheckConfiguration.getContext(), is(nullValue()));
+        assertThat(statusCheckConfiguration.getIntegrationId(), is(nullValue()));
+    }
+
+    /**
+     * Tests to cover WorkflowFileReference class.
+     */
+    @Test
+    public void testWorkflowFileReference() {
+        WorkflowFileReference workflowFileReference = new WorkflowFileReference();
+        assertThat(workflowFileReference.getPath(), is(nullValue()));
+        assertThat(workflowFileReference.getRef(), is(nullValue()));
+        assertThat(workflowFileReference.getRepositoryId(), is(equalTo(0L)));
+        assertThat(workflowFileReference.getSha(), is(nullValue()));
+    }
+
+    /**
+     * Tests to cover CodeScanningTool class.
+     */
+    @Test
+    public void testCodeScanningTool() {
+        CodeScanningTool codeScanningTool = new CodeScanningTool();
+        codeScanningTool = new CodeScanningTool();
+        assertThat(codeScanningTool.getAlertsThreshold(), is(nullValue()));
+        assertThat(codeScanningTool.getSecurityAlertsThreshold(), is(nullValue()));
+        assertThat(codeScanningTool.getTool(), is(nullValue()));
+    }
+
+    /**
+     * Tests to cover AlertsThreshold enum.
+     */
+    @Test
+    public void testAlertsThreshold() {
+        assertThat(AlertsThreshold.ERRORS, is(notNullValue()));
+    }
+
+    /**
+     * Tests to cover SecurityAlertsThreshold enum.
+     */
+    @Test
+    public void testSecurityAlertsThreshold() {
+        assertThat(SecurityAlertsThreshold.HIGH_OR_HIGHER, is(notNullValue()));
+    }
+
+    /**
+     * Tests to cover Operator enum.
+     */
+    @Test
+    public void testOperator() {
+        assertThat(Operator.ENDS_WITH, is(notNullValue()));
+    }
+
+    /**
+     * Tests that apply on null JsonNode returns null.
+     *
+     * @throws Exception
+     *             if something goes wrong.
+     */
+    @Test
+    public void testParameterReturnsNullOnNullArg() throws Exception {
+        Parameter<String> parameter = new StringParameter("any");
+        assertThat(parameter.apply(null, null), is(nullValue()));
+    }
+}
diff --git a/src/test/java/org/kohsuke/github/GHRepositoryTest.java b/src/test/java/org/kohsuke/github/GHRepositoryTest.java
index 5e1626bec..839f7f188 100644
--- a/src/test/java/org/kohsuke/github/GHRepositoryTest.java
+++ b/src/test/java/org/kohsuke/github/GHRepositoryTest.java
@@ -493,7 +493,8 @@ public class GHRepositoryTest extends AbstractGitHubWireMockTest {
         }
 
         if (false) {
-            // can't easily test this; there's no private repository visible to the test user
+            // can't easily test this; there's no private repository visible to the test
+            // user
             r = gitHub.getOrganization("cloudbees").getRepository("private-repo-not-writable-by-me");
             try {
                 r.getPermission("jglick");
@@ -1159,7 +1160,8 @@ public class GHRepositoryTest extends AbstractGitHubWireMockTest {
         assertThat(ghRefsWithPrefix.get(0).getRef(), equalTo(ghRefs.get(0).getRef()));
 
         // git/refs/heads/gh-pages
-        // passing a specific ref to listRefs will fail to parse due to returning a single item not an array
+        // passing a specific ref to listRefs will fail to parse due to returning a
+        // single item not an array
         try {
             ghRefs = repo.listRefs("heads/gh-pages").toList();
             fail();
@@ -1849,6 +1851,45 @@ public class GHRepositoryTest extends AbstractGitHubWireMockTest {
         assertThat(referralSources.size(), greaterThan(0));
     }
 
+    /**
+     * Test getRulesForBranch.
+     *
+     * @throws Exception
+     *             the exception
+     */
+    @Test
+    public void testGetRulesForBranch() throws Exception {
+        GHRepository repository = gitHub.getRepository("ihrigb/node-doorbird");
+        List<GHRepositoryRule> rules = repository.listRulesForBranch("main").toList();
+        assertThat(rules.size(), equalTo(3));
+
+        GHRepositoryRule rule = rules.get(0);
+        assertThat(rule.getType(), is(equalTo(GHRepositoryRule.Type.DELETION)));
+        assertThat(rule.getRulesetSourceType(), is(equalTo(GHRepositoryRule.RulesetSourceType.REPOSITORY)));
+        assertThat(rule.getRulesetSource(), is(equalTo("ihrigb/node-doorbird")));
+        assertThat(rule.getRulesetId(), is(equalTo(1170520L)));
+
+        rule = rules.get(1);
+        assertThat(rule.getType(), is(equalTo(GHRepositoryRule.Type.NON_FAST_FORWARD)));
+        assertThat(rule.getRulesetSourceType(), is(equalTo(GHRepositoryRule.RulesetSourceType.REPOSITORY)));
+        assertThat(rule.getRulesetSource(), is(equalTo("ihrigb/node-doorbird")));
+        assertThat(rule.getRulesetId(), is(equalTo(1170520L)));
+
+        rule = rules.get(2);
+        assertThat(rule.getType(), is(equalTo(GHRepositoryRule.Type.PULL_REQUEST)));
+        assertThat(rule.getRulesetSourceType(), is(equalTo(GHRepositoryRule.RulesetSourceType.REPOSITORY)));
+        assertThat(rule.getRulesetSource(), is(equalTo("ihrigb/node-doorbird")));
+        assertThat(rule.getRulesetId(), is(equalTo(1170520L)));
+
+        // check parameters
+        assertThat(rule.getParameter(GHRepositoryRule.Parameters.NEGATE).isPresent(), is(equalTo(false)));
+        assertThat(rule.getParameter(GHRepositoryRule.Parameters.REQUIRED_APPROVING_REVIEW_COUNT).get(),
+                is(equalTo(1)));
+        assertThat(rule.getParameter(GHRepositoryRule.Parameters.DISMISS_STALE_REVIEWS_ON_PUSH).get(),
+                is(equalTo(true)));
+        assertThat(rule.getParameter(GHRepositoryRule.Parameters.REQUIRE_CODE_OWNER_REVIEW).get(), is(equalTo(false)));
+    }
+
     private void verifyEmptyResult(PagedSearchIterable<GHPullRequest> searchResult) {
         assertThat(searchResult.getTotalCount(), is(0));
     }
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/__files/1-user.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/__files/1-user.json
new file mode 100644
index 000000000..4e07e04a7
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/__files/1-user.json
@@ -0,0 +1,34 @@
+{
+  "login": "ihrigb",
+  "id": 3423161,
+  "node_id": "MDQ6VXNlcjM0MjMxNjE=",
+  "avatar_url": "https://avatars.githubusercontent.com/u/3423161?v=4",
+  "gravatar_id": "",
+  "url": "https://api.github.com/users/ihrigb",
+  "html_url": "https://github.com/ihrigb",
+  "followers_url": "https://api.github.com/users/ihrigb/followers",
+  "following_url": "https://api.github.com/users/ihrigb/following{/other_user}",
+  "gists_url": "https://api.github.com/users/ihrigb/gists{/gist_id}",
+  "starred_url": "https://api.github.com/users/ihrigb/starred{/owner}{/repo}",
+  "subscriptions_url": "https://api.github.com/users/ihrigb/subscriptions",
+  "organizations_url": "https://api.github.com/users/ihrigb/orgs",
+  "repos_url": "https://api.github.com/users/ihrigb/repos",
+  "events_url": "https://api.github.com/users/ihrigb/events{/privacy}",
+  "received_events_url": "https://api.github.com/users/ihrigb/received_events",
+  "type": "User",
+  "site_admin": false,
+  "name": "Benjamin Ihrig",
+  "company": "SAP SE",
+  "blog": "",
+  "location": "Germany",
+  "email": null,
+  "hireable": null,
+  "bio": "Working at @SAP.\r\nDoing software projects for a volunteer fire brigade in free time. Smart home enthusiast. Scuba diving instructor.",
+  "twitter_username": null,
+  "public_repos": 27,
+  "public_gists": 1,
+  "followers": 5,
+  "following": 20,
+  "created_at": "2013-01-30T02:20:16Z",
+  "updated_at": "2024-07-08T08:46:37Z"
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/__files/2-r_i_node-doorbird.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/__files/2-r_i_node-doorbird.json
new file mode 100644
index 000000000..22b2e05ec
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/__files/2-r_i_node-doorbird.json
@@ -0,0 +1,150 @@
+{
+  "id": 404133501,
+  "node_id": "MDEwOlJlcG9zaXRvcnk0MDQxMzM1MDE=",
+  "name": "node-doorbird",
+  "full_name": "ihrigb/node-doorbird",
+  "private": false,
+  "owner": {
+    "login": "ihrigb",
+    "id": 3423161,
+    "node_id": "MDQ6VXNlcjM0MjMxNjE=",
+    "avatar_url": "https://avatars.githubusercontent.com/u/3423161?v=4",
+    "gravatar_id": "",
+    "url": "https://api.github.com/users/ihrigb",
+    "html_url": "https://github.com/ihrigb",
+    "followers_url": "https://api.github.com/users/ihrigb/followers",
+    "following_url": "https://api.github.com/users/ihrigb/following{/other_user}",
+    "gists_url": "https://api.github.com/users/ihrigb/gists{/gist_id}",
+    "starred_url": "https://api.github.com/users/ihrigb/starred{/owner}{/repo}",
+    "subscriptions_url": "https://api.github.com/users/ihrigb/subscriptions",
+    "organizations_url": "https://api.github.com/users/ihrigb/orgs",
+    "repos_url": "https://api.github.com/users/ihrigb/repos",
+    "events_url": "https://api.github.com/users/ihrigb/events{/privacy}",
+    "received_events_url": "https://api.github.com/users/ihrigb/received_events",
+    "type": "User",
+    "site_admin": false
+  },
+  "html_url": "https://github.com/ihrigb/node-doorbird",
+  "description": "Node client library for Doorbird's HTTP API.",
+  "fork": false,
+  "url": "https://api.github.com/repos/ihrigb/node-doorbird",
+  "forks_url": "https://api.github.com/repos/ihrigb/node-doorbird/forks",
+  "keys_url": "https://api.github.com/repos/ihrigb/node-doorbird/keys{/key_id}",
+  "collaborators_url": "https://api.github.com/repos/ihrigb/node-doorbird/collaborators{/collaborator}",
+  "teams_url": "https://api.github.com/repos/ihrigb/node-doorbird/teams",
+  "hooks_url": "https://api.github.com/repos/ihrigb/node-doorbird/hooks",
+  "issue_events_url": "https://api.github.com/repos/ihrigb/node-doorbird/issues/events{/number}",
+  "events_url": "https://api.github.com/repos/ihrigb/node-doorbird/events",
+  "assignees_url": "https://api.github.com/repos/ihrigb/node-doorbird/assignees{/user}",
+  "branches_url": "https://api.github.com/repos/ihrigb/node-doorbird/branches{/branch}",
+  "tags_url": "https://api.github.com/repos/ihrigb/node-doorbird/tags",
+  "blobs_url": "https://api.github.com/repos/ihrigb/node-doorbird/git/blobs{/sha}",
+  "git_tags_url": "https://api.github.com/repos/ihrigb/node-doorbird/git/tags{/sha}",
+  "git_refs_url": "https://api.github.com/repos/ihrigb/node-doorbird/git/refs{/sha}",
+  "trees_url": "https://api.github.com/repos/ihrigb/node-doorbird/git/trees{/sha}",
+  "statuses_url": "https://api.github.com/repos/ihrigb/node-doorbird/statuses/{sha}",
+  "languages_url": "https://api.github.com/repos/ihrigb/node-doorbird/languages",
+  "stargazers_url": "https://api.github.com/repos/ihrigb/node-doorbird/stargazers",
+  "contributors_url": "https://api.github.com/repos/ihrigb/node-doorbird/contributors",
+  "subscribers_url": "https://api.github.com/repos/ihrigb/node-doorbird/subscribers",
+  "subscription_url": "https://api.github.com/repos/ihrigb/node-doorbird/subscription",
+  "commits_url": "https://api.github.com/repos/ihrigb/node-doorbird/commits{/sha}",
+  "git_commits_url": "https://api.github.com/repos/ihrigb/node-doorbird/git/commits{/sha}",
+  "comments_url": "https://api.github.com/repos/ihrigb/node-doorbird/comments{/number}",
+  "issue_comment_url": "https://api.github.com/repos/ihrigb/node-doorbird/issues/comments{/number}",
+  "contents_url": "https://api.github.com/repos/ihrigb/node-doorbird/contents/{+path}",
+  "compare_url": "https://api.github.com/repos/ihrigb/node-doorbird/compare/{base}...{head}",
+  "merges_url": "https://api.github.com/repos/ihrigb/node-doorbird/merges",
+  "archive_url": "https://api.github.com/repos/ihrigb/node-doorbird/{archive_format}{/ref}",
+  "downloads_url": "https://api.github.com/repos/ihrigb/node-doorbird/downloads",
+  "issues_url": "https://api.github.com/repos/ihrigb/node-doorbird/issues{/number}",
+  "pulls_url": "https://api.github.com/repos/ihrigb/node-doorbird/pulls{/number}",
+  "milestones_url": "https://api.github.com/repos/ihrigb/node-doorbird/milestones{/number}",
+  "notifications_url": "https://api.github.com/repos/ihrigb/node-doorbird/notifications{?since,all,participating}",
+  "labels_url": "https://api.github.com/repos/ihrigb/node-doorbird/labels{/name}",
+  "releases_url": "https://api.github.com/repos/ihrigb/node-doorbird/releases{/id}",
+  "deployments_url": "https://api.github.com/repos/ihrigb/node-doorbird/deployments",
+  "created_at": "2021-09-07T21:58:15Z",
+  "updated_at": "2024-07-01T18:54:00Z",
+  "pushed_at": "2024-07-10T21:44:07Z",
+  "git_url": "git://github.com/ihrigb/node-doorbird.git",
+  "ssh_url": "git@github.com:ihrigb/node-doorbird.git",
+  "clone_url": "https://github.com/ihrigb/node-doorbird.git",
+  "svn_url": "https://github.com/ihrigb/node-doorbird",
+  "homepage": "",
+  "size": 1055,
+  "stargazers_count": 4,
+  "watchers_count": 4,
+  "language": "TypeScript",
+  "has_issues": true,
+  "has_projects": false,
+  "has_downloads": true,
+  "has_wiki": false,
+  "has_pages": false,
+  "has_discussions": false,
+  "forks_count": 2,
+  "mirror_url": null,
+  "archived": false,
+  "disabled": false,
+  "open_issues_count": 5,
+  "license": {
+    "key": "apache-2.0",
+    "name": "Apache License 2.0",
+    "spdx_id": "Apache-2.0",
+    "url": "https://api.github.com/licenses/apache-2.0",
+    "node_id": "MDc6TGljZW5zZTI="
+  },
+  "allow_forking": true,
+  "is_template": false,
+  "web_commit_signoff_required": false,
+  "topics": [
+    "client-library",
+    "doorbell",
+    "doorbird",
+    "library",
+    "smarthome"
+  ],
+  "visibility": "public",
+  "forks": 2,
+  "open_issues": 5,
+  "watchers": 4,
+  "default_branch": "main",
+  "permissions": {
+    "admin": true,
+    "maintain": true,
+    "push": true,
+    "triage": true,
+    "pull": true
+  },
+  "temp_clone_token": "",
+  "allow_squash_merge": true,
+  "allow_merge_commit": true,
+  "allow_rebase_merge": true,
+  "allow_auto_merge": false,
+  "delete_branch_on_merge": false,
+  "allow_update_branch": false,
+  "use_squash_pr_title_as_default": false,
+  "squash_merge_commit_message": "COMMIT_MESSAGES",
+  "squash_merge_commit_title": "COMMIT_OR_PR_TITLE",
+  "merge_commit_message": "PR_TITLE",
+  "merge_commit_title": "MERGE_MESSAGE",
+  "security_and_analysis": {
+    "secret_scanning": {
+      "status": "disabled"
+    },
+    "secret_scanning_push_protection": {
+      "status": "disabled"
+    },
+    "dependabot_security_updates": {
+      "status": "disabled"
+    },
+    "secret_scanning_non_provider_patterns": {
+      "status": "disabled"
+    },
+    "secret_scanning_validity_checks": {
+      "status": "disabled"
+    }
+  },
+  "network_count": 2,
+  "subscribers_count": 6
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/__files/3-r_i_n_rules_branches_main.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/__files/3-r_i_n_rules_branches_main.json
new file mode 100644
index 000000000..82223a475
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/__files/3-r_i_n_rules_branches_main.json
@@ -0,0 +1,27 @@
+[
+  {
+    "type": "deletion",
+    "ruleset_source_type": "Repository",
+    "ruleset_source": "ihrigb/node-doorbird",
+    "ruleset_id": 1170520
+  },
+  {
+    "type": "non_fast_forward",
+    "ruleset_source_type": "Repository",
+    "ruleset_source": "ihrigb/node-doorbird",
+    "ruleset_id": 1170520
+  },
+  {
+    "type": "pull_request",
+    "parameters": {
+      "required_approving_review_count": 1,
+      "dismiss_stale_reviews_on_push": true,
+      "require_code_owner_review": false,
+      "require_last_push_approval": false,
+      "required_review_thread_resolution": false
+    },
+    "ruleset_source_type": "Repository",
+    "ruleset_source": "ihrigb/node-doorbird",
+    "ruleset_id": 1170520
+  }
+]
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/mappings/1-user.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/mappings/1-user.json
new file mode 100644
index 000000000..4bc414dbf
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/mappings/1-user.json
@@ -0,0 +1,48 @@
+{
+  "id": "3db4f955-4396-42bc-9025-19cf605fc06c",
+  "name": "user",
+  "request": {
+    "url": "/user",
+    "method": "GET",
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 200,
+    "bodyFileName": "1-user.json",
+    "headers": {
+      "Date": "Mon, 15 Jul 2024 08:30:49 GMT",
+      "Content-Type": "application/json; charset=utf-8",
+      "Cache-Control": "private, max-age=60, s-maxage=60",
+      "Vary": "Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With",
+      "ETag": "W/\"ddc9069d08e23a7137c1afd3a7582b40343a9531d163859e421e699865eed231\"",
+      "Last-Modified": "Mon, 08 Jul 2024 08:46:37 GMT",
+      "X-OAuth-Scopes": "admin:org, repo",
+      "X-Accepted-OAuth-Scopes": "",
+      "github-authentication-token-expiration": "2024-08-14 08:24:53 UTC",
+      "X-GitHub-Media-Type": "github.v3; format=json",
+      "x-github-api-version-selected": "2022-11-28",
+      "X-RateLimit-Limit": "5000",
+      "X-RateLimit-Remaining": "4986",
+      "X-RateLimit-Reset": "1721035644",
+      "X-RateLimit-Used": "14",
+      "X-RateLimit-Resource": "core",
+      "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset",
+      "Access-Control-Allow-Origin": "*",
+      "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
+      "X-Frame-Options": "deny",
+      "X-Content-Type-Options": "nosniff",
+      "X-XSS-Protection": "0",
+      "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "Content-Security-Policy": "default-src 'none'",
+      "Server": "github.com",
+      "X-GitHub-Request-Id": "2F9F:1AB9D3:A03037B:A25F83C:6694DE39"
+    }
+  },
+  "uuid": "3db4f955-4396-42bc-9025-19cf605fc06c",
+  "persistent": true,
+  "insertionIndex": 1
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/mappings/2-r_i_node-doorbird.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/mappings/2-r_i_node-doorbird.json
new file mode 100644
index 000000000..8345afaed
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/mappings/2-r_i_node-doorbird.json
@@ -0,0 +1,48 @@
+{
+  "id": "348f8bdb-afc0-42cf-8160-bf3bf5596ed7",
+  "name": "repos_ihrigb_node-doorbird",
+  "request": {
+    "url": "/repos/ihrigb/node-doorbird",
+    "method": "GET",
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 200,
+    "bodyFileName": "2-r_i_node-doorbird.json",
+    "headers": {
+      "Date": "Mon, 15 Jul 2024 08:30:49 GMT",
+      "Content-Type": "application/json; charset=utf-8",
+      "Cache-Control": "private, max-age=60, s-maxage=60",
+      "Vary": "Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With",
+      "ETag": "W/\"185e10d64c2a19173cb1150148d87a1c0da1f66d8b553c79689f0a5e73143d30\"",
+      "Last-Modified": "Mon, 01 Jul 2024 18:54:00 GMT",
+      "X-OAuth-Scopes": "admin:org, repo",
+      "X-Accepted-OAuth-Scopes": "repo",
+      "github-authentication-token-expiration": "2024-08-14 08:24:53 UTC",
+      "X-GitHub-Media-Type": "github.v3; format=json",
+      "x-github-api-version-selected": "2022-11-28",
+      "X-RateLimit-Limit": "5000",
+      "X-RateLimit-Remaining": "4984",
+      "X-RateLimit-Reset": "1721035644",
+      "X-RateLimit-Used": "16",
+      "X-RateLimit-Resource": "core",
+      "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset",
+      "Access-Control-Allow-Origin": "*",
+      "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
+      "X-Frame-Options": "deny",
+      "X-Content-Type-Options": "nosniff",
+      "X-XSS-Protection": "0",
+      "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "Content-Security-Policy": "default-src 'none'",
+      "Server": "github.com",
+      "X-GitHub-Request-Id": "442E:34EF67:55A9DC3:56E9441:6694DE39"
+    }
+  },
+  "uuid": "348f8bdb-afc0-42cf-8160-bf3bf5596ed7",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/mappings/3-r_i_n_rules_branches_main.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/mappings/3-r_i_n_rules_branches_main.json
new file mode 100644
index 000000000..8f7a60dd1
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/mappings/3-r_i_n_rules_branches_main.json
@@ -0,0 +1,47 @@
+{
+  "id": "5d5471fe-6842-47d0-876e-0083b8d7708f",
+  "name": "repos_ihrigb_node-doorbird_rules_branches_main",
+  "request": {
+    "url": "/repos/ihrigb/node-doorbird/rules/branches/main",
+    "method": "GET",
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 200,
+    "bodyFileName": "3-r_i_n_rules_branches_main.json",
+    "headers": {
+      "Date": "Mon, 15 Jul 2024 08:30:50 GMT",
+      "Content-Type": "application/json; charset=utf-8",
+      "Cache-Control": "private, max-age=60, s-maxage=60",
+      "Vary": "Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With",
+      "ETag": "W/\"bfdf4f7b088f8bb098a04db8694a3e420c4e6953de47a7a0fb0f1c8f756a1854\"",
+      "X-OAuth-Scopes": "admin:org, repo",
+      "X-Accepted-OAuth-Scopes": "",
+      "github-authentication-token-expiration": "2024-08-14 08:24:53 UTC",
+      "X-GitHub-Media-Type": "github.v3; format=json",
+      "x-github-api-version-selected": "2022-11-28",
+      "X-RateLimit-Limit": "5000",
+      "X-RateLimit-Remaining": "4983",
+      "X-RateLimit-Reset": "1721035644",
+      "X-RateLimit-Used": "17",
+      "X-RateLimit-Resource": "core",
+      "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset",
+      "Access-Control-Allow-Origin": "*",
+      "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
+      "X-Frame-Options": "deny",
+      "X-Content-Type-Options": "nosniff",
+      "X-XSS-Protection": "0",
+      "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "Content-Security-Policy": "default-src 'none'",
+      "Server": "github.com",
+      "X-GitHub-Request-Id": "E229:31B5A3:74633C:759FE7:6694DE39"
+    }
+  },
+  "uuid": "5d5471fe-6842-47d0-876e-0083b8d7708f",
+  "persistent": true,
+  "insertionIndex": 3
+}
\ No newline at end of file