mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-06 13:10:37 -04:00
fix(infisical): include imported secrets when fetching secrets
Closes #12267 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
f72041c513
commit
5131832cd8
@@ -46,6 +46,7 @@ class InfisicalService
|
||||
'projectId' => $projectId,
|
||||
'environment' => $environment,
|
||||
'secretPath' => $secretPath,
|
||||
'includeImports' => 'true',
|
||||
...$valueOptions,
|
||||
]);
|
||||
|
||||
@@ -55,6 +56,7 @@ class InfisicalService
|
||||
'workspaceId' => $projectId,
|
||||
'environment' => $environment,
|
||||
'secretPath' => $secretPath,
|
||||
'include_imports' => 'true',
|
||||
...$valueOptions,
|
||||
]);
|
||||
}
|
||||
@@ -63,7 +65,20 @@ class InfisicalService
|
||||
throw new \RuntimeException('Infisical API error: '.($response->json('message') ?? 'HTTP '.$response->status()));
|
||||
}
|
||||
|
||||
return collect($response->json('secrets', []))
|
||||
// Like `infisical export`: later imports override earlier ones, and the folder's own secrets override all imports.
|
||||
return collect($response->json('imports', []))
|
||||
->pluck('secrets')
|
||||
->push($response->json('secrets', []))
|
||||
->reduce(fn (array $merged, ?array $secrets) => array_replace($merged, $this->keyValues($secrets ?? [])), []);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, array<string, mixed>> $secrets
|
||||
* @return array<string, string>
|
||||
*/
|
||||
private function keyValues(array $secrets): array
|
||||
{
|
||||
return collect($secrets)
|
||||
->mapWithKeys(fn ($secret) => [(string) data_get($secret, 'secretKey') => (string) data_get($secret, 'secretValue', '')])
|
||||
->all();
|
||||
}
|
||||
|
||||
@@ -125,6 +125,67 @@ describe('InfisicalService', function () {
|
||||
&& $request['expandSecretReferences'] === 'true');
|
||||
});
|
||||
|
||||
test('merges imported secrets, with own secrets and later imports taking precedence', function () {
|
||||
Http::fake([
|
||||
'https://example.com/infisical/api/v1/auth/universal-auth/login' => Http::response([
|
||||
'accessToken' => 'short-lived-token',
|
||||
]),
|
||||
'https://example.com/infisical/api/v4/secrets*' => Http::response([
|
||||
'secrets' => [
|
||||
['secretKey' => 'APP_KEY', 'secretValue' => 'app'],
|
||||
['secretKey' => 'OVERRIDDEN', 'secretValue' => 'own'],
|
||||
],
|
||||
'imports' => [
|
||||
['secretPath' => '/shared', 'environment' => 'prod', 'secrets' => [
|
||||
['secretKey' => 'SHARED_KEY', 'secretValue' => 'shared'],
|
||||
['secretKey' => 'OVERRIDDEN', 'secretValue' => 'from-shared'],
|
||||
['secretKey' => 'IMPORT_CONFLICT', 'secretValue' => 'first-import'],
|
||||
]],
|
||||
['secretPath' => '/common', 'environment' => 'prod', 'secrets' => [
|
||||
['secretKey' => 'IMPORT_CONFLICT', 'secretValue' => 'last-import'],
|
||||
]],
|
||||
],
|
||||
]),
|
||||
]);
|
||||
|
||||
$service = new InfisicalService('https://example.com/infisical', 'client-id', 'client-secret');
|
||||
|
||||
expect($service->fetchSecrets('project-1', 'prod', '/apps/api'))->toBe([
|
||||
'SHARED_KEY' => 'shared',
|
||||
'OVERRIDDEN' => 'own',
|
||||
'IMPORT_CONFLICT' => 'last-import',
|
||||
'APP_KEY' => 'app',
|
||||
]);
|
||||
|
||||
Http::assertSent(fn ($request) => str_contains($request->url(), '/api/v4/secrets')
|
||||
&& $request['includeImports'] === 'true');
|
||||
});
|
||||
|
||||
test('requests imported secrets from the v3 raw endpoint', function () {
|
||||
Http::fake([
|
||||
'https://example.com/infisical/api/v1/auth/universal-auth/login' => Http::response([
|
||||
'accessToken' => 'short-lived-token',
|
||||
]),
|
||||
'https://example.com/infisical/api/v4/secrets*' => Http::response([], 404),
|
||||
'https://example.com/infisical/api/v3/secrets/raw*' => Http::response([
|
||||
'secrets' => [['secretKey' => 'APP_KEY', 'secretValue' => 'app']],
|
||||
'imports' => [['secretPath' => '/shared', 'secrets' => [
|
||||
['secretKey' => 'SHARED_KEY', 'secretValue' => 'shared'],
|
||||
]]],
|
||||
]),
|
||||
]);
|
||||
|
||||
$service = new InfisicalService('https://example.com/infisical', 'client-id', 'client-secret');
|
||||
|
||||
expect($service->fetchSecrets('project-1', 'prod', '/apps/api'))->toBe([
|
||||
'SHARED_KEY' => 'shared',
|
||||
'APP_KEY' => 'app',
|
||||
]);
|
||||
|
||||
Http::assertSent(fn ($request) => str_contains($request->url(), '/api/v3/secrets/raw')
|
||||
&& $request['include_imports'] === 'true');
|
||||
});
|
||||
|
||||
test('uses a 5 second connect timeout and a 10 second request timeout by default', function (?int $timeout, array $expected) {
|
||||
$timeouts = [];
|
||||
Http::fake(function ($request, array $options) use (&$timeouts) {
|
||||
|
||||
Reference in New Issue
Block a user