Skip to content

Commit c04bf3e

Browse files
authored
Validate field lengths in checks annotations + actions (#109)
Automatically validates the maximum length of properties. GitHub does not validate these properly on their side (at least in GHE 3.2) and returns 5xx HTTP responses instead. To avoid that, let's validate the data in this client library. The values are taken from the official GitHub documentation. Other fields might also have restrictions that are undocumented. We might add validation for these later.
1 parent d3a7af0 commit c04bf3e

File tree

4 files changed

+174
-0
lines changed

4 files changed

+174
-0
lines changed

src/main/java/com/spotify/github/v3/checks/Annotation.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
import com.fasterxml.jackson.annotation.JsonInclude;
2424
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
25+
import com.google.common.base.Preconditions;
2526
import com.spotify.github.GithubStyle;
2627
import java.util.Optional;
2728
import org.immutables.value.Value;
@@ -114,4 +115,23 @@ public interface Annotation {
114115
* @return the optional
115116
*/
116117
Optional<Integer> endColumn();
118+
119+
/**
120+
* Automatically validates the maximum length of properties.
121+
*
122+
* GitHub does not validate these properly on their side (at least in GHE 3.2)
123+
* and returns 5xx HTTP responses instead. To avoid that, let's validate the data
124+
* in this client library.
125+
*/
126+
@Value.Check
127+
@SuppressWarnings("checkstyle:magicnumber")
128+
default void check() {
129+
// max values from https://docs.github.com/en/rest/checks/runs
130+
Preconditions.checkState(title().map(String::length).orElse(0) <= 255,
131+
"'title' exceeded max length of 255");
132+
Preconditions.checkState(message().length() <= 64 * 1024,
133+
"'message' exceeded max length of 64kB");
134+
Preconditions.checkState(rawDetails().map(String::length).orElse(0) <= 64 * 1024,
135+
"'rawDetails' exceeded max length of 64kB");
136+
}
117137
}

src/main/java/com/spotify/github/v3/checks/CheckRunAction.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
package com.spotify.github.v3.checks;
2222

2323
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
24+
import com.google.common.base.Preconditions;
2425
import com.spotify.github.GithubStyle;
2526
import org.immutables.value.Value;
2627

@@ -57,4 +58,23 @@ public interface CheckRunAction {
5758
* @return the string
5859
*/
5960
String description();
61+
62+
/**
63+
* Automatically validates the maximum length of properties.
64+
*
65+
* GitHub does not validate these properly on their side (at least in GHE 3.2)
66+
* and returns 5xx HTTP responses instead. To avoid that, let's validate the data
67+
* in this client library.
68+
*/
69+
@Value.Check
70+
@SuppressWarnings("checkstyle:magicnumber")
71+
default void check() {
72+
// max values from https://docs.github.com/en/rest/checks/runs
73+
Preconditions.checkState(label().length() <= 20,
74+
"'label' exceeded max length of 20");
75+
Preconditions.checkState(identifier().length() <= 20,
76+
"'identifier' exceeded max length of 20");
77+
Preconditions.checkState(description().length() <= 40,
78+
"'description' exceeded max length of 40");
79+
}
6080
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*-
2+
* -\-\-
3+
* github-client
4+
* --
5+
* Copyright (C) 2016 - 2022 Spotify AB
6+
* --
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* -/-/-
19+
*/
20+
21+
package com.spotify.github.v3.checks;
22+
23+
import static org.hamcrest.CoreMatchers.is;
24+
import static org.hamcrest.MatcherAssert.assertThat;
25+
import static org.junit.jupiter.api.Assertions.assertThrows;
26+
27+
import com.spotify.github.FixtureHelper;
28+
import com.spotify.github.jackson.Json;
29+
import com.spotify.github.v3.checks.ImmutableAnnotation.Builder;
30+
import java.io.IOException;
31+
import java.time.ZonedDateTime;
32+
import org.junit.Test;
33+
34+
public class AnnotationTest {
35+
private Builder builder() {
36+
return ImmutableAnnotation.builder()
37+
.title("title")
38+
.message("message")
39+
.rawDetails("rawDetails")
40+
.path("path")
41+
.startLine(1)
42+
.endLine(2)
43+
.annotationLevel(AnnotationLevel.notice);
44+
}
45+
46+
@Test
47+
public void allowsCreationWithinLimits(){
48+
builder().build();
49+
50+
builder()
51+
.title("a".repeat(255))
52+
.message("a".repeat(64000))
53+
.rawDetails("a".repeat(64000))
54+
.build();
55+
}
56+
57+
@Test
58+
public void failsCreationWhenMaxLengthExceeded(){
59+
assertThrows(IllegalStateException.class, () ->
60+
builder().title("a".repeat(256)).build()
61+
);
62+
assertThrows(IllegalStateException.class, () ->
63+
builder().message("a".repeat(66000)).build()
64+
);
65+
assertThrows(IllegalStateException.class, () ->
66+
builder().rawDetails("a".repeat(66000)).build()
67+
);
68+
}
69+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*-
2+
* -\-\-
3+
* github-client
4+
* --
5+
* Copyright (C) 2016 - 2022 Spotify AB
6+
* --
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* -/-/-
19+
*/
20+
21+
package com.spotify.github.v3.checks;
22+
23+
import static org.hamcrest.CoreMatchers.is;
24+
import static org.hamcrest.MatcherAssert.assertThat;
25+
import static org.junit.jupiter.api.Assertions.assertThrows;
26+
27+
import com.spotify.github.FixtureHelper;
28+
import com.spotify.github.jackson.Json;
29+
import com.spotify.github.v3.checks.ImmutableCheckRunAction.Builder;
30+
import java.io.IOException;
31+
import java.time.ZonedDateTime;
32+
import org.junit.Test;
33+
34+
public class CheckRunActionTest {
35+
private Builder builder() {
36+
return ImmutableCheckRunAction.builder()
37+
.label("label")
38+
.identifier("identifier")
39+
.description("description");
40+
}
41+
42+
@Test
43+
public void allowsCreationWithinLimits(){
44+
builder().build();
45+
46+
builder()
47+
.label("a".repeat(20))
48+
.identifier("a".repeat(20))
49+
.description("a".repeat(40))
50+
.build();
51+
}
52+
53+
@Test
54+
public void failsCreationWhenMaxLengthExceeded(){
55+
assertThrows(IllegalStateException.class, () ->
56+
builder().label("a".repeat(21)).build()
57+
);
58+
assertThrows(IllegalStateException.class, () ->
59+
builder().identifier("a".repeat(21)).build()
60+
);
61+
assertThrows(IllegalStateException.class, () ->
62+
builder().description("a".repeat(41)).build()
63+
);
64+
}
65+
}

0 commit comments

Comments
 (0)