diff --git a/pom.xml b/pom.xml index 798f08c8fd..927b6d1675 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 org.kohsuke cortexapps-github-api - 1.326 + 1.327 GitHub API for Java https://github-api.kohsuke.org/ GitHub API for Java diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 784242672c..aa6d7fcdc0 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -3496,6 +3496,47 @@ public void dispatch(String eventType, @Nullable T clientPayload) throws IOE .send(); } + /** + * Lists the secret scanning alerts for this repository + * + * @return the paged iterable + */ + public PagedIterable listSecretScanningAlerts() { + return listSecretScanningAlerts(Collections.emptyMap()); + } + + /** + * Lists the secret scanning alerts for this repository filtered on the alert state + * + * @param state + * state of the alert + * @return the paged iterable + */ + public PagedIterable listSecretScanningAlerts(GHSecretScanningAlertState state) { + return listSecretScanningAlerts(Collections.singletonMap("state", state.name().toLowerCase())); + } + + private PagedIterable listSecretScanningAlerts(Map filters) { + return new GHSecretScanningAlertsIterable(this, + root().createRequest().withUrlPath(getApiTailUrl("secret-scanning/alerts")).with(filters).build()); + } + + /** + * Get secret scanning alert by number + * + * @param number + * number of the secret scanning alert + * @return the secret scanning alert + * @throws IOException + * the io exception + */ + public GHSecretScanningAlert getSecretScanningAlert(long number) throws IOException { + return root().createRequest() + .withUrlPath(getApiTailUrl("secret-scanning/alerts"), String.valueOf(number)) + .fetch(GHSecretScanningAlert.class) + .wrap(this); + } + private T downloadArchive(@Nonnull String type, @CheckForNull String ref, @Nonnull InputStreamFunction streamFunction) throws IOException { diff --git a/src/main/java/org/kohsuke/github/GHSecretScanningAlert.java b/src/main/java/org/kohsuke/github/GHSecretScanningAlert.java new file mode 100644 index 0000000000..37e23eda70 --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHSecretScanningAlert.java @@ -0,0 +1,205 @@ +package org.kohsuke.github; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + +import java.io.IOException; +import java.net.URL; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +/** + * Secret scanning alert for a repository + * + * + */ +@SuppressFBWarnings(value = { "UUF_UNUSED_FIELD" }, justification = "JSON API") +public class GHSecretScanningAlert extends GHObject { + @JsonIgnore + private GHRepository owner; + private long number; + private String html_url; + private String locations_url; + private GHSecretScanningAlertState state; + private String resolution; + private String resolved_at; + private GHUser resolved_by; + private String secret_type; + private String secret_type_display_name; + private String secret; + + private Boolean push_protection_bypassed; + private GHUser push_protection_bypassed_by; + private String push_protection_bypassed_at; + + private String created_at; + private String updated_at; + + GHSecretScanningAlert wrap(GHRepository owner) { + this.owner = owner; + return this; + } + + /** + * Id/number of the alert. + * + * @return the id/number + * @see #getId() + */ + public long getNumber() { + return number; + } + + /** + * Id/number of the alert. + * + * @return the id/number + * @see #getNumber() + */ + @Override + public long getId() { + return getNumber(); + } + + @Override + public URL getHtmlUrl() throws IOException { + return GitHubClient.parseURL(html_url); + } + + /** + * State of alert + * + * @return the state + */ + public GHSecretScanningAlertState getState() { + return state; + } + + /** + * Resolution of the alert. Can be 'false_positive', 'wont_fix', 'revoked', 'used_in_tests', or null. + * + * @return the resolution + */ + public String getResolution() { + return resolution; + } + + /** + * Time when alert was resolved. Non-null when {@link #getState()} is Resolved + * + * @return the time + */ + public Date getResolvedAt() { + return GitHubClient.parseDate(resolved_at); + } + + /** + * User that has resolved the alert. Non-null when {@link #getState()} is Resolved + * + *

+ * Note: User object returned by secret scanning GitHub API does not contain all fields. Use with caution + *

+ * + * @return the user + */ + @SuppressFBWarnings(value = { "EI_EXPOSE_REP" }, justification = "Expected behavior") + public GHUser getResolvedBy() { + return resolved_by; + } + + /** + * Type of secret that was detected + * + * @return the secret type + */ + public String getSecretType() { + return secret_type; + } + + /** + * Display name for tyype of secret that was detected + * + * @return the secret type display name + */ + public String getSecretTypeDisplayName() { + return secret_type_display_name; + } + + /** + * Secret value that was detected + * + * @return the secret value + */ + public String getSecret() { + return secret; + } + + /** + * Whether push protection was bypassed for this alert + * + * @return true if push protection was bypassed, false otherwise + */ + public Boolean isPushProtectionBypassed() { + return push_protection_bypassed; + } + + /** + * User that bypassed push protection. Non-null when {@link #isPushProtectionBypassed()} is true + * + * @return the user + */ + @SuppressFBWarnings(value = { "EI_EXPOSE_REP" }, justification = "Expected behavior") + public GHUser getPushProtectionBypassedBy() { + return push_protection_bypassed_by; + } + + /** + * Time when push protection was bypassed. Non-null when {@link #isPushProtectionBypassed()} is true + * + * @return the time + */ + public Date getPushProtectionBypassedAt() { + return GitHubClient.parseDate(push_protection_bypassed_at); + } + + /** + * Gets created at. + * + * @return the created at + */ + public Date getCreatedAt() { + return GitHubClient.parseDate(created_at); + } + + /** + * Gets updated at. + * + * @return the updated at + */ + public Date getUpdatedAt() { + return GitHubClient.parseDate(updated_at); + } + + /** + * Gets locations url. + * + * @return the locations url + */ + public String getLocationsUrl() { + return locations_url; + } + + /** + * Gets locations. + * + * @return the locations array + * @throws IOException + * the io exception + */ + public List getLocations() throws IOException { + return Arrays.asList( + root().createRequest().withUrlPath(getLocationsUrl()).fetch(GHSecretScanningAlertLocation[].class)); + } + +} diff --git a/src/main/java/org/kohsuke/github/GHSecretScanningAlertLocation.java b/src/main/java/org/kohsuke/github/GHSecretScanningAlertLocation.java new file mode 100644 index 0000000000..dcf90d0869 --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHSecretScanningAlertLocation.java @@ -0,0 +1,39 @@ +package org.kohsuke.github; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + +/** + * Code scanning alert for a repository + * + * + */ +@SuppressFBWarnings(value = { "UWF_UNWRITTEN_FIELD" }, justification = "JSON API") +public class GHSecretScanningAlertLocation { + private String type; + private GHSecretScanningAlertLocationDetails details; + + /** + * Instantiates a new GH secret scanning alert location. + */ + public GHSecretScanningAlertLocation() { + } + + /** + * The type of location. + * + * @return the type + */ + public String getType() { + return type; + } + + /** + * The details of the location. + * + * @return the details + */ + public GHSecretScanningAlertLocationDetails getDetails() { + return details; + } + +} diff --git a/src/main/java/org/kohsuke/github/GHSecretScanningAlertLocationDetails.java b/src/main/java/org/kohsuke/github/GHSecretScanningAlertLocationDetails.java new file mode 100644 index 0000000000..8c0ec0ef20 --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHSecretScanningAlertLocationDetails.java @@ -0,0 +1,28 @@ +package org.kohsuke.github; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + +/** + * Code sc for a repository + * + * + */ +@SuppressFBWarnings(value = { "UWF_UNWRITTEN_FIELD" }, justification = "JSON API") +public class GHSecretScanningAlertLocationDetails { + private String path; + + /** + * Instantiates a new GH secret scanning alert location details. + */ + public GHSecretScanningAlertLocationDetails() { + } + + /** + * The path to the file containing the secret. + * + * @return the path + */ + public String getPath() { + return path; + } +} diff --git a/src/main/java/org/kohsuke/github/GHSecretScanningAlertState.java b/src/main/java/org/kohsuke/github/GHSecretScanningAlertState.java new file mode 100644 index 0000000000..200cf55ed5 --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHSecretScanningAlertState.java @@ -0,0 +1,15 @@ +package org.kohsuke.github; + +/** + * What is the current state of the Secret Scanning Alert + */ +public enum GHSecretScanningAlertState { + /** + * Alert is open and still an active issue. + */ + OPEN, + /** + * Issue that has caused the alert has been addressed. + */ + RESOLVED, +} diff --git a/src/main/java/org/kohsuke/github/GHSecretScanningAlertsIterable.java b/src/main/java/org/kohsuke/github/GHSecretScanningAlertsIterable.java new file mode 100644 index 0000000000..adbe02509e --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHSecretScanningAlertsIterable.java @@ -0,0 +1,45 @@ +package org.kohsuke.github; + +import java.util.Iterator; + +import javax.annotation.Nonnull; + +class GHSecretScanningAlertsIterable extends PagedIterable { + private final GHRepository owner; + private final GitHubRequest request; + private GHSecretScanningAlert[] result; + + GHSecretScanningAlertsIterable(GHRepository owner, GitHubRequest request) { + this.owner = owner; + this.request = request; + } + + @Nonnull + @Override + public PagedIterator _iterator(int pageSize) { + return new PagedIterator<>( + adapt(GitHubPageIterator + .create(owner.root().getClient(), GHSecretScanningAlert[].class, request, pageSize)), + null); + } + + protected Iterator adapt(final Iterator base) { + return new Iterator() { + public boolean hasNext() { + return base.hasNext(); + } + + public GHSecretScanningAlert[] next() { + GHSecretScanningAlert[] v = base.next(); + if (result == null) { + result = v; + } + + for (GHSecretScanningAlert alert : result) { + alert.wrap(owner); + } + return result; + } + }; + } +} diff --git a/src/test/java/org/kohsuke/github/GHSecretScanningAlertTest.java b/src/test/java/org/kohsuke/github/GHSecretScanningAlertTest.java new file mode 100644 index 0000000000..a34cb27bd0 --- /dev/null +++ b/src/test/java/org/kohsuke/github/GHSecretScanningAlertTest.java @@ -0,0 +1,79 @@ +package org.kohsuke.github; + +import org.junit.Before; +import org.junit.Test; + +import java.util.List; + +import static org.hamcrest.Matchers.*; + +/** + *

+ * Note : As the code scanning alerts cannot be tailored as part of test setup, lot of the test cases are dependent on + * manual setup of the mock repo. Assertions and verifications will often simply check that the values are non-null + * rather than depending on hard-coded values, to prevent making the tests flimsy + *

+ */ +public class GHSecretScanningAlertTest extends AbstractGitHubWireMockTest { + private static final String REPO_NAME = "Pixi"; + private GHRepository repo; + + /** + * Gets the mock repo + * + * @throws Exception + * the exception + */ + @Before + public void setUp() throws Exception { + repo = gitHub.getRepository("cortextests" + "/" + "secret-scanning"); + } + + /** + * Test list secret scanning alert payload + * + * @throws Exception + * the exception + */ + @Test + public void testListSecretScanningAlerts() throws Exception { + // Arrange + + // Act + List alerts = repo.listSecretScanningAlerts()._iterator(2).nextPage(); + + // Assert + assertThat(alerts.size(), equalTo(2)); + + GHSecretScanningAlert alert1 = alerts.get(0); + assertThat(alert1.getNumber(), equalTo(2L)); + assertThat(alert1.getState(), equalTo(GHSecretScanningAlertState.OPEN)); + assertThat(alert1.getSecretType(), equalTo("npm_access_token")); + assertThat(alert1.getSecret(), equalTo("secret1")); + assertThat(alert1.isPushProtectionBypassed(), equalTo(false)); + assertThat(alert1.getResolvedBy(), nullValue()); + assertThat(alert1.getResolvedAt(), nullValue()); + + List locations = alert1.getLocations(); + assertThat(locations.size(), equalTo(1)); + assertThat(locations.get(0).getType(), equalTo("commit")); + assertThat(locations.get(0).getDetails().getPath(), equalTo("secrets/secrets1.env")); + + GHSecretScanningAlert alert2 = alerts.get(1); + assertThat(alert2.getNumber(), equalTo(1L)); + assertThat(alert2.getState(), equalTo(GHSecretScanningAlertState.OPEN)); + assertThat(alert2.getSecretType(), equalTo("stripe_test_secret_key")); + assertThat(alert2.getSecret(), equalTo("secret2")); + assertThat(alert2.isPushProtectionBypassed(), equalTo(true)); + assertThat(alert2.getPushProtectionBypassedBy().getLogin(), equalTo("lukbla")); + assertThat(alert2.getPushProtectionBypassedAt(), equalTo(GitHubClient.parseDate("2025-05-05T15:32:05Z"))); + assertThat(alert2.getResolvedBy(), nullValue()); + assertThat(alert2.getResolvedAt(), nullValue()); + + List locations2 = alert2.getLocations(); + assertThat(locations2.size(), equalTo(1)); + assertThat(locations2.get(0).getType(), equalTo("commit")); + assertThat(locations2.get(0).getDetails().getPath(), equalTo("secrets.env")); + } + +} diff --git a/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/__files/repos_cortextests_secret-scanning-1.json b/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/__files/repos_cortextests_secret-scanning-1.json new file mode 100644 index 0000000000..ff0f3345d5 --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/__files/repos_cortextests_secret-scanning-1.json @@ -0,0 +1,161 @@ +{ + "id": 978177282, + "node_id": "R_kgDOOk3NAg", + "name": "secret-scanning", + "full_name": "cortextests/secret-scanning", + "private": false, + "owner": { + "login": "cortextests", + "id": 87100841, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjg3MTAwODQx", + "avatar_url": "https://avatars.githubusercontent.com/u/87100841?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/cortextests", + "html_url": "https://github.com/cortextests", + "followers_url": "https://api.github.com/users/cortextests/followers", + "following_url": "https://api.github.com/users/cortextests/following{/other_user}", + "gists_url": "https://api.github.com/users/cortextests/gists{/gist_id}", + "starred_url": "https://api.github.com/users/cortextests/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/cortextests/subscriptions", + "organizations_url": "https://api.github.com/users/cortextests/orgs", + "repos_url": "https://api.github.com/users/cortextests/repos", + "events_url": "https://api.github.com/users/cortextests/events{/privacy}", + "received_events_url": "https://api.github.com/users/cortextests/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/cortextests/secret-scanning", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/cortextests/secret-scanning", + "forks_url": "https://api.github.com/repos/cortextests/secret-scanning/forks", + "keys_url": "https://api.github.com/repos/cortextests/secret-scanning/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/cortextests/secret-scanning/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/cortextests/secret-scanning/teams", + "hooks_url": "https://api.github.com/repos/cortextests/secret-scanning/hooks", + "issue_events_url": "https://api.github.com/repos/cortextests/secret-scanning/issues/events{/number}", + "events_url": "https://api.github.com/repos/cortextests/secret-scanning/events", + "assignees_url": "https://api.github.com/repos/cortextests/secret-scanning/assignees{/user}", + "branches_url": "https://api.github.com/repos/cortextests/secret-scanning/branches{/branch}", + "tags_url": "https://api.github.com/repos/cortextests/secret-scanning/tags", + "blobs_url": "https://api.github.com/repos/cortextests/secret-scanning/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/cortextests/secret-scanning/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/cortextests/secret-scanning/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/cortextests/secret-scanning/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/cortextests/secret-scanning/statuses/{sha}", + "languages_url": "https://api.github.com/repos/cortextests/secret-scanning/languages", + "stargazers_url": "https://api.github.com/repos/cortextests/secret-scanning/stargazers", + "contributors_url": "https://api.github.com/repos/cortextests/secret-scanning/contributors", + "subscribers_url": "https://api.github.com/repos/cortextests/secret-scanning/subscribers", + "subscription_url": "https://api.github.com/repos/cortextests/secret-scanning/subscription", + "commits_url": "https://api.github.com/repos/cortextests/secret-scanning/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/cortextests/secret-scanning/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/cortextests/secret-scanning/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/cortextests/secret-scanning/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/cortextests/secret-scanning/contents/{+path}", + "compare_url": "https://api.github.com/repos/cortextests/secret-scanning/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/cortextests/secret-scanning/merges", + "archive_url": "https://api.github.com/repos/cortextests/secret-scanning/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/cortextests/secret-scanning/downloads", + "issues_url": "https://api.github.com/repos/cortextests/secret-scanning/issues{/number}", + "pulls_url": "https://api.github.com/repos/cortextests/secret-scanning/pulls{/number}", + "milestones_url": "https://api.github.com/repos/cortextests/secret-scanning/milestones{/number}", + "notifications_url": "https://api.github.com/repos/cortextests/secret-scanning/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/cortextests/secret-scanning/labels{/name}", + "releases_url": "https://api.github.com/repos/cortextests/secret-scanning/releases{/id}", + "deployments_url": "https://api.github.com/repos/cortextests/secret-scanning/deployments", + "created_at": "2025-05-05T15:30:32Z", + "updated_at": "2025-05-05T15:32:18Z", + "pushed_at": "2025-05-05T15:32:15Z", + "git_url": "git://github.com/cortextests/secret-scanning.git", + "ssh_url": "git@github.com:cortextests/secret-scanning.git", + "clone_url": "https://github.com/cortextests/secret-scanning.git", + "svn_url": "https://github.com/cortextests/secret-scanning", + "homepage": null, + "size": 1, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 0, + "license": null, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 0, + "open_issues": 0, + "watchers": 0, + "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", + "custom_properties": {}, + "organization": { + "login": "cortextests", + "id": 87100841, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjg3MTAwODQx", + "avatar_url": "https://avatars.githubusercontent.com/u/87100841?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/cortextests", + "html_url": "https://github.com/cortextests", + "followers_url": "https://api.github.com/users/cortextests/followers", + "following_url": "https://api.github.com/users/cortextests/following{/other_user}", + "gists_url": "https://api.github.com/users/cortextests/gists{/gist_id}", + "starred_url": "https://api.github.com/users/cortextests/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/cortextests/subscriptions", + "organizations_url": "https://api.github.com/users/cortextests/orgs", + "repos_url": "https://api.github.com/users/cortextests/repos", + "events_url": "https://api.github.com/users/cortextests/events{/privacy}", + "received_events_url": "https://api.github.com/users/cortextests/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "security_and_analysis": { + "secret_scanning": { + "status": "enabled" + }, + "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": 0, + "subscribers_count": 4 +} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/__files/repos_cortextests_secret-scanning_secret-scanning_alerts-2.json b/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/__files/repos_cortextests_secret-scanning_secret-scanning_alerts-2.json new file mode 100644 index 0000000000..47513c9d1d --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/__files/repos_cortextests_secret-scanning_secret-scanning_alerts-2.json @@ -0,0 +1,76 @@ +[ + { + "number": 2, + "created_at": "2025-05-05T15:32:16Z", + "updated_at": "2025-05-05T15:32:16Z", + "url": "https://api.github.com/repos/cortextests/secret-scanning/secret-scanning/alerts/2", + "html_url": "https://github.com/cortextests/secret-scanning/security/secret-scanning/2", + "locations_url": "https://api.github.com/repos/cortextests/secret-scanning/secret-scanning/alerts/2/locations", + "state": "open", + "secret_type": "npm_access_token", + "secret_type_display_name": "npm Access Token", + "secret": "secret1", + "validity": "unknown", + "multi_repo": false, + "is_base64_encoded": false, + "publicly_leaked": true, + "resolution": null, + "resolved_by": null, + "resolved_at": null, + "resolution_comment": null, + "push_protection_bypassed": false, + "push_protection_bypassed_by": null, + "push_protection_bypassed_at": null, + "push_protection_bypass_request_reviewer": null, + "push_protection_bypass_request_reviewer_comment": null, + "push_protection_bypass_request_comment": null, + "push_protection_bypass_request_html_url": null + }, + { + "number": 1, + "created_at": "2025-05-05T15:32:16Z", + "updated_at": "2025-05-05T15:32:16Z", + "url": "https://api.github.com/repos/cortextests/secret-scanning/secret-scanning/alerts/1", + "html_url": "https://github.com/cortextests/secret-scanning/security/secret-scanning/1", + "locations_url": "https://api.github.com/repos/cortextests/secret-scanning/secret-scanning/alerts/1/locations", + "state": "open", + "secret_type": "stripe_test_secret_key", + "secret_type_display_name": "Stripe Test API Secret Key", + "secret": "secret2", + "validity": "unknown", + "multi_repo": false, + "is_base64_encoded": false, + "publicly_leaked": true, + "resolution": null, + "resolved_by": null, + "resolved_at": null, + "resolution_comment": null, + "push_protection_bypassed": true, + "push_protection_bypassed_by": { + "login": "lukbla", + "id": 14848012, + "node_id": "MDQ6VXNlcjE0ODQ4MDEy", + "avatar_url": "https://avatars.githubusercontent.com/u/14848012?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/lukbla", + "html_url": "https://github.com/lukbla", + "followers_url": "https://api.github.com/users/lukbla/followers", + "following_url": "https://api.github.com/users/lukbla/following{/other_user}", + "gists_url": "https://api.github.com/users/lukbla/gists{/gist_id}", + "starred_url": "https://api.github.com/users/lukbla/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/lukbla/subscriptions", + "organizations_url": "https://api.github.com/users/lukbla/orgs", + "repos_url": "https://api.github.com/users/lukbla/repos", + "events_url": "https://api.github.com/users/lukbla/events{/privacy}", + "received_events_url": "https://api.github.com/users/lukbla/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "push_protection_bypassed_at": "2025-05-05T15:32:05Z", + "push_protection_bypass_request_reviewer": null, + "push_protection_bypass_request_reviewer_comment": null, + "push_protection_bypass_request_comment": null, + "push_protection_bypass_request_html_url": null + } +] \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/__files/repos_cortextests_secret-scanning_secret-scanning_alerts_1_locations-4.json b/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/__files/repos_cortextests_secret-scanning_secret-scanning_alerts_1_locations-4.json new file mode 100644 index 0000000000..99f13ef626 --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/__files/repos_cortextests_secret-scanning_secret-scanning_alerts_1_locations-4.json @@ -0,0 +1,16 @@ +[ + { + "type": "commit", + "details": { + "path": "secrets.env", + "start_line": 12, + "end_line": 12, + "start_column": 19, + "end_column": 51, + "blob_sha": "55b3a125e9a9432a82935f27b9c68c5cda615f73", + "blob_url": "https://api.github.com/repos/cortextests/secret-scanning/git/blobs/55b3a125e9a9432a82935f27b9c68c5cda615f73", + "commit_sha": "86d90215490fccfae2479cb037c2924857bda0e3", + "commit_url": "https://api.github.com/repos/cortextests/secret-scanning/git/commits/86d90215490fccfae2479cb037c2924857bda0e3" + } + } +] \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/__files/repos_cortextests_secret-scanning_secret-scanning_alerts_2_locations-3.json b/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/__files/repos_cortextests_secret-scanning_secret-scanning_alerts_2_locations-3.json new file mode 100644 index 0000000000..c89ac02b08 --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/__files/repos_cortextests_secret-scanning_secret-scanning_alerts_2_locations-3.json @@ -0,0 +1,16 @@ +[ + { + "type": "commit", + "details": { + "path": "secrets/secrets1.env", + "start_line": 9, + "end_line": 9, + "start_column": 11, + "end_column": 47, + "blob_sha": "55b3a125e9a9432a82935f27b9c68c5cda615f73", + "blob_url": "https://api.github.com/repos/cortextests/secret-scanning/git/blobs/55b3a125e9a9432a82935f27b9c68c5cda615f73", + "commit_sha": "86d90215490fccfae2479cb037c2924857bda0e3", + "commit_url": "https://api.github.com/repos/cortextests/secret-scanning/git/commits/86d90215490fccfae2479cb037c2924857bda0e3" + } + } +] \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/mappings/repos_cortextests_secret-scanning-1.json b/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/mappings/repos_cortextests_secret-scanning-1.json new file mode 100644 index 0000000000..8d43cb9130 --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/mappings/repos_cortextests_secret-scanning-1.json @@ -0,0 +1,45 @@ +{ + "id": "50b5d778-8619-4fde-b8e4-ffc7c2668f38", + "name": "repos_cortextests_secret-scanning", + "request": { + "url": "/repos/cortextests/secret-scanning", + "method": "GET", + "headers": { + "Accept": { + "equalTo": "application/vnd.github.v3+json" + } + } + }, + "response": { + "status": 200, + "bodyFileName": "repos_cortextests_secret-scanning-1.json", + "headers": { + "Date": "Tue, 06 May 2025 11:34:03 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/\"6534adbe51208ec686c4c331af35de5ce11f195f8be87f0549cb438eae49f3bd\"", + "Last-Modified": "Mon, 05 May 2025 15:32:18 GMT", + "X-OAuth-Scopes": "gist, notifications, project, repo, user, workflow, write:packages", + "X-Accepted-OAuth-Scopes": "repo", + "X-GitHub-Media-Type": "github.v3; format=json", + "x-github-api-version-selected": "2022-11-28", + "X-RateLimit-Limit": "5000", + "X-RateLimit-Remaining": "4987", + "X-RateLimit-Reset": "1746533117", + "X-RateLimit-Used": "13", + "X-RateLimit-Resource": "core", + "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": "573A:3BFDA3:9D7BC3:A07A43:6819F3AB" + } + }, + "uuid": "50b5d778-8619-4fde-b8e4-ffc7c2668f38", + "persistent": true, + "insertionIndex": 1 +} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/mappings/repos_cortextests_secret-scanning_secret-scanning_alerts-2.json b/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/mappings/repos_cortextests_secret-scanning_secret-scanning_alerts-2.json new file mode 100644 index 0000000000..5482d76b07 --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/mappings/repos_cortextests_secret-scanning_secret-scanning_alerts-2.json @@ -0,0 +1,44 @@ +{ + "id": "80193c8a-8098-444e-a590-70c276bb94e4", + "name": "repos_cortextests_secret-scanning_secret-scanning_alerts", + "request": { + "url": "/repos/cortextests/secret-scanning/secret-scanning/alerts?per_page=2", + "method": "GET", + "headers": { + "Accept": { + "equalTo": "application/vnd.github.v3+json" + } + } + }, + "response": { + "status": 200, + "bodyFileName": "repos_cortextests_secret-scanning_secret-scanning_alerts-2.json", + "headers": { + "Date": "Tue, 06 May 2025 11:34:04 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/\"bc86b69e772f3210a4a16816d4d561647a7ed9ecc91ffd21a6e80c57025f8787\"", + "X-OAuth-Scopes": "gist, notifications, project, repo, user, workflow, write:packages", + "X-Accepted-OAuth-Scopes": "public_repo, repo, security_events", + "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": "1746533117", + "X-RateLimit-Used": "14", + "X-RateLimit-Resource": "core", + "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": "56DB:12E1:2323E59:243C72B:6819F3AB" + } + }, + "uuid": "80193c8a-8098-444e-a590-70c276bb94e4", + "persistent": true, + "insertionIndex": 2 +} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/mappings/repos_cortextests_secret-scanning_secret-scanning_alerts_1_locations-4.json b/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/mappings/repos_cortextests_secret-scanning_secret-scanning_alerts_1_locations-4.json new file mode 100644 index 0000000000..af2e0aa16f --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/mappings/repos_cortextests_secret-scanning_secret-scanning_alerts_1_locations-4.json @@ -0,0 +1,44 @@ +{ + "id": "fee4f520-dcbd-4a14-97c0-e90f37f38990", + "name": "repos_cortextests_secret-scanning_secret-scanning_alerts_1_locations", + "request": { + "url": "/repos/cortextests/secret-scanning/secret-scanning/alerts/1/locations", + "method": "GET", + "headers": { + "Accept": { + "equalTo": "application/vnd.github.v3+json" + } + } + }, + "response": { + "status": 200, + "bodyFileName": "repos_cortextests_secret-scanning_secret-scanning_alerts_1_locations-4.json", + "headers": { + "Date": "Tue, 06 May 2025 11:34:05 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/\"1698ce505845ba9429be3096423e6e365f50c504f227e13f1962b09f09732931\"", + "X-OAuth-Scopes": "gist, notifications, project, repo, user, workflow, write:packages", + "X-Accepted-OAuth-Scopes": "public_repo, repo, security_events", + "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": "1746533117", + "X-RateLimit-Used": "16", + "X-RateLimit-Resource": "core", + "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": "56EB:9ECAB:8DFAD2:90F7B5:6819F3AD" + } + }, + "uuid": "fee4f520-dcbd-4a14-97c0-e90f37f38990", + "persistent": true, + "insertionIndex": 4 +} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/mappings/repos_cortextests_secret-scanning_secret-scanning_alerts_2_locations-3.json b/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/mappings/repos_cortextests_secret-scanning_secret-scanning_alerts_2_locations-3.json new file mode 100644 index 0000000000..1ac9fb79ca --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHSecretScanningAlertTest/wiremock/testListSecretScanningAlerts/mappings/repos_cortextests_secret-scanning_secret-scanning_alerts_2_locations-3.json @@ -0,0 +1,44 @@ +{ + "id": "a8c3dc32-9f17-4859-9262-1b42c91fe8c8", + "name": "repos_cortextests_secret-scanning_secret-scanning_alerts_2_locations", + "request": { + "url": "/repos/cortextests/secret-scanning/secret-scanning/alerts/2/locations", + "method": "GET", + "headers": { + "Accept": { + "equalTo": "application/vnd.github.v3+json" + } + } + }, + "response": { + "status": 200, + "bodyFileName": "repos_cortextests_secret-scanning_secret-scanning_alerts_2_locations-3.json", + "headers": { + "Date": "Tue, 06 May 2025 11:34:04 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/\"c979a2680d5d142dd92b108df539ea5887a02e138812fcff3e33033da9cc19f8\"", + "X-OAuth-Scopes": "gist, notifications, project, repo, user, workflow, write:packages", + "X-Accepted-OAuth-Scopes": "public_repo, repo, security_events", + "X-GitHub-Media-Type": "github.v3; format=json", + "x-github-api-version-selected": "2022-11-28", + "X-RateLimit-Limit": "5000", + "X-RateLimit-Remaining": "4985", + "X-RateLimit-Reset": "1746533117", + "X-RateLimit-Used": "15", + "X-RateLimit-Resource": "core", + "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": "5720:127514:893F1A:8C3BE2:6819F3AC" + } + }, + "uuid": "a8c3dc32-9f17-4859-9262-1b42c91fe8c8", + "persistent": true, + "insertionIndex": 3 +} \ No newline at end of file