diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsDecryptToLocalCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsDecryptToLocalCommand.php
index c9370768f0..e4fbfd287e 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsDecryptToLocalCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsDecryptToLocalCommand.php
@@ -45,7 +45,7 @@ final class SecretsDecryptToLocalCommand extends Command
->setDescription('Decrypts all secrets and stores them in the local vault.')
->addOption('force', 'f', InputOption::VALUE_NONE, 'Forces overriding of secrets that already exist in the local vault')
->setHelp(<<<'EOF'
-The %command.name% command list decrypts all secrets and stores them in the local vault..
+The %command.name% command decrypts all secrets and copies them in the local vault.
%command.full_name%
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsEncryptFromLocalCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsEncryptFromLocalCommand.php
index 3161a21982..607140e616 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsEncryptFromLocalCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsEncryptFromLocalCommand.php
@@ -14,7 +14,6 @@ namespace Symfony\Bundle\FrameworkBundle\Command;
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
-use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
@@ -43,15 +42,10 @@ final class SecretsEncryptFromLocalCommand extends Command
{
$this
->setDescription('Encrypts all local secrets to the vault.')
- ->addOption('force', 'f', InputOption::VALUE_NONE, 'Forces overriding of secrets that already exist in the vault')
->setHelp(<<<'EOF'
-The %command.name% command list encrypts all local secrets and stores them in the vault..
+The %command.name% command encrypts all locally overridden secrets to the vault.
%command.full_name%
-
-When the option --force is provided, secrets that already exist in the vault are overriden.
-
- %command.full_name% --force
EOF
)
;
@@ -67,22 +61,16 @@ EOF
return 1;
}
- $secrets = $this->localVault->list(true);
+ foreach ($this->vault->list(true) as $name => $value) {
+ $localValue = $this->localVault->reveal($name);
- if (!$input->getOption('force')) {
- foreach ($this->vault->list() as $k => $v) {
- unset($secrets[$k]);
- }
- }
-
- foreach ($secrets as $k => $v) {
- if (null === $v) {
- $io->error($this->localVault->getLastMessage());
+ if (null !== $localValue && $value !== $localValue) {
+ $this->vault->seal($name, $localValue);
+ } elseif (null !== $message = $this->localVault->getLastMessage()) {
+ $io->error($message);
return 1;
}
-
- $this->vault->seal($k, $v);
}
return 0;
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsListCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsListCommand.php
index 4ae190435d..1b0fbdf4ce 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsListCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsListCommand.php
@@ -89,11 +89,11 @@ EOF
}
foreach ($localSecrets ?? [] as $name => $value) {
- $rows[$name] = [$name, $rows[$name][1] ?? '', $dump($value)];
+ if (isset($rows[$name])) {
+ $rows[$name][] = $dump($value);
+ }
}
- uksort($rows, 'strnatcmp');
-
if (null !== $this->localVault && null !== $message = $this->localVault->getLastMessage()) {
$io->comment($message);
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsSetCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsSetCommand.php
index 850cf08ee3..555d616712 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsSetCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsSetCommand.php
@@ -86,6 +86,12 @@ EOF
return 1;
}
+ if ($this->localVault === $vault && !\array_key_exists($name, $this->vault->list())) {
+ $io->error(sprintf('Secret "%s" does not exist in the vault, you cannot override it locally.', $name));
+
+ return 1;
+ }
+
if (0 < $random = $input->getOption('random') ?? 16) {
$value = strtr(substr(base64_encode(random_bytes($random)), 0, $random), '+/', '-_');
} elseif (!$file = $input->getArgument('file')) {
diff --git a/src/Symfony/Bundle/FrameworkBundle/Secrets/DotenvVault.php b/src/Symfony/Bundle/FrameworkBundle/Secrets/DotenvVault.php
index 16df2a6045..93d8989502 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Secrets/DotenvVault.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Secrets/DotenvVault.php
@@ -36,14 +36,13 @@ class DotenvVault extends AbstractVault
{
$this->lastMessage = null;
$this->validateName($name);
- $k = $name.'_SECRET';
$v = str_replace("'", "'\\''", $value);
$content = file_exists($this->dotenvFile) ? file_get_contents($this->dotenvFile) : '';
- $content = preg_replace("/^$k=((\\\\'|'[^']++')++|.*)/m", "$k='$v'", $content, -1, $count);
+ $content = preg_replace("/^$name=((\\\\'|'[^']++')++|.*)/m", "$name='$v'", $content, -1, $count);
if (!$count) {
- $content .= "$k='$v'\n";
+ $content .= "$name='$v'\n";
}
file_put_contents($this->dotenvFile, $content);
@@ -55,8 +54,7 @@ class DotenvVault extends AbstractVault
{
$this->lastMessage = null;
$this->validateName($name);
- $k = $name.'_SECRET';
- $v = \is_string($_SERVER[$k] ?? null) ? $_SERVER[$k] : ($_ENV[$k] ?? null);
+ $v = \is_string($_SERVER[$name] ?? null) ? $_SERVER[$name] : ($_ENV[$name] ?? null);
if (null === $v) {
$this->lastMessage = sprintf('Secret "%s" not found in "%s".', $name, $this->getPrettyPath($this->dotenvFile));
@@ -71,10 +69,9 @@ class DotenvVault extends AbstractVault
{
$this->lastMessage = null;
$this->validateName($name);
- $k = $name.'_SECRET';
$content = file_exists($this->dotenvFile) ? file_get_contents($this->dotenvFile) : '';
- $content = preg_replace("/^$k=((\\\\'|'[^']++')++|.*)\n?/m", '', $content, -1, $count);
+ $content = preg_replace("/^$name=((\\\\'|'[^']++')++|.*)\n?/m", '', $content, -1, $count);
if ($count) {
file_put_contents($this->dotenvFile, $content);
@@ -94,14 +91,14 @@ class DotenvVault extends AbstractVault
$secrets = [];
foreach ($_ENV as $k => $v) {
- if (preg_match('/^(\w+)_SECRET$/D', $k, $m)) {
- $secrets[$m[1]] = $reveal ? $v : null;
+ if (preg_match('/^\w+$/D', $k)) {
+ $secrets[$k] = $reveal ? $v : null;
}
}
foreach ($_SERVER as $k => $v) {
- if (\is_string($v) && preg_match('/^(\w+)_SECRET$/D', $k, $m)) {
- $secrets[$m[1]] = $reveal ? $v : null;
+ if (\is_string($v) && preg_match('/^\w+$/D', $k)) {
+ $secrets[$k] = $reveal ? $v : null;
}
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Secrets/SecretEnvVarProcessor.php b/src/Symfony/Bundle/FrameworkBundle/Secrets/SecretEnvVarProcessor.php
index 5a4771fa36..e3a15febe4 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Secrets/SecretEnvVarProcessor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Secrets/SecretEnvVarProcessor.php
@@ -44,9 +44,9 @@ class SecretEnvVarProcessor implements EnvVarProcessorInterface
/**
* {@inheritdoc}
*/
- public function getEnv($prefix, $name, \Closure $getEnv)
+ public function getEnv($prefix, $name, \Closure $getEnv): string
{
- if (null !== $this->localVault && null !== $secret = $this->localVault->reveal($name)) {
+ if (null !== $this->localVault && null !== ($secret = $this->localVault->reveal($name)) && \array_key_exists($name, $this->vault->list())) {
return $secret;
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php b/src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php
index 8aae669d8f..17328b2a6d 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php
@@ -87,6 +87,12 @@ class SodiumVault extends AbstractVault
$this->validateName($name);
$this->loadKeys();
$this->export($name.'.'.substr_replace(md5($name), '.sodium', -26), sodium_crypto_box_seal($value, $this->encryptionKey ?? sodium_crypto_box_publickey($this->decryptionKey)));
+
+ $list = $this->list();
+ $list[$name] = null;
+ uksort($list, 'strnatcmp');
+ file_put_contents($this->pathPrefix.'sodium.list', sprintf("lastMessage = sprintf('Secret "%s" encrypted in "%s"; you can commit it.', $name, $this->getPrettyPath(\dirname($this->pathPrefix).\DIRECTORY_SEPARATOR));
}
@@ -123,6 +129,10 @@ class SodiumVault extends AbstractVault
return false;
}
+ $list = $this->list();
+ unset($list[$name]);
+ file_put_contents($this->pathPrefix.'sodium.list', sprintf("lastMessage = sprintf('Secret "%s" removed from "%s".', $name, $this->getPrettyPath(\dirname($this->pathPrefix).\DIRECTORY_SEPARATOR));
return @unlink($file) || !file_exists($file);
@@ -131,13 +141,19 @@ class SodiumVault extends AbstractVault
public function list(bool $reveal = false): array
{
$this->lastMessage = null;
- $secrets = [];
- $regexp = sprintf('{^%s(\w++)\.[0-9a-f]{6}\.sodium$}D', preg_quote(basename($this->pathPrefix)));
- foreach (scandir(\dirname($this->pathPrefix)) as $name) {
- if (preg_match($regexp, $name, $m)) {
- $secrets[$m[1]] = $reveal ? $this->reveal($m[1]) : null;
- }
+ if (!file_exists($file = $this->pathPrefix.'sodium.list')) {
+ return [];
+ }
+
+ $secrets = include $file;
+
+ if (!$reveal) {
+ return $secrets;
+ }
+
+ foreach ($secrets as $name => $value) {
+ $secrets[$name] = $this->reveal($name);
}
return $secrets;
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Secrets/DotenvVaultTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Secrets/DotenvVaultTest.php
index ba234349d7..d494c82e68 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Secrets/DotenvVaultTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Secrets/DotenvVaultTest.php
@@ -37,21 +37,21 @@ class DotenvVaultTest extends TestCase
$vault->seal('foo', $plain);
- unset($_SERVER['foo_SECRET'], $_ENV['foo_SECRET']);
+ unset($_SERVER['foo'], $_ENV['foo']);
(new Dotenv(false))->load($this->envFile);
$decrypted = $vault->reveal('foo');
$this->assertSame($plain, $decrypted);
- $this->assertSame(['foo' => null], $vault->list());
- $this->assertSame(['foo' => $plain], $vault->list(true));
+ $this->assertSame(['foo' => null], array_intersect_key($vault->list(), ['foo' => 123]));
+ $this->assertSame(['foo' => $plain], array_intersect_key($vault->list(true), ['foo' => 123]));
$this->assertTrue($vault->remove('foo'));
$this->assertFalse($vault->remove('foo'));
- unset($_SERVER['foo_SECRET'], $_ENV['foo_SECRET']);
+ unset($_SERVER['foo'], $_ENV['foo']);
(new Dotenv(false))->load($this->envFile);
- $this->assertSame([], $vault->list());
+ $this->assertArrayNotHasKey('foo', $vault->list());
}
}