Skip to content

Commit ca103a5

Browse files
minor #61316 [FrameworkBundle] Add tests for secrets:decrypt-to-local, encrypt-from-local, and generate-keys commands (santysisi)
This PR was merged into the 6.4 branch. Discussion ---------- [FrameworkBundle] Add tests for `secrets:decrypt-to-local`, `encrypt-from-local`, and `generate-keys` commands | Q | A | ------------- | --- | Branch? | 6.4 | Bug fix? | no | New feature? | no | Deprecations? | no | Issues | no | License | MIT Add tests for the following console commands: * `secrets:generate-keys` * `secrets:encrypt-from-local` * `secrets:decrypt-to-local` Commits ------- d3cd696f24c [FrameworkBundle] Add tests for `secrets:decrypt-to-local`, `encrypt-from-local`, and `generate-keys` commands
2 parents 366903a + 90ffe3f commit ca103a5

File tree

3 files changed

+296
-0
lines changed

3 files changed

+296
-0
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\Tests\Command;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bundle\FrameworkBundle\Command\SecretsDecryptToLocalCommand;
16+
use Symfony\Bundle\FrameworkBundle\Secrets\SodiumVault;
17+
use Symfony\Component\Console\Tester\CommandTester;
18+
use Symfony\Component\Filesystem\Filesystem;
19+
20+
/**
21+
* @requires extension sodium
22+
*/
23+
class SecretsDecryptToLocalCommandTest extends TestCase
24+
{
25+
private string $mainDir;
26+
private string $localDir;
27+
28+
protected function setUp(): void
29+
{
30+
$this->mainDir = sys_get_temp_dir().'/sf_secrets/main/';
31+
$this->localDir = sys_get_temp_dir().'/sf_secrets/local/';
32+
33+
$fs = new Filesystem();
34+
$fs->remove([$this->mainDir, $this->localDir]);
35+
36+
$mainVault = new SodiumVault($this->mainDir);
37+
$mainVault->generateKeys();
38+
$mainVault->seal('FOO_SECRET', 'super_secret_value');
39+
40+
$localVault = new SodiumVault($this->localDir);
41+
$localVault->generateKeys();
42+
}
43+
44+
protected function tearDown(): void
45+
{
46+
(new Filesystem())->remove([$this->mainDir, $this->localDir]);
47+
}
48+
49+
public function testSecretsAreDecryptedAndStoredInLocalVault()
50+
{
51+
$mainVault = new SodiumVault($this->mainDir);
52+
$localVault = new SodiumVault($this->localDir);
53+
$tester = new CommandTester(new SecretsDecryptToLocalCommand($mainVault, $localVault));
54+
55+
$this->assertSame(0, $tester->execute([]));
56+
$this->assertStringContainsString('1 secret found in the vault.', $tester->getDisplay());
57+
$this->assertStringContainsString('Secret "FOO_SECRET" encrypted', $tester->getDisplay());
58+
59+
$this->assertArrayHasKey('FOO_SECRET', $localVault->list(true));
60+
$this->assertSame('super_secret_value', $localVault->reveal('FOO_SECRET'));
61+
}
62+
63+
public function testExistingLocalSecretsAreSkippedWithoutForce()
64+
{
65+
$mainVault = new SodiumVault($this->mainDir);
66+
$localVault = new SodiumVault($this->localDir);
67+
$localVault->seal('FOO_SECRET', 'old_value');
68+
$tester = new CommandTester(new SecretsDecryptToLocalCommand($mainVault, $localVault));
69+
70+
$this->assertSame(0, $tester->execute([]));
71+
$this->assertStringContainsString('1 secret is already overridden in the local vault and will be skipped.', $tester->getDisplay());
72+
$this->assertSame('old_value', $localVault->reveal('FOO_SECRET'));
73+
}
74+
75+
public function testForceOptionOverridesLocalSecrets()
76+
{
77+
$mainVault = new SodiumVault($this->mainDir);
78+
$localVault = new SodiumVault($this->localDir);
79+
$localVault->seal('FOO_SECRET', 'old_value');
80+
$tester = new CommandTester(new SecretsDecryptToLocalCommand($mainVault, $localVault));
81+
82+
$this->assertSame(0, $tester->execute(['--force' => true]));
83+
$this->assertStringContainsString('Secret "FOO_SECRET" encrypted', $tester->getDisplay());
84+
$this->assertSame('super_secret_value', $localVault->reveal('FOO_SECRET'));
85+
}
86+
87+
public function testFailsGracefullyWhenLocalVaultIsDisabled()
88+
{
89+
$mainVault = new SodiumVault($this->mainDir);
90+
$tester = new CommandTester(new SecretsDecryptToLocalCommand($mainVault, null));
91+
92+
$this->assertSame(1, $tester->execute([]));
93+
$this->assertStringContainsString('The local vault is disabled.', $tester->getDisplay());
94+
}
95+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\Tests\Command;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bundle\FrameworkBundle\Command\SecretsEncryptFromLocalCommand;
16+
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
17+
use Symfony\Bundle\FrameworkBundle\Secrets\SodiumVault;
18+
use Symfony\Component\Console\Tester\CommandTester;
19+
use Symfony\Component\Filesystem\Filesystem;
20+
21+
/**
22+
* @requires extension sodium
23+
*/
24+
class SecretsEncryptFromLocalCommandTest extends TestCase
25+
{
26+
private string $vaultDir;
27+
private string $localVaultDir;
28+
private Filesystem $fs;
29+
30+
protected function setUp(): void
31+
{
32+
$this->vaultDir = sys_get_temp_dir().'/sf_secrets/vault_'.uniqid();
33+
$this->localVaultDir = sys_get_temp_dir().'/sf_secrets/local_'.uniqid();
34+
$this->fs = new Filesystem();
35+
$this->fs->remove([$this->vaultDir, $this->localVaultDir]);
36+
}
37+
38+
protected function tearDown(): void
39+
{
40+
$this->fs->remove([$this->vaultDir, $this->localVaultDir]);
41+
}
42+
43+
public function testFailsWhenLocalVaultIsDisabled()
44+
{
45+
$vault = $this->createMock(AbstractVault::class);
46+
$command = new SecretsEncryptFromLocalCommand($vault, null);
47+
$tester = new CommandTester($command);
48+
49+
$this->assertSame(1, $tester->execute([]));
50+
$this->assertStringContainsString('The local vault is disabled.', $tester->getDisplay());
51+
}
52+
53+
public function testEncryptsLocalOverrides()
54+
{
55+
$vault = new SodiumVault($this->vaultDir);
56+
$vault->generateKeys();
57+
58+
$localVault = new SodiumVault($this->localVaultDir);
59+
$localVault->generateKeys();
60+
61+
$vault->seal('MY_SECRET', 'prod-value');
62+
$localVault->seal('MY_SECRET', 'local-value');
63+
64+
$command = new SecretsEncryptFromLocalCommand($vault, $localVault);
65+
$tester = new CommandTester($command);
66+
67+
$exitCode = $tester->execute([]);
68+
$this->assertSame(0, $exitCode);
69+
70+
$revealed = $vault->reveal('MY_SECRET');
71+
$this->assertSame('local-value', $revealed);
72+
}
73+
74+
public function testDoesNotSealIfSameValue()
75+
{
76+
$vault = new SodiumVault($this->vaultDir);
77+
$vault->generateKeys();
78+
79+
$localVault = new SodiumVault($this->localVaultDir);
80+
$localVault->generateKeys();
81+
82+
$vault->seal('SHARED_SECRET', 'same-value');
83+
$localVault->seal('SHARED_SECRET', 'same-value');
84+
85+
$command = new SecretsEncryptFromLocalCommand($vault, $localVault);
86+
$tester = new CommandTester($command);
87+
88+
$exitCode = $tester->execute([]);
89+
$this->assertSame(0, $exitCode);
90+
91+
$revealed = $vault->reveal('SHARED_SECRET');
92+
$this->assertSame('same-value', $revealed);
93+
}
94+
95+
public function testFailsIfLocalSecretIsMissing()
96+
{
97+
$vault = new SodiumVault($this->vaultDir);
98+
$vault->generateKeys();
99+
100+
$localVault = new SodiumVault($this->localVaultDir);
101+
$localVault->generateKeys();
102+
103+
$vault->seal('MISSING_IN_LOCAL', 'prod-only');
104+
105+
$command = new SecretsEncryptFromLocalCommand($vault, $localVault);
106+
$tester = new CommandTester($command);
107+
108+
$this->assertSame(1, $tester->execute([]));
109+
$this->assertStringContainsString('Secret "MISSING_IN_LOCAL" not found', $tester->getDisplay());
110+
}
111+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\Tests\Command;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bundle\FrameworkBundle\Command\SecretsGenerateKeysCommand;
16+
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
17+
use Symfony\Bundle\FrameworkBundle\Secrets\SodiumVault;
18+
use Symfony\Component\Console\Tester\CommandTester;
19+
use Symfony\Component\Filesystem\Filesystem;
20+
21+
/**
22+
* @requires extension sodium
23+
*/
24+
class SecretsGenerateKeysCommandTest extends TestCase
25+
{
26+
private string $secretsDir;
27+
private const ENC_KEY_FILE = 'test.encrypt.public.php';
28+
private const DEC_KEY_FILE = 'test.decrypt.private.php';
29+
30+
protected function setUp(): void
31+
{
32+
$this->secretsDir = sys_get_temp_dir().'/sf_secrets/test/';
33+
(new Filesystem())->remove($this->secretsDir);
34+
}
35+
36+
protected function tearDown(): void
37+
{
38+
(new Filesystem())->remove($this->secretsDir);
39+
}
40+
41+
public function testItGeneratesSodiumKeys()
42+
{
43+
$vault = new SodiumVault($this->secretsDir);
44+
$tester = new CommandTester(new SecretsGenerateKeysCommand($vault));
45+
46+
$this->assertSame(0, $tester->execute([]));
47+
$this->assertKeysExistAndReadable();
48+
}
49+
50+
public function testItRotatesSodiumKeysWhenRequested()
51+
{
52+
$vault = new SodiumVault($this->secretsDir);
53+
$tester = new CommandTester(new SecretsGenerateKeysCommand($vault));
54+
55+
$this->assertSame(0, $tester->execute(['--rotate' => true]));
56+
$this->assertKeysExistAndReadable();
57+
}
58+
59+
public function testItFailsGracefullyWhenLocalVaultIsDisabled()
60+
{
61+
$vault = $this->createMock(AbstractVault::class);
62+
$tester = new CommandTester(new SecretsGenerateKeysCommand($vault));
63+
64+
$this->assertSame(1, $tester->execute(['--local' => true]));
65+
$this->assertStringContainsString('The local vault is disabled.', $tester->getDisplay());
66+
}
67+
68+
public function testFailsWhenKeysAlreadyExistAndRotateNotPassed()
69+
{
70+
$vault = new SodiumVault($this->secretsDir);
71+
$vault->generateKeys();
72+
73+
$command = new SecretsGenerateKeysCommand($vault);
74+
$tester = new CommandTester($command);
75+
76+
$this->assertSame(1, $tester->execute([]));
77+
$this->assertStringContainsString('Sodium keys already exist at', $tester->getDisplay());
78+
}
79+
80+
private function assertKeysExistAndReadable(): void
81+
{
82+
$encPath = $this->secretsDir.'/'.self::ENC_KEY_FILE;
83+
$decPath = $this->secretsDir.'/'.self::DEC_KEY_FILE;
84+
85+
$this->assertFileExists($encPath, 'Encryption key file does not exist.');
86+
$this->assertFileExists($decPath, 'Decryption key file does not exist.');
87+
$this->assertNotFalse(@file_get_contents($encPath), 'Encryption key file is not readable.');
88+
$this->assertNotFalse(@file_get_contents($decPath), 'Decryption key file is not readable.');
89+
}
90+
}

0 commit comments

Comments
 (0)