Restrict upgrade-status endpoint to authenticated root team members
- Add auth:sanctum middleware to /api/upgrade-status route - Check user belongs to root team (id 0) before returning status - Return 403 if user is not authorized - Update frontend to send credentials with fetch request - Update OpenAPI docs with 401/403 responses 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
dc9f612df4
commit
3cc416a806
3 changed files with 41 additions and 3 deletions
|
|
@ -189,9 +189,12 @@ public function healthcheck(Request $request)
|
||||||
|
|
||||||
#[OA\Get(
|
#[OA\Get(
|
||||||
summary: 'Upgrade Status',
|
summary: 'Upgrade Status',
|
||||||
description: 'Get the current upgrade status. Returns the step and message from the upgrade process.',
|
description: 'Get the current upgrade status. Returns the step and message from the upgrade process. Only available to root team members.',
|
||||||
path: '/upgrade-status',
|
path: '/upgrade-status',
|
||||||
operationId: 'upgrade-status',
|
operationId: 'upgrade-status',
|
||||||
|
security: [
|
||||||
|
['bearerAuth' => []],
|
||||||
|
],
|
||||||
responses: [
|
responses: [
|
||||||
new OA\Response(
|
new OA\Response(
|
||||||
response: 200,
|
response: 200,
|
||||||
|
|
@ -204,6 +207,19 @@ public function healthcheck(Request $request)
|
||||||
new OA\Property(property: 'message', type: 'string', example: 'Pulling Docker images'),
|
new OA\Property(property: 'message', type: 'string', example: 'Pulling Docker images'),
|
||||||
]
|
]
|
||||||
)),
|
)),
|
||||||
|
new OA\Response(
|
||||||
|
response: 401,
|
||||||
|
ref: '#/components/responses/401',
|
||||||
|
),
|
||||||
|
new OA\Response(
|
||||||
|
response: 403,
|
||||||
|
description: 'You are not allowed to view upgrade status.',
|
||||||
|
content: new OA\JsonContent(
|
||||||
|
type: 'object',
|
||||||
|
properties: [
|
||||||
|
new OA\Property(property: 'message', type: 'string', example: 'You are not allowed to view upgrade status.'),
|
||||||
|
]
|
||||||
|
)),
|
||||||
new OA\Response(
|
new OA\Response(
|
||||||
response: 400,
|
response: 400,
|
||||||
ref: '#/components/responses/400',
|
ref: '#/components/responses/400',
|
||||||
|
|
@ -212,6 +228,12 @@ public function healthcheck(Request $request)
|
||||||
)]
|
)]
|
||||||
public function upgradeStatus(Request $request)
|
public function upgradeStatus(Request $request)
|
||||||
{
|
{
|
||||||
|
// Only root team members can view upgrade status
|
||||||
|
$user = auth()->user();
|
||||||
|
if (! $user || $user->currentTeam()->id !== 0) {
|
||||||
|
return response()->json(['message' => 'You are not allowed to view upgrade status.'], 403);
|
||||||
|
}
|
||||||
|
|
||||||
$statusFile = '/data/coolify/source/.upgrade-status';
|
$statusFile = '/data/coolify/source/.upgrade-status';
|
||||||
|
|
||||||
if (! file_exists($statusFile)) {
|
if (! file_exists($statusFile)) {
|
||||||
|
|
|
||||||
|
|
@ -286,11 +286,17 @@ class="w-24 dark:bg-coolgray-200 dark:hover:bg-coolgray-300">Cancel
|
||||||
|
|
||||||
// Poll upgrade status API for real progress
|
// Poll upgrade status API for real progress
|
||||||
this.checkUpgradeStatusInterval = setInterval(() => {
|
this.checkUpgradeStatusInterval = setInterval(() => {
|
||||||
fetch('/api/upgrade-status')
|
fetch('/api/upgrade-status', {
|
||||||
|
credentials: 'same-origin',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
}
|
||||||
|
})
|
||||||
.then(response => {
|
.then(response => {
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
return response.json();
|
return response.json();
|
||||||
}
|
}
|
||||||
|
// Auth errors (401/403) or service down - switch to health check
|
||||||
throw new Error('Service unavailable');
|
throw new Error('Service unavailable');
|
||||||
})
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,21 @@
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
Route::get('/health', [OtherController::class, 'healthcheck']);
|
Route::get('/health', [OtherController::class, 'healthcheck']);
|
||||||
Route::get('/upgrade-status', [OtherController::class, 'upgradeStatus']);
|
|
||||||
Route::group([
|
Route::group([
|
||||||
'prefix' => 'v1',
|
'prefix' => 'v1',
|
||||||
], function () {
|
], function () {
|
||||||
Route::get('/health', [OtherController::class, 'healthcheck']);
|
Route::get('/health', [OtherController::class, 'healthcheck']);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::group([
|
||||||
|
'middleware' => ['auth:sanctum'],
|
||||||
|
], function () {
|
||||||
|
Route::get('/upgrade-status', [OtherController::class, 'upgradeStatus']);
|
||||||
|
});
|
||||||
|
Route::group([
|
||||||
|
'middleware' => ['auth:sanctum'],
|
||||||
|
'prefix' => 'v1',
|
||||||
|
], function () {
|
||||||
Route::get('/upgrade-status', [OtherController::class, 'upgradeStatus']);
|
Route::get('/upgrade-status', [OtherController::class, 'upgradeStatus']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue