diff --git a/pom.xml b/pom.xml
index 7d06b730cf..828a9c6507 100644
--- a/pom.xml
+++ b/pom.xml
@@ -409,6 +409,18 @@ OF THE POSSIBILITY OF SUCH DAMAGE.
0.0.3
test
+
+ uk.org.webcompere
+ system-stubs-core
+ 2.1.7
+ test
+
+
+ uk.org.webcompere
+ system-stubs-jupiter
+ 2.1.7
+ test
+
@@ -478,6 +490,30 @@ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ maven-resources-plugin
+
+
+ copy-resources
+ initialize
+
+ copy-resources
+
+
+ ${project.build.outputDirectory}/rultor-mf
+
+
+ src/main/resources/META-INF
+ false
+
+ MANIFEST.MF
+
+
+
+
+
+
+
maven-deploy-plugin
diff --git a/src/main/java/com/rultor/Env.java b/src/main/java/com/rultor/Env.java
new file mode 100644
index 0000000000..20a5e91da7
--- /dev/null
+++ b/src/main/java/com/rultor/Env.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2009-2024 Yegor Bugayenko
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met: 1) Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer. 2) Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution. 3) Neither the name of the rultor.com nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
+ * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.rultor;
+
+import com.jcabi.manifests.Manifests;
+import com.jcabi.xml.XMLDocument;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.cactoos.io.ResourceOf;
+import org.cactoos.text.TextOf;
+import org.cactoos.text.UncheckedText;
+
+/**
+ * Environment variables either provided in the {@code MANIFEST.MF}
+ * file or through shell variables.
+ *
+ * @since 1.50
+ */
+public final class Env {
+
+ /**
+ * Private.
+ */
+ private Env() {
+ // utility class
+ }
+
+ /**
+ * Read one.
+ * @param name The name of the variable
+ * @return The value
+ */
+ @SuppressWarnings("PMD.ProhibitPublicStaticMethods")
+ public static String read(final String name) {
+ final String xml = System.getenv("SETTINGS_XML");
+ final String ret;
+ if (xml == null) {
+ ret = Manifests.read(name);
+ } else {
+ final String res = "rultor-mf/MANIFEST.MF";
+ final String manifest = new UncheckedText(
+ new TextOf(new ResourceOf(res))
+ ).asString();
+ final Matcher matcher = Pattern.compile(
+ String.format("%s: \\$\\{([^}]+)}", name)
+ ).matcher(manifest);
+ if (!matcher.find()) {
+ throw new IllegalArgumentException(
+ String.format("Can't find '%s' in %s:%n%s", name, res, manifest)
+ );
+ }
+ final String prop = matcher.group(1);
+ ret = new XMLDocument(xml).xpath(
+ String.format("/settings//*[name()='%s']/text()", prop)
+ ).get(0);
+ }
+ return ret;
+ }
+
+}
diff --git a/src/test/java/com/rultor/EnvTest.java b/src/test/java/com/rultor/EnvTest.java
new file mode 100644
index 0000000000..cafa601121
--- /dev/null
+++ b/src/test/java/com/rultor/EnvTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2009-2024 Yegor Bugayenko
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met: 1) Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer. 2) Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution. 3) Neither the name of the rultor.com nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
+ * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.rultor;
+
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.extension.ExtendWith;
+import uk.org.webcompere.systemstubs.environment.EnvironmentVariables;
+import uk.org.webcompere.systemstubs.jupiter.SystemStub;
+import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension;
+
+/**
+ * Test case for {@link Env}.
+ *
+ * @since 1.58
+ */
+@ExtendWith(SystemStubsExtension.class)
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+final class EnvTest {
+
+ /**
+ * Environment variables.
+ */
+ @SystemStub
+ private EnvironmentVariables environment;
+
+ @Test
+ void readsFromManifest() {
+ this.environment.remove("SETTINGS_XML");
+ MatcherAssert.assertThat(
+ "takes the right value",
+ Env.read("Rultor-SecurityKey"),
+ Matchers.equalTo("${failsafe.security.key}")
+ );
+ }
+
+ @Test
+ void readsFromSettingsXml() {
+ this.environment.set(
+ "SETTINGS_XML",
+ String.join(
+ "",
+ "",
+ "hello",
+ ""
+ )
+ );
+ MatcherAssert.assertThat(
+ "has the right XML in env",
+ System.getenv("SETTINGS_XML"),
+ Matchers.not(Matchers.nullValue())
+ );
+ MatcherAssert.assertThat(
+ "takes the right value",
+ Env.read("Rultor-DynamoKey"),
+ Matchers.equalTo("hello")
+ );
+ }
+}