Skip to content

Commit

Permalink
feat (csas-migration): Extend GenericAKVWrapper with trans client
Browse files Browse the repository at this point in the history
  • Loading branch information
romantmb committed Feb 4, 2025
1 parent cd29f94 commit 4dc955a
Show file tree
Hide file tree
Showing 2 changed files with 173 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/Wrapper/GenericAKVWrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
use Keboola\ObjectEncryptor\EncryptorOptions;
use Keboola\ObjectEncryptor\Exception\ApplicationException;
use Keboola\ObjectEncryptor\Exception\UserException;
use Keboola\ObjectEncryptor\Temporary\TransClient;
use Keboola\ObjectEncryptor\Temporary\TransClientNotAvailableException;
use Psr\Log\NullLogger;
use Retry\BackOff\ExponentialBackOffPolicy;
use Retry\Policy\SimpleRetryPolicy;
Expand All @@ -37,13 +39,18 @@ class GenericAKVWrapper implements CryptoWrapperInterface
private string $keyVaultURL;
private ?Client $client = null;

private TransClient|false|null $transClient = null;
private ?string $encryptorId = null;

public function __construct(EncryptorOptions $encryptorOptions)
{
// there is no way to pass backOffMaxTries option to the Azure Key Vault client. Yet.
$this->keyVaultURL = (string) $encryptorOptions->getAkvUrl();
if (empty($this->keyVaultURL)) {
throw new ApplicationException('Cipher key settings are invalid.');
}

$this->encryptorId = $encryptorOptions->getEncryptorId();
}

public function getClient(): Client
Expand All @@ -58,6 +65,22 @@ public function getClient(): Client
return $this->client;
}

public function getTransClient(): ?TransClient
{
if ($this->transClient === null) {
try {
$this->transClient = new TransClient(
new GuzzleClientFactory(new NullLogger()),
$this->encryptorId,
);
} catch (TransClientNotAvailableException) {
$this->transClient = false;
}
}

return $this->transClient ?: null;
}

