fix(api): return the saved proxy configuration only with read:sensitive

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andras Bacsai
2026-09-28 13:10:25 +02:00
co-authored by Claude Opus 5.5
parent 5ab6e1b245
commit 1ecd927ca3
2 changed files with 35 additions and 2 deletions
@@ -20,6 +20,7 @@ use App\Rules\ValidServerIp;
use App\Support\ValidationPatterns;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Validation\ValidationException;
use OpenApi\Attributes as OA;
use Stringable;
@@ -47,14 +48,20 @@ class ServersController extends Controller
$server->makeHidden([
'id',
]);
if (request()->attributes->get('can_read_sensitive', false) === true) {
$canReadSensitive = request()->attributes->get('can_read_sensitive', false) === true;
if ($canReadSensitive) {
$server->makeVisible([
'logdrain_axiom_api_key',
'logdrain_newrelic_license_key',
]);
}
return serializeApiResponse($server);
$serialized = serializeApiResponse($server);
if (! $canReadSensitive && is_array($serialized->get('proxy'))) {
$serialized->put('proxy', Arr::except($serialized->get('proxy'), ['last_saved_proxy_configuration']));
}
return $serialized;
}
#[OA\Get(
@@ -135,6 +135,32 @@ describe('GET /api/v1/servers sensitive field gating', function () {
expect($body)->toContain('logdrain_axiom_api_key');
});
test('saved proxy configuration in server detail requires read sensitive', function () {
$this->server->proxy->set('last_saved_proxy_configuration', "services:\n traefik:\n environment:\n TOKEN: stored-proxy-config-value\n");
$this->server->save();
$readToken = makeApiToken($this->user, $this->team, ['read']);
$response = $this->withHeaders([
'Authorization' => 'Bearer '.$readToken,
])->getJson("/api/v1/servers/{$this->server->uuid}");
$response->assertStatus(200);
expect($response->getContent())->not->toContain('stored-proxy-config-value')
->and($response->json('proxy'))->toBeArray();
});
test('read sensitive token sees saved proxy configuration in server detail', function () {
$this->server->proxy->set('last_saved_proxy_configuration', "services:\n traefik:\n environment:\n TOKEN: stored-proxy-config-value\n");
$this->server->save();
$sensitiveToken = makeApiToken($this->user, $this->team, ['read', 'read:sensitive']);
$this->withHeaders([
'Authorization' => 'Bearer '.$sensitiveToken,
])->getJson("/api/v1/servers/{$this->server->uuid}")
->assertStatus(200)
->assertJsonPath('proxy.last_saved_proxy_configuration', "services:\n traefik:\n environment:\n TOKEN: stored-proxy-config-value\n");
});
test('server resources response does not leak server secrets', function () {
$token = makeApiToken($this->user, $this->team, ['read', 'read:sensitive']);