Permalink
Browse files

feature #27157 [DI] Select specific key from an array resolved env va…

…r (bobvandevijver)

This PR was squashed before being merged into the 4.2-dev branch (closes #27157).

Discussion
----------

[DI] Select specific key from an array resolved env var

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes <!-- don't forget to update src/**/CHANGELOG.md files -->
| BC breaks?    | no     <!-- see https://symfony.com/bc -->
| Deprecations? | no <!-- don't forget to update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tests pass?   | yes    <!-- please add some, will be required by reviewers -->
| Fixed tickets | Discussed in #25643    <!-- #-prefixed issue number(s), if any -->
| License       | MIT
| Doc PR        | symfony/symfony-docs#9734 <!-- required for new features -->

<!--
Write a short README entry for your feature/bugfix here (replace this comment block.)
This will help people understand your PR and can be used as a start of the Doc PR.
Additionally:
 - Bug fixes must be submitted against the lowest branch where they apply
   (lowest branches are regularly merged to upper ones so they get the fixes too).
 - Features and deprecations must be submitted against the master branch.
-->

As discussed in #25643, it would be convenient to have an key processor for environment variables which have been read from for example a JSON file.

The main advantage of this feature lies in specifying a single file for your secrets, that can be directly used in your configuration, without leaking them into your env.

## Example
**.secrets.json**
```json
{
  "database_password": "xxx"
}
```
**.env**
```env
APP_SECRETS=/opt/application/.secrets.json
DATABASE_URL=mysql://myuser:%database_password%@localhost:3306/mydb
```
**services.yaml**
```yaml
parameters:
  database_password: '%env(key:database_password:json:file:APP_SECRETS)%'
```

This example configuration will result in a `database_password` parameter being filled with `xxx`, and due to Doctrine defaults, the database url will be resolved with the correct password.

Commits
-------

42186a2 [DI] Select specific key from an array resolved env var
  • Loading branch information...
nicolas-grekas committed May 21, 2018
2 parents f827fec + 42186a2 commit eceabeecc57e564e2e32e828f7ff412cb1de39c1
@@ -41,6 +41,7 @@ public static function getProvidedTypes()
'float' => 'float',
'int' => 'int',
'json' => 'array',
'key' => 'bool|int|float|string|array',
'resolve' => 'string',
'string' => 'string',
);
@@ -53,6 +54,25 @@ public function getEnv($prefix, $name, \Closure $getEnv)
{
$i = strpos($name, ':');
if ('key' === $prefix) {
if (false === $i) {
throw new RuntimeException(sprintf('Invalid configuration: env var "key:%s" does not contain a key specifier.', $name));
}
$next = substr($name, $i + 1);
$key = substr($name, 0, $i);
$array = $getEnv($next);
if (!is_array($array)) {
throw new RuntimeException(sprintf('Resolved value of "%s" did not result in an array value.', $next));
}
if (!array_key_exists($key, $array)) {
throw new RuntimeException(sprintf('Key "%s" not found in "%s" (resolved from "%s")', $key, json_encode($array), $next));
}
return $array[$key];
}
if ('file' === $prefix) {
if (!is_scalar($file = $getEnv($name))) {
throw new RuntimeException(sprintf('Invalid file name: env var "%s" is non-scalar.', $name));
@@ -38,6 +38,7 @@ public function testSimpleProcessor()
'float' => array('float'),
'int' => array('int'),
'json' => array('array'),
'key' => array('bool', 'int', 'float', 'string', 'array'),
'resolve' => array('string'),
'string' => array('string'),
);
@@ -314,4 +314,110 @@ public function testGetEnvUnknown()
return 'foo';
});
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage Invalid configuration: env var "key:foo" does not contain a key specifier.
*/
public function testGetEnvKeyInvalidKey()
{
$processor = new EnvVarProcessor(new Container());
$processor->getEnv('key', 'foo', function ($name) {
$this->fail('Should not get here');
});
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage Resolved value of "foo" did not result in an array value.
* @dataProvider noArrayValues
*/
public function testGetEnvKeyNoArrayResult($value)
{
$processor = new EnvVarProcessor(new Container());
$processor->getEnv('key', 'index:foo', function ($name) use ($value) {
$this->assertSame('foo', $name);
return $value;
});
}
public function noArrayValues()
{
return array(
array(null),
array('string'),
array(1),
array(true),
);
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage Key "index" not found in
* @dataProvider invalidArrayValues
*/
public function testGetEnvKeyArrayKeyNotFound($value)
{
$processor = new EnvVarProcessor(new Container());
$processor->getEnv('key', 'index:foo', function ($name) use ($value) {
$this->assertSame('foo', $name);
return $value;
});
}
public function invalidArrayValues()
{
return array(
array(array()),
array(array('index2' => 'value')),
array(array('index', 'index2')),
);
}
/**
* @dataProvider arrayValues
*/
public function testGetEnvKey($value)
{
$processor = new EnvVarProcessor(new Container());
$this->assertSame($value['index'], $processor->getEnv('key', 'index:foo', function ($name) use ($value) {
$this->assertSame('foo', $name);
return $value;
}));
}
public function arrayValues()
{
return array(
array(array('index' => 'password')),
array(array('index' => 'true')),
array(array('index' => false)),
array(array('index' => '1')),
array(array('index' => 1)),
array(array('index' => '1.1')),
array(array('index' => 1.1)),
array(array('index' => array())),
array(array('index' => array('val1', 'val2'))),
);
}
public function testGetEnvKeyChained()
{
$processor = new EnvVarProcessor(new Container());
$this->assertSame('password', $processor->getEnv('key', 'index:file:foo', function ($name) {
$this->assertSame('file:foo', $name);
return array(
'index' => 'password',
);
}));
}
}

0 comments on commit eceabee

Please sign in to comment.