private function getRetryProxy(): RetryProxy
{
$retryPolicy = new SimpleRetryPolicy(3);
Expand Down
150 changes: 150 additions & 0 deletions tests/Temporary/AKVWrappersWithTransClientTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
<?php

declare(strict_types=1);

namespace Keboola\ObjectEncryptor\Tests\Temporary;

use Keboola\ObjectEncryptor\EncryptorOptions;
use Keboola\ObjectEncryptor\Temporary\TransClient;
use Keboola\ObjectEncryptor\Wrapper\BranchTypeConfigurationAKVWrapper;
use Keboola\ObjectEncryptor\Wrapper\BranchTypeProjectAKVWrapper;
use Keboola\ObjectEncryptor\Wrapper\BranchTypeProjectWideAKVWrapper;
use Keboola\ObjectEncryptor\Wrapper\ComponentAKVWrapper;
use Keboola\ObjectEncryptor\Wrapper\ConfigurationAKVWrapper;
use Keboola\ObjectEncryptor\Wrapper\GenericAKVWrapper;
use Keboola\ObjectEncryptor\Wrapper\ProjectAKVWrapper;
use Keboola\ObjectEncryptor\Wrapper\ProjectWideAKVWrapper;
use PHPUnit\Framework\TestCase;

class AKVWrappersWithTransClientTest extends TestCase
{
public function setUp(): void
{
parent::setUp();

putenv('TRANS_AZURE_TENANT_ID=');
putenv('TRANS_AZURE_CLIENT_ID=');
putenv('TRANS_AZURE_CLIENT_SECRET=');
}

public static function provideAKVWrappers(): iterable
{
$classes = [
GenericAKVWrapper::class,
ComponentAKVWrapper::class,
ProjectAKVWrapper::class,
ConfigurationAKVWrapper::class,
ProjectWideAKVWrapper::class,
BranchTypeProjectAKVWrapper::class,
BranchTypeProjectWideAKVWrapper::class,
BranchTypeConfigurationAKVWrapper::class,
];

foreach ($classes as $className) {
yield $className => [
'wrapperClass' => $className,
];
}
}

/**
* @dataProvider provideAKVWrappers
* @param class-string<GenericAKVWrapper> $wrapperClass
*/
public function testWrappersDoNotHaveTransClientInitializedWhenTransEnvsMissing(
string $wrapperClass,
): void {
$encryptorOptions = new EncryptorOptions(
stackId: 'some-stack',
akvUrl: 'some-url',
);

$wrapper = new $wrapperClass($encryptorOptions);

self::assertNull($wrapper->getTransClient());
}

/**
* @dataProvider provideAKVWrappers
* @param class-string<GenericAKVWrapper> $wrapperClass
*/
public function testWrappersHaveTransClientInitialized(
string $wrapperClass,
): void {
putenv('TRANS_AZURE_TENANT_ID=tenant-id');
putenv('TRANS_AZURE_CLIENT_ID=client-id');
putenv('TRANS_AZURE_CLIENT_SECRET=client-secret');
putenv('TRANS_AZURE_KEY_VAULT_URL=https://vault-url');

$encryptorOptions = new EncryptorOptions(
stackId: 'some-stack',
akvUrl: 'some-url',
);

$wrapper = new $wrapperClass($encryptorOptions);

$transClient = $wrapper->getTransClient();
self::assertInstanceOf(TransClient::class, $transClient);

// ensure getter returns a single instance of the TransClient
self::assertSame($transClient, $wrapper->getTransClient());
}

/**
* @dataProvider provideAKVWrappers
* @param class-string<GenericAKVWrapper> $wrapperClass
*/
public function testWrappersHaveTransClientWhenEncryptorIdMatches(
string $wrapperClass,
): void {
putenv('TRANS_AZURE_TENANT_ID=tenant-id');
putenv('TRANS_AZURE_CLIENT_ID=client-id');
putenv('TRANS_AZURE_CLIENT_SECRET=client-secret');
putenv('TRANS_AZURE_KEY_VAULT_URL=');
putenv('TRANS_AZURE_KEY_VAULT_URL_EXTRA_BRATWURST=https://german-vault-url');

$encryptorOptions = new EncryptorOptions(
stackId: 'some-stack',
akvUrl: 'some-url',
encryptorId: 'extra-bratwurst',
);

$wrapper = new $wrapperClass($encryptorOptions);

$transClient = $wrapper->getTransClient();
self::assertInstanceOf(TransClient::class, $transClient);

// ensure getter returns a single instance of the TransClient
self::assertSame($transClient, $wrapper->getTransClient());
}

/**
* @dataProvider provideAKVWrappers
* @param class-string<GenericAKVWrapper> $wrapperClass
*/
public function testWrappersDoNotHaveTransClientWhenEncryptorIdMismatches(
string $wrapperClass,
): void {
putenv('TRANS_AZURE_TENANT_ID=tenant-id');
putenv('TRANS_AZURE_CLIENT_ID=client-id');
putenv('TRANS_AZURE_CLIENT_SECRET=client-secret');
putenv('TRANS_AZURE_KEY_VAULT_URL=');
putenv('TRANS_AZURE_KEY_VAULT_URL_EXTRA_BRATWURST=https://german-vault-url');

// null encryptorId
$wrapper = new $wrapperClass(new EncryptorOptions(
stackId: 'some-stack',
akvUrl: 'some-url',
encryptorId: null,
));
self::assertNull($wrapper->getTransClient());

// encryptorId does not match env suffix ('extra-sausage' vs. _EXTRA_BRATWURST)
$wrapper = new $wrapperClass(new EncryptorOptions(
stackId: 'some-stack',
akvUrl: 'some-url',
encryptorId: 'extra-sausage',
));
self::assertNull($wrapper->getTransClient());
}
}

0 comments on commit 4dc955a

Please sign in to comment.