diff --git a/app/Http/Controllers/Api/CloudProviderTokensController.php b/app/Http/Controllers/Api/CloudProviderTokensController.php index d652f2ba1..2d8589662 100644 --- a/app/Http/Controllers/Api/CloudProviderTokensController.php +++ b/app/Http/Controllers/Api/CloudProviderTokensController.php @@ -16,9 +16,14 @@ private function removeSensitiveData($token) { $token->makeHidden([ 'id', - 'token', ]); + if (request()->attributes->get('can_read_sensitive', false) === true) { + $token->makeVisible([ + 'token', + ]); + } + return serializeApiResponse($token); } diff --git a/tests/Feature/CloudProviderTokenApiTest.php b/tests/Feature/CloudProviderTokenApiTest.php index da3acfd56..7f7b2546b 100644 --- a/tests/Feature/CloudProviderTokenApiTest.php +++ b/tests/Feature/CloudProviderTokenApiTest.php @@ -1,6 +1,7 @@ 0, 'is_api_enabled' => true]); + // Create a team with owner $this->team = Team::factory()->create(); $this->user = User::factory()->create(); @@ -69,6 +72,63 @@ $response = $this->getJson('/api/v1/cloud-tokens'); $response->assertStatus(401); }); + + test('read token does not include provider token values', function () { + CloudProviderToken::create([ + 'team_id' => $this->team->id, + 'name' => 'Hidden Token', + 'provider' => 'hetzner', + 'token' => 'hidden-cloud-provider-token', + ]); + + $readToken = $this->user->createToken('read-token', ['read'])->plainTextToken; + + $response = $this->withHeaders([ + 'Authorization' => 'Bearer '.$readToken, + 'Content-Type' => 'application/json', + ])->getJson('/api/v1/cloud-tokens'); + + $response->assertSuccessful(); + expect($response->getContent())->not->toContain('"token":'); + }); + + test('read sensitive token includes provider token values', function () { + CloudProviderToken::create([ + 'team_id' => $this->team->id, + 'name' => 'Visible Token', + 'provider' => 'hetzner', + 'token' => 'visible-cloud-provider-token', + ]); + + $readSensitiveToken = $this->user->createToken('read-sensitive-token', ['read', 'read:sensitive'])->plainTextToken; + + $response = $this->withHeaders([ + 'Authorization' => 'Bearer '.$readSensitiveToken, + 'Content-Type' => 'application/json', + ])->getJson('/api/v1/cloud-tokens'); + + $response->assertSuccessful(); + $response->assertJsonFragment(['token' => 'visible-cloud-provider-token']); + }); + + test('root token includes provider token values', function () { + CloudProviderToken::create([ + 'team_id' => $this->team->id, + 'name' => 'Root Visible Token', + 'provider' => 'hetzner', + 'token' => 'root-visible-cloud-provider-token', + ]); + + $rootToken = $this->user->createToken('root-token', ['root'])->plainTextToken; + + $response = $this->withHeaders([ + 'Authorization' => 'Bearer '.$rootToken, + 'Content-Type' => 'application/json', + ])->getJson('/api/v1/cloud-tokens'); + + $response->assertSuccessful(); + $response->assertJsonFragment(['token' => 'root-visible-cloud-provider-token']); + }); }); describe('GET /api/v1/cloud-tokens/{uuid}', function () {