From 1e9ae3df0ed3a5fb8a91c5489d0d6f4fa59aec61 Mon Sep 17 00:00:00 2001 From: "Hermann D. Schimpf" Date: Fri, 15 Sep 2023 11:51:46 -0400 Subject: [PATCH 1/4] We should be able to define a default value for an undefined parameter --- tests/SecretsTest.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/SecretsTest.php b/tests/SecretsTest.php index 6792ace..24f0926 100644 --- a/tests/SecretsTest.php +++ b/tests/SecretsTest.php @@ -48,6 +48,17 @@ public function test caches parameters to call SSM only once(): void $this->assertSame('foobar', getenv('SOME_VARIABLE')); } + public function test that parameter can have a default value(): void + { + putenv('SOME_VARIABLE=bref-ssm:/some/undefined-parameter;default-value'); + + $ssmClient = $this->mockSsmClient(); + Secrets::loadSecretEnvironmentVariables($ssmClient); + + // Check that the variable has the default value + $this->assertSame('default-value', getenv('SOME_VARIABLE')); + } + public function test throws a clear error message on missing permissions(): void { putenv('SOME_VARIABLE=bref-ssm:/app/test'); From f9802554a1062ba02ab0b2b9bd17578b9a0cd87c Mon Sep 17 00:00:00 2001 From: "Hermann D. Schimpf" Date: Fri, 15 Sep 2023 14:50:42 -0400 Subject: [PATCH 2/4] Update Test definition * Mock a custom SSM client to return a result with InvalidParameters --- tests/SecretsTest.php | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/tests/SecretsTest.php b/tests/SecretsTest.php index 24f0926..f0ee7fe 100644 --- a/tests/SecretsTest.php +++ b/tests/SecretsTest.php @@ -50,13 +50,23 @@ public function test caches parameters to call SSM only once(): void public function test that parameter can have a default value(): void { - putenv('SOME_VARIABLE=bref-ssm:/some/undefined-parameter;default-value'); + putenv('SOME_VARIABLE_WITH_DEFAULT=bref-ssm:/some/undefined-parameter;default-value'); + + $ssmClient = $this->getMockBuilder(SsmClient::class) + ->disableOriginalConstructor() + ->getMock(); + $result = ResultMockFactory::create(GetParametersResult::class, [ + 'InvalidParameters' => [ + '/some/undefined-parameter', + ], + ]); + $ssmClient->method('getParameters') + ->willReturn($result); - $ssmClient = $this->mockSsmClient(); Secrets::loadSecretEnvironmentVariables($ssmClient); // Check that the variable has the default value - $this->assertSame('default-value', getenv('SOME_VARIABLE')); + $this->assertSame('default-value', getenv('SOME_VARIABLE_WITH_DEFAULT')); } public function test throws a clear error message on missing permissions(): void From da3d1cd6157471a3758393ed6bf1f2974f838f31 Mon Sep 17 00:00:00 2001 From: "Hermann D. Schimpf" Date: Fri, 15 Sep 2023 14:52:19 -0400 Subject: [PATCH 3/4] Default values for parameters implementation --- src/Secrets.php | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/Secrets.php b/src/Secrets.php index 639e815..7eea7a9 100644 --- a/src/Secrets.php +++ b/src/Secrets.php @@ -42,6 +42,9 @@ public static function loadSecretEnvironmentVariables(?SsmClient $ssmClient = nu return self::retrieveParametersFromSsm($ssmClient, array_values($ssmNames)); }); + // Remove default values from parameter names + $ssmNames = array_map(static fn($name) => explode(';', $name, 2)[0], $ssmNames); + foreach ($parameters as $parameterName => $parameterValue) { $envVar = array_search($parameterName, $ssmNames, true); $_SERVER[$envVar] = $_ENV[$envVar] = $parameterValue; @@ -99,6 +102,16 @@ private static function retrieveParametersFromSsm(?SsmClient $ssmClient, array $ /** @var array $parameters Map of parameter name -> value */ $parameters = []; $parametersNotFound = []; + // Store default values for parameters + $parametersDefaults = array_reduce($ssmNames, static function ($carry, $item) { + [ $paramName, $defaultValue ] = explode(';', $item) + [ null, null ]; + + return $paramName !== null && $defaultValue !== null + ? array_merge($carry, [ $paramName => $defaultValue ]) + : $carry; + }, []); + // Remove default values from parameter names for querying SSM + $ssmNames = array_map(static fn($name) => explode(';', $name, 2)[0], $ssmNames); // The API only accepts up to 10 parameters at a time, so we batch the calls foreach (array_chunk($ssmNames, 10) as $batchOfSsmNames) { @@ -124,6 +137,20 @@ private static function retrieveParametersFromSsm(?SsmClient $ssmClient, array $ $parametersNotFound = array_merge($parametersNotFound, $result->getInvalidParameters()); } + // check any of the invalid parameters has a default value + $parametersNotFound = array_filter($parametersNotFound, static function($parameter) use (&$parameters, $parametersDefaults): bool { + // check if the parameter has a default value + if (array_key_exists($parameter, $parametersDefaults)) { + // load default value + $parameters[$parameter] = $parametersDefaults[$parameter]; + + // remove it from the not found list + return false; + } + + return true; + }); + if (count($parametersNotFound) > 0) { throw new RuntimeException('The following SSM parameters could not be found: ' . implode(', ', $parametersNotFound)); } From 9b2ca44bdd80fefa2efadb4d1cfda72e98965ee1 Mon Sep 17 00:00:00 2001 From: "Hermann D. Schimpf" Date: Mon, 2 Oct 2023 12:07:42 -0300 Subject: [PATCH 4/4] Use comma as separator just like serverless --- src/Secrets.php | 6 +++--- tests/SecretsTest.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Secrets.php b/src/Secrets.php index 7eea7a9..4a0d77f 100644 --- a/src/Secrets.php +++ b/src/Secrets.php @@ -43,7 +43,7 @@ public static function loadSecretEnvironmentVariables(?SsmClient $ssmClient = nu }); // Remove default values from parameter names - $ssmNames = array_map(static fn($name) => explode(';', $name, 2)[0], $ssmNames); + $ssmNames = array_map(static fn($name) => explode(',', $name, 2)[0], $ssmNames); foreach ($parameters as $parameterName => $parameterValue) { $envVar = array_search($parameterName, $ssmNames, true); @@ -104,14 +104,14 @@ private static function retrieveParametersFromSsm(?SsmClient $ssmClient, array $ $parametersNotFound = []; // Store default values for parameters $parametersDefaults = array_reduce($ssmNames, static function ($carry, $item) { - [ $paramName, $defaultValue ] = explode(';', $item) + [ null, null ]; + [ $paramName, $defaultValue ] = explode(',', $item) + [ null, null ]; return $paramName !== null && $defaultValue !== null ? array_merge($carry, [ $paramName => $defaultValue ]) : $carry; }, []); // Remove default values from parameter names for querying SSM - $ssmNames = array_map(static fn($name) => explode(';', $name, 2)[0], $ssmNames); + $ssmNames = array_map(static fn($name) => explode(',', $name, 2)[0], $ssmNames); // The API only accepts up to 10 parameters at a time, so we batch the calls foreach (array_chunk($ssmNames, 10) as $batchOfSsmNames) { diff --git a/tests/SecretsTest.php b/tests/SecretsTest.php index f0ee7fe..7bc7859 100644 --- a/tests/SecretsTest.php +++ b/tests/SecretsTest.php @@ -50,7 +50,7 @@ public function test caches parameters to call SSM only once(): void public function test that parameter can have a default value(): void { - putenv('SOME_VARIABLE_WITH_DEFAULT=bref-ssm:/some/undefined-parameter;default-value'); + putenv('SOME_VARIABLE_WITH_DEFAULT=bref-ssm:/some/undefined-parameter,default-value'); $ssmClient = $this->getMockBuilder(SsmClient::class) ->disableOriginalConstructor()