Skip to content

Commit

Permalink
do not render env variables in configs (#771)
Browse files Browse the repository at this point in the history
* do not render env variables in configs

* redact username when logging configs

* Update ActorSystemSpec.scala

* add test

scalafmt

* try/finally
  • Loading branch information
pjfanning authored Nov 13, 2023
1 parent 8832d7b commit 860d016
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,23 @@ class ActorSystemSpec extends PekkoSpec(ActorSystemSpec.config) with ImplicitSen
}
} finally shutdown(sys)
}
"not include username in toString" in {
// Actor System toString is output to logs and we don't want env variable values appearing in logs
val system =
ActorSystem(
"config-test-system",
ConfigFactory
.parseString("""pekko.test.java.property.home = "${user.home}"""")
.withFallback(PekkoSpec.testConf))
try {
val debugText = system.settings.toString
val username = System.getProperty("user.name")
val userHome = System.getProperty("user.home")
(debugText should not).include(username)
(debugText should not).include(userHome)
debugText should include("<username>")
} finally shutdown(system)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.pekko.actor.typed

import com.typesafe.config.ConfigFactory
import org.apache.pekko
import pekko.actor.typed.scaladsl.Behaviors
import pekko.testkit.PekkoSpec

import scala.annotation.nowarn

@nowarn("msg=possible missing interpolator")
class ActorSystemSpec extends PekkoSpec {
"ActorSystem" should {
"not include username in toString" in {
// Actor System toString is output to logs and we don't want env variable values appearing in logs
val system = ActorSystem(Behaviors.empty[String], "config-test-system",
ConfigFactory
.parseString("""pekko.test.java.property.home = "${user.home}"""")
.withFallback(PekkoSpec.testConf))
try {
val debugText = system.settings.toString
val username = System.getProperty("user.name")
val userHome = System.getProperty("user.home")
(debugText should not).include(username)
(debugText should not).include(userHome)
debugText should include("<username>")
} finally {
system.terminate()
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import scala.concurrent.{ ExecutionContextExecutor, Future }

import com.typesafe.config.{ Config, ConfigFactory }
import org.slf4j.Logger

import org.apache.pekko
import pekko.{ actor => classic, Done }
import pekko.actor.{ Address, BootstrapSetup, ClassicActorSystemProvider }
Expand All @@ -29,7 +28,7 @@ import pekko.actor.typed.internal.{ EventStreamExtension, InternalRecipientRef }
import pekko.actor.typed.internal.adapter.{ ActorSystemAdapter, GuardianStartupBehavior, PropsAdapter }
import pekko.actor.typed.receptionist.Receptionist
import pekko.annotation.DoNotInherit
import pekko.util.Helpers.Requiring
import pekko.util.Helpers.{ ConfigOps, Requiring }

/**
* An ActorSystem is home to a hierarchy of Actors. It is created using
Expand Down Expand Up @@ -324,7 +323,7 @@ final class Settings(val config: Config, val classicSettings: classic.ActorSyste
/**
* Returns the String representation of the Config that this Settings is backed by
*/
override def toString: String = config.root.render
override def toString: String = config.renderWithRedactions()

private val typedConfig = config.getConfig("pekko.actor.typed")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ object ActorSystem {
/**
* Returns the String representation of the Config that this Settings is backed by
*/
override def toString: String = config.root.render
override def toString: String = config.renderWithRedactions()

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
package org.apache.pekko.dispatch

import java.util.concurrent.{ ConcurrentHashMap, ThreadFactory }
import scala.concurrent.ExecutionContext
import scala.annotation.{ nowarn, tailrec }
import scala.concurrent.ExecutionContext

import com.typesafe.config.{ Config, ConfigFactory, ConfigValueType }
import org.apache.pekko
import pekko.ConfigurationException
Expand Down Expand Up @@ -259,7 +260,8 @@ class Dispatchers @InternalApi private[pekko] (
*/
private def configuratorFrom(cfg: Config): MessageDispatcherConfigurator = {
if (!cfg.hasPath("id"))
throw new ConfigurationException("Missing dispatcher 'id' property in config: " + cfg.root.render)
throw new ConfigurationException("Missing dispatcher 'id' property in config: " +
cfg.renderWithRedactions())

cfg.getString("type") match {
case "Dispatcher" => new DispatcherConfigurator(cfg, prerequisites)
Expand Down
26 changes: 19 additions & 7 deletions actor/src/main/scala/org/apache/pekko/util/Helpers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,12 @@ package org.apache.pekko.util

import java.time.{ Instant, LocalDateTime, ZoneId }
import java.time.format.DateTimeFormatter
import java.util.Comparator
import java.util.Locale
import java.util.{ Comparator, Locale }
import java.util.concurrent.TimeUnit
import java.util.regex.Pattern

import scala.annotation.tailrec
import scala.concurrent.duration.Duration
import scala.concurrent.duration.FiniteDuration

import com.typesafe.config.Config
import scala.concurrent.duration.{ Duration, FiniteDuration }
import com.typesafe.config.{ Config, ConfigRenderOptions }

object Helpers {

Expand Down Expand Up @@ -179,6 +175,22 @@ object Helpers {

def getNanosDuration(path: String): FiniteDuration = getDuration(path, TimeUnit.NANOSECONDS)

/**
* Used to redact sensitive information in config data when we are logging it
* or adding it to exception messages.
*
* This includes redacting environment variable values and the username associated with the running process.
*
* @return redacted version of the configuration text
* @see https://github.com/apache/incubator-pekko/pull/771
* @since 1.0.2
*/
def renderWithRedactions(): String = {
val username = System.getProperty("user.name")
val configText = config.root.render(ConfigRenderOptions.defaults().setShowEnvVariableValues(false))
configText.replace(username, "<username>")
}

private def getDuration(path: String, unit: TimeUnit): FiniteDuration =
Duration(config.getDuration(path, unit), unit)
}
Expand Down

0 comments on commit 860d016

Please sign in to comment.