Skip to content

Commit 62802f7

Browse files
Merge branch '4.4'
* 4.4: [DI] fix locators with numeric keys Add support for NO_COLOR env var [DI][FrameworkBundle] add EnvVarLoaderInterface - remove SecretEnvVarProcessor Fix error when we use VO for the marking property [DI] Remove LazyString from 4.4, before adding back to the String component
2 parents fa159a3 + c0b92a3 commit 62802f7

File tree

11 files changed

+52
-160
lines changed

11 files changed

+52
-160
lines changed

DependencyInjection/FrameworkExtension.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
use Symfony\Component\DependencyInjection\ContainerBuilder;
4949
use Symfony\Component\DependencyInjection\ContainerInterface;
5050
use Symfony\Component\DependencyInjection\Definition;
51+
use Symfony\Component\DependencyInjection\EnvVarLoaderInterface;
5152
use Symfony\Component\DependencyInjection\EnvVarProcessorInterface;
5253
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
5354
use Symfony\Component\DependencyInjection\Exception\LogicException;
@@ -378,6 +379,8 @@ public function load(array $configs, ContainerBuilder $container)
378379
->addTag('console.command');
379380
$container->registerForAutoconfiguration(ResourceCheckerInterface::class)
380381
->addTag('config_cache.resource_checker');
382+
$container->registerForAutoconfiguration(EnvVarLoaderInterface::class)
383+
->addTag('container.env_var_loader');
381384
$container->registerForAutoconfiguration(EnvVarProcessorInterface::class)
382385
->addTag('container.env_var_processor');
383386
$container->registerForAutoconfiguration(ServiceLocator::class)
@@ -1348,9 +1351,13 @@ private function registerSecretsConfiguration(array $config, ContainerBuilder $c
13481351
}
13491352

13501353
if ($config['decryption_env_var']) {
1351-
$container->getDefinition('secrets.decryption_key')->replaceArgument(1, $config['decryption_env_var']);
1354+
if (!preg_match('/^(?:\w*+:)*+\w++$/', $config['decryption_env_var'])) {
1355+
throw new InvalidArgumentException(sprintf('Invalid value "%s" set as "decryption_env_var": only "word" characters are allowed.', $config['decryption_env_var']));
1356+
}
1357+
1358+
$container->getDefinition('secrets.vault')->replaceArgument(1, "%env({$config['decryption_env_var']})%");
13521359
} else {
1353-
$container->removeDefinition('secrets.decryption_key');
1360+
$container->getDefinition('secrets.vault')->replaceArgument(1, null);
13541361
}
13551362
}
13561363

Resources/config/secrets.xml

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,36 +6,13 @@
66

77
<services>
88
<service id="secrets.vault" class="Symfony\Bundle\FrameworkBundle\Secrets\SodiumVault">
9+
<tag name="container.env_var_loader" />
910
<argument>%kernel.project_dir%/config/secrets/%kernel.environment%</argument>
10-
<argument type="service" id="secrets.decryption_key" on-invalid="ignore" />
11-
</service>
12-
13-
<!--
14-
LazyString::fromCallable() is used as a wrapper to lazily read the SYMFONY_DECRYPTION_SECRET var from the env.
15-
By overriding this service and using the same strategy, the decryption key can be fetched lazily from any other service if needed.
16-
-->
17-
<service id="secrets.decryption_key" class="Symfony\Component\DependencyInjection\LazyString">
18-
<factory class="Symfony\Component\DependencyInjection\LazyString" method="fromCallable" />
19-
<argument type="service">
20-
<service class="Closure">
21-
<factory class="Closure" method="fromCallable" />
22-
<argument type="collection">
23-
<argument type="service" id="service_container" />
24-
<argument>getEnv</argument>
25-
</argument>
26-
</service>
27-
</argument>
28-
<argument>base64:default::SYMFONY_DECRYPTION_SECRET</argument>
11+
<argument>%env(base64:default::SYMFONY_DECRYPTION_SECRET)%</argument>
2912
</service>
3013

3114
<service id="secrets.local_vault" class="Symfony\Bundle\FrameworkBundle\Secrets\DotenvVault">
3215
<argument>%kernel.project_dir%/.env.local</argument>
3316
</service>
34-
35-
<service id="secrets.env_var_processor" class="Symfony\Bundle\FrameworkBundle\Secrets\SecretEnvVarProcessor">
36-
<argument type="service" id="secrets.vault" />
37-
<argument type="service" id="secrets.local_vault" on-invalid="ignore" />
38-
<tag name="container.env_var_processor" />
39-
</service>
4017
</services>
4118
</container>

