Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/controllers.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
});

Http::post('/v1/runtimes/:runtimeId/commands')
->groups(['api', 'runtimes'])
->desc('Execute a command inside an existing runtime')
->param('runtimeId', '', new Text(64), 'Unique runtime ID.')
->param('command', '', new Text(1024), 'Command to execute.')
Expand Down
11 changes: 11 additions & 0 deletions tests/e2e/ExecutorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,17 @@ public function testGetRuntimesUnauthorized(): void
$this->client->setKey($this->key);
}

public function testCommandsUnauthorized(): void
{
$this->client->setKey('');
$response = $this->client->call(Client::METHOD_POST, '/runtimes/test-commands-unauth/commands', [], [
'command' => 'true',
]);
$this->assertEquals(401, $response['headers']['status-code']);
$this->assertEquals('Missing executor key', $response['body']['message']);
$this->client->setKey($this->key);
}

public function testBuild(): void
{
$output = '';
Expand Down
54 changes: 54 additions & 0 deletions tests/unit/Http/RouteAuthTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

declare(strict_types=1);

namespace Tests\Unit\Http;

use PHPUnit\Framework\TestCase;

final class RouteAuthTest extends TestCase
{
public function testNonPublicRoutesDeclareApiGroup(): void
{
$controllers = \dirname(__DIR__, 3) . '/app/controllers.php';
$source = \file_get_contents($controllers);
if ($source === false) {
$this->fail('Unable to read app/controllers.php');
}

$matches = [];
\preg_match_all(
"/Http::(?:get|post|put|patch|delete)\\('([^']+)'\\)(.*?)(?=Http::(?:get|post|put|patch|delete|init|error)\\(|\\z)/s",
$source,
$matches,
PREG_SET_ORDER
);

$this->assertNotEmpty($matches, 'Expected HTTP routes in app/controllers.php');

$paths = [];
foreach ($matches as $match) {
$path = $match[1];
$body = $match[2];
$paths[] = $path;

if ($path === '/v1/health') {
$this->assertDoesNotMatchRegularExpression(
"/->groups\\(\\[[^\\]]*?'api'/",
$body,
'Health must stay public for Docker healthchecks'
);
continue;
}

$this->assertMatchesRegularExpression(
"/->groups\\(\\[[^\\]]*?'api'/",
$body,
\sprintf('Route %s must declare the api group so the executor secret check applies', $path)
);
}

$this->assertContains('/v1/runtimes/:runtimeId/commands', $paths);
$this->assertContains('/v1/health', $paths);
}
}
Loading