diff --git a/src/Secrets.php b/src/Secrets.php index 639e815..4a0d77f 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)); } diff --git a/tests/SecretsTest.php b/tests/SecretsTest.php index 6792ace..7bc7859 100644 --- a/tests/SecretsTest.php +++ b/tests/SecretsTest.php @@ -48,6 +48,27 @@ 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_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); + + Secrets::loadSecretEnvironmentVariables($ssmClient); + + // Check that the variable has the default value + $this->assertSame('default-value', getenv('SOME_VARIABLE_WITH_DEFAULT')); + } + public function test throws a clear error message on missing permissions(): void { putenv('SOME_VARIABLE=bref-ssm:/app/test');