fix(api): avoid lazy loading nested server secrets
This commit is contained in:
parent
13172849e1
commit
99f60228ad
5 changed files with 28 additions and 58 deletions
|
|
@ -69,7 +69,6 @@ private function removeSensitiveData($application)
|
||||||
$application->makeHidden([
|
$application->makeHidden([
|
||||||
'private_key_id',
|
'private_key_id',
|
||||||
]);
|
]);
|
||||||
$this->hideNestedServerSecrets($application);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($application->is_shown_once ?? false) {
|
if ($application->is_shown_once ?? false) {
|
||||||
|
|
@ -79,31 +78,6 @@ private function removeSensitiveData($application)
|
||||||
return serializeApiResponse($application);
|
return serializeApiResponse($application);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function hideNestedServerSecrets($model): void
|
|
||||||
{
|
|
||||||
$server = $model->destination?->server ?? null;
|
|
||||||
if (! $server) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$server->makeHidden([
|
|
||||||
'logdrain_axiom_api_key',
|
|
||||||
'logdrain_newrelic_license_key',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$settings = $server->settings ?? null;
|
|
||||||
if ($settings) {
|
|
||||||
$settings->makeHidden([
|
|
||||||
'sentinel_token',
|
|
||||||
'sentinel_custom_url',
|
|
||||||
'logdrain_newrelic_license_key',
|
|
||||||
'logdrain_axiom_api_key',
|
|
||||||
'logdrain_custom_config',
|
|
||||||
'logdrain_custom_config_parser',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expose sensitive fields on eager-loaded nested Server + ServerSetting
|
* Expose sensitive fields on eager-loaded nested Server + ServerSetting
|
||||||
* relations for callers with the `read:sensitive` or `root` token ability.
|
* relations for callers with the `read:sensitive` or `root` token ability.
|
||||||
|
|
@ -184,8 +158,12 @@ public function applications(Request $request)
|
||||||
}
|
}
|
||||||
|
|
||||||
$tagName = $request->query('tag');
|
$tagName = $request->query('tag');
|
||||||
|
$applicationRelations = $request->attributes->get('can_read_sensitive', false) === true
|
||||||
|
? ['destination.server.settings']
|
||||||
|
: [];
|
||||||
|
|
||||||
$applications = Application::ownedByCurrentTeamAPI($teamId)
|
$applications = Application::ownedByCurrentTeamAPI($teamId)
|
||||||
|
->with($applicationRelations)
|
||||||
->when($tagName, function ($query, $tagName) {
|
->when($tagName, function ($query, $tagName) {
|
||||||
$query->whereHas('tags', function ($query) use ($tagName) {
|
$query->whereHas('tags', function ($query) use ($tagName) {
|
||||||
$query->where('name', $tagName);
|
$query->where('name', $tagName);
|
||||||
|
|
|
||||||
|
|
@ -60,37 +60,11 @@ private function removeSensitiveData($database)
|
||||||
'mariadb_root_password',
|
'mariadb_root_password',
|
||||||
]);
|
]);
|
||||||
$this->exposeNestedServerSecrets($database);
|
$this->exposeNestedServerSecrets($database);
|
||||||
} else {
|
|
||||||
$this->hideNestedServerSecrets($database);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return serializeApiResponse($database);
|
return serializeApiResponse($database);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function hideNestedServerSecrets(Model $model): void
|
|
||||||
{
|
|
||||||
$server = $model->destination?->server;
|
|
||||||
if ($server === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$server->makeHidden([
|
|
||||||
'logdrain_axiom_api_key',
|
|
||||||
'logdrain_newrelic_license_key',
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($server->settings !== null) {
|
|
||||||
$server->settings->makeHidden([
|
|
||||||
'sentinel_token',
|
|
||||||
'sentinel_custom_url',
|
|
||||||
'logdrain_newrelic_license_key',
|
|
||||||
'logdrain_axiom_api_key',
|
|
||||||
'logdrain_custom_config',
|
|
||||||
'logdrain_custom_config_parser',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expose sensitive fields on eager-loaded nested Server + ServerSetting
|
* Expose sensitive fields on eager-loaded nested Server + ServerSetting
|
||||||
* relations for callers with the `read:sensitive` or `root` token ability.
|
* relations for callers with the `read:sensitive` or `root` token ability.
|
||||||
|
|
|
||||||
|
|
@ -803,7 +803,7 @@
|
||||||
"category": "backend",
|
"category": "backend",
|
||||||
"logo": "svgs/convex.svg",
|
"logo": "svgs/convex.svg",
|
||||||
"minversion": "0.0.0",
|
"minversion": "0.0.0",
|
||||||
"template_last_updated_at": "2026-05-09T19:26:30+05:30",
|
"template_last_updated_at": "2026-06-12T10:45:52+02:00",
|
||||||
"port": "6791"
|
"port": "6791"
|
||||||
},
|
},
|
||||||
"cryptgeon": {
|
"cryptgeon": {
|
||||||
|
|
@ -1779,7 +1779,7 @@
|
||||||
"category": "devtools",
|
"category": "devtools",
|
||||||
"logo": "svgs/gitea.svg",
|
"logo": "svgs/gitea.svg",
|
||||||
"minversion": "0.0.0",
|
"minversion": "0.0.0",
|
||||||
"template_last_updated_at": "2026-06-01T07:54:27-05:00"
|
"template_last_updated_at": "2026-06-06T00:11:24+02:00"
|
||||||
},
|
},
|
||||||
"gitea-with-mariadb": {
|
"gitea-with-mariadb": {
|
||||||
"documentation": "https://docs.gitea.com?utm_source=coolify.io",
|
"documentation": "https://docs.gitea.com?utm_source=coolify.io",
|
||||||
|
|
@ -2361,7 +2361,7 @@
|
||||||
"category": "automation",
|
"category": "automation",
|
||||||
"logo": "svgs/inngest.png",
|
"logo": "svgs/inngest.png",
|
||||||
"minversion": "0.0.0",
|
"minversion": "0.0.0",
|
||||||
"template_last_updated_at": null,
|
"template_last_updated_at": "2026-07-02T13:25:47+02:00",
|
||||||
"port": "8288"
|
"port": "8288"
|
||||||
},
|
},
|
||||||
"invoice-ninja": {
|
"invoice-ninja": {
|
||||||
|
|
|
||||||
|
|
@ -803,7 +803,7 @@
|
||||||
"category": "backend",
|
"category": "backend",
|
||||||
"logo": "svgs/convex.svg",
|
"logo": "svgs/convex.svg",
|
||||||
"minversion": "0.0.0",
|
"minversion": "0.0.0",
|
||||||
"template_last_updated_at": "2026-05-09T19:26:30+05:30",
|
"template_last_updated_at": "2026-06-12T10:45:52+02:00",
|
||||||
"port": "6791"
|
"port": "6791"
|
||||||
},
|
},
|
||||||
"cryptgeon": {
|
"cryptgeon": {
|
||||||
|
|
@ -1779,7 +1779,7 @@
|
||||||
"category": "devtools",
|
"category": "devtools",
|
||||||
"logo": "svgs/gitea.svg",
|
"logo": "svgs/gitea.svg",
|
||||||
"minversion": "0.0.0",
|
"minversion": "0.0.0",
|
||||||
"template_last_updated_at": "2026-06-01T07:54:27-05:00"
|
"template_last_updated_at": "2026-06-06T00:11:24+02:00"
|
||||||
},
|
},
|
||||||
"gitea-with-mariadb": {
|
"gitea-with-mariadb": {
|
||||||
"documentation": "https://docs.gitea.com?utm_source=coolify.io",
|
"documentation": "https://docs.gitea.com?utm_source=coolify.io",
|
||||||
|
|
@ -2361,7 +2361,7 @@
|
||||||
"category": "automation",
|
"category": "automation",
|
||||||
"logo": "svgs/inngest.png",
|
"logo": "svgs/inngest.png",
|
||||||
"minversion": "0.0.0",
|
"minversion": "0.0.0",
|
||||||
"template_last_updated_at": null,
|
"template_last_updated_at": "2026-07-02T13:25:47+02:00",
|
||||||
"port": "8288"
|
"port": "8288"
|
||||||
},
|
},
|
||||||
"invoice-ninja": {
|
"invoice-ninja": {
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
use App\Models\StandalonePostgresql;
|
use App\Models\StandalonePostgresql;
|
||||||
use App\Models\Team;
|
use App\Models\Team;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
|
@ -550,6 +551,23 @@ function makeTeamUser(): array
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('read token database list does not lazy load nested server relations', function () {
|
||||||
|
$token = makeApiToken($this->user, $this->team, ['read']);
|
||||||
|
|
||||||
|
$preventedLazyLoading = Model::preventsLazyLoading();
|
||||||
|
Model::preventLazyLoading();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$response = $this->withoutExceptionHandling()->withHeaders([
|
||||||
|
'Authorization' => 'Bearer '.$token,
|
||||||
|
])->getJson('/api/v1/databases');
|
||||||
|
} finally {
|
||||||
|
Model::preventLazyLoading($preventedLazyLoading);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
});
|
||||||
|
|
||||||
test('read token does not leak postgres_password or db urls', function () {
|
test('read token does not leak postgres_password or db urls', function () {
|
||||||
$token = makeApiToken($this->user, $this->team, ['read']);
|
$token = makeApiToken($this->user, $this->team, ['read']);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue