Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 74496d3

Browse filesBrowse files
committed
Merge remote-tracking branch 'origin/master' into feature/base-event-payload
2 parents 929d9fb + 316e278 commit 74496d3
Copy full SHA for 74496d3

File tree

Expand file treeCollapse file tree

18 files changed

+905
-0
lines changed
Filter options
Expand file treeCollapse file tree

18 files changed

+905
-0
lines changed

‎pom.xml

Copy file name to clipboardExpand all lines: pom.xml
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,24 @@
484484
<version>5.9.0.202009080501-r</version>
485485
<scope>test</scope>
486486
</dependency>
487+
<dependency>
488+
<groupId>io.jsonwebtoken</groupId>
489+
<artifactId>jjwt-api</artifactId>
490+
<version>0.11.2</version>
491+
<scope>test</scope>
492+
</dependency>
493+
<dependency>
494+
<groupId>io.jsonwebtoken</groupId>
495+
<artifactId>jjwt-impl</artifactId>
496+
<version>0.11.2</version>
497+
<scope>test</scope>
498+
</dependency>
499+
<dependency>
500+
<groupId>io.jsonwebtoken</groupId>
501+
<artifactId>jjwt-jackson</artifactId>
502+
<version>0.11.2</version>
503+
<scope>test</scope>
504+
</dependency>
487505
<dependency>
488506
<groupId>com.squareup.okio</groupId>
489507
<artifactId>okio</artifactId>

‎src/main/java/org/kohsuke/github/GHAppInstallation.java

Copy file name to clipboardExpand all lines: src/main/java/org/kohsuke/github/GHAppInstallation.java
+32Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
import com.fasterxml.jackson.annotation.JsonProperty;
44

55
import java.io.IOException;
6+
import java.net.MalformedURLException;
67
import java.net.URL;
78
import java.util.List;
89
import java.util.Map;
910

1011
import static org.kohsuke.github.Previews.GAMBIT;
12+
import static org.kohsuke.github.Previews.MACHINE_MAN;
1113

