mirror of
https://github.com/lightbend/config.git
synced 2025-01-13 22:00:47 +08:00
fix: Optionally hide rendered environment variables (#798)
* new OriginType.ENV_VARIABLE * deserialization of unknown originType ordinal, but this doesn't really help for compatibility if serialized with new version and deserialized with old version
This commit is contained in:
parent
5d6a46631c
commit
3a4ebbfd02
@ -95,7 +95,11 @@ lazy val configLib = Project("config", file("config"))
|
|||||||
"CONFIG_FORCE_a__c" -> "3",
|
"CONFIG_FORCE_a__c" -> "3",
|
||||||
"CONFIG_FORCE_a___c" -> "4",
|
"CONFIG_FORCE_a___c" -> "4",
|
||||||
"CONFIG_FORCE_akka_version" -> "foo",
|
"CONFIG_FORCE_akka_version" -> "foo",
|
||||||
"CONFIG_FORCE_akka_event__handler__dispatcher_max__pool__size" -> "10")
|
"CONFIG_FORCE_akka_event__handler__dispatcher_max__pool__size" -> "10",
|
||||||
|
"SECRET_A" -> "A", // ConfigTest.renderShowEnvVariableValues
|
||||||
|
"SECRET_B" -> "B", // ConfigTest.renderShowEnvVariableValues
|
||||||
|
"SECRET_C" -> "C" // ConfigTest.renderShowEnvVariableValues
|
||||||
|
)
|
||||||
|
|
||||||
OsgiKeys.exportPackage := Seq("com.typesafe.config", "com.typesafe.config.impl")
|
OsgiKeys.exportPackage := Seq("com.typesafe.config", "com.typesafe.config.impl")
|
||||||
publish := sys.error("use publishSigned instead of plain publish")
|
publish := sys.error("use publishSigned instead of plain publish")
|
||||||
|
@ -21,13 +21,15 @@ public final class ConfigRenderOptions {
|
|||||||
private final boolean comments;
|
private final boolean comments;
|
||||||
private final boolean formatted;
|
private final boolean formatted;
|
||||||
private final boolean json;
|
private final boolean json;
|
||||||
|
private final boolean showEnvVariableValues;
|
||||||
|
|
||||||
private ConfigRenderOptions(boolean originComments, boolean comments, boolean formatted,
|
private ConfigRenderOptions(boolean originComments, boolean comments, boolean formatted,
|
||||||
boolean json) {
|
boolean json, boolean showEnvVariableValues) {
|
||||||
this.originComments = originComments;
|
this.originComments = originComments;
|
||||||
this.comments = comments;
|
this.comments = comments;
|
||||||
this.formatted = formatted;
|
this.formatted = formatted;
|
||||||
this.json = json;
|
this.json = json;
|
||||||
|
this.showEnvVariableValues = showEnvVariableValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,7 +40,7 @@ public final class ConfigRenderOptions {
|
|||||||
* @return the default render options
|
* @return the default render options
|
||||||
*/
|
*/
|
||||||
public static ConfigRenderOptions defaults() {
|
public static ConfigRenderOptions defaults() {
|
||||||
return new ConfigRenderOptions(true, true, true, true);
|
return new ConfigRenderOptions(true, true, true, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -48,7 +50,7 @@ public final class ConfigRenderOptions {
|
|||||||
* @return the concise render options
|
* @return the concise render options
|
||||||
*/
|
*/
|
||||||
public static ConfigRenderOptions concise() {
|
public static ConfigRenderOptions concise() {
|
||||||
return new ConfigRenderOptions(false, false, false, true);
|
return new ConfigRenderOptions(false, false, false, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,7 +66,7 @@ public final class ConfigRenderOptions {
|
|||||||
if (value == comments)
|
if (value == comments)
|
||||||
return this;
|
return this;
|
||||||
else
|
else
|
||||||
return new ConfigRenderOptions(originComments, value, formatted, json);
|
return new ConfigRenderOptions(originComments, value, formatted, json, showEnvVariableValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -97,7 +99,7 @@ public final class ConfigRenderOptions {
|
|||||||
if (value == originComments)
|
if (value == originComments)
|
||||||
return this;
|
return this;
|
||||||
else
|
else
|
||||||
return new ConfigRenderOptions(value, comments, formatted, json);
|
return new ConfigRenderOptions(value, comments, formatted, json, showEnvVariableValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -122,7 +124,7 @@ public final class ConfigRenderOptions {
|
|||||||
if (value == formatted)
|
if (value == formatted)
|
||||||
return this;
|
return this;
|
||||||
else
|
else
|
||||||
return new ConfigRenderOptions(originComments, comments, value, json);
|
return new ConfigRenderOptions(originComments, comments, value, json, showEnvVariableValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -150,7 +152,32 @@ public final class ConfigRenderOptions {
|
|||||||
if (value == json)
|
if (value == json)
|
||||||
return this;
|
return this;
|
||||||
else
|
else
|
||||||
return new ConfigRenderOptions(originComments, comments, formatted, value);
|
return new ConfigRenderOptions(originComments, comments, formatted, value, showEnvVariableValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns options with showEnvVariableValues toggled. This controls if values set from
|
||||||
|
* environment variables are included in the rendered string.
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* true to include environment variable values in the render
|
||||||
|
* @return options with requested setting for environment variables
|
||||||
|
*/
|
||||||
|
public ConfigRenderOptions setShowEnvVariableValues(boolean value) {
|
||||||
|
if (value == showEnvVariableValues)
|
||||||
|
return this;
|
||||||
|
else
|
||||||
|
return new ConfigRenderOptions(originComments, comments, formatted, json, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the options enable rendering of environment variable values. This method is mostly used
|
||||||
|
* by the config lib internally, not by applications.
|
||||||
|
*
|
||||||
|
* @return true if environment variable values should be rendered
|
||||||
|
*/
|
||||||
|
public boolean getShowEnvVariableValues() {
|
||||||
|
return showEnvVariableValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -174,6 +201,8 @@ public final class ConfigRenderOptions {
|
|||||||
sb.append("formatted,");
|
sb.append("formatted,");
|
||||||
if (json)
|
if (json)
|
||||||
sb.append("json,");
|
sb.append("json,");
|
||||||
|
if (showEnvVariableValues)
|
||||||
|
sb.append("showEnvVariableValues,");
|
||||||
if (sb.charAt(sb.length() - 1) == ',')
|
if (sb.charAt(sb.length() - 1) == ',')
|
||||||
sb.setLength(sb.length() - 1);
|
sb.setLength(sb.length() - 1);
|
||||||
sb.append(")");
|
sb.append(")");
|
||||||
|
@ -357,8 +357,20 @@ abstract class AbstractConfigValue implements ConfigValue, MergeableValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void render(StringBuilder sb, int indent, boolean atRoot, ConfigRenderOptions options) {
|
protected void render(StringBuilder sb, int indent, boolean atRoot, ConfigRenderOptions options) {
|
||||||
Object u = unwrapped();
|
if (hideEnvVariableValue(options)) {
|
||||||
sb.append(u.toString());
|
sb.append("<env variable>");
|
||||||
|
} else {
|
||||||
|
Object u = unwrapped();
|
||||||
|
sb.append(u.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean hideEnvVariableValue(ConfigRenderOptions options) {
|
||||||
|
return !options.getShowEnvVariableValues() && origin.originType() == OriginType.ENV_VARIABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void appendHiddenEnvVariableValue(StringBuilder sb) {
|
||||||
|
sb.append("\"<env variable>\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -342,7 +342,7 @@ public class ConfigImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static AbstractConfigObject loadEnvVariables() {
|
private static AbstractConfigObject loadEnvVariables() {
|
||||||
return PropertiesParser.fromStringMap(newSimpleOrigin("env variables"), System.getenv());
|
return PropertiesParser.fromStringMap(newEnvVariable("env variables"), System.getenv());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class EnvVariablesHolder {
|
private static class EnvVariablesHolder {
|
||||||
@ -544,4 +544,8 @@ public class ConfigImpl {
|
|||||||
public static ConfigOrigin newURLOrigin(URL url) {
|
public static ConfigOrigin newURLOrigin(URL url) {
|
||||||
return SimpleConfigOrigin.newURL(url);
|
return SimpleConfigOrigin.newURL(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ConfigOrigin newEnvVariable(String description) {
|
||||||
|
return SimpleConfigOrigin.newEnvVariable(description);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,11 +80,15 @@ abstract class ConfigString extends AbstractConfigValue implements Serializable
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void render(StringBuilder sb, int indent, boolean atRoot, ConfigRenderOptions options) {
|
protected void render(StringBuilder sb, int indent, boolean atRoot, ConfigRenderOptions options) {
|
||||||
String rendered;
|
if (hideEnvVariableValue(options)) {
|
||||||
if (options.getJson())
|
appendHiddenEnvVariableValue(sb);
|
||||||
rendered = ConfigImplUtil.renderJsonString(value);
|
} else {
|
||||||
else
|
String rendered;
|
||||||
rendered = ConfigImplUtil.renderStringUnquotedIfPossible(value);
|
if (options.getJson())
|
||||||
sb.append(rendered);
|
rendered = ConfigImplUtil.renderJsonString(value);
|
||||||
|
else
|
||||||
|
rendered = ConfigImplUtil.renderStringUnquotedIfPossible(value);
|
||||||
|
sb.append(rendered);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,5 +5,6 @@ enum OriginType {
|
|||||||
GENERIC,
|
GENERIC,
|
||||||
FILE,
|
FILE,
|
||||||
URL,
|
URL,
|
||||||
RESOURCE
|
RESOURCE,
|
||||||
|
ENV_VARIABLE
|
||||||
}
|
}
|
||||||
|
@ -77,6 +77,10 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
return newResource(resource, null);
|
return newResource(resource, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SimpleConfigOrigin newEnvVariable(String description) {
|
||||||
|
return new SimpleConfigOrigin(description, -1, -1, OriginType.ENV_VARIABLE, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SimpleConfigOrigin withLineNumber(int lineNumber) {
|
public SimpleConfigOrigin withLineNumber(int lineNumber) {
|
||||||
if (lineNumber == this.lineNumber && lineNumber == this.endLineNumber) {
|
if (lineNumber == this.lineNumber && lineNumber == this.endLineNumber) {
|
||||||
@ -139,6 +143,10 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OriginType originType() {
|
||||||
|
return originType;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if (other instanceof SimpleConfigOrigin) {
|
if (other instanceof SimpleConfigOrigin) {
|
||||||
@ -484,7 +492,11 @@ final class SimpleConfigOrigin implements ConfigOrigin {
|
|||||||
Number originTypeOrdinal = (Number) m.get(SerializedField.ORIGIN_TYPE);
|
Number originTypeOrdinal = (Number) m.get(SerializedField.ORIGIN_TYPE);
|
||||||
if (originTypeOrdinal == null)
|
if (originTypeOrdinal == null)
|
||||||
throw new IOException("Missing ORIGIN_TYPE field");
|
throw new IOException("Missing ORIGIN_TYPE field");
|
||||||
OriginType originType = OriginType.values()[originTypeOrdinal.byteValue()];
|
OriginType originType;
|
||||||
|
if (originTypeOrdinal.byteValue() < OriginType.values().length)
|
||||||
|
originType = OriginType.values()[originTypeOrdinal.byteValue()];
|
||||||
|
else
|
||||||
|
originType = OriginType.GENERIC; // ENV_VARIABLE was added in a later version
|
||||||
String urlOrNull = (String) m.get(SerializedField.ORIGIN_URL);
|
String urlOrNull = (String) m.get(SerializedField.ORIGIN_URL);
|
||||||
String resourceOrNull = (String) m.get(SerializedField.ORIGIN_RESOURCE);
|
String resourceOrNull = (String) m.get(SerializedField.ORIGIN_RESOURCE);
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
4
config/src/test/resources/env-variables.conf
Normal file
4
config/src/test/resources/env-variables.conf
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
secret = a
|
||||||
|
secret = ${?SECRET_A}
|
||||||
|
secrets = ["b", "c"]
|
||||||
|
secrets = [${?SECRET_B}, ${?SECRET_C}]
|
@ -1,3 +1,5 @@
|
|||||||
|
package foo;
|
||||||
|
|
||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
import com.typesafe.config.ConfigRenderOptions
|
import com.typesafe.config.ConfigRenderOptions
|
||||||
|
|
||||||
@ -6,11 +8,13 @@ object RenderExample extends App {
|
|||||||
val originComments = args.contains("--origin-comments")
|
val originComments = args.contains("--origin-comments")
|
||||||
val comments = args.contains("--comments")
|
val comments = args.contains("--comments")
|
||||||
val hocon = args.contains("--hocon")
|
val hocon = args.contains("--hocon")
|
||||||
|
val hideEnvVariableValues = args.contains("--hide-env-variable-values")
|
||||||
val options = ConfigRenderOptions.defaults()
|
val options = ConfigRenderOptions.defaults()
|
||||||
.setFormatted(formatted)
|
.setFormatted(formatted)
|
||||||
.setOriginComments(originComments)
|
.setOriginComments(originComments)
|
||||||
.setComments(comments)
|
.setComments(comments)
|
||||||
.setJson(!hocon)
|
.setJson(!hocon)
|
||||||
|
.setShowEnvVariableValues(!hideEnvVariableValues)
|
||||||
|
|
||||||
def render(what: String) {
|
def render(what: String) {
|
||||||
val conf = ConfigFactory.defaultOverrides()
|
val conf = ConfigFactory.defaultOverrides()
|
||||||
|
@ -1207,6 +1207,35 @@ class ConfigTest extends TestUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
def renderShowEnvVariableValues(): Unit = {
|
||||||
|
val config = ConfigFactory.load("env-variables")
|
||||||
|
assertEquals("A", config.getString("secret"))
|
||||||
|
assertEquals("B", config.getStringList("secrets").get(0))
|
||||||
|
assertEquals("C", config.getStringList("secrets").get(1))
|
||||||
|
val hideRenderOpt = ConfigRenderOptions.defaults().setShowEnvVariableValues(false)
|
||||||
|
val rendered1 = config.root().render(hideRenderOpt)
|
||||||
|
assertTrue(rendered1.contains(""""secret" : "<env variable>""""))
|
||||||
|
assertTrue(rendered1.contains(
|
||||||
|
"""| "secrets" : [
|
||||||
|
| # env variables
|
||||||
|
| "<env variable>",
|
||||||
|
| # env variables
|
||||||
|
| "<env variable>"
|
||||||
|
| ]""".stripMargin))
|
||||||
|
|
||||||
|
val showRenderOpt = ConfigRenderOptions.defaults()
|
||||||
|
val rendered2 = config.root().render(showRenderOpt)
|
||||||
|
assertTrue(rendered2.contains(""""secret" : "A""""))
|
||||||
|
assertTrue(rendered2.contains(
|
||||||
|
"""| "secrets" : [
|
||||||
|
| # env variables
|
||||||
|
| "B",
|
||||||
|
| # env variables
|
||||||
|
| "C"
|
||||||
|
| ]""".stripMargin))
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def serializeRoundTrip() {
|
def serializeRoundTrip() {
|
||||||
for (i <- 1 to 10) {
|
for (i <- 1 to 10) {
|
||||||
|
Loading…
Reference in New Issue
Block a user