Resources/config/services.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,12 @@
117117
<tag name="kernel.event_subscriber" />
118118
</service>
119119

120+
<service id="container.env_var_processor" class="Symfony\Component\DependencyInjection\EnvVarProcessor">
121+
<tag name="container.env_var_processor" />
122+
<argument type="service" id="service_container" />
123+
<argument type="tagged_iterator" tag="container.env_var_loader" />
124+
</service>
125+
120126
<service id="slugger" class="Symfony\Component\String\Slugger\AsciiSlugger">
121127
<argument>%kernel.default_locale%</argument>
122128
<tag name="kernel.locale_aware" />

Secrets/DotenvVault.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public function reveal(string $name): ?string
5454
{
5555
$this->lastMessage = null;
5656
$this->validateName($name);
57-
$v = \is_string($_SERVER[$name] ?? null) ? $_SERVER[$name] : ($_ENV[$name] ?? null);
57+
$v = \is_string($_SERVER[$name] ?? null) && 0 !== strpos($name, 'HTTP_') ? $_SERVER[$name] : ($_ENV[$name] ?? null);
5858

5959
if (null === $v) {
6060
$this->lastMessage = sprintf('Secret "%s" not found in "%s".', $name, $this->getPrettyPath($this->dotenvFile));

Secrets/SecretEnvVarProcessor.php

Lines changed: 0 additions & 59 deletions
This file was deleted.

Secrets/SodiumVault.php

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@
1111

1212
namespace Symfony\Bundle\FrameworkBundle\Secrets;
1313

14+
use Symfony\Component\DependencyInjection\EnvVarLoaderInterface;
15+
1416
/**
1517
* @author Tobias Schultze <http://tobion.de>
1618
* @author Jérémy Derussé <jeremy@derusse.com>
1719
* @author Nicolas Grekas <p@tchwork.com>
1820
*
1921
* @internal
2022
*/
21-
class SodiumVault extends AbstractVault
23+
class SodiumVault extends AbstractVault implements EnvVarLoaderInterface
2224
{
2325
private $encryptionKey;
2426
private $decryptionKey;
@@ -56,8 +58,8 @@ public function generateKeys(bool $override = false): bool
5658
// ignore failures to load keys
5759
}
5860

59-
if ('' !== $this->decryptionKey && !file_exists($this->pathPrefix.'sodium.encrypt.public')) {
60-
$this->export('sodium.encrypt.public', $this->encryptionKey);
61+
if ('' !== $this->decryptionKey && !file_exists($this->pathPrefix.'encrypt.public.php')) {
62+
$this->export('encrypt.public', $this->encryptionKey);
6163
}
6264

6365
if (!$override && null !== $this->encryptionKey) {
@@ -69,10 +71,10 @@ public function generateKeys(bool $override = false): bool
6971
$this->decryptionKey = sodium_crypto_box_keypair();
7072
$this->encryptionKey = sodium_crypto_box_publickey($this->decryptionKey);
7173

72-
$this->export('sodium.encrypt.public', $this->encryptionKey);
73-
$this->export('sodium.decrypt.private', $this->decryptionKey);
74+
$this->export('encrypt.public', $this->encryptionKey);
75+
$this->export('decrypt.private', $this->decryptionKey);
7476

75-
$this->lastMessage = sprintf('Sodium keys have been generated at "%s*.{public,private}".', $this->getPrettyPath($this->pathPrefix));
77+
$this->lastMessage = sprintf('Sodium keys have been generated at "%s*.public/private.php".', $this->getPrettyPath($this->pathPrefix));
7678

7779
return true;
7880
}
@@ -82,12 +84,12 @@ public function seal(string $name, string $value): void
8284
$this->lastMessage = null;
8385
$this->validateName($name);
8486
$this->loadKeys();
85-
$this->export($name.'.'.substr_replace(md5($name), '.sodium', -26), sodium_crypto_box_seal($value, $this->encryptionKey ?? sodium_crypto_box_publickey($this->decryptionKey)));
87+
$this->export($name.'.'.substr(md5($name), 0, 6), sodium_crypto_box_seal($value, $this->encryptionKey ?? sodium_crypto_box_publickey($this->decryptionKey)));
8688

8789
$list = $this->list();
8890
$list[$name] = null;
8991
uksort($list, 'strnatcmp');
90-
file_put_contents($this->pathPrefix.'sodium.list', sprintf("<?php\n\nreturn %s;\n", var_export($list, true), LOCK_EX));
92+
file_put_contents($this->pathPrefix.'list.php', sprintf("<?php\n\nreturn %s;\n", var_export($list, true), LOCK_EX));
9193

9294
$this->lastMessage = sprintf('Secret "%s" encrypted in "%s"; you can commit it.', $name, $this->getPrettyPath(\dirname($this->pathPrefix).\DIRECTORY_SEPARATOR));
9395
}
@@ -97,7 +99,7 @@ public function reveal(string $name): ?string
9799
$this->lastMessage = null;
98100
$this->validateName($name);
99101

100-
if (!file_exists($file = $this->pathPrefix.$name.'.'.substr_replace(md5($name), '.sodium', -26))) {
102+
if (!file_exists($file = $this->pathPrefix.$name.'.'.substr_replace(md5($name), '.php', -26))) {
101103
$this->lastMessage = sprintf('Secret "%s" not found in "%s".', $name, $this->getPrettyPath(\dirname($this->pathPrefix).\DIRECTORY_SEPARATOR));
102104

103105
return null;
@@ -131,15 +133,15 @@ public function remove(string $name): bool
131133
$this->lastMessage = null;
132134
$this->validateName($name);
133135

134-
if (!file_exists($file = $this->pathPrefix.$name.'.'.substr_replace(md5($name), '.sodium', -26))) {
136+
if (!file_exists($file = $this->pathPrefix.$name.'.'.substr_replace(md5($name), '.php', -26))) {
135137
$this->lastMessage = sprintf('Secret "%s" not found in "%s".', $name, $this->getPrettyPath(\dirname($this->pathPrefix).\DIRECTORY_SEPARATOR));
136138

137139
return false;
138140
}
139141

140142
$list = $this->list();
141143
unset($list[$name]);
142-
file_put_contents($this->pathPrefix.'sodium.list', sprintf("<?php\n\nreturn %s;\n", var_export($list, true), LOCK_EX));
144+
file_put_contents($this->pathPrefix.'list.php', sprintf("<?php\n\nreturn %s;\n", var_export($list, true), LOCK_EX));
143145

144146
$this->lastMessage = sprintf('Secret "%s" removed from "%s".', $name, $this->getPrettyPath(\dirname($this->pathPrefix).\DIRECTORY_SEPARATOR));
145147

@@ -150,7 +152,7 @@ public function list(bool $reveal = false): array
150152
{
151153
$this->lastMessage = null;
152154

153-
if (!file_exists($file = $this->pathPrefix.'sodium.list')) {
155+
if (!file_exists($file = $this->pathPrefix.'list.php')) {
154156
return [];
155157
}
156158

@@ -167,6 +169,11 @@ public function list(bool $reveal = false): array
167169
return $secrets;
168170
}
169171

172+
public function loadEnvVars(): array
173+
{
174+
return $this->list(true);
175+
}
176+
170177
private function loadKeys(): void
171178
{
172179
if (!\function_exists('sodium_crypto_box_seal')) {
@@ -177,12 +184,12 @@ private function loadKeys(): void
177184
return;
178185
}
179186

180-
if (file_exists($this->pathPrefix.'sodium.decrypt.private')) {
181-
$this->decryptionKey = (string) include $this->pathPrefix.'sodium.decrypt.private';
187+
if (file_exists($this->pathPrefix.'decrypt.private.php')) {
188+
$this->decryptionKey = (string) include $this->pathPrefix.'decrypt.private.php';
182189
}
183190

184-
if (file_exists($this->pathPrefix.'sodium.encrypt.public')) {
185-
$this->encryptionKey = (string) include $this->pathPrefix.'sodium.encrypt.public';
191+
if (file_exists($this->pathPrefix.'encrypt.public.php')) {
192+
$this->encryptionKey = (string) include $this->pathPrefix.'encrypt.public.php';
186193
} elseif ('' !== $this->decryptionKey) {
187194
$this->encryptionKey = sodium_crypto_box_publickey($this->decryptionKey);
188195
} else {
@@ -196,7 +203,7 @@ private function export(string $file, string $data): void
196203
$data = str_replace('%', '\x', rawurlencode($data));
197204
$data = sprintf("<?php // %s on %s\n\nreturn \"%s\";\n", $name, date('r'), $data);
198205

199-
if (false === file_put_contents($this->pathPrefix.$file, $data, LOCK_EX)) {
206+
if (false === file_put_contents($this->pathPrefix.$file.'.php', $data, LOCK_EX)) {
200207
$e = error_get_last();
201208
throw new \ErrorException($e['message'] ?? 'Failed to write secrets data.', 0, $e['type'] ?? E_USER_WARNING);
202209
}

Tests/DependencyInjection/Fixtures/php/cache_env_var.php

Lines changed: 0 additions & 9 deletions
This file was deleted.

Tests/DependencyInjection/Fixtures/xml/cache_env_var.xml

Lines changed: 0 additions & 17 deletions
This file was deleted.

Tests/DependencyInjection/Fixtures/yml/cache_env_var.yml

Lines changed: 0 additions & 6 deletions
This file was deleted.

Tests/DependencyInjection/FrameworkExtensionTest.php

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
use Symfony\Component\DependencyInjection\ContainerInterface;
3535
use Symfony\Component\DependencyInjection\Definition;
3636
use Symfony\Component\DependencyInjection\Loader\ClosureLoader;
37-
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
37+
use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
3838
use Symfony\Component\DependencyInjection\Reference;
3939
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
4040
use Symfony\Component\HttpClient\ScopingHttpClient;
@@ -1202,20 +1202,6 @@ public function testCacheDefaultRedisProvider()
12021202
$this->assertSame($redisUrl, $url);
12031203
}
12041204

1205-
public function testCacheDefaultRedisProviderWithEnvVar()
1206-
{
1207-
$container = $this->createContainerFromFile('cache_env_var');
1208-
1209-
$redisUrl = 'redis://paas.com';
1210-
$providerId = '.cache_connection.'.ContainerBuilder::hash($redisUrl);
1211-
1212-
$this->assertTrue($container->hasDefinition($providerId));
1213-
1214-
$url = $container->getDefinition($providerId)->getArgument(0);
1215-
1216-
$this->assertSame($redisUrl, $url);
1217-
}
1218-
12191205
public function testCachePoolServices()
12201206
{
12211207
$container = $this->createContainerFromFile('cache', [], true, false);
@@ -1383,7 +1369,7 @@ public function testMailer(): void
13831369

13841370
protected function createContainer(array $data = [])
13851371
{
1386-
return new ContainerBuilder(new ParameterBag(array_merge([
1372+
return new ContainerBuilder(new EnvPlaceholderParameterBag(array_merge([
13871373
'kernel.bundles' => ['FrameworkBundle' => 'Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle'],
13881374
'kernel.bundles_metadata' => ['FrameworkBundle' => ['namespace' => 'Symfony\\Bundle\\FrameworkBundle', 'path' => __DIR__.'/../..']],
13891375
'kernel.cache_dir' => __DIR__,

Tests/Secrets/SodiumVaultTest.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,19 @@ public function testGenerateKeys()
2626
$vault = new SodiumVault($this->secretsDir);
2727

2828
$this->assertTrue($vault->generateKeys());
29-
$this->assertFileExists($this->secretsDir.'/test.sodium.encrypt.public');
30-
$this->assertFileExists($this->secretsDir.'/test.sodium.decrypt.private');
29+
$this->assertFileExists($this->secretsDir.'/test.encrypt.public.php');
30+
$this->assertFileExists($this->secretsDir.'/test.decrypt.private.php');
3131

32-
$encKey = file_get_contents($this->secretsDir.'/test.sodium.encrypt.public');
33-
$decKey = file_get_contents($this->secretsDir.'/test.sodium.decrypt.private');
32+
$encKey = file_get_contents($this->secretsDir.'/test.encrypt.public.php');
33+
$decKey = file_get_contents($this->secretsDir.'/test.decrypt.private.php');
3434

3535
$this->assertFalse($vault->generateKeys());
36-
$this->assertStringEqualsFile($this->secretsDir.'/test.sodium.encrypt.public', $encKey);
37-
$this->assertStringEqualsFile($this->secretsDir.'/test.sodium.decrypt.private', $decKey);
36+
$this->assertStringEqualsFile($this->secretsDir.'/test.encrypt.public.php', $encKey);
37+
$this->assertStringEqualsFile($this->secretsDir.'/test.decrypt.private.php', $decKey);
3838

3939
$this->assertTrue($vault->generateKeys(true));
40-
$this->assertStringNotEqualsFile($this->secretsDir.'/test.sodium.encrypt.public', $encKey);
41-
$this->assertStringNotEqualsFile($this->secretsDir.'/test.sodium.decrypt.private', $decKey);
40+
$this->assertStringNotEqualsFile($this->secretsDir.'/test.encrypt.public.php', $encKey);
41+
$this->assertStringNotEqualsFile($this->secretsDir.'/test.decrypt.private.php', $decKey);
4242
}
4343

4444
public function testEncryptAndDecrypt()

0 commit comments

Comments
 (0)