Skip to content

Commit 878cfbc

Browse files
Merge pull request #218 from ls1intum/chore/pmd-test-sources
Analyse the test sources with PMD
2 parents 208763d + eeb9d7e commit 878cfbc

38 files changed

Lines changed: 334 additions & 470 deletions

.settings/cpd-allowed-duplications.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,14 @@ de.tum.cit.ase.ares.api.jupiter.JupiterSecurityExtension.java
99
de.tum.cit.ase.ares.api.architecture.java.archunit.JavaArchunitTestCase.java,de.tum.cit.ase.ares.api.architecture.java.wala.JavaWalaTestCase.java
1010
de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationAdviceNetworkSystemToolbox.java,de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationAdviceThreadSystemToolbox.java
1111
de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationAdviceCommandSystemToolbox.java
12+
de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationExecutePathConstructorAdviceTest.java,de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationOverwritePathConstructorAdviceTest.java,de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationReadPathConstructorAdviceTest.java
13+
de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationOverwritePathMethodAdviceTest.java,de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationReadPathMethodAdviceTest.java
14+
de.tum.cit.ase.ares.api.securitytest.java.essentialModel.EssentialClassesTest.java,de.tum.cit.ase.ares.api.securitytest.java.essentialModel.EssentialPackagesTest.java
15+
de.tum.cit.ase.ares.integration.aop.allowed.subject.threadSystem.create.completableFuture.CreateCompletableFutureMain.java,de.tum.cit.ase.ares.integration.aop.forbidden.subject.threadSystem.create.completableFuture.CreateCompletableFutureMain.java
16+
de.tum.cit.ase.ares.integration.aop.forbidden.SystemAccessTest.java,de.tum.cit.ase.ares.integration.architecture.forbidden.SystemAccessTest.java
17+
de.tum.cit.ase.ares.integration.testuser.subject.structural.astTestFiles.classes.no.ClassWithNoKindsOfClasses.java,de.tum.cit.ase.ares.integration.testuser.subject.structural.astTestFiles.conditionals.no.ClassWithNoKindsOfConditionals.java
18+
de.tum.cit.ase.ares.integration.testuser.subject.structural.astTestFiles.classes.no.ClassWithNoKindsOfClasses.java,de.tum.cit.ase.ares.integration.testuser.subject.structural.astTestFiles.conditionals.yes.ClassWithAnyKindsOfConditionals.java,de.tum.cit.ase.ares.integration.testuser.subject.structural.astTestFiles.exceptionHandlings.no.ClassWithNoKindsOfExceptionHandlings.java,de.tum.cit.ase.ares.integration.testuser.subject.structural.astTestFiles.excludeMain.no.ClassWithNoLoopsOutsideMainMethod.java,de.tum.cit.ase.ares.integration.testuser.subject.structural.astTestFiles.loops.no.ClassWithNoKindsOfLoops.java
19+
de.tum.cit.ase.ares.integration.testuser.subject.structural.astTestFiles.classes.no.ClassWithNoKindsOfClasses.java,de.tum.cit.ase.ares.integration.testuser.subject.structural.astTestFiles.exceptionHandlings.no.ClassWithNoKindsOfExceptionHandlings.java
20+
de.tum.cit.ase.ares.integration.testuser.subject.structural.astTestFiles.classes.no.ClassWithNoKindsOfClasses.java,de.tum.cit.ase.ares.integration.testuser.subject.structural.astTestFiles.exceptionHandlings.no.ClassWithNoKindsOfExceptionHandlings.java,de.tum.cit.ase.ares.integration.testuser.subject.structural.astTestFiles.loops.yes.ClassWithAnyKindsOfLoops.java
21+
de.tum.cit.ase.ares.integration.testuser.subject.structural.astTestFiles.classes.no.ClassWithNoKindsOfClasses.java,de.tum.cit.ase.ares.integration.testuser.subject.structural.astTestFiles.excludeMain.no.ClassWithNoLoopsOutsideMainMethod.java,de.tum.cit.ase.ares.integration.testuser.subject.structural.astTestFiles.loops.no.ClassWithNoKindsOfLoops.java
22+
de.tum.cit.ase.ares.integration.testuser.subject.structural.astTestFiles.conditionals.no.ClassWithNoKindsOfConditionals.java,de.tum.cit.ase.ares.integration.testuser.subject.structural.astTestFiles.loops.yes.ClassWithAnyKindsOfLoops.java

