diff --git a/.gitattributes b/.gitattributes index c94f078..e8d4140 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,6 @@ * text=auto *.sh eol=lf **/run eol=lf +*/usr/sbin/* eol=lf */services.d/* eol=lf cron-tick eol=lf \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index a5f05ca..11f19e2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM certbot/certbot:v1.18.0 as certbot -FROM homecentr/cron-base:2.0.4 +FROM homecentr/cron-base:2.0.6 ARG CERTBOT_PIP_VERSION="1.17.0" @@ -48,8 +48,8 @@ RUN apk add --no-cache \ COPY ./fs/ / -RUN mkdir /logs && chmod 0777 /logs +RUN chmod a+x /usr/sbin/check-dirs-writable -VOLUME "/etc/letsencrypt" -VOLUME "/data" +VOLUME "/state" +VOLUME "/certs" VOLUME "/logs" \ No newline at end of file diff --git a/README.md b/README.md index 4a09c16..c4cf315 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ services: | PUID | 7077 | UID of the user certbot be running as. | | PGID | 7077 | GID of the user certbot be running as. | | CERTBOT_ARGS | | Additional arguments passed to certbot's `certonly` command. The argument `--agree-tos` is passed automatically, but you have to provide the `--email` argument. | -| CERTS_GID | 7077 | GID of a group which set as group owner of the certificates in the `/data` directory. This is to simplify sharing the certificates with other containers/components. | +| CERTS_GID | 7077 | GID of a group which set as group owner of the certificates in the `/certs` directory. This is to simplify sharing the certificates with other containers/components. | ## Exposed ports @@ -45,9 +45,9 @@ This image does not expose any ports. | Container path | Description | |------------|---------------| -| /etc/letsencrypt | Directory where certbot keeps its state. This directory should be persisted to avoid issuing the same certificate multiple times. | -| /data | The output certificates will be placed in this directory. This is the directory you can/want share with other components. The certificates are standard files, not symlinks. | -| /logs | Certbot will output detailed logs into this directory. Make sure the PUID user has write permissions in this directory. | +| /state | Directory where certbot keeps its state. This directory should be persisted to avoid issuing the same certificate multiple times. This directory must be **writable** by PUID or PGID. | +| /certs | The output certificates will be placed in this directory. This is the directory you can/want share with other components. The certificates are standard files, not symlinks. This directory must be **writable** by PUID or PGID. | +| /logs | Certbot will output detailed logs into this directory. Make sure the PUID user has write permissions in this directory. This directory must be **writable** by PUID or PGID. | ## Security The container is regularly scanned for vulnerabilities and updated. Further info can be found in the [Security tab](https://github.com/homecentr/docker-certbot). diff --git a/fs/cron/cron-tick b/fs/cron/cron-tick index eba4ebf..48cfc48 100644 --- a/fs/cron/cron-tick +++ b/fs/cron/cron-tick @@ -1,17 +1,15 @@ #!/usr/bin/env ash # Execute certbot -certbot certonly --agree-tos --non-interactive --logs-dir /logs $CERTBOT_ARGS +certbot certonly --agree-tos --non-interactive --work-dir /state/work --config-dir /state/config --logs-dir /logs $CERTBOT_ARGS # Fix file permissions -echo "Updating certs ownership to $PUID:${CERTS_GID:-$PGID}" +echo "Updating certs group ownership to gid=${CERTS_GID:-$PGID}" -chown "$PUID" -R /etc/letsencrypt -chgrp "${CERTS_GID:-$PGID}" -R /etc/letsencrypt -chmod "0750" -R /etc/letsencrypt +# Chmod etc. usually do not follow symlinks when in recursive mode. All files in .../live/... +# are symlinks and hence the target files' permissions must be changed directly. +chgrp "${CERTS_GID:-$PGID}" -R /state/config/archive/*/*.pem +chmod "0640" -R /state/config/archive/*/*.pem -# Copy files over to /data while preserving the file permissions -cp -p /etc/letsencrypt/live/*/*.pem /data - -# Output the log files to stdout -cat /logs/* \ No newline at end of file +# Copy files over to /certs while preserving the file permissions +cp -p /state/config/live/*/*.pem /certs \ No newline at end of file diff --git a/fs/etc/cont-init.d/15-readers-group.sh b/fs/etc/cont-init.d/15-readers-group.sh index 454003c..239334a 100644 --- a/fs/etc/cont-init.d/15-readers-group.sh +++ b/fs/etc/cont-init.d/15-readers-group.sh @@ -1,29 +1,21 @@ #!/usr/bin/with-contenv ash +source homecentr_create_group +source homecentr_set_s6_env_var +source homecentr_get_s6_env_var + EXEC_USER=$(cat /var/run/s6/container_environment/EXEC_USER) if [ "$CERTS_GID" == "0" ] || [ "$CERTS_GID" == "" ] then - # User doesn't want special group ownership, the group owner of the files will be PGID, skip creating the group return fi -if [ "$CERTS_GID" == "$PGID" ] -then - CERTS_GID=$PGID -fi - -# Check if the group already exists -cat /etc/group | grep ^ssl-readers: > /dev/null - -if [ $? == 0 ] -then - # Group already exists, delete it - delgroup ssl-readers -fi - # Make sure we really need to create a separate group if [ "$PGID" != "$CERTS_GID" ] then - addgroup -g $CERTS_GID ssl-readers + homecentr_create_group "$CERTS_GID" "ssl-readers" + + # Add executing user to the group + addgroup "$EXEC_USER" ssl-readers fi \ No newline at end of file diff --git a/fs/etc/cont-init.d/16-file-permissions.sh b/fs/etc/cont-init.d/16-file-permissions.sh deleted file mode 100644 index 944d916..0000000 --- a/fs/etc/cont-init.d/16-file-permissions.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/with-contenv ash - -echo "Updating certs ownership to $PUID:${CERTS_GID:-$PGID}" -chown "$PUID" -R /data -chgrp "${CERTS_GID:-$PGID}" -R /data -chmod "0750" -R /data \ No newline at end of file diff --git a/fs/etc/cont-init.d/60-check-file-permissions.sh b/fs/etc/cont-init.d/60-check-file-permissions.sh new file mode 100644 index 0000000..b508265 --- /dev/null +++ b/fs/etc/cont-init.d/60-check-file-permissions.sh @@ -0,0 +1,4 @@ +#!/usr/bin/with-contenv ash + +# Check if directory writable as PUID/PGID, this is why it's in a separate script because it's running PUID/PGID context +runas check-dirs-writable \ No newline at end of file diff --git a/fs/etc/cont-init.d/98-verify-args.sh b/fs/etc/cont-init.d/98-verify-args.sh index 9d867f1..5d040aa 100644 --- a/fs/etc/cont-init.d/98-verify-args.sh +++ b/fs/etc/cont-init.d/98-verify-args.sh @@ -2,4 +2,6 @@ if [[ "$CERTBOT_ARGS" != *"--email"* ]]; then echo "The CERTBOT_ARGS variable must contain '--email' as certbot is executed in a non-interactive way." + + exit 1 fi \ No newline at end of file diff --git a/fs/etc/cont-init.d/99-first-execution.sh b/fs/etc/cont-init.d/99-first-execution.sh index 78d1415..0daa856 100644 --- a/fs/etc/cont-init.d/99-first-execution.sh +++ b/fs/etc/cont-init.d/99-first-execution.sh @@ -1,4 +1,4 @@ #!/usr/bin/with-contenv ash echo "Executing the certbot immediately to ensure the certificate exists..." -cron-tick-execute \ No newline at end of file +runas cron-tick-execute \ No newline at end of file diff --git a/fs/usr/sbin/check-dirs-writable b/fs/usr/sbin/check-dirs-writable new file mode 100644 index 0000000..f20fb9b --- /dev/null +++ b/fs/usr/sbin/check-dirs-writable @@ -0,0 +1,28 @@ +#!/usr/bin/env ash + +ls -l / + +SHOULD_EXIT=0 + +if ! test -w "/certs" +then + echo "Directory /certs is not writable by the user $(whoami)!" + SHOULD_EXIT=1 +fi + +if ! test -w "/logs" +then + echo "Directory /logs is not writable by the user $(whoami)!" + SHOULD_EXIT=1 +fi + +if ! test -w "/state" +then + echo "Directory /state is not writable by the user $(whoami)!" + SHOULD_EXIT=1 +fi + +if [ "$SHOULD_EXIT" != "0" ] +then + exit 2 +fi \ No newline at end of file diff --git a/tests/.idea/uiDesigner.xml b/tests/.idea/uiDesigner.xml new file mode 100644 index 0000000..e96534f --- /dev/null +++ b/tests/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/build.gradle b/tests/build.gradle index ef3a9c8..886f8f2 100644 --- a/tests/build.gradle +++ b/tests/build.gradle @@ -23,7 +23,7 @@ repositories { dependencies { testImplementation group: 'junit', name: 'junit', version: '4.13.2' testImplementation group: 'org.testcontainers', name: 'testcontainers', version: '1.16.0' - testImplementation group: 'io.homecentr', name: 'testcontainers-extensions', version: '1.6.0' + testImplementation group: 'io.homecentr', name: 'testcontainers-extensions', version: '1.7.0' testImplementation group: 'org.slf4j', name: 'slf4j-api', version: '1.7.32' testImplementation group: 'org.slf4j', name: 'slf4j-simple', version: '1.7.32' } diff --git a/tests/src/test/java/CertbotContainerShould.java b/tests/src/test/java/CertbotContainerShould.java index 84c48de..52b95a7 100644 --- a/tests/src/test/java/CertbotContainerShould.java +++ b/tests/src/test/java/CertbotContainerShould.java @@ -25,14 +25,16 @@ public class CertbotContainerShould { @BeforeClass public static void before() throws Exception { _testConfig = TestConfiguration.create(); - _testConfig.createCredentialsSecretFile(); _certbotContainer = new GenericContainerEx<>(new CertbotDockerTagResolver()) .withEnv("PUID", "9001") .withEnv("PGID", "9002") .withEnv("CRON_SCHEDULE", "* * * * *") .withEnv("CERTBOT_ARGS", _testConfig.getCertbotArgs()) - .withFileSystemBind(TestConfiguration.cloudflareCredentialsHostPath, TestConfiguration.cloudflareCredentialsContainerPath) + .withFileSystemBind(_testConfig.getCloudflareCredentialFilePath(), TestConfiguration.cloudflareCredentialsContainerPath) + .withTempDirectoryBind("/certs", 9002) + .withTempDirectoryBind("/logs", 9002) + .withTempDirectoryBind("/state", 9002) .withImagePullPolicy(PullPolicyEx.never()) .waitingFor(WaitEx.forS6OverlayStart()); @@ -49,34 +51,34 @@ public static void after() { @Test public void createCertificateFullChainFile() throws IOException, InterruptedException { - assertTrue(fileExists("/data/fullchain.pem")); + assertTrue(fileExists("/certs/fullchain.pem")); - assertEquals((Integer)9001, _certbotContainer.getFileOwnerUid("/data/fullchain.pem")); - assertEquals((Integer)9002, _certbotContainer.getFileOwningGid("/data/fullchain.pem")); + assertEquals((Integer)9001, _certbotContainer.getFileOwnerUid("/certs/fullchain.pem")); + assertEquals((Integer)9002, _certbotContainer.getFileOwningGid("/certs/fullchain.pem")); } @Test public void createCertificateChainFile() throws IOException, InterruptedException { - assertTrue(fileExists("/data/chain.pem")); + assertTrue(fileExists("/certs/chain.pem")); - assertEquals((Integer)9001, _certbotContainer.getFileOwnerUid("/data/chain.pem")); - assertEquals((Integer)9002, _certbotContainer.getFileOwningGid("/data/chain.pem")); + assertEquals((Integer)9001, _certbotContainer.getFileOwnerUid("/certs/chain.pem")); + assertEquals((Integer)9002, _certbotContainer.getFileOwningGid("/certs/chain.pem")); } @Test public void createPrivateKeyFile() throws IOException, InterruptedException { - assertTrue(fileExists("/data/privkey.pem")); + assertTrue(fileExists("/certs/privkey.pem")); - assertEquals((Integer)9001, _certbotContainer.getFileOwnerUid("/data/privkey.pem")); - assertEquals((Integer)9002, _certbotContainer.getFileOwningGid("/data/privkey.pem")); + assertEquals((Integer)9001, _certbotContainer.getFileOwnerUid("/certs/privkey.pem")); + assertEquals((Integer)9002, _certbotContainer.getFileOwningGid("/certs/privkey.pem")); } @Test public void createPublicKeyFile() throws IOException, InterruptedException { - assertTrue(fileExists("/data/cert.pem")); + assertTrue(fileExists("/certs/cert.pem")); - assertEquals((Integer)9001, _certbotContainer.getFileOwnerUid("/data/cert.pem")); - assertEquals((Integer)9002, _certbotContainer.getFileOwningGid("/data/cert.pem")); + assertEquals((Integer)9001, _certbotContainer.getFileOwnerUid("/certs/cert.pem")); + assertEquals((Integer)9002, _certbotContainer.getFileOwningGid("/certs/cert.pem")); } private boolean fileExists(String fileNamePattern) throws IOException, InterruptedException { diff --git a/tests/src/test/java/CertbotContainerWithCertsGidEnvShould.java b/tests/src/test/java/CertbotContainerWithCertsGidEnvShould.java index 022ae82..99d97e3 100644 --- a/tests/src/test/java/CertbotContainerWithCertsGidEnvShould.java +++ b/tests/src/test/java/CertbotContainerWithCertsGidEnvShould.java @@ -25,7 +25,6 @@ public class CertbotContainerWithCertsGidEnvShould { @BeforeClass public static void before() throws Exception { _testConfig = TestConfiguration.create(); - _testConfig.createCredentialsSecretFile(); _certbotContainer = new GenericContainerEx<>(new CertbotDockerTagResolver()) .withEnv("PUID", "9001") @@ -33,7 +32,10 @@ public static void before() throws Exception { .withEnv("CRON_SCHEDULE", "* * * * *") .withEnv("CERTBOT_ARGS", _testConfig.getCertbotArgs()) .withEnv("CERTS_GID", "9003") - .withFileSystemBind(TestConfiguration.cloudflareCredentialsHostPath, TestConfiguration.cloudflareCredentialsContainerPath) + .withFileSystemBind(_testConfig.getCloudflareCredentialFilePath(), TestConfiguration.cloudflareCredentialsContainerPath) + .withTempDirectoryBind("/certs", 9002) + .withTempDirectoryBind("/logs", 9002) + .withTempDirectoryBind("/state", 9002) .withImagePullPolicy(PullPolicyEx.never()) .waitingFor(WaitEx.forS6OverlayStart()); @@ -50,34 +52,34 @@ public static void after() { @Test public void createCertificateFullChainFile() throws IOException, InterruptedException { - assertTrue(fileExists("/data/fullchain.pem")); + assertTrue(fileExists("/certs/fullchain.pem")); - assertEquals((Integer)9001, _certbotContainer.getFileOwnerUid("/data/fullchain.pem")); - assertEquals((Integer)9003, _certbotContainer.getFileOwningGid("/data/fullchain.pem")); + assertEquals((Integer)9001, _certbotContainer.getFileOwnerUid("/certs/fullchain.pem")); + assertEquals((Integer)9003, _certbotContainer.getFileOwningGid("/certs/fullchain.pem")); } @Test public void createCertificateChainFile() throws IOException, InterruptedException { - assertTrue(fileExists("/data/chain.pem")); + assertTrue(fileExists("/certs/chain.pem")); - assertEquals((Integer)9001, _certbotContainer.getFileOwnerUid("/data/chain.pem")); - assertEquals((Integer)9003, _certbotContainer.getFileOwningGid("/data/chain.pem")); + assertEquals((Integer)9001, _certbotContainer.getFileOwnerUid("/certs/chain.pem")); + assertEquals((Integer)9003, _certbotContainer.getFileOwningGid("/certs/chain.pem")); } @Test public void createPrivateKeyFile() throws IOException, InterruptedException { - assertTrue(fileExists("/data/privkey.pem")); + assertTrue(fileExists("/certs/privkey.pem")); - assertEquals((Integer)9001, _certbotContainer.getFileOwnerUid("/data/privkey.pem")); - assertEquals((Integer)9003, _certbotContainer.getFileOwningGid("/data/privkey.pem")); + assertEquals((Integer)9001, _certbotContainer.getFileOwnerUid("/certs/privkey.pem")); + assertEquals((Integer)9003, _certbotContainer.getFileOwningGid("/certs/privkey.pem")); } @Test public void createPublicKeyFile() throws IOException, InterruptedException { - assertTrue(fileExists("/data/cert.pem")); + assertTrue(fileExists("/certs/cert.pem")); - assertEquals((Integer)9001, _certbotContainer.getFileOwnerUid("/data/cert.pem")); - assertEquals((Integer)9003, _certbotContainer.getFileOwningGid("/data/cert.pem")); + assertEquals((Integer)9001, _certbotContainer.getFileOwnerUid("/certs/cert.pem")); + assertEquals((Integer)9003, _certbotContainer.getFileOwningGid("/certs/cert.pem")); } private boolean fileExists(String fileNamePattern) throws IOException, InterruptedException { diff --git a/tests/src/test/java/CertbotContainerWithoutEmailShould.java b/tests/src/test/java/CertbotContainerWithoutEmailShould.java index 8ce425b..6fc772e 100644 --- a/tests/src/test/java/CertbotContainerWithoutEmailShould.java +++ b/tests/src/test/java/CertbotContainerWithoutEmailShould.java @@ -7,30 +7,41 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.testcontainers.containers.output.Slf4jLogConsumer; +import org.testcontainers.containers.ContainerLaunchException; +import java.io.IOException; import java.time.Duration; import static io.homecentr.testcontainers.WaitLoop.waitFor; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; public class CertbotContainerWithoutEmailShould { private static final Logger logger = LoggerFactory.getLogger(CertbotContainerWithoutEmailShould.class); private static GenericContainerEx _certbotContainer; + private static TestConfiguration _testConfig; @BeforeClass - public static void before() { + public static void before() throws IOException { + _testConfig = TestConfiguration.create(); + _certbotContainer = new GenericContainerEx<>(new CertbotDockerTagResolver()) .withEnv("CRON_SCHEDULE", "* * * * *") .withEnv("CERTBOT_ARGS", "") - .withFileSystemBind(TestConfiguration.cloudflareCredentialsHostPath, TestConfiguration.cloudflareCredentialsContainerPath) + .withEnv("PUID", "0") + .withEnv("PGID", "0") + .withFileSystemBind(_testConfig.getCloudflareCredentialFilePath(), TestConfiguration.cloudflareCredentialsContainerPath) + .withTempDirectoryBind("/certs", 9002) + .withTempDirectoryBind("/logs", 9002) + .withTempDirectoryBind("/state", 9002) .withImagePullPolicy(PullPolicyEx.never()) .waitingFor(WaitEx.forS6OverlayStart()); - _certbotContainer.start(); - _certbotContainer.followOutput(new Slf4jLogConsumer(logger)); + try { + _certbotContainer.start(); + } + catch (ContainerLaunchException ex) { + // Expected + } } @AfterClass @@ -39,12 +50,12 @@ public static void after() { } @Test - public void printWarning() { - assertTrue(_certbotContainer.getLogsAnalyzer().contains("The CERTBOT_ARGS variable must contain '--email'")); + public void printWarning() throws Exception { + waitFor(Duration.ofSeconds(20), () -> _certbotContainer.getLogsAnalyzer().contains("The CERTBOT_ARGS variable must contain '--email'")); } @Test public void exitContainer() throws Exception { - waitFor(Duration.ofSeconds(20), () -> _certbotContainer.isRunning()); + waitFor(Duration.ofSeconds(20), () -> !_certbotContainer.isRunning()); } } diff --git a/tests/src/test/java/CertbotContainerWithoutWritableVolumesShould.java b/tests/src/test/java/CertbotContainerWithoutWritableVolumesShould.java new file mode 100644 index 0000000..d164500 --- /dev/null +++ b/tests/src/test/java/CertbotContainerWithoutWritableVolumesShould.java @@ -0,0 +1,74 @@ +import helpers.CertbotDockerTagResolver; +import io.homecentr.testcontainers.containers.GenericContainerEx; +import io.homecentr.testcontainers.containers.wait.strategy.WaitEx; +import io.homecentr.testcontainers.images.PullPolicyEx; +import org.junit.Test; +import org.testcontainers.containers.ContainerLaunchException; + +import java.time.Duration; + +import static io.homecentr.testcontainers.WaitLoop.waitFor; + +public class CertbotContainerWithoutWritableVolumesShould { + @Test + public void failWhenCertsDirNotWritable() throws Exception { + GenericContainerEx container = new GenericContainerEx<>(new CertbotDockerTagResolver()) + .withEnv("CRON_SCHEDULE", "* * * * *") + .withEnv("CERTBOT_ARGS", "") + .withEnv("PUID", "9001") + .withEnv("PGID", "9002") + .withTempDirectoryBind("/certs", 0) + .withTempDirectoryBind("/logs", 9002) + .withTempDirectoryBind("/state", 9002) + .withImagePullPolicy(PullPolicyEx.never()) + .waitingFor(WaitEx.forS6OverlayStart()); + + assertExits(container); + } + + @Test + public void failWhenLogsDirNotWritable() throws Exception { + GenericContainerEx container = new GenericContainerEx<>(new CertbotDockerTagResolver()) + .withEnv("CRON_SCHEDULE", "* * * * *") + .withEnv("CERTBOT_ARGS", "") + .withEnv("PUID", "9001") + .withEnv("PGID", "9002") + .withTempDirectoryBind("/certs", 9002) + .withTempDirectoryBind("/logs", 0) + .withTempDirectoryBind("/state", 9002) + .withImagePullPolicy(PullPolicyEx.never()) + .waitingFor(WaitEx.forS6OverlayStart()); + + assertExits(container); + } + + @Test + public void failWhenStateDirNotWritable() throws Exception { + GenericContainerEx container = new GenericContainerEx<>(new CertbotDockerTagResolver()) + .withEnv("CRON_SCHEDULE", "* * * * *") + .withEnv("CERTBOT_ARGS", "") + .withEnv("PUID", "9001") + .withEnv("PGID", "9002") + .withTempDirectoryBind("/certs", 9002) + .withTempDirectoryBind("/logs", 9002) + .withTempDirectoryBind("/state", 0) + .withImagePullPolicy(PullPolicyEx.never()) + .waitingFor(WaitEx.forS6OverlayStart()); + + assertExits(container); + } + + private void assertExits(GenericContainerEx container) throws Exception { + // start + + try { + container.start(); + } + catch (ContainerLaunchException ex) { + // Expected + } + + waitFor(Duration.ofSeconds(10), () -> !container.isRunning()); + waitFor(Duration.ofSeconds(10), () -> !container.getLogsAnalyzer().contains(".*not writable.*")); + } +} diff --git a/tests/src/test/java/ContainerTestBase.java b/tests/src/test/java/ContainerTestBase.java deleted file mode 100644 index 2b143bd..0000000 --- a/tests/src/test/java/ContainerTestBase.java +++ /dev/null @@ -1,36 +0,0 @@ -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.output.Slf4jLogConsumer; -import org.testcontainers.containers.wait.strategy.Wait; - -public abstract class ContainerTestBase { - private static final Logger logger = LoggerFactory.getLogger(ContainerTestBase.class); - - private static GenericContainer _container; - - @BeforeClass - public static void setUp() { - String dockerImageTag = System.getProperty("image_tag", "homecentr/certbot"); - - logger.info("Tested Docker image tag: {}", dockerImageTag); - - _container = new GenericContainer<>(dockerImageTag) - .waitingFor(Wait.forHealthcheck()); - - _container.start(); - _container.followOutput(new Slf4jLogConsumer(logger)); - } - - @AfterClass - public static void cleanUp() { - _container.stop(); - _container.close(); - } - - protected GenericContainer getContainer() { - return _container; - } -} \ No newline at end of file diff --git a/tests/src/test/java/TestConfiguration.java b/tests/src/test/java/TestConfiguration.java index 0e49906..dd9725a 100644 --- a/tests/src/test/java/TestConfiguration.java +++ b/tests/src/test/java/TestConfiguration.java @@ -2,21 +2,23 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; -import java.nio.file.Paths; import java.util.UUID; public class TestConfiguration { private final String _randomPrefix; + private String _cloudflareCredentialFilePath; + public static final String cloudflareCredentialsContainerPath = "/config/cloudflare.init.tmp"; - public static final String cloudflareCredentialsHostPath = Paths.get(System.getProperty("user.dir"), "..", "cloudflare.init.tmp").normalize().toString(); - public static TestConfiguration create() { + public static TestConfiguration create() throws IOException { String prefix = UUID.randomUUID().toString(); - return new TestConfiguration(prefix); - } + TestConfiguration result = new TestConfiguration(prefix); + result.createCredentialsSecretFile(); + return result; + } private TestConfiguration(String randomPrefix) { _randomPrefix = randomPrefix; @@ -33,17 +35,19 @@ public String getCertbotArgs() { getDomain()); } - public void createCredentialsSecretFile() throws IOException { - File secretFile = new File(cloudflareCredentialsHostPath); + public String getCloudflareCredentialFilePath() { + return _cloudflareCredentialFilePath; + } - if(secretFile.exists()) { - secretFile.delete(); - } + private void createCredentialsSecretFile() throws IOException { + File credentialsFile = File.createTempFile("cloudflare", "creds"); - try (BufferedWriter writer = new BufferedWriter(new FileWriter(secretFile))) { + try (BufferedWriter writer = new BufferedWriter(new FileWriter(credentialsFile))) { writer.write("dns_cloudflare_api_token = " + getCloudflareToken()); writer.flush(); } + + _cloudflareCredentialFilePath = credentialsFile.getAbsolutePath(); } private String getCloudflareToken() {