fix(api): require deploy ability for Hostinger setup options

Require deploy permission when setting a post-install script or extra SSH keys, document the 403 response, and cover both denial and allowed deployment cases.
This commit is contained in:
Andras Bacsai committed 2026-10-19 00:02:52 +02:00
1 parent e3d4411ff2
commit 0fb816bcb5
4 files changed
+61

No files matched your search

@@ -122,6 +122,7 @@ class HostingerController extends Controller
responses: [
new OA\Response(response: 201, description: 'Hostinger VPS purchased and linked to a Coolify server.'),
new OA\Response(response: 401, ref: '#/components/responses/401'),
new OA\Response(response: 403, description: 'The token needs the deploy ability to set post_install_script_id or public_key_ids.'),
new OA\Response(response: 422, description: 'Validation failed.'),
new OA\Response(response: 429, description: 'Hostinger rate limit exceeded.'),
]
@@ -182,6 +183,10 @@ class HostingerController extends Controller
], 422);
}
if ($request->filled('post_install_script_id') || $request->array('public_key_ids')) {
abort_unless($request->user()->tokenCan('deploy') || $request->user()->tokenCan('root'), 403, 'Missing required permissions: deploy');
}
$team = Team::find($teamId);
if (Team::serverLimitReached($team)) {
return response()->json(['message' => 'Server limit reached for your subscription.'], 400);
+3
View File
@@ -13108,6 +13108,9 @@
"401": {
"$ref": "#\/components\/responses\/401"
},
"403": {
"description": "The token needs the deploy ability to set post_install_script_id or public_key_ids."
},
"422": {
"description": "Validation failed."
},
+2
View File
@@ -8402,6 +8402,8 @@ paths:
description: 'Hostinger VPS purchased and linked to a Coolify server.'
'401':
$ref: '#/components/responses/401'
'403':
description: 'The token needs the deploy ability to set post_install_script_id or public_key_ids.'
'422':
description: 'Validation failed.'
'429':
+51
View File
@@ -192,6 +192,57 @@ it('turns paid Hostinger backups off when the API request does not enable them',
&& $request['setup']['enable_backups'] === false);
});
it('requires the deploy ability to run a post-install script or add SSH keys on a Hostinger VPS', function (array $extra) {
Http::fake();
$writeToken = $this->user->createToken('write-token', ['read', 'write'])->plainTextToken;
$this->withToken($writeToken)
->postJson('/api/v1/servers/hostinger', [
'cloud_provider_token_uuid' => $this->hostingerToken->uuid,
'item_id' => 'hostingercom-vps-kvm1-usd-1m',
'data_center_id' => 19,
'template_id' => 1130,
'private_key_uuid' => $this->privateKey->uuid,
...$extra,
])
->assertForbidden()
->assertJsonFragment(['message' => 'Missing required permissions: deploy']);
Http::assertNothingSent();
$this->assertDatabaseMissing('servers', ['team_id' => $this->team->id]);
})->with([
'post-install script' => [['post_install_script_id' => 73]],
'extra SSH keys' => [['public_key_ids' => [42]]],
]);
it('lets a deploy token run a post-install script on a Hostinger VPS', function () {
Http::fake([
'https://developers.hostinger.com/api/vps/v1/virtual-machines' => Http::response([
'virtual_machine' => [
'id' => 17923,
'state' => 'creating',
'ipv4' => [['address' => '203.0.113.10']],
],
]),
]);
$deployToken = $this->user->createToken('deploy-token', ['read', 'write', 'deploy'])->plainTextToken;
$this->withToken($deployToken)
->postJson('/api/v1/servers/hostinger', [
'cloud_provider_token_uuid' => $this->hostingerToken->uuid,
'item_id' => 'hostingercom-vps-kvm1-usd-1m',
'data_center_id' => 19,
'template_id' => 1130,
'private_key_uuid' => $this->privateKey->uuid,
'post_install_script_id' => 73,
])
->assertCreated();
Http::assertSent(fn ($request) => $request->method() === 'POST'
&& $request->url() === 'https://developers.hostinger.com/api/vps/v1/virtual-machines'
&& $request['setup']['post_install_script_id'] === 73);
});
it('keeps a charged Hostinger VPS when the purchase returns an error through the API', function () {
$listRequests = 0;
Http::fake([