Commit graph

4906 commits

Author SHA1 Message Date
Andras Bacsai
eefc97fccc
feat: prioritize main/master branch selection (#7520) 2025-12-15 15:47:57 +01:00
Andras Bacsai
5e90fc6b8f Fix S3 credential whitespace issue with proper trimming
- Add model saving event to trim key/secret fields (encrypted casts)
- Add attribute mutators to trim endpoint, bucket, region fields
- Create migration to fix existing S3 storage records with whitespace
- Use chunking in migration to handle large datasets efficiently
- Verify re-encryption validity before committing changes

Fixes #7469 #7594

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-15 12:05:54 +01:00
Andras Bacsai
36d7844989 Fix deployment log view UX issues
- Prevent text selection from being cleared when logs are re-rendered during polling
- Preserve fullscreen state when toggling debug logs or other Livewire updates
- Fix log filtering to properly apply when debug mode is toggled

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-15 10:47:03 +01:00
Andras Bacsai
2a21b18998
Improve upgrade process UX with better progress visibility (#7609) 2025-12-13 22:37:37 +01:00
Andras Bacsai
918959b7f5 Remove unused ChangelogService import from Upgrade component 2025-12-13 22:26:31 +01:00
Andras Bacsai
20a9855c04 Address CodeRabbit review feedback
- Fix null-safe operator on currentTeam() call in Upgrade.php
- Add --rm flag to docker run in upgrade.sh for cleanup consistency
- Store beforeunload handler as named reference and clean up on success
- Add clarifying comments for upgrade method calls
- Add error state handling with close option in upgrade modal
- Add step mapping documentation comment in upgrade-progress component

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-13 21:42:19 +01:00
Andras Bacsai
dc12cbc6a0 Remove changelog loading logic from upgrade component 2025-12-13 21:14:00 +01:00
Andras Bacsai
deb9a7dab0 Refactor upgrade status to use Livewire instead of API endpoint
- Remove /api/upgrade-status endpoint and route
- Add getUpgradeStatus() method to Upgrade Livewire component
- Update frontend to call Livewire method via $wire.getUpgradeStatus()
- Simpler approach: no separate API, auth handled by Livewire

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-12 21:37:32 +01:00
Andras Bacsai
abbfd60f1c Add debug info to upgrade-status endpoint for troubleshooting
Temporary debug fields added to identify why status returns 'none'

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-12 21:30:41 +01:00
Andras Bacsai
f0d6ae289c Read upgrade status file via SSH from localhost server
The status file is on the host filesystem, not inside the container.
Use instant_remote_process() to read the file via SSH to Server::find(0).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-12 21:20:35 +01:00
Andras Bacsai
3cc416a806 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>
2025-12-12 21:16:36 +01:00
Andras Bacsai
dc9f612df4 Clean up status file after upgrade and reduce data exposure
- Delete status file 10 seconds after upgrade completes
- Reduce stale timeout from 30 to 10 minutes
- Remove timestamp from API response (internal detail)
- Treat timestamp parse failures as stale for security

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-12 21:14:31 +01:00
Andras Bacsai
b8cfc3f7c9 Add real-time upgrade progress tracking via status file
- upgrade.sh now writes status to /data/coolify/source/.upgrade-status
- New /api/upgrade-status endpoint reads status file for real progress
- Frontend polls status API instead of simulating progress
- Falls back to health check when service goes down during restart

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-12 21:11:32 +01:00
Andras Bacsai
a3bc59dae2
Fix Docker container race condition during upgrades (#7603) 2025-12-12 17:38:30 +01:00
Andras Bacsai
92326c09ea Improve upgrade process UX with better progress visibility
- Add step-by-step progress indicator (Preparing → Helper → Image → Restart)
- Display elapsed time during upgrade (MM:SS format)
- Show version transition in header (v4.0.0-beta.454 → v4.0.0-beta.456)
- Add expandable changelog preview before upgrading
- Reduce reload delay from 5s to 3s with countdown timer
- Add "Reload Now" button to skip countdown
- Improve status messages with step-specific descriptions
- Add success state with clear indication when upgrade completes
- Create new upgrade-progress component for visual step tracking

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-12 17:26:08 +01:00
Andras Bacsai
6a9027dcbf Add human-friendly output to upgrade script
- Show clear progress with numbered steps (1/6 through 6/6)
- Display header and footer banners
- Show individual image pull progress
- Show which containers are being stopped
- Display final success message with version and log location
- Keep detailed logging to file for debugging

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-12 15:18:57 +01:00
Andras Bacsai
ad013ca7da
Skip password confirmation for OAuth users (#7608) 2025-12-12 14:51:33 +01:00
Andras Bacsai
b0d50669b1 fix: skip password confirmation for OAuth users
OAuth users don't have passwords set, so they should not be prompted for password confirmation when performing destructive actions. This fix:
- Detects OAuth users via the hasPassword() method
- Skips password confirmation in modal for OAuth users
- Keeps text name confirmation as the final step
- Centralizes logic in helper functions for maintainability
- Changes button text to "Confirm" when password step is skipped

Fixes #4457

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-12 14:12:02 +01:00
Andras Bacsai
0e47de81d1 Fix: Prevent double deployments when multiple GitHub Apps access same repository (#2315)
Filter webhook-triggered deployments by source_id to ensure only applications
associated with the GitHub App that sent the webhook are deployed, preventing
duplicate deployments when the same repository is configured in multiple teams.
2025-12-12 11:35:00 +01:00
Andras Bacsai
546256b22c Fix: Allow test emails to be sent to any email address
Test emails should work with any recipient email address for verification purposes, not just team members. Added an isTestNotification flag to both Test notification classes and modified EmailChannel to skip team membership validation for test notifications.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-12 11:12:19 +01:00
Andras Bacsai
67b1db9254 feat: add Hetzner Cloud server linking for manually-added servers
Allow manually-added servers to be linked to Hetzner Cloud instances by
matching IP address. Once linked, servers gain power controls and status
monitoring.

Changes:
- Add getServers() and findServerByIp() methods to HetznerService
- Add Hetzner linking UI section to Server General page
- Add unit tests for new HetznerService methods

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-11 22:14:41 +01:00
Andras Bacsai
98b99cbb09
Fix read-only volume detection and add refresh capability (#7588) 2025-12-11 21:41:36 +01:00
Andras Bacsai
9bc33d65ab fix: Improve read-only volume detection and UI messaging
- Add isServiceResource() and shouldBeReadOnlyInUI() to LocalFileVolume
- Update path matching to handle leading slashes in volume comparisons
- Update FileStorage and Show components to use shouldBeReadOnlyInUI()
- Show consolidated warning message for service/compose resources in all.blade.php
- Remove redundant per-volume warnings for service resources
- Clean up configuration.blade.php formatting

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-11 21:25:33 +01:00
Andras Bacsai
475cfd78cd fix: Prevent N+1 query in LocalPersistentVolume.isDockerComposeResource()
Use relationLoaded() check before accessing the application relationship
to avoid triggering individual queries for each volume when rendering
storage lists. Update Storage.php to eager load the relationship.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-11 21:23:46 +01:00
Andras Bacsai
f152ec00ad fix: Detect read-only Docker volumes with long-form syntax and enable refresh
- Fixed isReadOnlyVolume() to detect both short-form (:ro) and long-form (read_only: true) Docker Compose volume syntax
- Fixed path matching to use mount_path only (fs_path is transformed during parsing from ./file to absolute path)
- Added "Load from server" button for read-only volumes to allow users to refresh content
- Changed loadStorageOnServer() authorization from 'update' to 'view' since loading is a read operation
- Added helper text to Content field warning users that content may be outdated
- Applied fixes to both LocalFileVolume and LocalPersistentVolume models

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 14:18:58 +01:00
Andras Bacsai
6ea563c6ac Fix: Prevent coolify-helper and coolify-realtime images from being pruned
Current version of infrastructure images (coolify-helper, coolify-realtime) are now protected from deletion during docker cleanup, regardless of which registry they're pulled from (ghcr.io, docker.io, or Docker Hub implicit). Old versions continue to be cleaned up as intended.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 13:38:52 +01:00
Andras Bacsai
5d38147899 feat(api): Improve OpenAPI spec and add rate limit handling for Hetzner
- Add 429 response with Retry-After header for Hetzner server creation
- Create RateLimitException for proper rate limit error handling
- Rename cloud_provider_token_id to cloud_provider_token_uuid with deprecation
- Fix prices array schema in server-types endpoint with proper items definition
- Add explicit default: true to autogenerate_domain properties
- Add timeout and retry options to Docker install curl commands
- Fix race condition in deployment status update using atomic query
2025-12-11 12:12:43 +01:00
Andras Bacsai
700550b26f
Fix: Concurrent builds ignored & add deployment queue limit (#7488) 2025-12-11 11:03:02 +01:00
Andras Bacsai
d019553809 Add Retry-After header to 429 rate limit responses
Adds Retry-After: 60 header to all deployment queue full responses,
helping webhook clients know when to retry their requests.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 11:02:29 +01:00
Andras Bacsai
4afc58cb53
perf: Remove dead server filtering code from Kernel scheduler (#7585) 2025-12-11 10:55:21 +01:00
Andras Bacsai
3962f1a5b9 perf: Remove dead server filtering code from Kernel scheduler
Remove unused server filtering logic in Kernel.php that was querying servers
but never using the results. Simplify Sentinel update checks in ServerManagerJob
by reusing the $isSentinelEnabled variable and removing unnecessary timezone
parameter for hourly cron execution.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 10:33:55 +01:00
Andras Bacsai
07153de68d
Fix deployment marked as failed after healthy container rolling update (#7583) 2025-12-11 10:01:00 +01:00
Andras Bacsai
a2e5b2d67d Fix deployment marked as failed when healthy container completes rolling update
Prevent deployment status from regressing to FAILED after it's marked as FINISHED by:
1. Calling completeDeployment() first in post_deployment() before any operations that could fail
2. Wrapping all post-deployment side effects in try-catch blocks
3. Adding FINISHED to terminal states that cannot be changed
4. Protecting ExecuteRemoteCommand from overwriting FINISHED status

This fixes the issue where a deployment with a healthy container and successful rolling update was still marked as Failed in the UI.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 09:42:02 +01:00
Andras Bacsai
18675c8a4d
Fix restart counter persistence and add crash loop example (#7582) 2025-12-11 09:40:56 +01:00
Andras Bacsai
9598562ca0
Fix deployment logs overlap with indicator (#7580) 2025-12-11 09:40:39 +01:00
Andras Bacsai
c6a89087c5 Refactor deployment indicator to use server-side route detection
Replace client-side JavaScript URL checking with Laravel's routeIs() for determining when to reduce indicator opacity. This simplifies the code and uses route names as the source of truth.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 09:39:56 +01:00
Andras Bacsai
01308dede5 Fix restart counter persistence and add crash loop example
- Move restart counter reset from Livewire to ApplicationDeploymentJob to prevent race conditions with GetContainersStatus
- Remove artificial restart_type=manual tracking (never used in codebase)
- Add Crash Loop Example in seeder for testing restart tracking UI

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 09:39:55 +01:00
Andras Bacsai
918dc788ce
Remove duplicate getArchDockerInstallCommand() method (#7581) 2025-12-11 09:31:43 +01:00
Andras Bacsai
206a9c03d2 Remove duplicate getArchDockerInstallCommand() method
The method was defined twice with the first (outdated) definition using
-Syyy and lacking proper flags. Keep the improved version that uses -Syu
with --needed for idempotency and proper systemctl ordering.
2025-12-11 09:25:35 +01:00
Andras Bacsai
56102f6321 Prevent multiple deploymentFinished event dispatches
Add flag to ensure event is only dispatched once, avoiding wasteful
duplicate dispatches during the race condition window before Livewire
removes wire:poll from the DOM.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 09:25:22 +01:00
Andras Bacsai
d9762e0310 Fix deployment log follow feature stopping mid-deployment
Removed auto-disable behaviors that caused follow logs to stop unexpectedly:
- Removed scroll detection that disabled following when user scrolled >50px from bottom
- Removed fullscreen exit handler that disabled following
- Removed ServiceChecked event listener that caused unnecessary flickers

Follow logs now only stops when:
- User explicitly clicks the Follow Logs button
- Deployment finishes (auto-scrolls to end first, then disables after 500ms delay)

Also improved get-logs component with memory optimizations:
- Limited display to last 2000 lines to prevent memory exhaustion
- Added debounced search (300ms) and scroll handling (150ms)
- Optimized DOM rendering

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-11 09:14:27 +01:00
Andras Bacsai
56394ba093 fix: return actual error message from token validation endpoint
- Return the specific error from validateProviderToken() instead of
  generic "Failed to validate token." message
- Update test to expect the actual error message

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-10 13:22:53 +01:00
Andras Bacsai
596b1cb76e refactor: extract token validation into reusable method
- Add validateProviderToken() helper method to reduce code duplication
- Use request body only ($request->json()->all()) to avoid route parameter conflicts
- Add proper logging for token validation failures
- Add missing DB import to migration file
- Minor test formatting fix

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-10 12:56:57 +01:00
Andras Bacsai
10003cec3d fix: add UUID support to CloudProviderToken model
- Add uuid column to cloud_provider_tokens table via migration
- Update CloudProviderToken to extend BaseModel for auto UUID generation
- Generate UUIDs for existing records in migration
- Fixes null uuid issue in API responses

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-10 08:59:13 +01:00
Andras Bacsai
ef0a1241b0 fix: rename validate() to validateToken() to avoid parent method conflict
The validate() method conflicted with Controller::validate(). Renamed to
validateToken() to resolve the declaration compatibility issue.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-10 08:57:04 +01:00
Andras Bacsai
62c394d3a1 feat: add Hetzner server provisioning API endpoints
Add complete API support for Hetzner server provisioning, matching UI functionality:

Cloud Provider Token Management:
- POST /api/v1/cloud-tokens - Create and validate tokens
- GET /api/v1/cloud-tokens - List all tokens
- GET /api/v1/cloud-tokens/{uuid} - Get specific token
- PATCH /api/v1/cloud-tokens/{uuid} - Update token name
- DELETE /api/v1/cloud-tokens/{uuid} - Delete token
- POST /api/v1/cloud-tokens/{uuid}/validate - Validate token

Hetzner Resource Discovery:
- GET /api/v1/hetzner/locations - List datacenters
- GET /api/v1/hetzner/server-types - List server types
- GET /api/v1/hetzner/images - List OS images
- GET /api/v1/hetzner/ssh-keys - List SSH keys

Server Provisioning:
- POST /api/v1/servers/hetzner - Create server with full options

Features:
- Token validation against provider APIs before storage
- Smart SSH key management with MD5 fingerprint deduplication
- IPv4/IPv6 network configuration with preference logic
- Cloud-init script support with YAML validation
- Team-based isolation and security
- Comprehensive test coverage (40+ test cases)
- Complete documentation with curl examples and Yaak collection

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-10 08:38:09 +01:00
Andras Bacsai
6e15d8e5f8
Add ValidProxyConfigFilename rule for dynamic proxy config validation (#7544) 2025-12-09 16:32:41 +01:00
Andras Bacsai
7c552e8a6a
Fix API response to return fqdn instead of non-existent domains attribute (#7546) 2025-12-09 16:29:02 +01:00
Andras Bacsai
32e047e512 Fix API response to return fqdn instead of non-existent domains attribute
The Application model stores domain as 'fqdn' not 'domains'. The API response
was incorrectly using data_get($application, 'domains') which always returned
null. Fixed all 5 application creation endpoint responses.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 16:26:08 +01:00
Andras Bacsai
5ec3f39b9b
Add autogenerate_domain API parameter for applications (#7515) 2025-12-09 16:19:49 +01:00