1214
/**
1315
* A Github App Installation.
@@ -117,6 +119,36 @@ public String getRepositoriesUrl() {
117119
return repositoriesUrl;
118120
}
119121

122+
/**
123+
* List repositories that this app installation can access.
124+
*
125+
* @return the paged iterable
126+
*/
127+
@Preview
128+
@Deprecated
129+
public PagedSearchIterable<GHRepository> listRepositories() {
130+
GitHubRequest request;
131+
132+
try {
133+
request = root.createRequest().withPreview(MACHINE_MAN).withUrlPath("/installation/repositories").build();
134+
} catch (MalformedURLException e) {
135+
throw new GHException("", e);
136+
}
137+
138+
return new PagedSearchIterable<>(root, request, GHAppInstallationRepositoryResult.class);
139+
}
140+
141+
private static class GHAppInstallationRepositoryResult extends SearchResult<GHRepository> {
142+
private GHRepository[] repositories;
143+
144+
@Override
145+
GHRepository[] getItems(GitHub root) {
146+
for (GHRepository item : repositories)
147+
item.wrap(root);
148+
return repositories;
149+
}
150+
}
151+
120152
/**
121153
* Sets repositories url.
122154
*
+90Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package org.kohsuke.github;
2+
3+
import io.jsonwebtoken.Jwts;
4+
import org.apache.commons.io.IOUtils;
5+
import org.junit.Test;
6+
7+
import java.io.IOException;
8+
import java.security.KeyFactory;
9+
import java.security.PrivateKey;
10+
import java.security.spec.PKCS8EncodedKeySpec;
11+
import java.time.Instant;
12+
import java.time.temporal.ChronoUnit;
13+
import java.util.*;
14+
15+
public class GHAppInstallationTest extends AbstractGitHubWireMockTest {
16+
17+
private static String TEST_APP_ID_1 = "82994";
18+
private static String TEST_APP_ID_2 = "83009";
19+
private static String PRIVATE_KEY_FILE_APP_1 = "/ghapi-test-app-1.private-key.pem";
20+
private static String PRIVATE_KEY_FILE_APP_2 = "/ghapi-test-app-2.private-key.pem";
21+
22+
private String createJwtToken(String keyFileResouceName, String appId) {
23+
try {
24+
String keyPEM = IOUtils.toString(this.getClass().getResource(keyFileResouceName), "US-ASCII")
25+
.replaceAll("(?m)^--.*", "") // remove comments from PEM to allow decoding
26+
.replaceAll("\\s", "");
27+
28+
PKCS8EncodedKeySpec keySpecPKCS8 = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(keyPEM));
29+
PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpecPKCS8);
30+
31+
return Jwts.builder()
32+
.setIssuedAt(Date.from(Instant.now()))
33+
.setExpiration(Date.from(Instant.now().plus(5, ChronoUnit.MINUTES)))
34+
.setIssuer(appId)
35+
.signWith(privateKey)
36+
.compact();
37+
} catch (Exception e) {
38+
throw new RuntimeException("Error creating JWT token.", e);
39+
}
40+
}
41+
42+
private GHAppInstallation getAppInstallationWithToken(String jwtToken) throws IOException {
43+
GitHub gitHub = getGitHubBuilder().withJwtToken(jwtToken)
44+
.withEndpoint(mockGitHub.apiServer().baseUrl())
45+
.build();
46+
47+
GHAppInstallation appInstallation = gitHub.getApp()
48+
.listInstallations()
49+
.toList()
50+
.stream()
51+
.filter(it -> it.getAccount().login.equals("hub4j-test-org"))
52+
.findFirst()
53+
.get();
54+
55+
appInstallation
56+
.setRoot(getGitHubBuilder().withAppInstallationToken(appInstallation.createToken().create().getToken())
57+
.withEndpoint(mockGitHub.apiServer().baseUrl())
58+
.build());
59+
60+
return appInstallation;
61+
}
62+
63+
private GHAppInstallation getAppInstallationWithTokenApp1() throws IOException {
64+
return getAppInstallationWithToken(createJwtToken(PRIVATE_KEY_FILE_APP_1, TEST_APP_ID_1));
65+
}
66+
67+
private GHAppInstallation getAppInstallationWithTokenApp2() throws IOException {
68+
return getAppInstallationWithToken(createJwtToken(PRIVATE_KEY_FILE_APP_2, TEST_APP_ID_2));
69+
}
70+
71+
@Test
72+
public void testListRepositoriesTwoRepos() throws IOException {
73+
GHAppInstallation appInstallation = getAppInstallationWithTokenApp1();
74+
75+
List<GHRepository> repositories = appInstallation.listRepositories().toList();
76+
77+
assertEquals(2, repositories.size());
78+
assertTrue(repositories.stream().anyMatch(it -> it.getName().equals("empty")));
79+
assertTrue(repositories.stream().anyMatch(it -> it.getName().equals("test-readme")));
80+
}
81+
82+
@Test
83+
public void testListRepositoriesNoPermissions() throws IOException {
84+
GHAppInstallation appInstallation = getAppInstallationWithTokenApp2();
85+
86+
assertTrue("App does not have permissions and should have 0 repositories",
87+
appInstallation.listRepositories().toList().isEmpty());
88+
}
89+
90+
}
+28Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDG98AU2pNVCCp/
3+
THwEqlDUZ8GRKY9TO52x+3FPTnx69D63f4k44N0DOCEk4q1mKQ0QYy6rgQcyWtwd
4+
GYRpgP/KU5Q3ozEnHUJ82d5HgOCMcYdpqaOb9wJRmj0s9cibDd7TmGBv0DTx5KZi
5+
ilqv1mYFbeIC/eVv/id0aG6PMef1+fJeGplQQ1mfdvQP/6ftxsVBHyIhYvZLLGLL
6+
FrcONmKTJ9Iy4F4M64PE7YkNVIEMu2cVpIxkHiZuTamr3DPgm4nRp2qe3EA2bLRA
7+
Zp4Q+WJmJsVgaDRqJYe8U2IVO72eHdWjoG/lV9HOfc+eH4ns8ZnRNtTnH67DnocT
8+
+GAbZp0NAgMBAAECggEARlWIGhcWI+XqF+vynzeRsTQoUedOGg8l9Ke861sEV/aF
9+
QRqdaHTcy+mIleBniYiTbKqS8d9/qsZBryu5Cg6m3V/kMjLHClumiDoAAGjHd/4d
10+
7zUfd9++exg57e3Ihz9E+KmR1ZTVUnkQdB8SZbw1fk/UqFgWRhui2Nyd0JLEu8eK
11+
QTE7MMs3w8Iv8FtC7BJBrEW2uc0h/f5gV4XrS2PR+YFKlFDN566+TILS2Q3h1h6p
12+
yqriZygLTQc/z0nqB098KgRcNr3LtCTlaSBBKfFEwG5Glj9QybfEuP6PihrYOFN1
13+
SeDCI+/b/WNDsspBheks/AYy6zVSPsWxWoHXhLxSQQKBgQD2Q4FtH6n8gqFMmFX3
14+
74Suvoi1YKKbeFjloQ4Pu3rPdEKuza5lgfw+YlO/nMDnQF0b+mogRD2Xs23CIub5
15+
RS3TZuhxkdz7VhPRwKHuYs7D5oa3BGAgRyEjG0JIZePNHO1kUSkIRrF4FXFgGpQ8
16+
ghdDtodXbrMjZNak8bIq6X/zkQKBgQDO1Y0ifMv3rAu0PEbfnaqXrl09c892cpjP
17+
A57T7e53x2WKaNwQbYixNdAbDtGEKXjIHRaV9csG1XSQh+OchT7BSOpgIDxFtK5l
18+
aRuov+tcMInjojZjwMv87Pet0QrZhLIZU1883q+LiM/HtHPtgsem0AzovcLoY8mH
19+
RuR37oebvQKBgA54ewN5h9iRqH7CuNJ/3ZETGx9lVUjDcp3Tr+rWvmmwUDbLWUMX
20+
t0XHK1qoEGHGU3JQbaoFuITQg1OUD3R4TzAL7P63bn/KWBHMOveyEKpMQoBAnpFm
21+
/Jh+go+UhSVJXN23My0MUmNXBzl5dlpz3oAZGqzVkWs0ArTgivKgk+cxAoGAGp7r
22+
ulubmPYAz6LOcGuHkFw1zfoA4rrfJg3OPHKsNahpTkYuxMKETGKjtUfT+ZGo5QCx
23+
bn2jMu74QL3ssrGHoTL0T4j2mPYnWBAOKksBTO1GYhD3tSEUYCpTuoBkSBjHH3FW
24+
mawDpg7mx0pXfWNOtQ6kCrSZyHVHc+zQ7Qq7U3UCgYBAZEnFW3MIwAizcioEmc53
25+
TJuWSvdvRsfJRNqFSpPxj5xfY9HfgpPceRlh4+jwG1bRWzt4MQKh4DyFvi06NhD7
26+
MnYhTX+P1jIyzV5SU8GUud/r6TFwhOWpW3zqaTCep5+VIS5W2rR322NQAZmD2u1+
27+
h+U8DZTYFDiNzmsHem2tNA==
28+
-----END PRIVATE KEY-----
+28Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDYm8i4enZxXwQR
3+
rfyBkKIroJIMGw3JSG+JPaxvcxpp6GpGOqmGsEQwzEOeuxX705CeTjpZ6/5xOCYV
4+
kNLmwTBG/wGpsjGLY1kV6FAC1jHkFIBWSxkmQaZRsK+MhQtREd81uMa1wA/2j3II
5+
AUNd0aVWLRlGte2RlDq16mvnqlgzfKB40TgC0Rww2OdoEYsVJ0tph9JvpVgGSMJD
6+
Irr3ZVn5hwpJBliC+obst8lIJw1JfEoYT8jU6QvfgViMzRhKNNPy22fCazfxsk1m
7+
+uh7c3tM0I8jnaNFkHgRXPzuXFrcgyixXczHThEP+bifWtsBRPYSVy5/RAGDIzXO
8+
e3npKTS1AgMBAAECggEBAMXhs4IMpm21zsLT/ozi87QFccbLZFHQ8cwf4orCTYwZ
9+
PhVAfCTGnNUzlkbJRTEUutZUQuxpMr59/BTRhEo4jQEe74b2elqLfRQNciLVSSjD
10+
Lecnnicb7HROhGFMHeWG/TJXxni9qBeoPhVgCgoIfxH2C1RU2V6YWvZb3Q37ya3l
11+
6kCoRfHkSBTkAySdlZDEfYCmIyx6KPIzLFX3VI/T1CAcSuTJnHe+7gdiX4ngq4Ee
12+
ZPppHLo76kyQjd05reGTtLq40utIfzHkSgh5nLHMnU+O3xNyyPZbZE1Gp8czgaBe
13+
AoAMCPfwY7l1fBy4RQ1TE2FT9sRksNO6VuV+AT4fwzUCgYEA/dVvhT8hVVldLwgn
14+
EObgyU35NLyHWba3AanhETI+bCERq1sUXd5LMVPCRJoT/i+zNRMhELmMeVxMYEqW
15+
hzBF9XoE6ONqJ7pdRh9brysfKOye0goOXWr2XKZL8mO8utWsV6ehYiKLvgrAjEDR
16+
rToknzp8jIQqPaiheWZZIjFvdCMCgYEA2nUFQGss5Iy3FyNLQITwNRgzu75XAYML
17+
wM69iW5eF5dNF5p/6kcu12pgSW2mMI9rSVPiMqJqig2F5sIsqvBxIKS1yWuWn1CO
18+
wdP3O7GVHiDXpdra0j8z8PBhJ0jRHED5q259dXC0BvqqU8U8cOFxlgr96ZZP+TS3
19+
2Tw/RRzkdUcCgYBpcjXuu4gEZahBNnjMG6070wl4b+0mRrIFneWieCXYU3B8p8xx
20+
JjxEVJA6YWt2x6gBn124DeyeKcqMoc+gf1xAmpzZhkd+E3xV+gbjYN2D6bAcfxLy
21+
mdGYMXkRS3+GeecrTrbLBqDYpKzSVscD2EiIYQqGcQz/KkNSJENY4gJz0wKBgQCX
22+
6eR7BYy0an4v4uVDuq5n3aqsFhLfBEg6DgqT9WINObPshA4L1vBl8J2AsnVtM27C
23+
EUktOPCpi/nfnIv/WzDwKFoZ9W1K4HRFqac1paoyx1fvCCA/MKBoHmERNnvkD/MP
24+
Gci40GUArXOgyXncbYnVc1NbCqIWhGiM8m51G0BrpQKBgAffan4sPiNnWeQlvbAj
25+
kW1GkGCIOqMHVgjOxVlDGri/GLwAt1zOxHT7i9nQb6wpE0fAb05ydjPOuA7iIeG4
26+
jZdQWfY6QIhlYkDq7JiRCkcQ3auMzplSV17rDSiBL+ttOY8tLdX5fJVmeGdq7Gs1
27+
YPW1uoYsHNTFWew5Ae31KaLn
28+
-----END PRIVATE KEY-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"id": 83009,
3+
"slug": "ghapi-test-app-2",
4+
"node_id": "MDM6QXBwODMwMDk=",
5+
"owner": {
6+
"login": "hub4j-test-org",
7+
"id": 7544739,
8+
"node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NDQ3Mzk=",
9+
"avatar_url": "https://avatars3.githubusercontent.com/u/7544739?v=4",
10+
"gravatar_id": "",
11+
"url": "https://api.github.com/users/hub4j-test-org",
12+
"html_url": "https://github.com/hub4j-test-org",
13+
"followers_url": "https://api.github.com/users/hub4j-test-org/followers",
14+
"following_url": "https://api.github.com/users/hub4j-test-org/following{/other_user}",
15+
"gists_url": "https://api.github.com/users/hub4j-test-org/gists{/gist_id}",
16+
"starred_url": "https://api.github.com/users/hub4j-test-org/starred{/owner}{/repo}",
17+
"subscriptions_url": "https://api.github.com/users/hub4j-test-org/subscriptions",
18+
"organizations_url": "https://api.github.com/users/hub4j-test-org/orgs",
19+
"repos_url": "https://api.github.com/users/hub4j-test-org/repos",
20+
"events_url": "https://api.github.com/users/hub4j-test-org/events{/privacy}",
21+
"received_events_url": "https://api.github.com/users/hub4j-test-org/received_events",
22+
"type": "Organization",
23+
"site_admin": false
24+
},
25+
"name": "GHApi Test app 2",
26+
"description": "",
27+
"external_url": "https://localhost",
28+
"html_url": "https://github.com/apps/ghapi-test-app-2",
29+
"created_at": "2020-09-30T15:02:20Z",
30+
"updated_at": "2020-09-30T15:02:20Z",
31+
"permissions": {},
32+
"events": [],
33+
"installations_count": 1
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
[
2+
{
3+
"id": 12131496,
4+
"account": {
5+
"login": "hub4j-test-org",
6+
"id": 7544739,
7+
"node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NDQ3Mzk=",
8+
"avatar_url": "https://avatars3.githubusercontent.com/u/7544739?v=4",
9+
"gravatar_id": "",
10+
"url": "https://api.github.com/users/hub4j-test-org",
11+
"html_url": "https://github.com/hub4j-test-org",
12+
"followers_url": "https://api.github.com/users/hub4j-test-org/followers",
13+
"following_url": "https://api.github.com/users/hub4j-test-org/following{/other_user}",
14+
"gists_url": "https://api.github.com/users/hub4j-test-org/gists{/gist_id}",
15+
"starred_url": "https://api.github.com/users/hub4j-test-org/starred{/owner}{/repo}",
16+
"subscriptions_url": "https://api.github.com/users/hub4j-test-org/subscriptions",
17+
"organizations_url": "https://api.github.com/users/hub4j-test-org/orgs",
18+
"repos_url": "https://api.github.com/users/hub4j-test-org/repos",
19+
"events_url": "https://api.github.com/users/hub4j-test-org/events{/privacy}",
20+
"received_events_url": "https://api.github.com/users/hub4j-test-org/received_events",
21+
"type": "Organization",
22+
"site_admin": false
23+
},
24+
"repository_selection": "selected",
25+
"access_tokens_url": "https://api.github.com/app/installations/12131496/access_tokens",
26+
"repositories_url": "https://api.github.com/installation/repositories",
27+
"html_url": "https://github.com/organizations/hub4j-test-org/settings/installations/12131496",
28+
"app_id": 83009,
29+
"app_slug": "ghapi-test-app-2",
30+
"target_id": 7544739,
31+
"target_type": "Organization",
32+
"permissions": {},
33+
"events": [],
34+
"created_at": "2020-09-30T15:05:32.000Z",
35+
"updated_at": "2020-09-30T15:05:32.000Z",
36+
"single_file_name": null,
37+
"has_multiple_single_files": false,
38+
"single_file_paths": [],
39+
"suspended_by": null,
40+
"suspended_at": null
41+
}
42+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"id": "bb7cf5bb-fba2-45b3-afd8-939b2c24787a",
3+
"name": "app",
4+
"request": {
5+
"url": "/app",
6+
"method": "GET",
7+
"headers": {
8+
"Accept": {
9+
"equalTo": "application/vnd.github.machine-man-preview+json"
10+
}
11+
}
12+
},
13+
"response": {
14+
"status": 200,
15+
"bodyFileName": "app-1.json",
16+
"headers": {
17+
"Date": "Thu, 05 Nov 2020 20:42:31 GMT",
18+
"Content-Type": "application/json; charset=utf-8",
19+
"Server": "GitHub.com",
20+
"Status": "200 OK",
21+
"Cache-Control": "public, max-age=60, s-maxage=60",
22+
"Vary": [
23+
"Accept",
24+
"Accept-Encoding, Accept, X-Requested-With",
25+
"Accept-Encoding"
26+
],
27+
"ETag": "W/\"b3d319dbb4dba93fbda071208d874e5ab566d827e1ad1d7dc59f26d68694dc48\"",
28+
"X-GitHub-Media-Type": "github.v3; param=machine-man-preview; format=json",
29+
"Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
30+
"X-Frame-Options": "deny",
31+
"X-Content-Type-Options": "nosniff",
32+
"X-XSS-Protection": "1; mode=block",
33+
"Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
34+
"Content-Security-Policy": "default-src 'none'",
35+
"X-GitHub-Request-Id": "9294:AE05:BDAC761:DB35838:5FA463B6"
36+
}
37+
},
38+
"uuid": "bb7cf5bb-fba2-45b3-afd8-939b2c24787a",
39+
"persistent": true,
40+
"insertionIndex": 1
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"id": "45ac2593-8123-49ae-ad1a-ded446491b14",
3+
"name": "app_installations",
4+
"request": {
5+
"url": "/app/installations",
6+
"method": "GET",
7+
"headers": {
8+
"Accept": {
9+
"equalTo": "application/vnd.github.machine-man-preview+json"
10+
}
11+
}
12+
},
13+
"response": {
14+
"status": 200,
15+
"bodyFileName": "app_installations-2.json",
16+
"headers": {
17+
"Date": "Thu, 05 Nov 2020 20:42:31 GMT",
18+
"Content-Type": "application/json; charset=utf-8",
19+
"Server": "GitHub.com",
20+
"Status": "200 OK",
21+
"Cache-Control": "public, max-age=60, s-maxage=60",
22+
"Vary": [
23+
"Accept",
24+
"Accept-Encoding, Accept, X-Requested-With",
25+
"Accept-Encoding"
26+
],
27+
"ETag": "W/\"60d3ec5c9014799f5e12b88e16e771a386b905ad8d41cd18aed34e58b11c58d4\"",
28+
"X-GitHub-Media-Type": "github.v3; param=machine-man-preview; format=json",
29+
"Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
30+
"X-Frame-Options": "deny",
31+
"X-Content-Type-Options": "nosniff",
32+
"X-XSS-Protection": "1; mode=block",
33+
"Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
34+
"Content-Security-Policy": "default-src 'none'",
35+
"X-GitHub-Request-Id": "9294:AE05:BDAC831:DB35870:5FA463B7"
36+
}
37+
},
38+
"uuid": "45ac2593-8123-49ae-ad1a-ded446491b14",
39+
"persistent": true,
40+
"insertionIndex": 2
41+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.