.settings/pmd-rules.xml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,26 @@
1717

1818
<description>Ares rules: the maven-pmd-plugin defaults without the style rules the formatter owns.</description>
1919

20+
<!--
21+
Fixtures are excluded because they are test input that happens to be written in Java, not
22+
code with a quality standard to meet. `subject/` holds the student code Ares is asked to
23+
supervise, `astTestFiles` holds the deliberately malformed sources the structural analysis
24+
parses, `example/student` and `org/apache/xyz` hold impostor and malicious classes, and
25+
`testuser` holds the supervised users the integration tests execute.
26+
27+
The distinction matters in both directions. An empty catch block in the harness is a
28+
swallowed failure; in a fixture it is the behaviour under test. `UselessPureMethodCall` in
29+
MaliciousExceptionB is the attack: the class reads a forbidden file and discards the
30+
result. Cleaning any of that up would change what the suite measures while leaving it
31+
green, which is the worst possible outcome.
32+
-->
33+
<exclude-pattern>.*/src/test/java/.*/subject/.*</exclude-pattern>
34+
<exclude-pattern>.*/src/test/java/.*/astTestFiles/.*</exclude-pattern>
35+
<exclude-pattern>.*/src/test/java/example/student/.*</exclude-pattern>
36+
<exclude-pattern>.*/src/test/java/org/apache/xyz/.*</exclude-pattern>
37+
<exclude-pattern>.*/src/test/java/de/tum/cit/ase/ares/integration/testuser/.*</exclude-pattern>
38+
<exclude-pattern>.*Probe\.java</exclude-pattern>
39+
2040
<rule ref="rulesets/java/maven-pmd-plugin-default.xml">
2141
<!-- Formatting and style: owned by spotless and the Eclipse formatter. -->
2242
<exclude name="UnnecessaryFullyQualifiedName"/>

pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,11 @@
860860
<ruleset>${basedir}${file.separator}.settings${file.separator}pmd-rules.xml</ruleset>
861861
</rulesets>
862862
<excludeFromFailureFile>${basedir}${file.separator}.settings${file.separator}cpd-allowed-duplications.txt</excludeFromFailureFile>
863+
<!-- Test sources carry the harness that decides whether a security violation was
864+
detected, so leaving them unanalysed left exactly the code whose defects fail silently.
865+
The fixtures are excluded in the ruleset rather than here, because the boundary is
866+
"is this an assertion or is this the thing being asserted about", not "main or test". -->
867+
<includeTests>true</includeTests>
863868
<failOnViolation>true</failOnViolation>
864869
<printFailingErrors>true</printFailingErrors>
865870
</configuration>

