Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Optionally hide rendered environment variables #798

Merged
merged 1 commit into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,11 @@ lazy val configLib = Project("config", file("config"))
"CONFIG_FORCE_a__c" -> "3",
"CONFIG_FORCE_a___c" -> "4",
"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")
publish := sys.error("use publishSigned instead of plain publish")
Expand Down
43 changes: 36 additions & 7 deletions config/src/main/java/com/typesafe/config/ConfigRenderOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@ public final class ConfigRenderOptions {
private final boolean comments;
private final boolean formatted;
private final boolean json;
private final boolean showEnvVariableValues;

private ConfigRenderOptions(boolean originComments, boolean comments, boolean formatted,
boolean json) {
boolean json, boolean showEnvVariableValues) {
this.originComments = originComments;
this.comments = comments;
this.formatted = formatted;
this.json = json;
this.showEnvVariableValues = showEnvVariableValues;
}

/**
Expand All @@ -38,7 +40,7 @@ private ConfigRenderOptions(boolean originComments, boolean comments, boolean fo
* @return the default render options
*/
public static ConfigRenderOptions defaults() {
return new ConfigRenderOptions(true, true, true, true);
return new ConfigRenderOptions(true, true, true, true, true);
}

/**
Expand All @@ -48,7 +50,7 @@ public static ConfigRenderOptions defaults() {
* @return the concise render options
*/
public static ConfigRenderOptions concise() {
return new ConfigRenderOptions(false, false, false, true);
return new ConfigRenderOptions(false, false, false, true, true);
}

/**
Expand All @@ -64,7 +66,7 @@ public ConfigRenderOptions setComments(boolean value) {
if (value == comments)
return this;
else
return new ConfigRenderOptions(originComments, value, formatted, json);
return new ConfigRenderOptions(originComments, value, formatted, json, showEnvVariableValues);
}

/**
Expand Down Expand Up @@ -97,7 +99,7 @@ public ConfigRenderOptions setOriginComments(boolean value) {
if (value == originComments)
return this;
else
return new ConfigRenderOptions(value, comments, formatted, json);
return new ConfigRenderOptions(value, comments, formatted, json, showEnvVariableValues);
}

/**
Expand All @@ -122,7 +124,7 @@ public ConfigRenderOptions setFormatted(boolean value) {
if (value == formatted)
return this;
else
return new ConfigRenderOptions(originComments, comments, value, json);
return new ConfigRenderOptions(originComments, comments, value, json, showEnvVariableValues);
}

/**
Expand Down Expand Up @@ -150,7 +152,32 @@ public ConfigRenderOptions setJson(boolean value) {
if (value == json)
return this;
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;
}

/**
Expand All @@ -174,6 +201,8 @@ public String toString() {
sb.append("formatted,");
if (json)
sb.append("json,");
if (showEnvVariableValues)
sb.append("showEnvVariableValues,");
if (sb.charAt(sb.length() - 1) == ',')
sb.setLength(sb.length() - 1);
sb.append(")");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,8 +357,20 @@ protected void render(StringBuilder sb, int indent, boolean atRoot, String atKey
}

protected void render(StringBuilder sb, int indent, boolean atRoot, ConfigRenderOptions options) {
Object u = unwrapped();
sb.append(u.toString());
if (hideEnvVariableValue(options)) {
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ public static void reloadSystemPropertiesConfig() {
}

private static AbstractConfigObject loadEnvVariables() {
return PropertiesParser.fromStringMap(newSimpleOrigin("env variables"), System.getenv());
return PropertiesParser.fromStringMap(newEnvVariable("env variables"), System.getenv());
}

private static class EnvVariablesHolder {
Expand Down Expand Up @@ -544,4 +544,8 @@ public static ConfigOrigin newFileOrigin(String filename) {
public static ConfigOrigin newURLOrigin(URL url) {
return SimpleConfigOrigin.newURL(url);
}

public static ConfigOrigin newEnvVariable(String description) {
return SimpleConfigOrigin.newEnvVariable(description);
}
}
16 changes: 10 additions & 6 deletions config/src/main/java/com/typesafe/config/impl/ConfigString.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,15 @@ String transformToString() {

@Override
protected void render(StringBuilder sb, int indent, boolean atRoot, ConfigRenderOptions options) {
String rendered;
if (options.getJson())
rendered = ConfigImplUtil.renderJsonString(value);
else
rendered = ConfigImplUtil.renderStringUnquotedIfPossible(value);
sb.append(rendered);
if (hideEnvVariableValue(options)) {
appendHiddenEnvVariableValue(sb);
} else {
String rendered;
if (options.getJson())
rendered = ConfigImplUtil.renderJsonString(value);
else
rendered = ConfigImplUtil.renderStringUnquotedIfPossible(value);
sb.append(rendered);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ enum OriginType {
GENERIC,
FILE,
URL,
RESOURCE
RESOURCE,
ENV_VARIABLE
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ static SimpleConfigOrigin newResource(String resource) {
return newResource(resource, null);
}

static SimpleConfigOrigin newEnvVariable(String description) {
return new SimpleConfigOrigin(description, -1, -1, OriginType.ENV_VARIABLE, null, null, null);
}

@Override
public SimpleConfigOrigin withLineNumber(int lineNumber) {
if (lineNumber == this.lineNumber && lineNumber == this.endLineNumber) {
Expand Down Expand Up @@ -139,6 +143,10 @@ public String description() {
}
}

OriginType originType() {
return originType;
}

@Override
public boolean equals(Object other) {
if (other instanceof SimpleConfigOrigin) {
Expand Down Expand Up @@ -484,7 +492,11 @@ static SimpleConfigOrigin fromFields(Map<SerializedField, Object> m) throws IOEx
Number originTypeOrdinal = (Number) m.get(SerializedField.ORIGIN_TYPE);
if (originTypeOrdinal == null)
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 resourceOrNull = (String) m.get(SerializedField.ORIGIN_RESOURCE);
@SuppressWarnings("unchecked")
Expand Down
4 changes: 4 additions & 0 deletions config/src/test/resources/env-variables.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
secret = a
secret = ${?SECRET_A}
secrets = ["b", "c"]
secrets = [${?SECRET_B}, ${?SECRET_C}]
4 changes: 4 additions & 0 deletions config/src/test/scala/Rendering.scala
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
package foo;

import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigRenderOptions

Expand All @@ -6,11 +8,13 @@ object RenderExample extends App {
val originComments = args.contains("--origin-comments")
val comments = args.contains("--comments")
val hocon = args.contains("--hocon")
val hideEnvVariableValues = args.contains("--hide-env-variable-values")
val options = ConfigRenderOptions.defaults()
.setFormatted(formatted)
.setOriginComments(originComments)
.setComments(comments)
.setJson(!hocon)
.setShowEnvVariableValues(!hideEnvVariableValues)

def render(what: String) {
val conf = ConfigFactory.defaultOverrides()
Expand Down
29 changes: 29 additions & 0 deletions config/src/test/scala/com/typesafe/config/impl/ConfigTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
def serializeRoundTrip() {
for (i <- 1 to 10) {
Expand Down
Loading