Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve deploy key and user key handling #1616

Merged
merged 2 commits into from
Feb 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,12 @@
<version>${hamcrest.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.npathai</groupId>
<artifactId>hamcrest-optional</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Expand Down
58 changes: 57 additions & 1 deletion src/main/java/org/kohsuke/github/GHDeployKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.apache.commons.lang3.builder.ToStringBuilder;

import java.io.IOException;
import java.util.Date;

// TODO: Auto-generated Javadoc
/**
Expand All @@ -20,6 +21,18 @@ public class GHDeployKey {
protected long id;
private GHRepository owner;

/** Creation date of the deploy key */
private String created_at;

/** Last used date of the deploy key */
private String last_used;

/** Name of user that added the deploy key */
private String added_by;

/** Whether the deploykey has readonly permission or full access */
private boolean read_only;

/**
* Gets id.
*
Expand Down Expand Up @@ -65,6 +78,42 @@ public boolean isVerified() {
return verified;
}

/**
* Gets created_at.
*
* @return the created_at
*/
public Date getCreatedAt() {
return GitHubClient.parseDate(created_at);
}

/**
* Gets last_used.
*
* @return the last_used
*/
public Date getLastUsedAt() {
return GitHubClient.parseDate(last_used);
}

/**
* Gets added_by
*
* @return the added_by
*/
public String getAdded_by() {
return added_by;
}

/**
* Is read_only
*
* @return true if the key can only read. False if the key has write permission as well.
*/
public boolean isRead_only() {
return read_only;
}

/**
* Wrap gh deploy key.
*
Expand Down Expand Up @@ -95,7 +144,14 @@ GHDeployKey lateBind(GHRepository repo) {
* @return the string
*/
public String toString() {
return new ToStringBuilder(this).append("title", title).append("id", id).append("key", key).toString();
return new ToStringBuilder(this).append("title", title)
.append("id", id)
.append("key", key)
.append("created_at", created_at)
.append("last_used", last_used)
.append("added_by", added_by)
.append("read_only", read_only)
.toString();
}

/**
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/org/kohsuke/github/GHKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.commons.lang3.builder.ToStringBuilder;

import java.io.IOException;

// TODO: Auto-generated Javadoc
/**
* SSH public key.
Expand Down Expand Up @@ -74,4 +76,14 @@ public boolean isVerified() {
public String toString() {
return new ToStringBuilder(this).append("title", title).append("id", id).append("key", key).toString();
}

/**
* Delete the GHKey
*
* @throws IOException
* the io exception
*/
public void delete() throws IOException {
root().createRequest().method("DELETE").withUrlPath(String.format("/user/keys/%d", id)).send();
}
}
22 changes: 22 additions & 0 deletions src/main/java/org/kohsuke/github/GHMyself.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,28 @@ public List<GHKey> getPublicKeys() throws IOException {
return root().createRequest().withUrlPath("/user/keys").toIterable(GHKey[].class, null).toList();
}

/**
* Add public SSH key for the user.
* <p>
* https://docs.github.com/en/rest/users/keys?apiVersion=2022-11-28#create-a-public-ssh-key-for-the-authenticated-user
*
* @param title
* Title of the SSH key
* @param key
* the public key
* @return the newly created Github key
* @throws IOException
* the io exception
*/
public GHKey addPublicKey(String title, String key) throws IOException {
return root().createRequest()
.withUrlPath("/user/keys")
.method("POST")
.with("title", title)
.with("key", key)
.fetch(GHKey.class);
}

