Skip to content

Commit 7af0dc5

Browse files
josh-cainrnorth
authored andcommitted
add container arguments to specify SELinux contexts for mounts (#334)
* add container arguments to specify SELinux contexts for mounts * remove unused import in test * address review requests comments for formatting, lombok annotations, and clarity around SELinux
1 parent 6411ce5 commit 7af0dc5

File tree

4 files changed

+78
-8
lines changed

4 files changed

+78
-8
lines changed

core/src/main/java/org/testcontainers/containers/Container.java

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,24 @@ public String getStderr() {
8080
* Adds a file system binding. Consider using {@link #withFileSystemBind(String, String, BindMode)}
8181
* for building a container in a fluent style.
8282
*
83-
* @param hostPath the file system path on the host
83+
* @param hostPath the file system path on the host
8484
* @param containerPath the file system path inside the container
85-
* @param mode the bind mode
85+
* @param mode the bind mode
86+
*/
87+
default void addFileSystemBind(final String hostPath, final String containerPath, final BindMode mode) {
88+
addFileSystemBind(hostPath, containerPath, mode, SelinuxContext.NONE);
89+
}
90+
91+
/**
92+
* Adds a file system binding. Consider using {@link #withFileSystemBind(String, String, BindMode)}
93+
* for building a container in a fluent style.
94+
*
95+
* @param hostPath the file system path on the host
96+
* @param containerPath the file system path inside the container
97+
* @param mode the bind mode
98+
* @param selinuxContext selinux context argument to use for this file
8699
*/
87-
void addFileSystemBind(String hostPath, String containerPath, BindMode mode);
100+
void addFileSystemBind(String hostPath, String containerPath, BindMode mode, SelinuxContext selinuxContext);
88101

89102
/**
90103
* Add a link to another container.
@@ -205,7 +218,22 @@ public String getStderr() {
205218
* @param mode access mode for the file
206219
* @return this
207220
*/
208-
SELF withClasspathResourceMapping(String resourcePath, String containerPath, BindMode mode);
221+
default SELF withClasspathResourceMapping(final String resourcePath, final String containerPath, final BindMode mode) {
222+
withClasspathResourceMapping(resourcePath, containerPath, mode, SelinuxContext.NONE);
223+
return self();
224+
}
225+
226+
/**
227+
* Map a resource (file or directory) on the classpath to a path inside the container.
228+
* This will only work if you are running your tests outside a Docker container.
229+
*
230+
* @param resourcePath path to the resource on the classpath (relative to the classpath root; should not start with a leading slash)
231+
* @param containerPath path this should be mapped to inside the container
232+
* @param mode access mode for the file
233+
* @param selinuxContext selinux context argument to use for this file
234+
* @return this
235+
*/
236+
SELF withClasspathResourceMapping(String resourcePath, String containerPath, BindMode mode, SelinuxContext selinuxContext);
209237

210238
/**
211239
* Set the duration of waiting time until container treated as started.

core/src/main/java/org/testcontainers/containers/GenericContainer.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -485,10 +485,10 @@ public void addEnv(String key, String value) {
485485
* {@inheritDoc}
486486
*/
487487
@Override
488-
public void addFileSystemBind(String hostPath, String containerPath, BindMode mode) {
488+
public void addFileSystemBind(final String hostPath, final String containerPath, final BindMode mode, final SelinuxContext selinuxContext) {
489489

490490
final MountableFile mountableFile = MountableFile.forHostPath(hostPath);
491-
binds.add(new Bind(mountableFile.getResolvedPath(), new Volume(containerPath), mode.accessMode));
491+
binds.add(new Bind(mountableFile.getResolvedPath(), new Volume(containerPath), mode.accessMode, selinuxContext.selContext));
492492
}
493493

494494
/**
@@ -619,10 +619,18 @@ public SELF withNetworkMode(String networkMode) {
619619
* {@inheritDoc}
620620
*/
621621
@Override
622-
public SELF withClasspathResourceMapping(String resourcePath, String containerPath, BindMode mode) {
622+
public SELF withClasspathResourceMapping(final String resourcePath, final String containerPath, final BindMode mode) {
623+
return withClasspathResourceMapping(resourcePath, containerPath, mode, SelinuxContext.NONE);
624+
}
625+
626+
/**
627+
* {@inheritDoc}
628+
*/
629+
@Override
630+
public SELF withClasspathResourceMapping(final String resourcePath, final String containerPath, final BindMode mode, final SelinuxContext selinuxContext) {
623631
final MountableFile mountableFile = MountableFile.forClasspathResource(resourcePath);
624632

625-
this.addFileSystemBind(mountableFile.getResolvedPath(), containerPath, mode);
633+
this.addFileSystemBind(mountableFile.getResolvedPath(), containerPath, mode, selinuxContext);
626634

627635
return self();
628636
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.testcontainers.containers;
2+
3+
import com.github.dockerjava.api.model.SELContext;
4+
import lombok.AllArgsConstructor;
5+
6+
/**
7+
* Possible contexts for use with SELinux
8+
*/
9+
@AllArgsConstructor
10+
public enum SelinuxContext {
11+
SHARED(SELContext.shared),
12+
SINGLE(SELContext.single),
13+
NONE(SELContext.none);
14+
15+
public final SELContext selContext;
16+
17+
}

core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525

2626
import static org.rnorth.visibleassertions.VisibleAssertions.*;
2727
import static org.testcontainers.containers.BindMode.READ_ONLY;
28+
import static org.testcontainers.containers.BindMode.READ_WRITE;
29+
import static org.testcontainers.containers.SelinuxContext.SHARED;
2830

2931
/**
3032
* Tests for GenericContainerRules
@@ -101,6 +103,15 @@ public static void setupContent() throws FileNotFoundException {
101103
.withClasspathResourceMapping("mappable-resource/test-resource.txt", "/content.txt", READ_ONLY)
102104
.withCommand("/bin/sh", "-c", "while true; do cat /content.txt | nc -l -p 80; done");
103105

106+
/**
107+
* Map a file on the classpath to a file in the container, and then expose the content for testing.
108+
*/
109+
@ClassRule
110+
public static GenericContainer alpineClasspathResourceSelinux = new GenericContainer("alpine:3.2")
111+
.withExposedPorts(80)
112+
.withClasspathResourceMapping("mappable-resource/test-resource.txt", "/content.txt", READ_WRITE, SHARED)
113+
.withCommand("/bin/sh", "-c", "while true; do cat /content.txt | nc -l -p 80; done");
114+
104115
/**
105116
* Create a container with an extra host entry and expose the content of /etc/hosts for testing.
106117
*/
@@ -203,6 +214,12 @@ public void customClasspathResourceMappingTest() throws IOException {
203214
assertEquals("Resource on the classpath can be mapped using calls to withClasspathResourceMapping", "FOOBAR", line);
204215
}
205216

217+
@Test
218+
public void customClasspathResourceMappingWithSelinuxTest() throws IOException {
219+
String line = getReaderForContainerPort80(alpineClasspathResourceSelinux).readLine();
220+
assertEquals("Resource on the classpath can be mapped using calls to withClasspathResourceMappingSelinux", "FOOBAR", line);
221+
}
222+
206223
@Test
207224
public void exceptionThrownWhenMappedPortNotFound() throws IOException {
208225
assertThrows("When the requested port is not mapped, getMappedPort() throws an exception",

0 commit comments

Comments
 (0)