From f6402cffc48c28a0c1d29774346595e8a115e200 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 24 Jan 2026 22:49:50 +0200 Subject: [PATCH] Add GitHub publish script and bump version to 0.9-rc2 --- CLAUDE.md | 13 ++-- README.md | 2 +- VERSION | 2 +- app/Filament/Jabali/Pages/Auth/Login.php | 77 +++++++++++++++++++----- bin/jabali-agent | 6 +- bin/publish-github | 50 +++++++++++++++ install.sh | 2 +- tests/Unit/PublishGithubScriptTest.php | 25 ++++++++ tests/Unit/VersionFileTest.php | 2 +- 9 files changed, 149 insertions(+), 30 deletions(-) create mode 100755 bin/publish-github create mode 100644 tests/Unit/PublishGithubScriptTest.php diff --git a/CLAUDE.md b/CLAUDE.md index ff628de..5a05162 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -59,22 +59,21 @@ php artisan route:cache # Cache routes **Important:** Only push to git when explicitly requested by the user. Do not auto-push after commits. -### Version & Build Numbers +### Version Numbers -**IMPORTANT:** Before every push, bump the BUILD number in the `VERSION` file: +**IMPORTANT:** Before every push, bump the `VERSION` in the `VERSION` file: ```bash # VERSION file format: -VERSION=1.0.3 -BUILD=005 +VERSION=0.9-rc -# Increment BUILD before pushing (e.g., 005 → 006) +# Bump before pushing: +# 0.9-rc → 0.9-rc1 → 0.9-rc2 → 0.9-rc3 → ... ``` | Field | When to Bump | Format | |-------|--------------|--------| -| `VERSION` | Major releases, new features | Semantic versioning (X.Y.Z) | -| `BUILD` | Every push | Zero-padded number (001, 002, etc.) | +| `VERSION` | Every push | `0.9-rc`, `0.9-rc1`, `0.9-rc2`, ... | ## Test Server diff --git a/README.md b/README.md index 18ec3c7..1af758e 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A modern web hosting control panel for WordPress and general PHP hosting. Built with Laravel 12, Filament v5, Livewire 4, and Tailwind CSS v4. -Version: 0.9-rc1 (release candidate) +Version: 0.9-rc2 (release candidate) This is a release candidate. Expect rapid iteration and breaking changes until 1.0. diff --git a/VERSION b/VERSION index 5661e51..96fd4ae 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -VERSION=0.9-rc1 +VERSION=0.9-rc2 diff --git a/app/Filament/Jabali/Pages/Auth/Login.php b/app/Filament/Jabali/Pages/Auth/Login.php index bffeb46..4dd3b6e 100644 --- a/app/Filament/Jabali/Pages/Auth/Login.php +++ b/app/Filament/Jabali/Pages/Auth/Login.php @@ -4,41 +4,86 @@ declare(strict_types=1); namespace App\Filament\Jabali\Pages\Auth; -use App\Models\User; +use DanHarrin\LivewireRateLimiting\Exceptions\TooManyRequestsException; use Filament\Auth\Http\Responses\Contracts\LoginResponse; +use Filament\Auth\MultiFactor\Contracts\HasBeforeChallengeHook; use Filament\Auth\Pages\Login as BaseLogin; use Filament\Facades\Filament; +use Filament\Models\Contracts\FilamentUser; +use Illuminate\Contracts\Auth\Guard; use Illuminate\Support\Facades\Auth; class Login extends BaseLogin { public function authenticate(): ?LoginResponse { + $panel = Filament::getPanel('jabali'); + Filament::setCurrentPanel($panel); + + try { + $this->rateLimit(5); + } catch (TooManyRequestsException $exception) { + $this->getRateLimitedNotification($exception)?->send(); + + return null; + } + $data = $this->form->getState(); - // Check credentials without logging in - $user = User::where('email', $data['email'])->first(); + /** @var Guard $authGuard */ + $authGuard = Auth::guard($panel->getAuthGuard()); + $authProvider = $authGuard->getProvider(); + $credentials = $this->getCredentialsFromFormData($data); - if ($user && \Hash::check($data['password'], $user->password)) { - // Check if 2FA is enabled - if ($user->two_factor_secret && $user->two_factor_confirmed_at) { - // Store user ID in session for 2FA challenge - session(['login.id' => $user->id]); - session(['login.remember' => $data['remember'] ?? false]); + $user = $authProvider->retrieveByCredentials($credentials); + + if ((! $user) || (! $authProvider->validateCredentials($user, $credentials))) { + $this->userUndertakingMultiFactorAuthentication = null; + + $this->fireFailedEvent($authGuard, $user, $credentials); + $this->throwFailureValidationException(); + } + + if ( + filled($this->userUndertakingMultiFactorAuthentication) && + (decrypt($this->userUndertakingMultiFactorAuthentication) === $user->getAuthIdentifier()) + ) { + $this->multiFactorChallengeForm->validate(); + } else { + foreach (Filament::getMultiFactorAuthenticationProviders() as $multiFactorAuthenticationProvider) { + if (! $multiFactorAuthenticationProvider->isEnabled($user)) { + continue; + } + + $this->userUndertakingMultiFactorAuthentication = encrypt($user->getAuthIdentifier()); + + if ($multiFactorAuthenticationProvider instanceof HasBeforeChallengeHook) { + $multiFactorAuthenticationProvider->beforeChallenge($user); + } + + break; + } + + if (filled($this->userUndertakingMultiFactorAuthentication)) { + $this->multiFactorChallengeForm->fill(); - // Redirect to 2FA challenge - $this->redirect(route('filament.jabali.auth.two-factor-challenge')); return null; } } - $response = parent::authenticate(); + if ($user instanceof FilamentUser && ! $user->canAccessPanel($panel)) { + $this->fireFailedEvent($authGuard, $user, $credentials); + $this->throwFailureValidationException(); + } + + $authGuard->login($user, $data['remember'] ?? false); + + session()->regenerate(); // If authentication successful, check if user is admin - $user = Filament::auth()->user(); + $user = $authGuard->user(); if ($user && $user->is_admin) { - // Log out from user panel guard - Filament::auth()->logout(); + $authGuard->logout(); // Redirect admins to admin panel using Livewire's redirect $this->redirect(route('filament.admin.pages.dashboard')); @@ -46,6 +91,6 @@ class Login extends BaseLogin return null; } - return $response; + return app(LoginResponse::class); } } diff --git a/bin/jabali-agent b/bin/jabali-agent index 53349d5..1d3d508 100755 --- a/bin/jabali-agent +++ b/bin/jabali-agent @@ -1092,7 +1092,7 @@ server { location ~ \.php$ { fastcgi_pass unix:SOCKET_PLACEHOLDER; - fastcgi_next_upstream error timeout invalid_header http_500 http_503 http_504; + fastcgi_next_upstream error timeout invalid_header http_500 http_503; fastcgi_next_upstream_tries 2; fastcgi_next_upstream_timeout 5s; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; @@ -6929,7 +6929,7 @@ server { location ~ \.php\$ { fastcgi_pass unix:/var/run/php/php8.4-fpm-{$username}.sock; - fastcgi_next_upstream error timeout invalid_header http_500 http_503 http_504; + fastcgi_next_upstream error timeout invalid_header http_500 http_503; fastcgi_next_upstream_tries 2; fastcgi_next_upstream_timeout 5s; fastcgi_index index.php; @@ -11714,7 +11714,7 @@ server { location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/var/run/php/php8.4-fpm-$username.sock; - fastcgi_next_upstream error timeout invalid_header http_500 http_503 http_504; + fastcgi_next_upstream error timeout invalid_header http_500 http_503; fastcgi_next_upstream_tries 2; fastcgi_next_upstream_timeout 5s; fastcgi_param SCRIPT_FILENAME \$realpath_root\$fastcgi_script_name; diff --git a/bin/publish-github b/bin/publish-github new file mode 100755 index 0000000..72a031d --- /dev/null +++ b/bin/publish-github @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +set -euo pipefail + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$repo_root" + +remote_name="github" +source_branch="main" +publish_branch="github-main" + +if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then + echo "Not a git repository." >&2 + exit 1 +fi + +if ! git remote get-url "$remote_name" >/dev/null 2>&1; then + echo "Remote '$remote_name' is not configured." >&2 + exit 1 +fi + +if ! git diff --quiet || ! git diff --cached --quiet; then + echo "Working tree is not clean. Commit or stash changes first." >&2 + exit 1 +fi + +original_branch="$(git rev-parse --abbrev-ref HEAD)" +if [[ "$original_branch" != "$source_branch" && "$original_branch" != "$publish_branch" ]]; then + echo "Switch to '$source_branch' or '$publish_branch' before publishing." >&2 + exit 1 +fi + +if git fetch "$remote_name" --quiet; then + current_version="$(grep -E '^VERSION=' VERSION | head -n1 | cut -d= -f2-)" + remote_version="$(git show "$remote_name/main:VERSION" 2>/dev/null | grep -E '^VERSION=' | head -n1 | cut -d= -f2- || true)" + + if [[ -n "$remote_version" && "$current_version" == "$remote_version" ]]; then + echo "VERSION unchanged vs GitHub ($current_version). Bump VERSION before pushing." >&2 + exit 1 + fi +fi + +git checkout -B "$publish_branch" "$source_branch" + +FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch --force --index-filter \ + "git rm --cached --ignore-unmatch CLAUDE.md" \ + --prune-empty --tag-name-filter cat -- "$publish_branch" + +git push "$remote_name" "$publish_branch:main" --force + +git checkout "$original_branch" diff --git a/install.sh b/install.sh index d3d8f87..8a13fcf 100755 --- a/install.sh +++ b/install.sh @@ -12,7 +12,7 @@ set -e # Version - will be read from VERSION file after clone, this is fallback -JABALI_VERSION="0.9-rc" +JABALI_VERSION="0.9-rc2" # Colors RED='\033[0;31m' diff --git a/tests/Unit/PublishGithubScriptTest.php b/tests/Unit/PublishGithubScriptTest.php new file mode 100644 index 0000000..38d2e18 --- /dev/null +++ b/tests/Unit/PublishGithubScriptTest.php @@ -0,0 +1,25 @@ +assertFileExists($scriptPath); + $this->assertTrue(is_executable($scriptPath)); + + $content = file_get_contents($scriptPath); + + $this->assertNotFalse($content); + $this->assertStringContainsString('CLAUDE.md', $content); + $this->assertStringContainsString('github-main', $content); + $this->assertStringContainsString('github', $content); + } +} diff --git a/tests/Unit/VersionFileTest.php b/tests/Unit/VersionFileTest.php index 9595f75..0529324 100644 --- a/tests/Unit/VersionFileTest.php +++ b/tests/Unit/VersionFileTest.php @@ -14,7 +14,7 @@ class VersionFileTest extends TestCase $content = file_get_contents($versionPath); $this->assertNotFalse($content); - $this->assertStringContainsString('VERSION=0.9-rc1', $content); + $this->assertStringContainsString('VERSION=0.9-rc2', $content); $this->assertStringNotContainsString('BUILD=', $content); } }