args4c
package args4c
Args4c (arguments for configuration) is intended to add some helpers and utilities in obtaining a typesafe configuration from user arguments.
The core is simply to convert an Array[String] to a Config where the arguments are either paths to configuration resources or simple key=value pairs via args4c.configForArgs
Left-most arguments take precedence. In this example, we assume 'prod.conf' is a resource on the classpath:
MyApp foo.x=bar foo.x=ignored /opt/etc/overrides.conf prod.conf
In addition to this core concept, this library also provides some additional configuration utilities via args4c.RichConfigOps which can be made available by extending args4c.LowPriorityArgs4cImplicits or importing args4c.implicits:
import args4c.implicits._ object MyApp { override def main(args : Array[String]) : Unit = { val config = args.asConfig() println("Starting MyApp with config:") // let's "log" our app's config on startup: val flatSummary : String = config.filter(_.startsWith("myapp")).summary() println(flatSummary) // "logging" our config } }
Where the 'summary' will produce sorted args4c.StringEntry values with potentially sensitive entries (e.g. passwords) obscured and a source comment for some sanity as to where each entry comes from:
myapp.foo : bar # command-line myapp.password : **** obscured **** # command-line myapp.saveTo : afile # file:/opt/etc/myapp/[email protected]3
Also, when extracting user arguments into a configuration, an additional 'fallback' config is specified. Typically this would just be the ConfigFactory.load() configuration, but args4c uses the args4c.defaultConfig, which is essentially just the system environment variables converted from snake-caes to dotted lowercase values first, then falling back on ConfigFactory.load().
Applications can elect to not have this behaviour and provide their own fallback configs when parsing args, but the default provides a convenience for system environment variables to override e.g. 'foo.bar.x=default' by specifying
FOO_BAR_X=override
as a system environment variable. Otherwise you may end up having to repeat this sort of thing all over you config:
foo.bar=default foo.bar=$${?FOO_BAR} foo.bazz=default2 foo.bazz=$${?FOO_BAZZ} ...
Finally, args4c also provides a args4c.ConfigApp which provides some additional functionality to configuration-based applications.
- Alphabetic
- By Inheritance
- args4c
- AnyRef
- Any
- Hide All
- Show All
- Public
- All
Type Members
-
trait
ConfigApp extends LowPriorityArgs4cImplicits
A convenience mix-in utility for a main entry point.
A convenience mix-in utility for a main entry point.
It parsed the user arguments using the default config (which is ConfigFactory.load() but w/ system environment variables overlaid)
If the config has a 'show=<path>' in it, then that path will be printed out and the program with return.
e.g. MyAppWhichExtendsConfigApp show=myapp.database.url
will display the value of myapp.database.url
It also interprets a single '--setup' to enable the configuration of sensitive configuration entries into a locally encrypted file.
Subsequent runs of your application would then use '--secure=path/to/encrypted.conf' to load that encrypted configuration and either take the password from an environment variable or standard input.
For example, running 'MyApp --setup' would then prompt like this:
Save secure config to (/opt/etc/myapp/.config/secure.conf):config/secure.conf Config Permissions (defaults to rwx------): rwxrw---- Add config path in the form <key>=<value> (leave blank when finished):myapp.secure.password=hi Add config path in the form <key>=<value> (leave blank when finished):myapp.another.config.entry=123 Add config path in the form <key>=<value> (leave blank when finished): Config Password:password
Then, running 'MyApp --secure=config/secure.conf -myapp.whocares=visible -show=myapp'
would prompt for the password from standard input, then produce the following, hiding the values which were present in the secure config:
myapp.another.config.entry : **** obscured **** # secure.conf: 1 myapp.secure.password : **** obscured **** # secure.conf: 1 myapp.whocares : visible # command-line
NOTE: even though the summary obscures the values, they ARE present as PLAIN TEXT STRINGS in the configuration, so take care in limiting the scope of where the configuration is used, either by filtering back out those values, otherwise separating the secure config from the remaining config, or just ensuring to limit the scope of the config itself.
- trait LowPriorityArgs4cImplicits extends AnyRef
- sealed trait PasswordPrompt extends Prompt
-
sealed
trait
Prompt extends AnyRef
Represents a request for user input when configuring the 'sensitive configurations'
- case class PromptForExistingPassword(configPath: Path) extends PasswordPrompt with Product with Serializable
- case class ReadNextKeyValuePair(requiredConfigPath: String, secureConfig: Config) extends Prompt with Product with Serializable
- case class ReadNextKeyValuePairAfterError(previousInvalidEntry: String) extends Prompt with Product with Serializable
-
class
RichConfig extends RichConfigOps
Adds some scala utility around a typesafe config
-
trait
RichConfigOps extends Dynamic with LowPriorityArgs4cImplicits
Exposes new operations on a 'config'
- case class SaveSecretPrompt(configPath: Path) extends Prompt with Product with Serializable
- case class SecureConfig(promptForInput: UserInput) extends Product with Serializable
-
case class
Selected(value: ConfigValue) extends Dynamic with Product with Serializable
An object returned from a dynamic select
- case class StringEntry(comments: List[String], origin: String, key: String, value: String) extends Product with Serializable
-
type
UserInput = (Prompt) ⇒ String
A means to get a values from user prompts in order to set up a secure configuration
Value Members
-
def
configForArgs(args: Array[String], fallback: Config = defaultConfig(), onUnrecognizedArg: (String) ⇒ Config = ParseArg.Throw): Config
Given the user arguments, produce a loaded configuration which interprets the user-args from left to right as:
Given the user arguments, produce a loaded configuration which interprets the user-args from left to right as:
$ a configuration file on the classpath or file system $ a key=value pair
Left-most values take precedence over right
- args
the user command-line arguments
- fallback
the default configuration to fall back to
- onUnrecognizedArg
the handler for unrecognized user arguments
- returns
a parsed configuration
-
def
configForMap(confMap: Map[String, String]): Config
- returns
a config for this map
-
def
defaultConfig(): Config
- returns
ConfigFactory.load()
- val defaultObscuredText: String
- def env(key: String): Option[String]
- def envOrProp(key: String): Option[String]
-
def
obscurePassword(configPath: String, value: String, blacklist: Set[String] = passwordBlacklist, obscuredValue: String = defaultObscuredText): String
- configPath
the config key (e.g. foo.bar.bazz)
- value
the config value, as a string
- blacklist
a 'blacklist' which, if any of the entries are found anywhere in the configPath, then the value will be obscured
- returns
the
- def passwordBlacklist: Set[String]
- def pathAsFile(path: String): Option[Path]
- def pathAsUrl(path: String): Option[URL]
- def prop(key: String): Option[String]
-
def
unquote(str: String): String
trims and unquotes a string (the single quotes is mine - added to demonstrate the full text):
trims and unquotes a string (the single quotes is mine - added to demonstrate the full text):
'"quoted"' becomes: 'quoted' ' "quoted" ' becomes: 'quoted' 'quoted" ' is unchanged: 'quoted" ' '"quoted ' is unchanged: 'quoted" '
- str
the string to unquote
- returns
either the string unchanged or the single quotes removed as trimming whitespace around the quotes
- object Encryption
- object Prompt
- object PromptForConfigFilePermissions extends Prompt with Product with Serializable
- object PromptForPassword extends PasswordPrompt with Product with Serializable
- object PromptForUpdatedPassword extends PasswordPrompt with Product with Serializable
- object RichConfig
-
object
SecureConfig extends Serializable
Makes available a means to initialize a sensitive, encrypted config file via SecureConfig.setupSecureConfig and ConfigApp.secureConfigForArgs
Makes available a means to initialize a sensitive, encrypted config file via SecureConfig.setupSecureConfig and ConfigApp.secureConfigForArgs
The idea is that a (service) user-only readable, password-protected AES encrypted config file can be set up via reading entries from standard input, and an application an use those configuration entries thereafter by taking the password from standard input.
- object Selected extends Serializable
-
object
implicits extends LowPriorityArgs4cImplicits
Exposes the entry point for using a RichConfig,
Exposes the entry point for using a RichConfig,
mostly for converting user-args into a config