/**
* Returns the read-only list of all the public verified keys of the current user.
* <p>
Expand Down
1 change: 1 addition & 0 deletions src/test/java/org/kohsuke/github/ArchTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ public void testRequireUseOfOnlySpecificApacheCommons() {
targetMethodIs(ToStringBuilder.class, "append", String.class, Object.class),
targetMethodIs(ToStringBuilder.class, "append", String.class, long.class),
targetMethodIs(ToStringBuilder.class, "append", String.class, int.class),
targetMethodIs(ToStringBuilder.class, "append", String.class, boolean.class),
targetMethodIs(ToStringBuilder.class, "isEmpty"),
targetMethodIs(ToStringBuilder.class, "equals"),
targetMethodIs(ToStringBuilder.class, "capitalize"),
Expand Down
81 changes: 81 additions & 0 deletions src/test/java/org/kohsuke/github/GHDeployKeyTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package org.kohsuke.github;

import org.junit.Test;

import java.io.IOException;
import java.time.Instant;
import java.util.Date;
import java.util.List;
import java.util.Optional;

import static com.github.npathai.hamcrestopt.OptionalMatchers.isPresent;
import static org.hamcrest.Matchers.*;

/**
* The Class GHDeployKeyTest.
*
* @author Jonas van Vliet
*/
public class GHDeployKeyTest extends AbstractGitHubWireMockTest {
private static final String DEPLOY_KEY_TEST_REPO_NAME = "hub4j-test-org/GHDeployKeyTest";
private static final String ED_25519_READONLY = "DeployKey - ed25519 - readonly";
private static final String RSA_4096_READWRITE = "Deploykey - rsa4096 - readwrite";
private static final String KEY_CREATOR_USERNAME = "van-vliet";

/**
* Test get deploymentkeys.
*
* @throws IOException
* Signals that an I/O exception has occurred.
*/
@Test
public void testGetDeployKeys() throws IOException {
final GHRepository repo = getRepository();
final List<GHDeployKey> deployKeys = repo.getDeployKeys();
assertThat("There should be 2 deploykeys in " + DEPLOY_KEY_TEST_REPO_NAME, deployKeys, hasSize(2));

Optional<GHDeployKey> ed25519Key = deployKeys.stream()
.filter(key -> key.getTitle().equals(ED_25519_READONLY))
.findAny();
assertThat("The key exists", ed25519Key, isPresent());
assertThat("The key was created at the specified date",
ed25519Key.get().getCreatedAt(),
is(Date.from(Instant.parse("2023-02-08T10:00:15.00Z"))));
assertThat("The key is created by " + KEY_CREATOR_USERNAME,
ed25519Key.get().getAdded_by(),
is(KEY_CREATOR_USERNAME));
assertThat("The key has a last_used value",
ed25519Key.get().getLastUsedAt(),
is(Date.from(Instant.parse("2023-02-08T10:02:11.00Z"))));
assertThat("The key only has read access", ed25519Key.get().isRead_only(), is(true));
assertThat("Object has a toString()", ed25519Key.get().toString(), is(notNullValue()));

Optional<GHDeployKey> rsa_4096Key = deployKeys.stream()
.filter(key -> key.getTitle().equals(RSA_4096_READWRITE))
.findAny();
assertThat("The key exists", rsa_4096Key, isPresent());
assertThat("The key was created at the specified date",
rsa_4096Key.get().getCreatedAt(),
is(Date.from(Instant.parse("2023-01-26T14:12:12.00Z"))));
assertThat("The key is created by " + KEY_CREATOR_USERNAME,
rsa_4096Key.get().getAdded_by(),
is(KEY_CREATOR_USERNAME));
assertThat("The key has never been used", rsa_4096Key.get().getLastUsedAt(), is(nullValue()));
assertThat("The key only has read/write access", rsa_4096Key.get().isRead_only(), is(false));
}

/**
* Gets the repository.
*
* @return the repository
* @throws IOException
* Signals that an I/O exception has occurred.
*/
protected GHRepository getRepository() throws IOException {
return getRepository(gitHub);
}

private GHRepository getRepository(final GitHub gitHub) throws IOException {
return gitHub.getRepository(DEPLOY_KEY_TEST_REPO_NAME);
}
}
33 changes: 33 additions & 0 deletions src/test/java/org/kohsuke/github/GHPublicKeyTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.kohsuke.github;

import org.junit.Test;

/**
* The Class GHPublicKeyTest.
*
* @author Jonas van Vliet
*/
public class GHPublicKeyTest extends AbstractGitHubWireMockTest {

private static final String TMP_KEY_NAME = "Temporary user key";
private static final String WIREMOCK_SSH_PUBLIC_KEY = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDepW2/BSVFM2AfuGGsvi+vjQzC0EBD3R+/7PNEvP0/nvTWxiC/tthfvvCJR6TKrsprCir5tiJFm73gX+K18W0RKYpkyg8H6d1eZu3q/JOiGvoDPeN8Oe9hOGeeexw1WOiz7ESPHzZYXI981evzHAzxxn8zibr2EryopVNsXyoenw==";

/**
* Test adding a public key to the user
*
* @throws Exception
* the exception
*/
@Test
public void testAddPublicKey() throws Exception {
GHKey newPublicKey = null;
try {
GHMyself me = gitHub.getMyself();
newPublicKey = me.addPublicKey(TMP_KEY_NAME, WIREMOCK_SSH_PUBLIC_KEY);
} finally {
if (newPublicKey != null) {
newPublicKey.delete();
}
}
}
}