src/test/java/de/tum/cit/ase/ares/api/aop/fileSystem/java/JavaFileSystemExtractorTest.java

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,7 @@ public class JavaFileSystemExtractorTest {
3535
*/
3636
@Test
3737
public void testExtractPathsAllPermissionTypesAndValid() {
38-
List<FilePermission> configs = List.of(
39-
FilePermission.builder().onThisPathAndAllPathsBelow("/a").readAllFiles(true).overwriteAllFiles(true)
40-
.executeAllFiles(true).deleteAllFiles(true).build(),
41-
FilePermission.builder().onThisPathAndAllPathsBelow("/b").readAllFiles(true).overwriteAllFiles(false)
42-
.executeAllFiles(false).deleteAllFiles(false).build(),
43-
FilePermission.builder().onThisPathAndAllPathsBelow("/c").readAllFiles(false).overwriteAllFiles(true)
44-
.executeAllFiles(false).deleteAllFiles(false).build(),
45-
FilePermission.builder().onThisPathAndAllPathsBelow("/d").readAllFiles(false).overwriteAllFiles(false)
46-
.executeAllFiles(true).deleteAllFiles(false).build(),
47-
FilePermission.builder().onThisPathAndAllPathsBelow("/e").readAllFiles(false).overwriteAllFiles(false)
48-
.executeAllFiles(false).deleteAllFiles(true).build(),
49-
FilePermission.builder().onThisPathAndAllPathsBelow("/f").readAllFiles(false).overwriteAllFiles(false)
50-
.executeAllFiles(false).deleteAllFiles(false).build());
38+
List<FilePermission> configs = sampleFilePermissions();
5139
// read
5240
List<String> readPathsExpected = List.of("/a", "/b");
5341
List<String> readPathsActual = JavaFileSystemExtractor.extractPaths(configs, FilePermission::readAllFiles);
@@ -83,19 +71,7 @@ public void testExtractPathsAllPermissionTypesAndValid() {
8371
*/
8472
@Test
8573
public void testGetPermittedFilePathsAllPermissionTypesAndInvalid() {
86-
Supplier<List<?>> supplier = () -> List.of(
87-
FilePermission.builder().onThisPathAndAllPathsBelow("/a").readAllFiles(true).overwriteAllFiles(true)
88-
.executeAllFiles(true).deleteAllFiles(true).build(),
89-
FilePermission.builder().onThisPathAndAllPathsBelow("/b").readAllFiles(true).overwriteAllFiles(false)
90-
.executeAllFiles(false).deleteAllFiles(false).build(),
91-
FilePermission.builder().onThisPathAndAllPathsBelow("/c").readAllFiles(false).overwriteAllFiles(true)
92-
.executeAllFiles(false).deleteAllFiles(false).build(),
93-
FilePermission.builder().onThisPathAndAllPathsBelow("/d").readAllFiles(false).overwriteAllFiles(false)
94-
.executeAllFiles(true).deleteAllFiles(false).build(),
95-
FilePermission.builder().onThisPathAndAllPathsBelow("/e").readAllFiles(false).overwriteAllFiles(false)
96-
.executeAllFiles(false).deleteAllFiles(true).build(),
97-
FilePermission.builder().onThisPathAndAllPathsBelow("/f").readAllFiles(false).overwriteAllFiles(false)
98-
.executeAllFiles(false).deleteAllFiles(false).build());
74+
Supplier<List<?>> supplier = () -> sampleFilePermissions();
9975
JavaFileSystemExtractor extractor = new JavaFileSystemExtractor(supplier);
10076

10177
// read
@@ -121,4 +97,20 @@ public void testGetPermittedFilePathsAllPermissionTypesAndInvalid() {
12197
// invalid
12298
Assertions.assertThrows(SecurityException.class, () -> extractor.getPermittedFilePaths("kill"));
12399
}
100+
101+
private static List<FilePermission> sampleFilePermissions() {
102+
return List.of(
103+
FilePermission.builder().onThisPathAndAllPathsBelow("/a").readAllFiles(true).overwriteAllFiles(true)
104+
.executeAllFiles(true).deleteAllFiles(true).build(),
105+
FilePermission.builder().onThisPathAndAllPathsBelow("/b").readAllFiles(true).overwriteAllFiles(false)
106+
.executeAllFiles(false).deleteAllFiles(false).build(),
107+
FilePermission.builder().onThisPathAndAllPathsBelow("/c").readAllFiles(false).overwriteAllFiles(true)
108+
.executeAllFiles(false).deleteAllFiles(false).build(),
109+
FilePermission.builder().onThisPathAndAllPathsBelow("/d").readAllFiles(false).overwriteAllFiles(false)
110+
.executeAllFiles(true).deleteAllFiles(false).build(),
111+
FilePermission.builder().onThisPathAndAllPathsBelow("/e").readAllFiles(false).overwriteAllFiles(false)
112+
.executeAllFiles(false).deleteAllFiles(true).build(),
113+
FilePermission.builder().onThisPathAndAllPathsBelow("/f").readAllFiles(false).overwriteAllFiles(false)
114+
.executeAllFiles(false).deleteAllFiles(false).build());
115+
}
124116
}

src/test/java/de/tum/cit/ase/ares/api/aop/java/aspectj/adviceandpointcut/JavaAspectJThreadSystemAdviceDefinitionsTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ private static TestContext strictTimeoutContext() throws NoSuchMethodException {
5252
return context;
5353
}
5454

55+
// Read reflectively through the mocked test context, never called from Java,
56+
// which is
57+
// why PMD cannot see the use. Deleting it would make performTimeoutExecution
58+
// run the
59+
// supplier inline and the test would stop exercising the worker.
60+
@SuppressWarnings("PMD.UnusedPrivateMethod")
5561
@StrictTimeout(value = 30, unit = TimeUnit.SECONDS)
5662
private static void strictTimeoutTarget() {
5763
// Supplies the annotation the mocked test context reports, so that

src/test/java/de/tum/cit/ase/ares/api/aop/java/instrumentation/advice/JavaInstrumentationAdviceFileSystemToolboxTest.java

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323

2424
import example.student.InstrumentationSecurityProbe;
2525

26+
/**
27+
* Carries a loopback literal for the network-adjacent cases in this class.
28+
*/
29+
@SuppressWarnings("PMD.AvoidUsingHardCodedIP")
2630
class JavaInstrumentationAdviceFileSystemToolboxTest {
2731

2832
@Test
@@ -67,6 +71,12 @@ private static void configureInstrumentationMode() {
6771
JavaAOPTestCase.setJavaAdviceSettingValue("allowedListedClasses", new String[0], "ARCH", "INSTRUMENTATION");
6872
}
6973

74+
// The MockedStatic resource is never read, and that is the point: the static
75+
// mock is
76+
// active for the scope of the try-with-resources, not through the variable. PMD
77+
// counts
78+
// it as an unused local, but a resource cannot be declared without a name.
79+
@SuppressWarnings("PMD.UnusedLocalVariable")
7080
@Test
7181
void testCheckFileSystemInteraction_AllowedInteraction() {
7282
try (MockedStatic<JavaInstrumentationAdviceFileSystemToolbox> mockedToolbox = mockStatic(
@@ -132,17 +142,8 @@ void testInstrumentationPointcutsContainNewCoverage() {
132142
@Test
133143
void testCheckFileSystemInteraction_BlocksFileUrlOpenStream(@TempDir Path tempDir) throws Exception {
134144
try {
135-
resetSettings();
136-
configureInstrumentationMode();
137-
Path allowedDir = Files.createDirectory(tempDir.resolve("allowed"));
138-
Path forbiddenFile = tempDir.resolve("forbidden.txt");
139-
Files.writeString(forbiddenFile, "secret");
140-
JavaAOPTestCase.setJavaAdviceSettingValue("pathsAllowedToBeRead", new String[] { allowedDir.toString() },
141-
"ARCH", "INSTRUMENTATION");
142-
143-
SecurityException exception = assertThrows(SecurityException.class,
144-
() -> InstrumentationSecurityProbe.checkFileUrlOpenStream(forbiddenFile.toUri().toURL()));
145-
assertTrue(exception.getMessage().contains(forbiddenFile.toAbsolutePath().toString()));
145+
SecurityException exception = triggerBlockedFileUrlOpenStream(tempDir);
146+
assertTrue(exception.getMessage().contains(tempDir.resolve("forbidden.txt").toAbsolutePath().toString()));
146147
} finally {
147148
resetSettings();
148149
}
@@ -198,16 +199,7 @@ void checkFileSystemInteraction_appendsNoAllowlistReasonWhenNoRuleConfigured(@Te
198199
void checkFileSystemInteraction_appendsNotPermittedReasonWhenConfiguredButNotAllowed(@TempDir Path tempDir)
199200
throws Exception {
200201
try {
201-
resetSettings();
202-
configureInstrumentationMode();
203-
Path allowedDir = Files.createDirectory(tempDir.resolve("allowed"));
204-
Path forbiddenFile = tempDir.resolve("forbidden.txt");
205-
Files.writeString(forbiddenFile, "secret");
206-
JavaAOPTestCase.setJavaAdviceSettingValue("pathsAllowedToBeRead", new String[] { allowedDir.toString() },
207-
"ARCH", "INSTRUMENTATION");
208-
209-
SecurityException exception = assertThrows(SecurityException.class,
210-
() -> InstrumentationSecurityProbe.checkFileUrlOpenStream(forbiddenFile.toUri().toURL()));
202+
SecurityException exception = triggerBlockedFileUrlOpenStream(tempDir);
211203
assertTrue(exception.getMessage().contains(" | Reason:") || exception.getMessage().contains(" | Grund:"),
212204
() -> "File exception should carry a denial reason suffix, but was:\n" + exception.getMessage());
213205
assertTrue(
@@ -441,4 +433,16 @@ void checkFileSystemInteraction_fileChannelTransferFromDatagramChannelChecksNetw
441433
}
442434

443435
// </editor-fold>
436+
437+
private SecurityException triggerBlockedFileUrlOpenStream(Path tempDir) throws Exception {
438+
resetSettings();
439+
configureInstrumentationMode();
440+
Path allowedDir = Files.createDirectory(tempDir.resolve("allowed"));
441+
Path forbiddenFile = tempDir.resolve("forbidden.txt");
442+
Files.writeString(forbiddenFile, "secret");
443+
JavaAOPTestCase.setJavaAdviceSettingValue("pathsAllowedToBeRead", new String[] { allowedDir.toString() },
444+
"ARCH", "INSTRUMENTATION");
445+
return assertThrows(SecurityException.class,
446+
() -> InstrumentationSecurityProbe.checkFileUrlOpenStream(forbiddenFile.toUri().toURL()));
447+
}
444448
}

src/test/java/de/tum/cit/ase/ares/api/aop/java/instrumentation/advice/JavaInstrumentationAdviceNetworkSystemToolboxTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@
3333

3434
import example.student.InstrumentationSecurityProbe;
3535

36+
/**
37+
* Loopback addresses are the input this toolbox is asked to classify.
38+
*/
39+
@SuppressWarnings("PMD.AvoidUsingHardCodedIP")
3640
class JavaInstrumentationAdviceNetworkSystemToolboxTest {
3741

3842
/**
@@ -186,6 +190,12 @@ void toTarget_returnsNullForUnresolvedSocketReceiver() throws Exception {
186190
}
187191
}
188192

193+
// `acceptedSocket` is never read either. Accepting the connection is what makes
194+
// the
195+
// client socket connected, which is the precondition under test; closing it is
196+
// what the
197+
// try-with-resources is for. Removing the resource would change the fixture.
198+
@SuppressWarnings("PMD.UnusedLocalVariable")
189199
@Test
190200
void toTarget_extractsHostAndPortFromConnectedSocket() throws Exception {
191201
Method toTarget = JavaInstrumentationAdviceNetworkSystemToolbox.class.getDeclaredMethod("toTarget",

src/test/java/de/tum/cit/ase/ares/api/aop/java/instrumentation/advice/JavaInstrumentationAdviceThreadSystemToolboxTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,9 @@ private static TestContext strictTimeoutContext() throws NoSuchMethodException {
197197
return context;
198198
}
199199

200+
// See the note in JavaAspectJThreadSystemAdviceDefinitionsTest: reflective use
201+
// only.
202+
@SuppressWarnings("PMD.UnusedPrivateMethod")
200203
@StrictTimeout(value = 30, unit = TimeUnit.SECONDS)
201204
private static void strictTimeoutTarget() {
202205
// Supplies the annotation the mocked test context reports, so that

src/test/java/de/tum/cit/ase/ares/api/aop/networkSystem/java/JavaNetworkSystemExtractorTest.java

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121
* @author Markus Paulsen
2222
* @version 2.0.0
2323
*/
24+
/**
25+
* Extracting host and port from a socket is what this class tests, so the
26+
* addresses are the subject matter rather than a configuration smell.
27+
*/
28+
@SuppressWarnings("PMD.AvoidUsingHardCodedIP")
2429
public class JavaNetworkSystemExtractorTest {
2530

2631
/**
@@ -34,17 +39,7 @@ public class JavaNetworkSystemExtractorTest {
3439
*/
3540
@Test
3641
public void testExtractHostsAndPortsAllPermissionTypesAndValid() {
37-
List<NetworkPermission> configs = List.of(
38-
NetworkPermission.builder().onTheHost("0.0.0.0").onThePort(0).openConnections(true).sendData(true)
39-
.receiveData(true).build(),
40-
NetworkPermission.builder().onTheHost("10.10.10.10").onThePort(10).openConnections(true).sendData(false)
41-
.receiveData(false).build(),
42-
NetworkPermission.builder().onTheHost("100.100.100.100").onThePort(100).openConnections(false)
43-
.sendData(true).receiveData(false).build(),
44-
NetworkPermission.builder().onTheHost("200.200.200.200").onThePort(1000).openConnections(false)
45-
.sendData(false).receiveData(true).build(),
46-
NetworkPermission.builder().onTheHost("255.255.255.255").onThePort(10000).openConnections(false)
47-
.sendData(false).receiveData(false).build());
42+
List<NetworkPermission> configs = sampleNetworkPermissions();
4843
// connect
4944
List<String> connectHosts = List.of("0.0.0.0", "10.10.10.10");
5045
List<String> connectPorts = List.of("0", "10");
@@ -82,17 +77,7 @@ public void testExtractHostsAndPortsAllPermissionTypesAndValid() {
8277
*/
8378
@Test
8479
public void testExtractHostsAndPortsAllPermissionTypesAndInvalid() {
85-
Supplier<List<?>> supplier = () -> List.of(
86-
NetworkPermission.builder().onTheHost("0.0.0.0").onThePort(0).openConnections(true).sendData(true)
87-
.receiveData(true).build(),
88-
NetworkPermission.builder().onTheHost("10.10.10.10").onThePort(10).openConnections(true).sendData(false)
89-
.receiveData(false).build(),
90-
NetworkPermission.builder().onTheHost("100.100.100.100").onThePort(100).openConnections(false)
91-
.sendData(true).receiveData(false).build(),
92-
NetworkPermission.builder().onTheHost("200.200.200.200").onThePort(1000).openConnections(false)
93-
.sendData(false).receiveData(true).build(),
94-
NetworkPermission.builder().onTheHost("255.255.255.255").onThePort(10000).openConnections(false)
95-
.sendData(false).receiveData(false).build());
80+
Supplier<List<?>> supplier = () -> sampleNetworkPermissions();
9681
JavaNetworkSystemExtractor extractor = new JavaNetworkSystemExtractor(supplier);
9782

9883
// connect hosts
@@ -122,4 +107,18 @@ public void testExtractHostsAndPortsAllPermissionTypesAndInvalid() {
122107
// invalid
123108
Assertions.assertThrows(SecurityException.class, () -> extractor.getPermittedNetworkHosts("kill"));
124109
}
110+
111+
private static List<NetworkPermission> sampleNetworkPermissions() {
112+
return List.of(
113+
NetworkPermission.builder().onTheHost("0.0.0.0").onThePort(0).openConnections(true).sendData(true)
114+
.receiveData(true).build(),
115+
NetworkPermission.builder().onTheHost("10.10.10.10").onThePort(10).openConnections(true).sendData(false)
116+
.receiveData(false).build(),
117+
NetworkPermission.builder().onTheHost("100.100.100.100").onThePort(100).openConnections(false)
118+
.sendData(true).receiveData(false).build(),
119+
NetworkPermission.builder().onTheHost("200.200.200.200").onThePort(1000).openConnections(false)
120+
.sendData(false).receiveData(true).build(),
121+
NetworkPermission.builder().onTheHost("255.255.255.255").onThePort(10000).openConnections(false)
122+
.sendData(false).receiveData(false).build());
123+
}
125124
}

0 commit comments

Comments
 (0)