|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
use App\Http\Middleware\AccountInterstitial;
|
|
|
|
|
use App\Http\Middleware\Admin;
|
|
|
|
|
use App\Http\Middleware\Api\Admin as ApiAdmin;
|
|
|
|
|
use App\Http\Middleware\FrameGuard;
|
|
|
|
|
use App\Http\Middleware\GrantFirstPartyToken;
|
|
|
|
|
use App\Http\Middleware\Localization;
|
|
|
|
|
use App\Http\Middleware\RedirectIfAuthenticated;
|
|
|
|
|
use App\Http\Middleware\RestrictedAccess;
|
|
|
|
|
use App\Services\PendingLoginService;
|
|
|
|
|
use Illuminate\Auth\AuthenticationException;
|
|
|
|
|
use Illuminate\Auth\Middleware\Authenticate;
|
|
|
|
|
use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth;
|
|
|
|
|
use Illuminate\Auth\Middleware\Authorize;
|
feat: add critical path test suite and fix auth/config issues
Test Infrastructure:
- Modernize phpunit.xml (bootstrap, source block, Laravel 12 env vars)
- Configure tests/Pest.php with pest()->extend(TestCase::class)->in('Feature')
- Add docker-compose.test.yml (Redis for test suite)
- Add composer test/test:quick scripts
- Rename CACHE_DRIVER to CACHE_STORE across config (backwards compatible)
- Update .env.testing for in-memory SQLite + Docker Redis
Test Coverage (190 tests):
- CriticalRoutes: public routes, auth routes, API endpoints, middleware, schedule
- Auth/LoginTest: login, logout, rate limiting, redirect behavior
- Auth/RegisterTest: registration flow, validation, disabled registration
- Auth/PasswordResetTest: reset request, token validation, password update
- Auth/TwoFactorTest: 2FA checkpoint, setup behind password confirmation
- Auth/PasswordConfirmationTest: sudo mode flow via Laravel password.confirm
- Api/ScopeTest: scope enforcement, public endpoints, admin access
Bugs Fixed:
- Fix unauthenticated API returning 500 instead of 401 (AuthenticationException
not handled in custom exception renderer in bootstrap/app.php)
- Replace custom DangerZone middleware with Laravel password.confirm
- Add HasFactory trait to Profile model for test factories
Bugs Documented (known-bugs group):
- Registration crashes with str_ends_with TypeError (RegisterController:82)
- OAuth routes use legacy array syntax causing ReflectionFunction TypeError
4 weeks ago
|
|
|
use Illuminate\Auth\Middleware\RequirePassword;
|
|
|
|
|
use Illuminate\Console\Scheduling\Schedule;
|
|
|
|
|
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
|
|
|
|
|
use Illuminate\Cookie\Middleware\EncryptCookies;
|
|
|
|
|
use Illuminate\Foundation\Application;
|
|
|
|
|
use Illuminate\Foundation\Configuration\Exceptions;
|
|
|
|
|
use Illuminate\Foundation\Configuration\Middleware;
|
|
|
|
|
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
|
Upgrade to Laravel 13
- laravel/framework ^12.0 -> ^13.0
- spatie/laravel-backup ^9.2.9 -> ^10.0 (forced: 9.x pins
illuminate/notifications ^12.40, incompatible with L13)
- Drop psalm/plugin-laravel + vimeo/psalm (dev-only static analysis):
the only version chain compatible with L13's testbench-core needs
vimeo/psalm ^7.0.0-beta, which requires narrowing the project's
declared PHP floor (composer platform.php is pinned to 8.3.0 to
keep composer.lock installable on the oldest supported PHP patch;
the psalm 7 betas require specific 8.3.16+/8.4.3+/8.5.0+ floors).
Its CI workflow (.github/workflows/php-psalm.yml) was already
disabled (`on: []`, "too many errors"). Larastan/PHPStan remains
as the project's static analysis tool, unaffected.
- Rename VerifyCsrfToken/ValidateCsrfToken -> PreventRequestForgery
in bootstrap/app.php and config/sanctum.php (the L13 rename; old
classes remain as deprecated aliases but new code should reference
the new name), and validateCsrfTokens() -> preventRequestForgery()
in the middleware config.
Everything else (cache serializable_classes, cache/session/redis key
prefixes, upsert() uniqueBy, JobAttempted/QueueBusy event properties,
pagination view names, Manager::extend bindings, model-boot nested
instantiation) was checked against the app's actual code and found
to be either already handled, already using the new convention, or
not applicable to any pattern in this codebase.
All 715 tests pass (verified against a clean baseline with Redis
available locally via Docker); Pint and Larastan (the project's
configured `composer analyse` scope) are both clean.
2 weeks ago
|
|
|
use Illuminate\Foundation\Http\Middleware\PreventRequestForgery;
|
|
|
|
|
use Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance;
|
|
|
|
|
use Illuminate\Foundation\Http\Middleware\TrimStrings;
|
|
|
|
|
use Illuminate\Foundation\Http\Middleware\ValidatePostSize;
|
|
|
|
|
use Illuminate\Http\Client\ConnectionException;
|
|
|
|
|
use Illuminate\Http\Exceptions\HttpResponseException;
|
|
|
|
|
use Illuminate\Http\Middleware\HandleCors;
|
|
|
|
|
use Illuminate\Http\Middleware\SetCacheHeaders;
|
|
|
|
|
use Illuminate\Http\Middleware\TrustProxies;
|
|
|
|
|
use Illuminate\Http\Request;
|
|
|
|
|
use Illuminate\Routing\Middleware\SubstituteBindings;
|
|
|
|
|
use Illuminate\Routing\Middleware\ThrottleRequests;
|
|
|
|
|
use Illuminate\Routing\Middleware\ValidateSignature;
|
|
|
|
|
use Illuminate\Session\Middleware\AuthenticateSession;
|
|
|
|
|
use Illuminate\Session\Middleware\StartSession;
|
|
|
|
|
use Illuminate\Session\TokenMismatchException;
|
|
|
|
|
use Illuminate\Support\Facades\Auth;
|
|
|
|
|
use Illuminate\Support\Facades\Route;
|
|
|
|
|
use Illuminate\Validation\ValidationException;
|
|
|
|
|
use Illuminate\View\Middleware\ShareErrorsFromSession;
|
|
|
|
|
use Laravel\Passport\Http\Middleware\CheckToken;
|
|
|
|
|
use Laravel\Passport\Http\Middleware\CheckTokenForAnyScope;
|
|
|
|
|
use Laravel\Passport\Http\Middleware\CreateFreshApiToken;
|
|
|
|
|
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;
|
|
|
|
|
use League\OAuth2\Server\Exception\OAuthServerException;
|
|
|
|
|
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
|
|
|
|
|
|
|
|
|
|
return Application::configure(basePath: dirname(__DIR__))
|
|
|
|
|
->withRouting(
|
|
|
|
|
using: function () {
|
|
|
|
|
Route::middleware('web')
|
|
|
|
|
->group(base_path('routes/web-admin.php'));
|
|
|
|
|
|
|
|
|
|
Route::middleware('web')
|
|
|
|
|
->group(base_path('routes/web-portfolio.php'));
|
|
|
|
|
|
|
|
|
|
Route::middleware('web')
|
|
|
|
|
->group(base_path('routes/web-api.php'));
|
|
|
|
|
|
|
|
|
|
Route::middleware('web')
|
|
|
|
|
->group(base_path('routes/web.php'));
|
|
|
|
|
|
|
|
|
|
Route::middleware('api')
|
|
|
|
|
->group(base_path('routes/api.php'));
|
|
|
|
|
},
|
|
|
|
|
channels: __DIR__.'/../routes/channels.php',
|
|
|
|
|
commands: __DIR__.'/../routes/console.php',
|
|
|
|
|
)
|
|
|
|
|
->withMiddleware(function (Middleware $middleware) {
|
|
|
|
|
$middleware->use([
|
|
|
|
|
HandleCors::class,
|
|
|
|
|
PreventRequestsDuringMaintenance::class,
|
|
|
|
|
ValidatePostSize::class,
|
|
|
|
|
TrustProxies::class,
|
|
|
|
|
TrimStrings::class,
|
|
|
|
|
ConvertEmptyStringsToNull::class,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$middleware->group('web', [
|
|
|
|
|
EncryptCookies::class,
|
|
|
|
|
FrameGuard::class,
|
|
|
|
|
AddQueuedCookiesToResponse::class,
|
|
|
|
|
StartSession::class,
|
|
|
|
|
AuthenticateSession::class,
|
|
|
|
|
ShareErrorsFromSession::class,
|
Upgrade to Laravel 13
- laravel/framework ^12.0 -> ^13.0
- spatie/laravel-backup ^9.2.9 -> ^10.0 (forced: 9.x pins
illuminate/notifications ^12.40, incompatible with L13)
- Drop psalm/plugin-laravel + vimeo/psalm (dev-only static analysis):
the only version chain compatible with L13's testbench-core needs
vimeo/psalm ^7.0.0-beta, which requires narrowing the project's
declared PHP floor (composer platform.php is pinned to 8.3.0 to
keep composer.lock installable on the oldest supported PHP patch;
the psalm 7 betas require specific 8.3.16+/8.4.3+/8.5.0+ floors).
Its CI workflow (.github/workflows/php-psalm.yml) was already
disabled (`on: []`, "too many errors"). Larastan/PHPStan remains
as the project's static analysis tool, unaffected.
- Rename VerifyCsrfToken/ValidateCsrfToken -> PreventRequestForgery
in bootstrap/app.php and config/sanctum.php (the L13 rename; old
classes remain as deprecated aliases but new code should reference
the new name), and validateCsrfTokens() -> preventRequestForgery()
in the middleware config.
Everything else (cache serializable_classes, cache/session/redis key
prefixes, upsert() uniqueBy, JobAttempted/QueueBusy event properties,
pagination view names, Manager::extend bindings, model-boot nested
instantiation) was checked against the app's actual code and found
to be either already handled, already using the new convention, or
not applicable to any pattern in this codebase.
All 715 tests pass (verified against a clean baseline with Redis
available locally via Docker); Pint and Larastan (the project's
configured `composer analyse` scope) are both clean.
2 weeks ago
|
|
|
PreventRequestForgery::class,
|
|
|
|
|
SubstituteBindings::class,
|
|
|
|
|
CreateFreshApiToken::class,
|
|
|
|
|
'restricted',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$middleware->group('oauth-web', [
|
|
|
|
|
EncryptCookies::class,
|
|
|
|
|
FrameGuard::class,
|
|
|
|
|
AddQueuedCookiesToResponse::class,
|
|
|
|
|
StartSession::class,
|
|
|
|
|
ShareErrorsFromSession::class,
|
Upgrade to Laravel 13
- laravel/framework ^12.0 -> ^13.0
- spatie/laravel-backup ^9.2.9 -> ^10.0 (forced: 9.x pins
illuminate/notifications ^12.40, incompatible with L13)
- Drop psalm/plugin-laravel + vimeo/psalm (dev-only static analysis):
the only version chain compatible with L13's testbench-core needs
vimeo/psalm ^7.0.0-beta, which requires narrowing the project's
declared PHP floor (composer platform.php is pinned to 8.3.0 to
keep composer.lock installable on the oldest supported PHP patch;
the psalm 7 betas require specific 8.3.16+/8.4.3+/8.5.0+ floors).
Its CI workflow (.github/workflows/php-psalm.yml) was already
disabled (`on: []`, "too many errors"). Larastan/PHPStan remains
as the project's static analysis tool, unaffected.
- Rename VerifyCsrfToken/ValidateCsrfToken -> PreventRequestForgery
in bootstrap/app.php and config/sanctum.php (the L13 rename; old
classes remain as deprecated aliases but new code should reference
the new name), and validateCsrfTokens() -> preventRequestForgery()
in the middleware config.
Everything else (cache serializable_classes, cache/session/redis key
prefixes, upsert() uniqueBy, JobAttempted/QueueBusy event properties,
pagination view names, Manager::extend bindings, model-boot nested
instantiation) was checked against the app's actual code and found
to be either already handled, already using the new convention, or
not applicable to any pattern in this codebase.
All 715 tests pass (verified against a clean baseline with Redis
available locally via Docker); Pint and Larastan (the project's
configured `composer analyse` scope) are both clean.
2 weeks ago
|
|
|
PreventRequestForgery::class,
|
|
|
|
|
SubstituteBindings::class,
|
|
|
|
|
CreateFreshApiToken::class,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$middleware->group('api', [
|
|
|
|
|
EnsureFrontendRequestsAreStateful::class,
|
|
|
|
|
'throttle:api',
|
|
|
|
|
'bindings',
|
|
|
|
|
GrantFirstPartyToken::class,
|
|
|
|
|
]);
|
|
|
|
|
|
Upgrade to Laravel 13
- laravel/framework ^12.0 -> ^13.0
- spatie/laravel-backup ^9.2.9 -> ^10.0 (forced: 9.x pins
illuminate/notifications ^12.40, incompatible with L13)
- Drop psalm/plugin-laravel + vimeo/psalm (dev-only static analysis):
the only version chain compatible with L13's testbench-core needs
vimeo/psalm ^7.0.0-beta, which requires narrowing the project's
declared PHP floor (composer platform.php is pinned to 8.3.0 to
keep composer.lock installable on the oldest supported PHP patch;
the psalm 7 betas require specific 8.3.16+/8.4.3+/8.5.0+ floors).
Its CI workflow (.github/workflows/php-psalm.yml) was already
disabled (`on: []`, "too many errors"). Larastan/PHPStan remains
as the project's static analysis tool, unaffected.
- Rename VerifyCsrfToken/ValidateCsrfToken -> PreventRequestForgery
in bootstrap/app.php and config/sanctum.php (the L13 rename; old
classes remain as deprecated aliases but new code should reference
the new name), and validateCsrfTokens() -> preventRequestForgery()
in the middleware config.
Everything else (cache serializable_classes, cache/session/redis key
prefixes, upsert() uniqueBy, JobAttempted/QueueBusy event properties,
pagination view names, Manager::extend bindings, model-boot nested
instantiation) was checked against the app's actual code and found
to be either already handled, already using the new convention, or
not applicable to any pattern in this codebase.
All 715 tests pass (verified against a clean baseline with Redis
available locally via Docker); Pint and Larastan (the project's
configured `composer analyse` scope) are both clean.
2 weeks ago
|
|
|
$middleware->preventRequestForgery(except: [
|
|
|
|
|
'oauth/token',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$middleware->alias([
|
|
|
|
|
'api.admin' => ApiAdmin::class,
|
|
|
|
|
'admin' => Admin::class,
|
|
|
|
|
'auth' => Authenticate::class,
|
|
|
|
|
'auth.basic' => AuthenticateWithBasicAuth::class,
|
|
|
|
|
'bindings' => SubstituteBindings::class,
|
|
|
|
|
'cache.headers' => SetCacheHeaders::class,
|
|
|
|
|
'can' => Authorize::class,
|
feat: add critical path test suite and fix auth/config issues
Test Infrastructure:
- Modernize phpunit.xml (bootstrap, source block, Laravel 12 env vars)
- Configure tests/Pest.php with pest()->extend(TestCase::class)->in('Feature')
- Add docker-compose.test.yml (Redis for test suite)
- Add composer test/test:quick scripts
- Rename CACHE_DRIVER to CACHE_STORE across config (backwards compatible)
- Update .env.testing for in-memory SQLite + Docker Redis
Test Coverage (190 tests):
- CriticalRoutes: public routes, auth routes, API endpoints, middleware, schedule
- Auth/LoginTest: login, logout, rate limiting, redirect behavior
- Auth/RegisterTest: registration flow, validation, disabled registration
- Auth/PasswordResetTest: reset request, token validation, password update
- Auth/TwoFactorTest: 2FA checkpoint, setup behind password confirmation
- Auth/PasswordConfirmationTest: sudo mode flow via Laravel password.confirm
- Api/ScopeTest: scope enforcement, public endpoints, admin access
Bugs Fixed:
- Fix unauthenticated API returning 500 instead of 401 (AuthenticationException
not handled in custom exception renderer in bootstrap/app.php)
- Replace custom DangerZone middleware with Laravel password.confirm
- Add HasFactory trait to Profile model for test factories
Bugs Documented (known-bugs group):
- Registration crashes with str_ends_with TypeError (RegisterController:82)
- OAuth routes use legacy array syntax causing ReflectionFunction TypeError
4 weeks ago
|
|
|
'dangerzone' => RequirePassword::class,
|
|
|
|
|
'localization' => Localization::class,
|
|
|
|
|
'guest' => RedirectIfAuthenticated::class,
|
|
|
|
|
'signed' => ValidateSignature::class,
|
|
|
|
|
'throttle' => ThrottleRequests::class,
|
|
|
|
|
'interstitial' => AccountInterstitial::class,
|
|
|
|
|
'scopes' => CheckToken::class,
|
|
|
|
|
'scope' => CheckTokenForAnyScope::class,
|
|
|
|
|
'restricted' => RestrictedAccess::class,
|
|
|
|
|
]);
|
|
|
|
|
})
|
|
|
|
|
->withSchedule(function (Schedule $schedule) {
|
|
|
|
|
require __DIR__.'/scheduledtasks.php';
|
|
|
|
|
})
|
|
|
|
|
->withExceptions(function (Exceptions $exceptions) {
|
|
|
|
|
$exceptions->shouldRenderJsonWhen(
|
|
|
|
|
fn (Request $request) => $request->is('api/*') || $request->expectsJson(),
|
|
|
|
|
);
|
|
|
|
|
$exceptions->dontReport([
|
|
|
|
|
OAuthServerException::class,
|
|
|
|
|
ConnectionException::class,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$exceptions->dontFlash([
|
|
|
|
|
'password',
|
|
|
|
|
'password_confirmation',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$exceptions->reportable(function (BadMethodCallException $e) {
|
|
|
|
|
return app()->environment() !== 'production';
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$exceptions->reportable(function (ConnectionException $e) {
|
|
|
|
|
return app()->environment() !== 'production';
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// A login-flow form submitted from a tab whose CSRF token is stale
|
|
|
|
|
// (the session was regenerated by a login or a pending step elsewhere)
|
|
|
|
|
// lands on wherever the session actually is instead of a 419.
|
|
|
|
|
$exceptions->render(function (TokenMismatchException $e, Request $request) {
|
|
|
|
|
if ($request->wantsJson() || ! $request->is('login', 'login/*')) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Auth::check()) {
|
|
|
|
|
return redirect('/i/web');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($step = PendingLoginService::step($request)) {
|
|
|
|
|
return redirect()->route('login', ['step' => $step]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return redirect()->route('login')->withErrors([
|
|
|
|
|
'login' => __('Your sign-in session expired. Please sign in again.'),
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$exceptions->render(function (Throwable $e, $request) {
|
|
|
|
|
if ($request->wantsJson()) {
|
|
|
|
|
if ($e instanceof HttpResponseException) {
|
|
|
|
|
return $e->getResponse();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($e instanceof AuthenticationException) {
|
feat: add critical path test suite and fix auth/config issues
Test Infrastructure:
- Modernize phpunit.xml (bootstrap, source block, Laravel 12 env vars)
- Configure tests/Pest.php with pest()->extend(TestCase::class)->in('Feature')
- Add docker-compose.test.yml (Redis for test suite)
- Add composer test/test:quick scripts
- Rename CACHE_DRIVER to CACHE_STORE across config (backwards compatible)
- Update .env.testing for in-memory SQLite + Docker Redis
Test Coverage (190 tests):
- CriticalRoutes: public routes, auth routes, API endpoints, middleware, schedule
- Auth/LoginTest: login, logout, rate limiting, redirect behavior
- Auth/RegisterTest: registration flow, validation, disabled registration
- Auth/PasswordResetTest: reset request, token validation, password update
- Auth/TwoFactorTest: 2FA checkpoint, setup behind password confirmation
- Auth/PasswordConfirmationTest: sudo mode flow via Laravel password.confirm
- Api/ScopeTest: scope enforcement, public endpoints, admin access
Bugs Fixed:
- Fix unauthenticated API returning 500 instead of 401 (AuthenticationException
not handled in custom exception renderer in bootstrap/app.php)
- Replace custom DangerZone middleware with Laravel password.confirm
- Add HasFactory trait to Profile model for test factories
Bugs Documented (known-bugs group):
- Registration crashes with str_ends_with TypeError (RegisterController:82)
- OAuth routes use legacy array syntax causing ReflectionFunction TypeError
4 weeks ago
|
|
|
return response()->json(
|
|
|
|
|
['error' => $e->getMessage()],
|
|
|
|
|
401,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($e instanceof ValidationException) {
|
|
|
|
|
return response()->json([
|
|
|
|
|
'message' => $e->getMessage(),
|
|
|
|
|
'errors' => $e->validator->getMessageBag(),
|
|
|
|
|
], $e->status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$isHttp = $e instanceof HttpExceptionInterface;
|
|
|
|
|
|
|
|
|
|
return response()->json(
|
|
|
|
|
['error' => $e->getMessage()],
|
|
|
|
|
$isHttp ? $e->getStatusCode() : 500,
|
|
|
|
|
$isHttp ? $e->getHeaders() : [],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
->create();
|