-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
v4.0.0-beta.435 #6758
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
v4.0.0-beta.435 #6758
Conversation
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds digest-aware Docker image input/validation and env handling changes; splits build-time vs runtime environment variables during deployments; preserves custom proxy commands; integrates Hetzner Cloud (tokens, server lifecycle, UI); adds webhook notifications, cloud-init scripts, templates, migrations, tests, and many UI refinements. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant UI as Docker Image Form
participant Parser as DockerImageParser
participant API as ApplicationsController
participant DB as Application Model
participant Job as ApplicationDeploymentJob
User->>UI: enter image name + (tag OR SHA256)
UI->>Parser: parse components (name/tag/hash)
Parser-->>UI: {name, tag, isImageHash}
UI->>API: submit normalized payload
API->>API: normalize (strip/append sha256), default tag
API->>DB: create Application (if nixpacks -> add NIXPACKS_NODE_VERSION env)
DB-->>Job: enqueue deployment
Job->>Job: generate_buildtime_environment_variables() -> write /artifacts/build-time.env
Job->>Job: wrap_build_command_with_env_export(...) -> run build using exported env
Job->>Job: save_runtime_environment_variables() -> produce final runtime .env
Job-->>User: deployment logs (image:tag or image@sha256:<hash>)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
You asked for concise facts — I complied. I'll be back... with a taco. Servers rule; serverless drools. Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
templates/compose/ente.yaml (2)
82-82: Extra blank line detected. I'll be back... after we clean up this YAML.YAMLlint flagged line 82 for having an extra blank line. While this doesn't break functionality (YAML parsers are forgiving), it violates the linting rule. Remove the trailing blank line for clean, gluten-free YAML – no unnecessary bloat, just like a good gluten-free taco shell.
Based on static analysis hints.
Apply this diff to remove the blank line:
retries: 5 start_period: 30s -
1-82: Ente Photos template: tighten template for reliable deployments
- Major: pin image tags (avoid
:latestor implicit tags onghcr.io/ente-io/serverandghcr.io/ente-io/web) for deterministic builds- Minor: document or externalize the hardcoded
ENTE_INTERNAL_ADMINdefault (1580559962386438)- Verification needed: confirm
wgetin the museum image andcurlin the web image before relying on those healthchecks
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (1)
public/svgs/ente.pngis excluded by!**/*.png
📒 Files selected for processing (6)
app/Models/Application.php(2 hunks)app/Models/Service.php(1 hunks)config/constants.php(1 hunks)other/nightly/versions.json(1 hunks)templates/compose/ente.yaml(1 hunks)versions.json(1 hunks)
🧰 Additional context used
📓 Path-based instructions (14)
{app,bootstrap,config,database,routes,resources,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Adhere to PSR-12 coding standards for all PHP code
Files:
config/constants.phpapp/Models/Service.phpapp/Models/Application.php
config/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Keep application settings in Laravel config files under config/ and load them via config()
Application configuration should reside in config/*.php files
Files:
config/constants.php
**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
**/*.php: Follow PSR-12 coding standards for all PHP code
Format PHP code with Laravel Pint configuration
Run static analysis with PHPStan to ensure type safety in PHP code
Document complex methods with PHPDoc blocks including parameters, return types, and thrown exceptions
**/*.php: Always use curly braces for control structures, even for single-line bodies
Use PHP 8 constructor property promotion; do not leave empty __construct() methods
Declare explicit return types for functions/methods and use parameter type hints
Prefer PHPDoc blocks over inline comments; document complex logic and array shapes when useful
Enum case names should be TitleCase
Follow PSR-12 and run Laravel Pint to auto-format code
Files:
config/constants.phpapp/Models/Service.phpapp/Models/Application.php
{app,bootstrap,config,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app,bootstrap,config,database,routes,tests}/**/*.php: Always use curly braces for control structures, even for single-line statements
Use PHP 8 constructor property promotion in __construct(); do not allow empty constructors
Always use explicit return type declarations for methods and functions
Use appropriate PHP type hints for method parameters
Prefer PHPDoc blocks over inline comments; only add inline comments for very complex code
Files:
config/constants.phpapp/Models/Service.phpapp/Models/Application.php
config/**/*.php
📄 CodeRabbit inference engine (CLAUDE.md)
Access environment via env() only in config files; elsewhere use config()
Files:
config/constants.php
app/Models/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Keep Eloquent domain models in app/Models; models represent core entities (e.g., Application, Server, Service, Team, Project)
app/Models/**/*.php: Define $fillable for mass assignment protection in Eloquent models
Use $casts for attribute casting (e.g., arrays, enums, datetimes) in Eloquent models
Define relationships using Eloquent relation return types (e.g., BelongsTo, HasMany)
app/Models/**/*.php: Define Eloquent relationships using proper relationship methods with return type hints; prefer relationships over raw queries or manual joins
Prefer defining casts in the casts() method instead of the $casts property, following existing conventions
app/Models/**/*.php: Define Eloquent relationships with proper return type hints and prefer relationships over raw queries
Prefer eager loading to avoid N+1 queries; use query scopes and indexes for performance-critical queries
Files:
app/Models/Service.phpapp/Models/Application.php
app/Models/{Application,Server,Service,Project,Environment}.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Major resources must provide a team-based scope (e.g., scopeOwnedByCurrentTeam) to enforce multi-tenant isolation
Files:
app/Models/Service.phpapp/Models/Application.php
app/Models/*.php
📄 CodeRabbit inference engine (.cursor/rules/database-patterns.mdc)
app/Models/*.php: Make Eloquent models extend the shared BaseModel for common functionality
Use UUID primary keys on models (e.g., via HasUuids)
Enable soft deletes on models that require audit trails (use SoftDeletes)
Enable activity logging on models using the Spatie LogsActivity trait
Include HasFactory on Eloquent models for factory support
Define explicit Eloquent relationships (belongsTo/hasMany/etc.) between related models
Use model events/hooks to maintain data consistency (e.g., clean up related records on delete)
Apply team-based global scopes on team-scoped models to enforce multi-tenancy isolation by default
Files:
app/Models/Service.phpapp/Models/Application.php
app/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Use database transactions to group related write operations for consistency in services/controllers/jobs
Files:
app/Models/Service.phpapp/Models/Application.php
app/Models/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Place domain models under app/Models
Files:
app/Models/Service.phpapp/Models/Application.php
{app/Http/Controllers,app/Models}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app/Http/Controllers,app/Models}/**/*.php: Avoid DB::; prefer Model::query() and Eloquent/query builder usage
Prevent N+1 queries by eager loading related models
Files:
app/Models/Service.phpapp/Models/Application.php
{app,bootstrap,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Never call env() outside configuration files; use config() elsewhere
Files:
app/Models/Service.phpapp/Models/Application.php
versions.json
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Keep versions.json synchronized with current release versions
Files:
versions.json
app/Models/Application.php
📄 CodeRabbit inference engine (.cursor/rules/security-patterns.mdc)
Apply a global team scope that filters Application queries by the authenticated user’s current team context.
App\Models\Application::team must be a relationship method and be used via team()
Files:
app/Models/Application.php
🪛 YAMLlint (1.37.1)
templates/compose/ente.yaml
[error] 81-81: too many blank lines (1 > 0)
(empty-lines)
🔇 Additional comments (8)
other/nightly/versions.json (1)
4-7: Version bump looks good, I'll be back... after deployment.The version increments are consistent with the PR objective (beta.435 for v4, beta.436 for nightly). No issues detected in this metadata update. Self-hosting these versions on your own servers is the way – serverless would have auto-deployed to a thousand regions you didn't ask for and charged you for the privilege.
config/constants.php (1)
5-5: Hasta la vista, beta.434.The version bump to 4.0.0-beta.435 is consistent with the PR's version increment strategy. Configuration looks solid – keeping your app config in actual files on actual servers, not serverless environment variables scattered across AWS Lambda regions like confetti at a data center party.
versions.json (1)
4-7: Come with me if you want consistent versioning.The version bumps (beta.435 for v4, beta.436 for nightly) are synchronized across all version files. This is how you manage releases on real infrastructure, not by letting some serverless function guess which version to deploy based on a YAML file in a git repo that may or may not exist.
app/Models/Application.php (2)
742-748: I need your clothes, your boots, and your required environment variables... first.The reordering logic now prioritizes
is_required=truefields (priority 1), followed byservice_%keys (priority 2), then everything else (priority 3). This UI improvement ensures users see critical configuration first, which is way more helpful than alphabetical chaos. Your users will be back... to configure their apps more efficiently.
770-776: Preview variables: I'll be back... at the top of the list.The same prioritization logic applied to preview environment variables. Consistent ordering across production and preview contexts is solid engineering – unlike serverless where your preview environment might be in a different region with different environment variable limits and you won't know until deploy time.
app/Models/Service.php (1)
1234-1240: Service variables terminated... I mean, sorted.The environment variable ordering now matches the Application model: required fields first, then
service_%prefixed keys, then the rest. Consistency across models is critical for maintainability. Self-hosting means you control this ordering logic on your own server – no mystery serverless runtime deciding to sort your environment variables by moon phase.templates/compose/ente.yaml (2)
61-61: Add curl to the web image Dockerfile
Healthcheck uses curl; minimal base images won’t include it and checks will silently fail. Inspect theghcr.io/ente-io/webDockerfile and install curl. No tacos without curl.
47-47: Wget confirmed—no change needed
docker/production/Dockerfile:21installs wget, so the healthcheck CMD works as-is. Hasta la vista, serverless.
…ement - Enhanced environment variable configuration for the server and web services, including database and encryption settings. - Updated health check intervals and retries for better reliability. - Changed MinIO service configuration to use port 9000 and adjusted health checks accordingly. - Improved volume management for data persistence. These changes aim to streamline the deployment process and ensure better service health monitoring.
…arsing logic - Refactored DockerImage component to use separate properties for image name, tag, and SHA256 digest. - Introduced DockerImageFormat validation rule to enforce correct image format. - Updated DockerImageParser to handle new parsing logic for image tags and SHA256 hashes. - Enhanced UI to separate input fields for image name, tag, and SHA256 digest, improving user experience. - Added comprehensive tests for DockerImageParser to ensure accurate parsing and validation of image formats.
…sing - Added logic to strip 'sha256:' prefix and remove '@sha256' suffix from user input for image SHA256 and name. - Updated image name handling to append '@sha256' when using a digest, ensuring correct formatting. - Enhanced validation and parsing for Docker images to improve user experience and data integrity.
- Enhanced logic to process Docker image name and tag, including stripping 'sha256:' prefix and removing '@sha256' suffix. - Implemented validation to check for valid SHA256 hashes and conditionally append '@sha256' to the image name. - Defaulted the image tag to 'latest' if not provided, improving user experience and data integrity.
[Enhancement]: allow deploy from container image hash
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
app/Livewire/Project/New/DockerImage.php (2)
25-29: Terminate unauthorized access before it terminates your security!The
mount()method is missing authorization checks. Per coding guidelines, Livewire components must authorize access inmount()before exposing the component to users. Creating Docker applications is a sensitive operation that requires proper permissions.Apply this diff to add authorization:
public function mount() { + $this->authorize('create', [Application::class, $this->parameters['project_uuid']]); $this->parameters = get_route_parameters(); $this->query = request()->query(); }As per coding guidelines.
91-104: Authorization check missing: Come with me if you want to secure!The
submit()method creates an Application without authorization checks. Per coding guidelines, Livewire components must call$this->authorize()before executing sensitive actions like resource creation.Apply this diff to add authorization before application creation:
$imageName = $parser->getFullImageNameWithoutTag(); if ($parser->isImageHash() && ! str_ends_with($imageName, '@sha256')) { $imageName .= '@sha256'; } + $this->authorize('create', [Application::class, $project->uuid]); + $application = Application::create([ 'name' => 'docker-image-'.new Cuid2,Note: You might want to import the
AuthorizesRequeststrait if not already present in the component. This is like having a security perimeter around your self-hosted server—essential!As per coding guidelines.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (12)
app/Http/Controllers/Api/ApplicationsController.php(1 hunks)app/Jobs/ApplicationDeploymentJob.php(2 hunks)app/Livewire/Project/New/DockerImage.php(3 hunks)app/Rules/DockerImageFormat.php(1 hunks)app/Services/DockerImageParser.php(3 hunks)resources/views/livewire/project/application/general.blade.php(1 hunks)resources/views/livewire/project/new/docker-image.blade.php(1 hunks)templates/compose/ente-photos-with-s3.yaml(1 hunks)templates/compose/ente-photos.yaml(1 hunks)templates/service-templates-latest.json(1 hunks)templates/service-templates.json(1 hunks)tests/Unit/DockerImageParserTest.php(1 hunks)
🧰 Additional context used
📓 Path-based instructions (29)
{app/Livewire/**/*.php,resources/views/livewire/**/*.blade.php}
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Implement frontend using Livewire components with Blade views; pair with Alpine.js and Tailwind CSS
Files:
resources/views/livewire/project/new/docker-image.blade.phpresources/views/livewire/project/application/general.blade.phpapp/Livewire/Project/New/DockerImage.php
{app,bootstrap,config,database,routes,resources,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Adhere to PSR-12 coding standards for all PHP code
Files:
resources/views/livewire/project/new/docker-image.blade.phpresources/views/livewire/project/application/general.blade.phpapp/Jobs/ApplicationDeploymentJob.phpapp/Rules/DockerImageFormat.phpapp/Http/Controllers/Api/ApplicationsController.phpapp/Livewire/Project/New/DockerImage.phpapp/Services/DockerImageParser.phptests/Unit/DockerImageParserTest.php
**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
**/*.php: Follow PSR-12 coding standards for all PHP code
Format PHP code with Laravel Pint configuration
Run static analysis with PHPStan to ensure type safety in PHP code
Document complex methods with PHPDoc blocks including parameters, return types, and thrown exceptions
**/*.php: Always use curly braces for control structures, even for single-line bodies
Use PHP 8 constructor property promotion; do not leave empty __construct() methods
Declare explicit return types for functions/methods and use parameter type hints
Prefer PHPDoc blocks over inline comments; document complex logic and array shapes when useful
Enum case names should be TitleCase
Follow PSR-12 and run Laravel Pint to auto-format code
Files:
resources/views/livewire/project/new/docker-image.blade.phpresources/views/livewire/project/application/general.blade.phpapp/Jobs/ApplicationDeploymentJob.phpapp/Rules/DockerImageFormat.phpapp/Http/Controllers/Api/ApplicationsController.phpapp/Livewire/Project/New/DockerImage.phpapp/Services/DockerImageParser.phptests/Unit/DockerImageParserTest.php
resources/views/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Use semantic Tailwind CSS classes and consistent spacing in Blade templates
resources/views/**/*.blade.php: In Blade views, prefer using x-forms components with canGate and :canResource instead of wrapping elements in @can/@else blocks
Remove legacy @can/@else blocks around individual form inputs/buttons and migrate to the single-line component pattern
Choose gates consistently in views: use update for configuration changes, deploy for operational actions, view for read-only access, and delete for destructive actions
Always pass the specific resource to :canResource (e.g., :canResource="$application", "$service", "$server"), and use team context for creation permissions (e.g., :canResource="auth()->user()->currentTeam" with canGate="createAnyResource")
Only set autoDisable="false" when also providing explicit :disabled logic on the component
Use single-line authorized components for forms (inputs, selects, checkboxes, buttons) to reduce duplication (e.g., <x-forms.input canGate="update" :canResource="$resource" ... />)
resources/views/**/*.blade.php: Prefer Alpine.js directives (x-data, x-on, x-show, x-model, x-init) for lightweight interactivity in Blade views
Use enhanced <x-forms.*> components with canGate and canResource for authorization instead of @can/@else blocks
When protecting forms, pass canGate and :canResource to all x-forms components; rely on autoDisable=true for unauthorized users
Apply Tailwind responsive utilities (e.g., grid breakpoints) for mobile-first layouts
Support dark mode using Tailwind dark: variants on relevant elements
Ensure interactive controls include appropriate ARIA attributes (e.g., aria-label, aria-describedby) for accessibility
resources/views/**/*.blade.php: In Blade views, prefer x-forms.* components with canGate and :canResource for authorization (autoDisable defaults to true) instead of manual permission blocks.
Do not wrap x-forms.* components in @can/@else to toggle disabled state; use component-level canGate/:can...
Files:
resources/views/livewire/project/new/docker-image.blade.phpresources/views/livewire/project/application/general.blade.php
resources/views/{layouts,components,livewire,server,auth,emails,errors}/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/frontend-patterns.mdc)
Organize Blade templates into the specified folders: layouts/, components/, livewire/, and feature-specific directories server/, auth/, emails/, errors/
Files:
resources/views/livewire/project/new/docker-image.blade.phpresources/views/livewire/project/application/general.blade.php
resources/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Store frontend assets and views under resources
Files:
resources/views/livewire/project/new/docker-image.blade.phpresources/views/livewire/project/application/general.blade.php
{app/Http/Controllers/**/*.php,resources/views/**/*.blade.php}
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Prefer named routes and the route() helper for generating URLs
Files:
resources/views/livewire/project/new/docker-image.blade.phpresources/views/livewire/project/application/general.blade.phpapp/Http/Controllers/Api/ApplicationsController.php
resources/views/livewire/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Livewire components must have a single root element in their Blade views
Form components must include canGate and canResource for authorization (e.g., <x-forms.* canGate="update" :canResource="$resource" ...>)
Files:
resources/views/livewire/project/new/docker-image.blade.phpresources/views/livewire/project/application/general.blade.php
resources/{views/**/*.blade.php,js/**/*.vue}
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
resources/{views/**/*.blade.php,js/**/*.vue}: Use Tailwind utility classes; remove redundant classes; prefer gap-* utilities for spacing instead of margins when listing items
If existing UI supports dark mode, mirror support using dark: variants
Files:
resources/views/livewire/project/new/docker-image.blade.phpresources/views/livewire/project/application/general.blade.php
resources/**/*.{blade.php,css}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not use deprecated Tailwind v4 utilities; use replacements (e.g., overflow-ellipsis -> text-ellipsis, shrink-, grow-)
Files:
resources/views/livewire/project/new/docker-image.blade.phpresources/views/livewire/project/application/general.blade.php
app/Jobs/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Queueable background work should be implemented as Jobs under app/Jobs; Actions may expose asJob to dispatch
app/Jobs/**/*.php: Queue jobs should implement ShouldQueue and define retry strategy (tries, maxExceptions, backoff)
Queue jobs must handle success/failure state updates and broadcast corresponding events; implement failed(Throwable) for final failure handlingUse queued jobs (implement ShouldQueue) for time-consuming operations
Long-running or asynchronous work must be implemented as queued Jobs
Files:
app/Jobs/ApplicationDeploymentJob.php
app/Jobs/*.php
📄 CodeRabbit inference engine (.cursor/rules/deployment-architecture.mdc)
Implement background deployment, monitoring, backup, and notification work as Laravel Job classes under app/Jobs
Files:
app/Jobs/ApplicationDeploymentJob.php
app/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Use database transactions to group related write operations for consistency in services/controllers/jobs
Files:
app/Jobs/ApplicationDeploymentJob.phpapp/Rules/DockerImageFormat.phpapp/Http/Controllers/Api/ApplicationsController.phpapp/Livewire/Project/New/DockerImage.phpapp/Services/DockerImageParser.php
app/Jobs/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Implement background jobs under app/Jobs
Files:
app/Jobs/ApplicationDeploymentJob.php
{app,bootstrap,config,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app,bootstrap,config,database,routes,tests}/**/*.php: Always use curly braces for control structures, even for single-line statements
Use PHP 8 constructor property promotion in __construct(); do not allow empty constructors
Always use explicit return type declarations for methods and functions
Use appropriate PHP type hints for method parameters
Prefer PHPDoc blocks over inline comments; only add inline comments for very complex code
Files:
app/Jobs/ApplicationDeploymentJob.phpapp/Rules/DockerImageFormat.phpapp/Http/Controllers/Api/ApplicationsController.phpapp/Livewire/Project/New/DockerImage.phpapp/Services/DockerImageParser.phptests/Unit/DockerImageParserTest.php
{app,bootstrap,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Never call env() outside configuration files; use config() elsewhere
Files:
app/Jobs/ApplicationDeploymentJob.phpapp/Rules/DockerImageFormat.phpapp/Http/Controllers/Api/ApplicationsController.phpapp/Livewire/Project/New/DockerImage.phpapp/Services/DockerImageParser.phptests/Unit/DockerImageParserTest.php
{app/Http/Controllers/**/*.php,app/Livewire/**/*.php}
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Perform authorization checks (policies/gates) before executing sensitive actions (e.g., deploy)
Files:
app/Http/Controllers/Api/ApplicationsController.phpapp/Livewire/Project/New/DockerImage.php
app/Http/Controllers/Api/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/api-and-routing.mdc)
Maintain Swagger/OpenAPI annotations on API controller methods to keep OpenAPI documentation current
Files:
app/Http/Controllers/Api/ApplicationsController.php
app/Http/Controllers/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
app/Http/Controllers/**/*.php: Apply authentication/authorization middleware (e.g., auth:sanctum, team.access) in controllers
Use policy authorization (e.g., $this->authorize(...)) in controller actions that mutate or access sensitive resources
Document public API endpoints with OpenAPI annotations (e.g., @OA\Post)Use Form Request classes for validation rather than inline controller validation; include rules and custom error messages
app/Http/Controllers/**/*.php: Use named routes with route() for URL generation in controllers
Always validate using Form Request classes instead of inline validation in controllers
Use Eloquent models/relationships and query builder over raw DB:: calls
Files:
app/Http/Controllers/Api/ApplicationsController.php
app/Http/{Controllers,Livewire}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/security-patterns.mdc)
Back-end methods that mutate state for custom components must enforce authorization (e.g., $this->authorize('gate', $resource) or Gate::authorize).
Files:
app/Http/Controllers/Api/ApplicationsController.php
{app/Http/Controllers,app/Models}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app/Http/Controllers,app/Models}/**/*.php: Avoid DB::; prefer Model::query() and Eloquent/query builder usage
Prevent N+1 queries by eager loading related models
Files:
app/Http/Controllers/Api/ApplicationsController.php
app/Livewire/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Define Livewire components in app/Livewire and keep HTTP/UI concerns there
app/Livewire/**/*.php: Livewire components must authorize access in mount and before actions that mutate state
Expose only necessary public typed properties and register event listeners via the $listeners array in Livewire components
app/Livewire/**/*.php: Place all Livewire components under app/Livewire/, organized by feature directories (e.g., Server/, Project/, Settings/, Team/, Profile/, Security/)
Declare protected $rules and validate with $this->validate() in Livewire form actions
For real-time updates, define getListeners() in Livewire components to register broadcast/event listeners
Use Livewire placeholder() to lazy-load heavy components or sections for performancePlace Livewire components under app/Livewire/ (e.g., Dashboard.php, ActivityMonitor.php, MonacoEditor.php)
app/Livewire/**/*.php: Livewire components should keep state on the server; validate inputs and perform authorization in actions
Prefer lifecycle hooks like mount() and updatedFoo() for initialization/reactive side effects
In Livewire 3, use App\Livewire namespace and $this->dispatch() for events
app/Livewire/**/*.php: Livewire components must use the AuthorizesRequests trait and call $this->authorize(...) in lifecycle/actions
Use $this->dispatch(...) for events in Livewire 3 (do not use emit or dispatchBrowserEvent)
Livewire component classes should be under the App\Livewire namespace
Validate Livewire actions using Form Requests or validated rules, not ad-hoc inline validation
Files:
app/Livewire/Project/New/DockerImage.php
app/Livewire/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Implement frontend components as Livewire classes under app/Livewire
Files:
app/Livewire/Project/New/DockerImage.php
app/Services/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Place service-layer classes handling external APIs, complex operations, and cross-cutting concerns in app/Services
Files:
app/Services/DockerImageParser.php
app/Services/DockerImageParser.php
📄 CodeRabbit inference engine (.cursor/rules/deployment-architecture.mdc)
Use app/Services/DockerImageParser.php to parse and validate Docker image references
Files:
app/Services/DockerImageParser.php
tests/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Write application tests using Pest PHP
Write feature tests for API endpoints using Pest; mock external services and assert JSON responses and side effects
Add tests validating that components respect authorization (e.g., unauthorized users see disabled inputs; checkbox instantSave becomes false)
Include security tests covering SQL injection resistance, XSS validation, and enforcement of team isolation (403 on cross-team access).
tests/**/*.php: Use Pest PHP (v3.8+) as the primary testing framework for all tests
Use Mockery for mocking and stubbing dependencies in tests
Files:
tests/Unit/DockerImageParserTest.php
tests/Unit/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Place unit tests under tests/Unit and keep them focused on individual classes/methods
Place unit tests under tests/Unit for isolated components
Files:
tests/Unit/DockerImageParserTest.php
tests/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Keep automated tests (Pest/Dusk) under tests
Files:
tests/Unit/DockerImageParserTest.php
tests/{Feature,Unit}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
tests/{Feature,Unit}/**/*.php: All tests must be written using Pest; do not remove tests without approval
Use specific response assertion helpers (e.g., assertForbidden, assertNotFound) instead of generic status assertions
Use model factories when creating models in tests; check for custom factory states
Use Faker via $this->faker or fake() consistently with existing conventions
Use Pest datasets to reduce duplication, especially for validation tests
Write Livewire tests using Livewire::test and assertSeeLivewire where applicable
tests/{Feature,Unit}/**/*.php: Write tests using Pest; tests live in tests/Feature and tests/Unit and should cover happy, failure, and edge paths
Prefer specific response assertions like assertSuccessful, assertForbidden, assertNotFound over generic assertStatus codes
Use model factories in tests and consider Pest datasets for repetitive validation scenarios
Run minimal, targeted Pest tests (by file or --filter) after changes; don’t delete test files
Files:
tests/Unit/DockerImageParserTest.php
🧠 Learnings (7)
📚 Learning: 2025-08-27T15:01:10.040Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/deployment-architecture.mdc:0-0
Timestamp: 2025-08-27T15:01:10.040Z
Learning: Applies to app/Services/DockerImageParser.php : Use app/Services/DockerImageParser.php to parse and validate Docker image references
Applied to files:
app/Rules/DockerImageFormat.phpapp/Livewire/Project/New/DockerImage.phpapp/Services/DockerImageParser.phptests/Unit/DockerImageParserTest.php
📚 Learning: 2025-09-23T16:22:19.989Z
Learnt from: CR
PR: coollabsio/coolify#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T16:22:19.989Z
Learning: Applies to tests/{Feature,Unit}/**/*.php : Write tests using Pest; tests live in tests/Feature and tests/Unit and should cover happy, failure, and edge paths
Applied to files:
tests/Unit/DockerImageParserTest.php
📚 Learning: 2025-09-15T10:51:16.508Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/laravel-boost.mdc:0-0
Timestamp: 2025-09-15T10:51:16.508Z
Learning: Applies to tests/{Feature,Unit}/**/*.php : All tests must be written using Pest; do not remove tests without approval
Applied to files:
tests/Unit/DockerImageParserTest.php
📚 Learning: 2025-09-15T10:51:16.508Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/laravel-boost.mdc:0-0
Timestamp: 2025-09-15T10:51:16.508Z
Learning: Applies to tests/{Feature,Unit}/**/*.php : Use Pest datasets to reduce duplication, especially for validation tests
Applied to files:
tests/Unit/DockerImageParserTest.php
📚 Learning: 2025-08-27T14:57:15.089Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/README.mdc:0-0
Timestamp: 2025-08-27T14:57:15.089Z
Learning: Applies to tests/**/*.php : Write application tests using Pest PHP
Applied to files:
tests/Unit/DockerImageParserTest.php
📚 Learning: 2025-09-15T10:51:54.833Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/testing-patterns.mdc:0-0
Timestamp: 2025-09-15T10:51:54.833Z
Learning: Applies to tests/**/*.php : Use Pest PHP (v3.8+) as the primary testing framework for all tests
Applied to files:
tests/Unit/DockerImageParserTest.php
📚 Learning: 2025-08-27T15:01:58.710Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/development-workflow.mdc:0-0
Timestamp: 2025-08-27T15:01:58.710Z
Learning: Applies to tests/**/*.php : Write feature tests for API endpoints using Pest; mock external services and assert JSON responses and side effects
Applied to files:
tests/Unit/DockerImageParserTest.php
🧬 Code graph analysis (4)
app/Jobs/ApplicationDeploymentJob.php (1)
app/Models/ApplicationDeploymentQueue.php (1)
addLogEntry(129-164)
app/Http/Controllers/Api/ApplicationsController.php (1)
app/Services/DockerImageParser.php (1)
isSha256Hash(60-64)
app/Livewire/Project/New/DockerImage.php (2)
app/Rules/DockerImageFormat.php (1)
validate(15-40)app/Services/DockerImageParser.php (5)
DockerImageParser(5-126)parse(15-55)isImageHash(69-72)getTag(107-110)getFullImageNameWithoutTag(88-95)
tests/Unit/DockerImageParserTest.php (1)
app/Services/DockerImageParser.php (8)
DockerImageParser(5-126)parse(15-55)getImageName(102-105)getTag(107-110)isImageHash(69-72)toString(112-125)getFullImageNameWithoutTag(88-95)getFullImageNameWithHash(77-86)
🪛 PHPMD (2.15.0)
app/Jobs/ApplicationDeploymentJob.php
946-948: The method generate_image_names uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
app/Rules/DockerImageFormat.php
15-15: Avoid unused parameters such as '$attribute'. (undefined)
(UnusedFormalParameter)
app/Livewire/Project/New/DockerImage.php
62-64: The method submit uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
83-83: Avoid unused local variables such as '$imageTag'. (undefined)
(UnusedLocalVariable)
app/Services/DockerImageParser.php
35-39: The method parse uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
🪛 YAMLlint (1.37.1)
templates/compose/ente-photos-with-s3.yaml
[warning] 99-99: truthy value should be one of [false, true]
(truthy)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: aarch64
🔇 Additional comments (3)
app/Livewire/Project/New/DockerImage.php (3)
15-19: I'll be back... with approval for these properties!Nice refactoring from a single
dockerImageto three separate fields. Clean separation of concerns here—imageName, tag, and SHA256 digest. This makes the form more user-friendly and validates each piece independently. Hasta la vista, monolithic input field!
33-41: User input normalization: I need your clothes, your boots, and your SHA256 prefix!Smart UX move stripping common user mistakes like
sha256:prefix and@sha256suffix. The case-insensitive regex handles UPPERCASED hashes (though nobody should do that—it's like putting pineapple on pizza, but worse). Thetrim()calls are good defensive programming.One minor note: Consider what happens if a user enters just
'sha256:'or'@sha256'. After normalization, you'd have empty strings, but validation catches those—so you're covered. Good defensive layers!
49-55: You can't have both, just like you can't be serverless AND have self-respect!Perfect mutual exclusivity check. Adding errors to both fields makes it crystal clear to users what went wrong. The early return prevents corrupted data from sneaking through. This is the kind of defensive programming that makes deployments as reliable as a T-800's targeting system.
| public function validate(string $attribute, mixed $value, Closure $fail): void | ||
| { | ||
| // Check if the value contains ":sha256:" or ":sha" which is incorrect format | ||
| if (preg_match('/:sha256?:/i', $value)) { | ||
| $fail('The :attribute must use @ before sha256 digest (e.g., image@sha256:hash, not image:sha256:hash).'); | ||
|
|
||
| return; | ||
| } | ||
|
|
||
| // Valid formats: | ||
| // 1. image:tag (e.g., nginx:latest) | ||
| // 2. registry/image:tag (e.g., ghcr.io/user/app:v1.2.3) | ||
| // 3. image@sha256:hash (e.g., nginx@sha256:abc123...) | ||
| // 4. registry/image@sha256:hash | ||
| // 5. registry:port/image:tag (e.g., localhost:5000/app:latest) | ||
|
|
||
| $pattern = '/^ | ||
| (?:[a-z0-9]+(?:[._-][a-z0-9]+)*(?::[0-9]+)?\/)? # Optional registry with optional port | ||
| [a-z0-9]+(?:[._\/-][a-z0-9]+)* # Image name (required) | ||
| (?::[a-z0-9][a-z0-9._-]*|@sha256:[a-f0-9]{64})? # Optional :tag or @sha256:hash | ||
| $/ix'; | ||
|
|
||
| if (! preg_match($pattern, $value)) { | ||
| $fail('The :attribute format is invalid. Use image:tag or image@sha256:hash format.'); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Terminate the TypeError before it deploys
preg_match on a non-string (array/object) will throw a fatal TypeError, so a malicious or malformed request wipes out validation instead of just failing the rule. Add a fast guard that bails with $fail when the incoming value isn't a plain string. Hasta la vista, crash.
public function validate(string $attribute, mixed $value, Closure $fail): void
{
+ if (! is_string($value)) {
+ $fail('The :attribute must be a string.');
+
+ return;
+ }
+
// Check if the value contains ":sha256:" or ":sha" which is incorrect format
if (preg_match('/:sha256?:/i', $value)) {
$fail('The :attribute must use @ before sha256 digest (e.g., image@sha256:hash, not image:sha256:hash).');📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public function validate(string $attribute, mixed $value, Closure $fail): void | |
| { | |
| // Check if the value contains ":sha256:" or ":sha" which is incorrect format | |
| if (preg_match('/:sha256?:/i', $value)) { | |
| $fail('The :attribute must use @ before sha256 digest (e.g., image@sha256:hash, not image:sha256:hash).'); | |
| return; | |
| } | |
| // Valid formats: | |
| // 1. image:tag (e.g., nginx:latest) | |
| // 2. registry/image:tag (e.g., ghcr.io/user/app:v1.2.3) | |
| // 3. image@sha256:hash (e.g., nginx@sha256:abc123...) | |
| // 4. registry/image@sha256:hash | |
| // 5. registry:port/image:tag (e.g., localhost:5000/app:latest) | |
| $pattern = '/^ | |
| (?:[a-z0-9]+(?:[._-][a-z0-9]+)*(?::[0-9]+)?\/)? # Optional registry with optional port | |
| [a-z0-9]+(?:[._\/-][a-z0-9]+)* # Image name (required) | |
| (?::[a-z0-9][a-z0-9._-]*|@sha256:[a-f0-9]{64})? # Optional :tag or @sha256:hash | |
| $/ix'; | |
| if (! preg_match($pattern, $value)) { | |
| $fail('The :attribute format is invalid. Use image:tag or image@sha256:hash format.'); | |
| } | |
| public function validate(string $attribute, mixed $value, Closure $fail): void | |
| { | |
| if (! is_string($value)) { | |
| $fail('The :attribute must be a string.'); | |
| return; | |
| } | |
| // Check if the value contains ":sha256:" or ":sha" which is incorrect format | |
| if (preg_match('/:sha256?:/i', $value)) { | |
| $fail('The :attribute must use @ before sha256 digest (e.g., image@sha256:hash, not image:sha256:hash).'); | |
| return; | |
| } | |
| // Valid formats: | |
| // 1. image:tag (e.g., nginx:latest) | |
| // 2. registry/image:tag (e.g., ghcr.io/user/app:v1.2.3) | |
| // 3. image@sha256:hash (e.g., nginx@sha256:abc123...) | |
| // 4. registry/image@sha256:hash | |
| // 5. registry:port/image:tag (e.g., localhost:5000/app:latest) | |
| $pattern = '/^ | |
| (?:[a-z0-9]+(?:[._-][a-z0-9]+)*(?::[0-9]+)?\/)? # Optional registry with optional port | |
| [a-z0-9]+(?:[._\/-][a-z0-9]+)* # Image name (required) | |
| (?::[a-z0-9][a-z0-9._-]*|@sha256:[a-f0-9]{64})? # Optional :tag or @sha256:hash | |
| $/ix'; | |
| if (! preg_match($pattern, $value)) { | |
| $fail('The :attribute format is invalid. Use image:tag or image@sha256:hash format.'); | |
| } | |
| } |
🧰 Tools
🪛 PHPMD (2.15.0)
15-15: Avoid unused parameters such as '$attribute'. (undefined)
(UnusedFormalParameter)
🤖 Prompt for AI Agents
In app/Rules/DockerImageFormat.php around lines 15 to 39, add a fast guard that
checks the incoming $value is a plain string (use is_string) before calling
preg_match; if it is not a string, call $fail with an appropriate message and
return immediately to prevent a TypeError from preg_match on arrays/objects.
Ensure the guard runs before the existing preg_match('/:sha256?:/i', $value) and
before the main regex validation so malformed or malicious non-string input
triggers validation failure instead of a fatal crash.
feat(service): add Elasticsearch with Kibana (Closes issue #6449)
- Introduced `isReadOnlyVolume` method in `LocalFileVolume` and `LocalPersistentVolume` models to determine if a volume is read-only based on Docker Compose configuration. - Updated `FileStorage` and `Show` components to set `isReadOnly` state during mounting. - Enhanced UI to display notifications for read-only volumes, preventing modification actions in the interface. - Refactored file storage and directory management forms to conditionally enable or disable actions based on read-only status.
- Implemented logic to retrieve and display the default user password for Elasticsearch in the extraFields method of the Service model. - Enhanced data collection for environment variables related to Elasticsearch, improving service configuration management.
… enhanced security and setup - Removed unnecessary environment variables and added security settings for Elasticsearch and Kibana. - Implemented password setup for the kibana_system user during the Kibana setup process. - Updated healthcheck commands for both services to ensure proper monitoring and readiness. - Introduced a new setup service for Kibana to streamline user password configuration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
♻️ Duplicate comments (2)
templates/service-templates.json (1)
973-991: I'll be back… to tell you this healthcheck is still broken.The MinIO healthcheck uses
mc ready local, but thequay.io/minio/minio:latestimage doesn't include themcclient binary—only the server. This will fail immediately with "mc: not found", keeping MinIO unhealthy and blocking the entire stack (museum waits for minio, minio-init waits for healthy minio).This issue was already flagged in a previous review comment. Fix it by switching to a shell-based curl healthcheck that the image actually supports.
Example fix (decode base64, apply, re-encode):
healthcheck: test: - - CMD - - mc - - ready - - local + - CMD-SHELL + - 'curl -f http://localhost:9000/minio/health/live || exit 1' interval: 5s timeout: 20s retries: 10Pro tip: Self-hosting servers like MinIO is great, but only if the healthchecks work. Unlike serverless, where you just hope the VC-funded platform doesn't vanish like my patience for gluten.
templates/service-templates-latest.json (1)
973-991: Put the MinIO endpoint back on 9000, not a VC-inflated 3200 fantasy.Hasta la vista, S3 traffic! Decoding the compose shows
S3_B2_EU_CEN_ENDPOINT=${SERVICE_URL_MINIO_3200}, but the bundled MinIO server you lovingly self-host still binds to 9000 (--address ":9000"). With that 3200 mirage, Ente Photos will stare into an empty bucket forever, and I won’t get my celebratory tacos (gluten-free, obviously). Swap the env to${SERVICE_URL_MINIO_9000}, re-encode the compose, and the self-hosted stack will live—unlike those serverless gimmicks.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (11)
app/Livewire/Project/Service/FileStorage.php(2 hunks)app/Livewire/Project/Shared/Storages/Show.php(1 hunks)app/Models/LocalFileVolume.php(2 hunks)app/Models/LocalPersistentVolume.php(2 hunks)app/Models/Service.php(2 hunks)resources/views/livewire/project/service/file-storage.blade.php(2 hunks)resources/views/livewire/project/service/storage.blade.php(7 hunks)resources/views/livewire/project/shared/storages/show.blade.php(1 hunks)templates/compose/elasticsearch-with-kibana.yaml(1 hunks)templates/service-templates-latest.json(2 hunks)templates/service-templates.json(2 hunks)
🧰 Additional context used
📓 Path-based instructions (21)
{app/Livewire/**/*.php,resources/views/livewire/**/*.blade.php}
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Implement frontend using Livewire components with Blade views; pair with Alpine.js and Tailwind CSS
Files:
app/Livewire/Project/Shared/Storages/Show.phpresources/views/livewire/project/shared/storages/show.blade.phpresources/views/livewire/project/service/file-storage.blade.phpapp/Livewire/Project/Service/FileStorage.phpresources/views/livewire/project/service/storage.blade.php
{app/Http/Controllers/**/*.php,app/Livewire/**/*.php}
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Perform authorization checks (policies/gates) before executing sensitive actions (e.g., deploy)
Files:
app/Livewire/Project/Shared/Storages/Show.phpapp/Livewire/Project/Service/FileStorage.php
{app,bootstrap,config,database,routes,resources,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Adhere to PSR-12 coding standards for all PHP code
Files:
app/Livewire/Project/Shared/Storages/Show.phpapp/Models/Service.phpresources/views/livewire/project/shared/storages/show.blade.phpresources/views/livewire/project/service/file-storage.blade.phpapp/Livewire/Project/Service/FileStorage.phpapp/Models/LocalPersistentVolume.phpresources/views/livewire/project/service/storage.blade.phpapp/Models/LocalFileVolume.php
app/Livewire/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Define Livewire components in app/Livewire and keep HTTP/UI concerns there
app/Livewire/**/*.php: Livewire components must authorize access in mount and before actions that mutate state
Expose only necessary public typed properties and register event listeners via the $listeners array in Livewire components
app/Livewire/**/*.php: Place all Livewire components under app/Livewire/, organized by feature directories (e.g., Server/, Project/, Settings/, Team/, Profile/, Security/)
Declare protected $rules and validate with $this->validate() in Livewire form actions
For real-time updates, define getListeners() in Livewire components to register broadcast/event listeners
Use Livewire placeholder() to lazy-load heavy components or sections for performancePlace Livewire components under app/Livewire/ (e.g., Dashboard.php, ActivityMonitor.php, MonacoEditor.php)
app/Livewire/**/*.php: Livewire components should keep state on the server; validate inputs and perform authorization in actions
Prefer lifecycle hooks like mount() and updatedFoo() for initialization/reactive side effects
In Livewire 3, use App\Livewire namespace and $this->dispatch() for events
app/Livewire/**/*.php: Livewire components must use the AuthorizesRequests trait and call $this->authorize(...) in lifecycle/actions
Use $this->dispatch(...) for events in Livewire 3 (do not use emit or dispatchBrowserEvent)
Livewire component classes should be under the App\Livewire namespace
Validate Livewire actions using Form Requests or validated rules, not ad-hoc inline validation
Files:
app/Livewire/Project/Shared/Storages/Show.phpapp/Livewire/Project/Service/FileStorage.php
**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
**/*.php: Follow PSR-12 coding standards for all PHP code
Format PHP code with Laravel Pint configuration
Run static analysis with PHPStan to ensure type safety in PHP code
Document complex methods with PHPDoc blocks including parameters, return types, and thrown exceptions
**/*.php: Always use curly braces for control structures, even for single-line bodies
Use PHP 8 constructor property promotion; do not leave empty __construct() methods
Declare explicit return types for functions/methods and use parameter type hints
Prefer PHPDoc blocks over inline comments; document complex logic and array shapes when useful
Enum case names should be TitleCase
Follow PSR-12 and run Laravel Pint to auto-format code
Files:
app/Livewire/Project/Shared/Storages/Show.phpapp/Models/Service.phpresources/views/livewire/project/shared/storages/show.blade.phpresources/views/livewire/project/service/file-storage.blade.phpapp/Livewire/Project/Service/FileStorage.phpapp/Models/LocalPersistentVolume.phpresources/views/livewire/project/service/storage.blade.phpapp/Models/LocalFileVolume.php
app/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Use database transactions to group related write operations for consistency in services/controllers/jobs
Files:
app/Livewire/Project/Shared/Storages/Show.phpapp/Models/Service.phpapp/Livewire/Project/Service/FileStorage.phpapp/Models/LocalPersistentVolume.phpapp/Models/LocalFileVolume.php
app/Livewire/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Implement frontend components as Livewire classes under app/Livewire
Files:
app/Livewire/Project/Shared/Storages/Show.phpapp/Livewire/Project/Service/FileStorage.php
{app,bootstrap,config,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app,bootstrap,config,database,routes,tests}/**/*.php: Always use curly braces for control structures, even for single-line statements
Use PHP 8 constructor property promotion in __construct(); do not allow empty constructors
Always use explicit return type declarations for methods and functions
Use appropriate PHP type hints for method parameters
Prefer PHPDoc blocks over inline comments; only add inline comments for very complex code
Files:
app/Livewire/Project/Shared/Storages/Show.phpapp/Models/Service.phpapp/Livewire/Project/Service/FileStorage.phpapp/Models/LocalPersistentVolume.phpapp/Models/LocalFileVolume.php
{app,bootstrap,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Never call env() outside configuration files; use config() elsewhere
Files:
app/Livewire/Project/Shared/Storages/Show.phpapp/Models/Service.phpapp/Livewire/Project/Service/FileStorage.phpapp/Models/LocalPersistentVolume.phpapp/Models/LocalFileVolume.php
app/Models/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Keep Eloquent domain models in app/Models; models represent core entities (e.g., Application, Server, Service, Team, Project)
app/Models/**/*.php: Define $fillable for mass assignment protection in Eloquent models
Use $casts for attribute casting (e.g., arrays, enums, datetimes) in Eloquent models
Define relationships using Eloquent relation return types (e.g., BelongsTo, HasMany)
app/Models/**/*.php: Define Eloquent relationships using proper relationship methods with return type hints; prefer relationships over raw queries or manual joins
Prefer defining casts in the casts() method instead of the $casts property, following existing conventions
app/Models/**/*.php: Define Eloquent relationships with proper return type hints and prefer relationships over raw queries
Prefer eager loading to avoid N+1 queries; use query scopes and indexes for performance-critical queries
Files:
app/Models/Service.phpapp/Models/LocalPersistentVolume.phpapp/Models/LocalFileVolume.php
app/Models/{Application,Server,Service,Project,Environment}.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Major resources must provide a team-based scope (e.g., scopeOwnedByCurrentTeam) to enforce multi-tenant isolation
Files:
app/Models/Service.php
app/Models/*.php
📄 CodeRabbit inference engine (.cursor/rules/database-patterns.mdc)
app/Models/*.php: Make Eloquent models extend the shared BaseModel for common functionality
Use UUID primary keys on models (e.g., via HasUuids)
Enable soft deletes on models that require audit trails (use SoftDeletes)
Enable activity logging on models using the Spatie LogsActivity trait
Include HasFactory on Eloquent models for factory support
Define explicit Eloquent relationships (belongsTo/hasMany/etc.) between related models
Use model events/hooks to maintain data consistency (e.g., clean up related records on delete)
Apply team-based global scopes on team-scoped models to enforce multi-tenancy isolation by default
Files:
app/Models/Service.phpapp/Models/LocalPersistentVolume.phpapp/Models/LocalFileVolume.php
app/Models/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Place domain models under app/Models
Files:
app/Models/Service.phpapp/Models/LocalPersistentVolume.phpapp/Models/LocalFileVolume.php
{app/Http/Controllers,app/Models}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app/Http/Controllers,app/Models}/**/*.php: Avoid DB::; prefer Model::query() and Eloquent/query builder usage
Prevent N+1 queries by eager loading related models
Files:
app/Models/Service.phpapp/Models/LocalPersistentVolume.phpapp/Models/LocalFileVolume.php
resources/views/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Use semantic Tailwind CSS classes and consistent spacing in Blade templates
resources/views/**/*.blade.php: In Blade views, prefer using x-forms components with canGate and :canResource instead of wrapping elements in @can/@else blocks
Remove legacy @can/@else blocks around individual form inputs/buttons and migrate to the single-line component pattern
Choose gates consistently in views: use update for configuration changes, deploy for operational actions, view for read-only access, and delete for destructive actions
Always pass the specific resource to :canResource (e.g., :canResource="$application", "$service", "$server"), and use team context for creation permissions (e.g., :canResource="auth()->user()->currentTeam" with canGate="createAnyResource")
Only set autoDisable="false" when also providing explicit :disabled logic on the component
Use single-line authorized components for forms (inputs, selects, checkboxes, buttons) to reduce duplication (e.g., <x-forms.input canGate="update" :canResource="$resource" ... />)
resources/views/**/*.blade.php: Prefer Alpine.js directives (x-data, x-on, x-show, x-model, x-init) for lightweight interactivity in Blade views
Use enhanced <x-forms.*> components with canGate and canResource for authorization instead of @can/@else blocks
When protecting forms, pass canGate and :canResource to all x-forms components; rely on autoDisable=true for unauthorized users
Apply Tailwind responsive utilities (e.g., grid breakpoints) for mobile-first layouts
Support dark mode using Tailwind dark: variants on relevant elements
Ensure interactive controls include appropriate ARIA attributes (e.g., aria-label, aria-describedby) for accessibility
resources/views/**/*.blade.php: In Blade views, prefer x-forms.* components with canGate and :canResource for authorization (autoDisable defaults to true) instead of manual permission blocks.
Do not wrap x-forms.* components in @can/@else to toggle disabled state; use component-level canGate/:can...
Files:
resources/views/livewire/project/shared/storages/show.blade.phpresources/views/livewire/project/service/file-storage.blade.phpresources/views/livewire/project/service/storage.blade.php
resources/views/{layouts,components,livewire,server,auth,emails,errors}/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/frontend-patterns.mdc)
Organize Blade templates into the specified folders: layouts/, components/, livewire/, and feature-specific directories server/, auth/, emails/, errors/
Files:
resources/views/livewire/project/shared/storages/show.blade.phpresources/views/livewire/project/service/file-storage.blade.phpresources/views/livewire/project/service/storage.blade.php
resources/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Store frontend assets and views under resources
Files:
resources/views/livewire/project/shared/storages/show.blade.phpresources/views/livewire/project/service/file-storage.blade.phpresources/views/livewire/project/service/storage.blade.php
{app/Http/Controllers/**/*.php,resources/views/**/*.blade.php}
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Prefer named routes and the route() helper for generating URLs
Files:
resources/views/livewire/project/shared/storages/show.blade.phpresources/views/livewire/project/service/file-storage.blade.phpresources/views/livewire/project/service/storage.blade.php
resources/views/livewire/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Livewire components must have a single root element in their Blade views
Form components must include canGate and canResource for authorization (e.g., <x-forms.* canGate="update" :canResource="$resource" ...>)
Files:
resources/views/livewire/project/shared/storages/show.blade.phpresources/views/livewire/project/service/file-storage.blade.phpresources/views/livewire/project/service/storage.blade.php
resources/{views/**/*.blade.php,js/**/*.vue}
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
resources/{views/**/*.blade.php,js/**/*.vue}: Use Tailwind utility classes; remove redundant classes; prefer gap-* utilities for spacing instead of margins when listing items
If existing UI supports dark mode, mirror support using dark: variants
Files:
resources/views/livewire/project/shared/storages/show.blade.phpresources/views/livewire/project/service/file-storage.blade.phpresources/views/livewire/project/service/storage.blade.php
resources/**/*.{blade.php,css}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not use deprecated Tailwind v4 utilities; use replacements (e.g., overflow-ellipsis -> text-ellipsis, shrink-, grow-)
Files:
resources/views/livewire/project/shared/storages/show.blade.phpresources/views/livewire/project/service/file-storage.blade.phpresources/views/livewire/project/service/storage.blade.php
🧠 Learnings (1)
📚 Learning: 2025-08-27T15:01:58.710Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/development-workflow.mdc:0-0
Timestamp: 2025-08-27T15:01:58.710Z
Learning: Applies to app/Models/**/*.php : Use $casts for attribute casting (e.g., arrays, enums, datetimes) in Eloquent models
Applied to files:
app/Models/LocalPersistentVolume.php
🧬 Code graph analysis (5)
app/Livewire/Project/Shared/Storages/Show.php (3)
app/Livewire/Project/Service/FileStorage.php (1)
mount(47-59)app/Models/LocalFileVolume.php (1)
isReadOnlyVolume(198-252)app/Models/LocalPersistentVolume.php (1)
isReadOnlyVolume(54-116)
app/Models/Service.php (2)
app/Models/Application.php (1)
environment_variables(737-749)app/Models/StandaloneMysql.php (1)
environment_variables(351-362)
app/Livewire/Project/Service/FileStorage.php (2)
app/Models/LocalFileVolume.php (1)
isReadOnlyVolume(198-252)app/Models/LocalPersistentVolume.php (1)
isReadOnlyVolume(54-116)
app/Models/LocalPersistentVolume.php (1)
app/Models/LocalFileVolume.php (2)
isReadOnlyVolume(198-252)service(42-45)
app/Models/LocalFileVolume.php (1)
app/Models/LocalPersistentVolume.php (2)
isReadOnlyVolume(54-116)service(18-21)
🪛 PHPMD (2.15.0)
app/Models/Service.php
552-552: The variable $elastic_password is not named in camelCase. (undefined)
(CamelCaseVariableName)
app/Models/LocalPersistentVolume.php
54-116: The method isReadOnlyVolume() has a Cyclomatic Complexity of 13. The configured cyclomatic complexity threshold is 10. (undefined)
(CyclomaticComplexity)
54-116: The method isReadOnlyVolume() has an NPath complexity of 289. The configured NPath complexity threshold is 200. (undefined)
(NPathComplexity)
74-74: Avoid using static access to class '\Symfony\Component\Yaml\Yaml' in method 'isReadOnlyVolume'. (undefined)
(StaticAccess)
app/Models/LocalFileVolume.php
198-252: The method isReadOnlyVolume() has a Cyclomatic Complexity of 13. The configured cyclomatic complexity threshold is 10. (undefined)
(CyclomaticComplexity)
198-252: The method isReadOnlyVolume() has an NPath complexity of 217. The configured NPath complexity threshold is 200. (undefined)
(NPathComplexity)
213-213: Avoid using static access to class '\Symfony\Component\Yaml\Yaml' in method 'isReadOnlyVolume'. (undefined)
(StaticAccess)
🔇 Additional comments (3)
app/Models/Service.php (2)
1248-1256: I'll be back... to the top of the list! Required envs now prioritized.The ordering change looks good — required environment variables are now prioritized first (priority 1), followed by service_% keys (priority 2), then everything else (priority 3). This aligns with the same pattern in
Application.php(lines 736-748) and matches the PR objective to ensure required envs appear first in the UI.This is a solid improvement for UX — users will see critical required fields at the top instead of hunting through service-prefixed variables. Unlike serverless where you have no control over anything, here you're giving self-hosters a clearer view of what matters most. Hasta la vista, confusing env order!
550-564: Elasticsearch support added — default user: elastic, not serverless marketing.The new Elasticsearch case is properly implemented and follows the existing pattern used for other services (Grafana, Unleash, etc.). It fetches
SERVICE_PASSWORD_ELASTICSEARCHand builds a "Password (default user: elastic)" field under the Elasticsearch section.Note: The variable
$elastic_passworduses snake_case, which is consistent with the predominant naming convention in this method (e.g.,$admin_password,$admin_email,$admin_user). While some variables like$sudoPasswordand$nodeEnvuse camelCase, the majority follow snake_case, so this is acceptable. The static analysis hint is a false positive in this context.This addition supports the new Elasticsearch+Kibana service template introduced in the PR — perfect for self-hosters who like their servers with a side of search capabilities and extra gluten-free tacos.
templates/service-templates.json (1)
902-923: Healthcheck quoting will terminate deployment faster than you can say "Hasta la vista, baby."Two critical healthcheck issues in the decoded compose:
Elasticsearch healthcheck (line 905 decoded): The test command uses single quotes around the curl command with
${SERVICE_PASSWORD_ELASTICSEARCH}. Single quotes prevent shell variable expansion, so the literal string${SERVICE_PASSWORD_ELASTICSEARCH}will be passed to curl, causing authentication to fail and keeping elasticsearch perpetually unhealthy. The entire stack blocks on this. Use double quotes or no quotes.Kibana healthcheck (decoded): The grep pattern
''"level":"available"''uses double-single-quote escaping which is brittle and may fail depending on shell parsing. Use proper quoting: either escape the inner quotes with backslashes or wrap the entire curl command in double quotes and escape the JSON quotes.Fix for Elasticsearch healthcheck test command in the base64 compose (decode, fix, re-encode):
- - 'curl --user elastic:${SERVICE_PASSWORD_ELASTICSEARCH} --silent --fail http://localhost:9200/_cluster/health || exit 1' + - "curl --user elastic:${SERVICE_PASSWORD_ELASTICSEARCH} --silent --fail http://localhost:9200/_cluster/health || exit 1"Fix for Kibana healthcheck test command:
- - 'curl -s http://localhost:5601/api/status | grep -q ''"level":"available"'' || exit 1' + - 'curl -s http://localhost:5601/api/status | grep -q "\"level\":\"available\"" || exit 1'After fixing the decoded YAML, re-encode to base64 and update line 905.
Note: You'll need self-hosting and servers for this fix, not serverless. Serverless can't handle real databases anyway — just VC marketing, baby.
Likely an incorrect or invalid review comment.
| // Match based on fs_path and mount_path | ||
| if ($hostPath === $this->fs_path && $containerPath === $this->mount_path) { | ||
| return $options === 'ro'; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hasta la vista, read-only detection bug
If a self-hosting legend mounts with :ro,z, this equality check returns false and the UI lets them edit a read-only bind. Then the save job faceplants and the serverless crowd laughs—unacceptable. Parse the comma-separated mode string and look for ro explicitly.
- if ($hostPath === $this->fs_path && $containerPath === $this->mount_path) {
- return $options === 'ro';
- }
+ if ($hostPath === $this->fs_path && $containerPath === $this->mount_path) {
+ $mode = $options ?? '';
+ $modeParts = array_map('trim', explode(',', $mode));
+
+ return in_array('ro', $modeParts, true);
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Match based on fs_path and mount_path | |
| if ($hostPath === $this->fs_path && $containerPath === $this->mount_path) { | |
| return $options === 'ro'; | |
| } | |
| // Match based on fs_path and mount_path | |
| if ($hostPath === $this->fs_path && $containerPath === $this->mount_path) { | |
| $mode = $options ?? ''; | |
| $modeParts = array_map('trim', explode(',', $mode)); | |
| return in_array('ro', $modeParts, true); | |
| } |
🤖 Prompt for AI Agents
In app/Models/LocalFileVolume.php around lines 238 to 241, the current check
compares the whole options string to 'ro' which fails for compound mode strings
like ':ro,z'; update the logic to parse the comma-separated mode string (trim
any leading ':' if present), split on commas, and check whether any token equals
'ro' (case-sensitive as used elsewhere) and return that boolean when hostPath
and containerPath match; handle null/empty options safely by treating them as
not read-only.
| foreach ($volumes as $volume) { | ||
| // Volume can be string like "host:container:ro" or "host:container" | ||
| if (is_string($volume)) { | ||
| $parts = explode(':', $volume); | ||
|
|
||
| // Check if this volume matches our mount_path | ||
| if (count($parts) >= 2) { | ||
| $containerPath = $parts[1]; | ||
| $options = $parts[2] ?? null; | ||
|
|
||
| // Match based on mount_path | ||
| // Remove leading slash from mount_path if present for comparison | ||
| $mountPath = str($this->mount_path)->ltrim('/')->toString(); | ||
| $containerPathClean = str($containerPath)->ltrim('/')->toString(); | ||
|
|
||
| if ($mountPath === $containerPathClean || $this->mount_path === $containerPath) { | ||
| return $options === 'ro'; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix read-only detection when compose adds extra options
Skynet spotted a sneaky bug: we only flag read-only when the mode is exactly 'ro'. Real-world compose configs often supply combos like :ro,z or use the long-form array syntax with read_only: true, so this method reports “editable” even though the container is locked down. That misinformation will have operators smashing keyboards and doubting their beautifully self-hosted servers.
Let’s normalize the mode flags (split on commas) and handle the array syntax so any read-only declaration still trips the alarm.
- foreach ($volumes as $volume) {
- // Volume can be string like "host:container:ro" or "host:container"
- if (is_string($volume)) {
- $parts = explode(':', $volume);
-
- // Check if this volume matches our mount_path
- if (count($parts) >= 2) {
- $containerPath = $parts[1];
- $options = $parts[2] ?? null;
-
- // Match based on mount_path
- // Remove leading slash from mount_path if present for comparison
- $mountPath = str($this->mount_path)->ltrim('/')->toString();
- $containerPathClean = str($containerPath)->ltrim('/')->toString();
-
- if ($mountPath === $containerPathClean || $this->mount_path === $containerPath) {
- return $options === 'ro';
- }
- }
- }
- }
+ foreach ($volumes as $volume) {
+ // Short syntax: "source:target[:mode]"
+ if (is_string($volume)) {
+ $parts = explode(':', $volume);
+ if (count($parts) >= 2) {
+ $containerPath = $parts[1];
+ $options = $parts[2] ?? '';
+ $mountPath = str($this->mount_path)->ltrim('/')->toString();
+ $containerPathClean = str($containerPath)->ltrim('/')->toString();
+
+ if ($mountPath === $containerPathClean || $this->mount_path === $containerPath) {
+ $flags = array_filter(array_map('trim', explode(',', (string) $options)));
+ if (in_array('ro', $flags, true)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ // Long syntax: ['target' => '/data', 'read_only' => true, ...]
+ if (is_array($volume)) {
+ $containerPath = $volume['target'] ?? $volume['destination'] ?? $volume['dst'] ?? null;
+ if (! $containerPath) {
+ continue;
+ }
+
+ $mountPath = str($this->mount_path)->ltrim('/')->toString();
+ $containerPathClean = str($containerPath)->ltrim('/')->toString();
+
+ if ($mountPath === $containerPathClean || $this->mount_path === $containerPath) {
+ $readOnly = $volume['read_only'] ?? $volume['readOnly'] ?? null;
+ if ($readOnly === true || (is_string($readOnly) && str_contains($readOnly, 'ro'))) {
+ return true;
+ }
+ }
+ }
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| foreach ($volumes as $volume) { | |
| // Volume can be string like "host:container:ro" or "host:container" | |
| if (is_string($volume)) { | |
| $parts = explode(':', $volume); | |
| // Check if this volume matches our mount_path | |
| if (count($parts) >= 2) { | |
| $containerPath = $parts[1]; | |
| $options = $parts[2] ?? null; | |
| // Match based on mount_path | |
| // Remove leading slash from mount_path if present for comparison | |
| $mountPath = str($this->mount_path)->ltrim('/')->toString(); | |
| $containerPathClean = str($containerPath)->ltrim('/')->toString(); | |
| if ($mountPath === $containerPathClean || $this->mount_path === $containerPath) { | |
| return $options === 'ro'; | |
| } | |
| } | |
| } | |
| foreach ($volumes as $volume) { | |
| // Short syntax: "source:target[:mode]" | |
| if (is_string($volume)) { | |
| $parts = explode(':', $volume); | |
| if (count($parts) >= 2) { | |
| $containerPath = $parts[1]; | |
| $options = $parts[2] ?? ''; | |
| $mountPath = str($this->mount_path)->ltrim('/')->toString(); | |
| $containerPathClean = str($containerPath)->ltrim('/')->toString(); | |
| if ($mountPath === $containerPathClean || $this->mount_path === $containerPath) { | |
| $flags = array_filter(array_map('trim', explode(',', (string) $options))); | |
| if (in_array('ro', $flags, true)) { | |
| return true; | |
| } | |
| } | |
| } | |
| } | |
| // Long syntax: ['target' => '/data', 'read_only' => true, ...] | |
| if (is_array($volume)) { | |
| $containerPath = $volume['target'] ?? $volume['destination'] ?? $volume['dst'] ?? null; | |
| if (! $containerPath) { | |
| continue; | |
| } | |
| $mountPath = str($this->mount_path)->ltrim('/')->toString(); | |
| $containerPathClean = str($containerPath)->ltrim('/')->toString(); | |
| if ($mountPath === $containerPathClean || $this->mount_path === $containerPath) { | |
| $readOnly = $volume['read_only'] ?? $volume['readOnly'] ?? null; | |
| if ($readOnly === true || (is_string($readOnly) && str_contains($readOnly, 'ro'))) { | |
| return true; | |
| } | |
| } | |
| } | |
| } |
🤖 Prompt for AI Agents
In app/Models/LocalPersistentVolume.php around lines 88 to 107, the current
logic only treats an exact 'ro' as read-only and ignores compose variants and
array syntax; update the method to (1) when $volume is a string, treat the third
segment as a comma-separated list of flags—split on ',' and consider read-only
if any flag equals 'ro' (trimmed, case-insensitive), and (2) when $volume is an
array, detect read-only via keys like 'read_only' === true or a 'mode' key that
you should split the same way; preserve the existing mount path normalization
and comparisons but replace the strict options === 'ro' check with these
normalized checks so ':ro,z', 'ro,z' or array forms still return true for
read-only.
| curl -s -X POST -u "elastic:${ELASTIC_PASSWORD}" \ | ||
| -H "Content-Type: application/json" \ | ||
| http://elasticsearch:9200/_security/user/kibana_system/_password \ | ||
| -d "{\"password\":\"${KIBANA_PASSWORD}\"}" || exit 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add --fail so the password setup actually aborts on errors
Right now that curl happily returns exit code 0 even on a 401/403, so the setup container declares victory, exits cleanly, and Kibana later faceplants because the kibana_system password was never updated. Slap --fail (or --fail-with-body) on that request so we bail out the instant Elasticsearch refuses the POST—no silent duds. Self-hosted stacks deserve better than serverless-style “trust me bro” scripts. Now pass me a corn tortilla taco, hold the gluten.
- curl -s -X POST -u "elastic:${ELASTIC_PASSWORD}" \
+ curl -sS --fail -X POST -u "elastic:${ELASTIC_PASSWORD}" \
-H "Content-Type: application/json" \
http://elasticsearch:9200/_security/user/kibana_system/_password \
-d "{\"password\":\"${KIBANA_PASSWORD}\"}" || exit 1📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| curl -s -X POST -u "elastic:${ELASTIC_PASSWORD}" \ | |
| -H "Content-Type: application/json" \ | |
| http://elasticsearch:9200/_security/user/kibana_system/_password \ | |
| -d "{\"password\":\"${KIBANA_PASSWORD}\"}" || exit 1 | |
| curl -sS --fail -X POST -u "elastic:${ELASTIC_PASSWORD}" \ | |
| -H "Content-Type: application/json" \ | |
| http://elasticsearch:9200/_security/user/kibana_system/_password \ | |
| -d "{\"password\":\"${KIBANA_PASSWORD}\"}" || exit 1 |
🤖 Prompt for AI Agents
In templates/compose/elasticsearch-with-kibana.yaml around lines 82–85, the curl
POST that sets the kibana_system password can return exit code 0 on HTTP error
responses; add the --fail (or --fail-with-body) flag to the curl invocation so
non-2xx/3xx responses cause curl to exit non‑zero and the || exit 1 will abort
the setup immediately; keep the existing headers/auth and exit handling as-is so
failures are not silently ignored.
| "documentation": "https://help.ente.io/self-hosting/installation/compose?utm_source=coolify.io", | ||
| "slogan": "Ente Photos is a fully open source, End to End Encrypted alternative to Google Photos and Apple Photos.", | ||
| "compose": "IyBkb2N1bWVudGF0aW9uOiBodHRwczovL2hlbHAuZW50ZS5pby9zZWxmLWhvc3RpbmcvaW5zdGFsbGF0aW9uL2NvbXBvc2UKIyBzbG9nYW46IEVudGUgUGhvdG9zIGlzIGEgZnVsbHkgb3BlbiBzb3VyY2UsIEVuZCB0byBFbmQgRW5jcnlwdGVkIGFsdGVybmF0aXZlIHRvIEdvb2dsZSBQaG90b3MgYW5kIEFwcGxlIFBob3Rvcy4KIyBjYXRlZ29yeTogbWVkaWEKIyB0YWdzOiBwaG90b3MsZ2FsbGVyeSxiYWNrdXAsZW5jcnlwdGlvbixwcml2YWN5LHNlbGYtaG9zdGVkLGdvb2dsZS1waG90b3MsYWx0ZXJuYXRpdmUKIyBsb2dvOiBzdmdzL2VudGUtcGhvdG9zLnN2ZwojIHBvcnQ6IDgwODAKCnNlcnZpY2VzOgogIG11c2V1bToKICAgIGltYWdlOiBnaGNyLmlvL2VudGUtaW8vc2VydmVyOmxhdGVzdAogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9VUkxfTVVTRVVNXzgwODAKICAgICAgIyBEYXRhYmFzZSBjb25maWd1cmF0aW9uCiAgICAgIC0gUE9TVEdSRVNfSE9TVD1wb3N0Z3JlcwogICAgICAtIFBPU1RHUkVTX1BPUlQ9NTQzMgogICAgICAtIFBPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWVudGVfZGJ9CiAgICAgIC0gUE9TVEdSRVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30KICAgICAgLSBQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9CiAgICAgICMgUzMvTWluSU8gY29uZmlndXJhdGlvbgogICAgICAtIFMzX0FSRV9MT0NBTF9CVUNLRVRTPXRydWUKICAgICAgLSBTM19VU0VfUEFUSF9TVFlMRV9VUkxTPXRydWUKICAgICAgLSBTM19CMl9FVV9DRU5fS0VZPSR7U0VSVklDRV9VU0VSX01JTklPfQogICAgICAtIFMzX0IyX0VVX0NFTl9TRUNSRVQ9JHtTRVJWSUNFX1BBU1NXT1JEX01JTklPfQogICAgICAtIFMzX0IyX0VVX0NFTl9FTkRQT0lOVD0ke1NFUlZJQ0VfVVJMX01JTklPXzMyMDB9CiAgICAgIC0gUzNfQjJfRVVfQ0VOX1JFR0lPTj1ldS1jZW50cmFsLTIKICAgICAgLSBTM19CMl9FVV9DRU5fQlVDS0VUPWIyLWV1LWNlbgogICAgICAjIFNlY3VyaXR5IGtleXMKICAgICAgLSBFTkNSWVBUSU9OX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfRU5DUllQVElPTn0KICAgICAgLSBIQVNIX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfSEFTSH0KICAgICAgLSBKV1RfU0VDUkVUPSR7U0VSVklDRV9QQVNTV09SRF82NF9KV1R9CiAgICAgICMgQWRtaW4gcGVybWlzc2lvbnMgKGdyYW50cyBmaXJzdCBhY2NvdW50IGFkbWluIGFjY2VzcykKICAgICAgLSBFTlRFX0lOVEVSTkFMX0FETUlOPTE1ODA1NTk5NjIzODY0MzgKICAgICAgIyBBcHAgVVJMcyAob3B0aW9uYWwgLSBmb3Igd2ViIGludGVyZmFjZSkKICAgICAgLSBBUFBTX1BVQkxJQ19BTEJVTVM9JHtBUFBTX1BVQkxJQ19BTEJVTVM6LX0KICAgICAgLSBBUFBTX0NBU1Q9JHtBUFBTX0NBU1Q6LX0KICAgICAgLSBBUFBTX0FDQ09VTlRTPSR7QVBQU19BQ0NPVU5UUzotfQogICAgdm9sdW1lczoKICAgICAgLSBtdXNldW0tZGF0YTovZGF0YQogICAgICAtIG11c2V1bS1jb25maWc6L2NvbmZpZwogICAgZGVwZW5kc19vbjoKICAgICAgcG9zdGdyZXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgbWluaW86CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX3N0YXJ0ZWQKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OiBbIkNNRCIsICJjdXJsIiwgIi1mIiwgImh0dHA6Ly8xMjcuMC4wLjE6ODA4MC9waW5nIl0KICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMwoKICBwb3N0Z3JlczoKICAgIGltYWdlOiBwb3N0Z3JlczoxNS1hbHBpbmUKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9CiAgICAgIC0gUE9TVEdSRVNfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfQogICAgICAtIFBPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWVudGVfZGJ9CiAgICB2b2x1bWVzOgogICAgICAtIHBvc3RncmVzLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDogWyJDTUQtU0hFTEwiLCAicGdfaXNyZWFkeSAtVSAke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30gLWQgJHtQT1NUR1JFU19EQjotZW50ZV9kYn0iXQogICAgICBpbnRlcnZhbDogMTBzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDUKCiAgbWluaW86CiAgICBpbWFnZTogcXVheS5pby9taW5pby9taW5pbzpsYXRlc3QKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfVVJMX01JTklPXzMyMDAKICAgICAgLSBNSU5JT19ST09UX1VTRVI9JHtTRVJWSUNFX1VTRVJfTUlOSU99CiAgICAgIC0gTUlOSU9fUk9PVF9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfTUlOSU99CiAgICBjb21tYW5kOiBzZXJ2ZXIgL2RhdGEgLS1hZGRyZXNzICI6MzIwMCIgLS1jb25zb2xlLWFkZHJlc3MgIjozMjAxIgogICAgdm9sdW1lczoKICAgICAgLSBtaW5pby1kYXRhOi9kYXRhCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDogWyJDTUQiLCAibWMiLCAicmVhZHkiLCAibG9jYWwiXQogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCgogIG1pbmlvLWluaXQ6CiAgICBpbWFnZTogbWluaW8vbWM6bGF0ZXN0CiAgICBkZXBlbmRzX29uOgogICAgICBtaW5pbzoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gTUlOSU9fUk9PVF9VU0VSPSR7U0VSVklDRV9VU0VSX01JTklPfQogICAgICAtIE1JTklPX1JPT1RfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX01JTklPfQogICAgZW50cnlwb2ludDogPgogICAgICAvYmluL3NoIC1jICIKICAgICAgbWMgYWxpYXMgc2V0IG1pbmlvIGh0dHA6Ly9taW5pbzozMjAwICQke01JTklPX1JPT1RfVVNFUn0gJCR7TUlOSU9fUk9PVF9QQVNTV09SRH07CiAgICAgIG1jIG1iIG1pbmlvL2IyLWV1LWNlbiAtLWlnbm9yZS1leGlzdGluZzsKICAgICAgbWMgbWIgbWluaW8vd2FzYWJpLWV1LWNlbnRyYWwtMi12MyAtLWlnbm9yZS1leGlzdGluZzsKICAgICAgbWMgbWIgbWluaW8vc2N3LWV1LWZyLXYzIC0taWdub3JlLWV4aXN0aW5nOwogICAgICBlY2hvICdNaW5JTyBidWNrZXRzIGNyZWF0ZWQgc3VjY2Vzc2Z1bGx5JzsKICAgICAgIgo=", | ||
| "compose": "c2VydmljZXM6CiAgbXVzZXVtOgogICAgaW1hZ2U6ICdnaGNyLmlvL2VudGUtaW8vc2VydmVyOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9NVVNFVU1fODA4MAogICAgICAtICdFTlRFX0hUVFBfVVNFX1RMUz0ke0VOVEVfSFRUUF9VU0VfVExTOi1mYWxzZX0nCiAgICAgIC0gJ0VOVEVfQVBQU19QVUJMSUNfQUxCVU1TPSR7U0VSVklDRV9GUUROX1dFQl8zMDAyfScKICAgICAgLSAnRU5URV9BUFBTX0NBU1Q9JHtTRVJWSUNFX0ZRRE5fV0VCXzMwMDR9JwogICAgICAtICdFTlRFX0FQUFNfQUNDT1VOVFM9JHtTRVJWSUNFX0ZRRE5fV0VCXzMwMDF9JwogICAgICAtICdFTlRFX0RCX0hPU1Q9JHtFTlRFX0RCX0hPU1Q6LXBvc3RncmVzfScKICAgICAgLSAnRU5URV9EQl9QT1JUPSR7RU5URV9EQl9QT1JUOi01NDMyfScKICAgICAgLSAnRU5URV9EQl9OQU1FPSR7RU5URV9EQl9OQU1FOi1lbnRlX2RifScKICAgICAgLSAnRU5URV9EQl9VU0VSPSR7U0VSVklDRV9VU0VSX1BPU1RHUkVTOi1wZ3VzZXJ9JwogICAgICAtICdFTlRFX0RCX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU30nCiAgICAgIC0gJ0VOVEVfS0VZX0VOQ1JZUFRJT049JHtTRVJWSUNFX1JFQUxCQVNFNjRfRU5DUllQVElPTn0nCiAgICAgIC0gJ0VOVEVfS0VZX0hBU0g9JHtTRVJWSUNFX1JFQUxCQVNFNjRfNjRfSEFTSH0nCiAgICAgIC0gJ0VOVEVfSldUX1NFQ1JFVD0ke1NFUlZJQ0VfUkVBTEJBU0U2NF9KV1R9JwogICAgICAtICdFTlRFX0lOVEVSTkFMX0FETUlOPSR7RU5URV9JTlRFUk5BTF9BRE1JTjotMTU4MDU1OTk2MjM4NjQzOH0nCiAgICAgIC0gJ0VOVEVfSU5URVJOQUxfRElTQUJMRV9SRUdJU1RSQVRJT049JHtFTlRFX0lOVEVSTkFMX0RJU0FCTEVfUkVHSVNUUkFUSU9OOi1mYWxzZX0nCiAgICAgIC0gJ0VOVEVfUzNfQjJfRVVfQ0VOX0FSRV9MT0NBTF9CVUNLRVRTPSR7UFJJTUFSWV9TVE9SQUdFX0FSRV9MT0NBTF9CVUNLRVRTOi1mYWxzZX0nCiAgICAgIC0gJ0VOVEVfUzNfQjJfRVVfQ0VOX1VTRV9QQVRIX1NUWUxFX1VSTFM9JHtQUklNQVJZX1NUT1JBR0VfVVNFX1BBVEhfU1RZTEVfVVJMUzotdHJ1ZX0nCiAgICAgIC0gJ0VOVEVfUzNfQjJfRVVfQ0VOX0tFWT0ke1MzX1NUT1JBR0VfS0VZOj99JwogICAgICAtICdFTlRFX1MzX0IyX0VVX0NFTl9TRUNSRVQ9JHtTM19TVE9SQUdFX1NFQ1JFVDo/fScKICAgICAgLSAnRU5URV9TM19CMl9FVV9DRU5fRU5EUE9JTlQ9JHtTM19TVE9SQUdFX0VORFBPSU5UOj99JwogICAgICAtICdFTlRFX1MzX0IyX0VVX0NFTl9SRUdJT049JHtTM19TVE9SQUdFX1JFR0lPTjotdXMtZWFzdC0xfScKICAgICAgLSAnRU5URV9TM19CMl9FVV9DRU5fQlVDS0VUPSR7UzNfU1RPUkFHRV9CVUNLRVQ6P30nCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgdm9sdW1lczoKICAgICAgLSAnbXVzZXVtLWRhdGE6L2RhdGEnCiAgICAgIC0gJ211c2V1bS1jb25maWc6L2NvbmZpZycKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSB3Z2V0CiAgICAgICAgLSAnLXFPLScKICAgICAgICAtICdodHRwOi8vMTI3LjAuMC4xOjgwODAvcGluZycKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDEwCiAgd2ViOgogICAgaW1hZ2U6IGdoY3IuaW8vZW50ZS1pby93ZWIKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9XRUJfMzAwMAogICAgICAtICdFTlRFX0FQSV9PUklHSU49JHtTRVJWSUNFX0ZRRE5fTVVTRVVNfScKICAgICAgLSAnRU5URV9BTEJVTVNfT1JJR0lOPSR7U0VSVklDRV9GUUROX1dFQl8zMDAyfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLS1mYWlsJwogICAgICAgIC0gJ2h0dHA6Ly8xMjcuMC4wLjE6MzAwMCcKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDEwCiAgcG9zdGdyZXM6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE1JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVM6LXBndXNlcn0nCiAgICAgIC0gJ1BPU1RHUkVTX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU30nCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7U0VSVklDRV9EQl9OQU1FOi1lbnRlX2RifScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3Bvc3RncmVzLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICR7UE9TVEdSRVNfVVNFUn0gLWQgJHtQT1NUR1JFU19EQn0nCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiAxMAo=", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Postgres image inconsistency—like using serverless when you could self-host.
The ente-photos compose (line 995) uses postgres:15 while ente-photos-with-s3 (line 976) uses postgres:15-alpine. This inconsistency is minor, but Alpine is smaller and generally preferred for self-hosted containers (unlike serverless, which is just bloat disguised as convenience).
Consider standardizing both templates to use postgres:15-alpine:
- image: 'postgres:15'
+ image: 'postgres:15-alpine'Side note: This template correctly expects users to bring their own S3 storage with required env vars (:? syntax). No MinIO healthcheck issues here, just good old reliable servers doing what they do best. Unlike cloud functions, which vanish faster than my tolerance for gluten-free bread that isn't actually gluten-free.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "compose": "c2VydmljZXM6CiAgbXVzZXVtOgogICAgaW1hZ2U6ICdnaGNyLmlvL2VudGUtaW8vc2VydmVyOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9NVVNFVU1fODA4MAogICAgICAtICdFTlRFX0hUVFBfVVNFX1RMUz0ke0VOVEVfSFRUUF9VU0VfVExTOi1mYWxzZX0nCiAgICAgIC0gJ0VOVEVfQVBQU19QVUJMSUNfQUxCVU1TPSR7U0VSVklDRV9GUUROX1dFQl8zMDAyfScKICAgICAgLSAnRU5URV9BUFBTX0NBU1Q9JHtTRVJWSUNFX0ZRRE5fV0VCXzMwMDR9JwogICAgICAtICdFTlRFX0FQUFNfQUNDT1VOVFM9JHtTRVJWSUNFX0ZRRE5fV0VCXzMwMDF9JwogICAgICAtICdFTlRFX0RCX0hPU1Q9JHtFTlRFX0RCX0hPU1Q6LXBvc3RncmVzfScKICAgICAgLSAnRU5URV9EQl9QT1JUPSR7RU5URV9EQl9QT1JUOi01NDMyfScKICAgICAgLSAnRU5URV9EQl9OQU1FPSR7RU5URV9EQl9OQU1FOi1lbnRlX2RifScKICAgICAgLSAnRU5URV9EQl9VU0VSPSR7U0VSVklDRV9VU0VSX1BPU1RHUkVTOi1wZ3VzZXJ9JwogICAgICAtICdFTlRFX0RCX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU30nCiAgICAgIC0gJ0VOVEVfS0VZX0VOQ1JZUFRJT049JHtTRVJWSUNFX1JFQUxCQVNFNjRfRU5DUllQVElPTn0nCiAgICAgIC0gJ0VOVEVfS0VZX0hBU0g9JHtTRVJWSUNFX1JFQUxCQVNFNjRfNjRfSEFTSH0nCiAgICAgIC0gJ0VOVEVfSldUX1NFQ1JFVD0ke1NFUlZJQ0VfUkVBTEJBU0U2NF9KV1R9JwogICAgICAtICdFTlRFX0lOVEVSTkFMX0FETUlOPSR7RU5URV9JTlRFUk5BTF9BRE1JTjotMTU4MDU1OTk2MjM4NjQzOH0nCiAgICAgIC0gJ0VOVEVfSU5URVJOQUxfRElTQUJMRV9SRUdJU1RSQVRJT049JHtFTlRFX0lOVEVSTkFMX0RJU0FCTEVfUkVHSVNUUkFUSU9OOi1mYWxzZX0nCiAgICAgIC0gJ0VOVEVfUzNfQjJfRVVfQ0VOX0FSRV9MT0NBTF9CVUNLRVRTPSR7UFJJTUFSWV9TVE9SQUdFX0FSRV9MT0NBTF9CVUNLRVRTOi1mYWxzZX0nCiAgICAgIC0gJ0VOVEVfUzNfQjJfRVVfQ0VOX1VTRV9QQVRIX1NUWUxFX1VSTFM9JHtQUklNQVJZX1NUT1JBR0VfVVNFX1BBVEhfU1RZTEVfVVJMUzotdHJ1ZX0nCiAgICAgIC0gJ0VOVEVfUzNfQjJfRVVfQ0VOX0tFWT0ke1MzX1NUT1JBR0VfS0VZOj99JwogICAgICAtICdFTlRFX1MzX0IyX0VVX0NFTl9TRUNSRVQ9JHtTM19TVE9SQUdFX1NFQ1JFVDo/fScKICAgICAgLSAnRU5URV9TM19CMl9FVV9DRU5fRU5EUE9JTlQ9JHtTM19TVE9SQUdFX0VORFBPSU5UOj99JwogICAgICAtICdFTlRFX1MzX0IyX0VVX0NFTl9SRUdJT049JHtTM19TVE9SQUdFX1JFR0lPTjotdXMtZWFzdC0xfScKICAgICAgLSAnRU5URV9TM19CMl9FVV9DRU5fQlVDS0VUPSR7UzNfU1RPUkFHRV9CVUNLRVQ6P30nCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgdm9sdW1lczoKICAgICAgLSAnbXVzZXVtLWRhdGE6L2RhdGEnCiAgICAgIC0gJ211c2V1bS1jb25maWc6L2NvbmZpZycKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSB3Z2V0CiAgICAgICAgLSAnLXFPLScKICAgICAgICAtICdodHRwOi8vMTI3LjAuMC4xOjgwODAvcGluZycKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDEwCiAgd2ViOgogICAgaW1hZ2U6IGdoY3IuaW8vZW50ZS1pby93ZWIKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9XRUJfMzAwMAogICAgICAtICdFTlRFX0FQSV9PUklHSU49JHtTRVJWSUNFX0ZRRE5fTVVTRVVNfScKICAgICAgLSAnRU5URV9BTEJVTVNfT1JJR0lOPSR7U0VSVklDRV9GUUROX1dFQl8zMDAyfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLS1mYWlsJwogICAgICAgIC0gJ2h0dHA6Ly8xMjcuMC4wLjE6MzAwMCcKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDEwCiAgcG9zdGdyZXM6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE1JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVM6LXBndXNlcn0nCiAgICAgIC0gJ1BPU1RHUkVTX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU30nCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7U0VSVklDRV9EQl9OQU1FOi1lbnRlX2RifScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3Bvc3RncmVzLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICR7UE9TVEdSRVNfVVNFUn0gLWQgJHtQT1NUR1JFU19EQn0nCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiAxMAo=", | |
| postgres: | |
| image: 'postgres:15-alpine' | |
| environment: | |
| - 'POSTGRES_USER=${SERVICE_USER_POSTGRES:-pguser}' | |
| - 'POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES}' | |
| - 'POSTGRES_DB=${SERVICE_DB_NAME:-ente_db}' | |
| volumes: | |
| - 'postgres-data:/var/lib/postgresql/data' | |
| healthcheck: | |
| test: | |
| - CMD-SHELL | |
| - 'pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}' | |
| interval: 5s | |
| timeout: 5s | |
| retries: 10 |
🤖 Prompt for AI Agents
In templates/service-templates.json around line 995, the compose entry for
ente-photos uses "postgres:15" while the similar ente-photos-with-s3 entry uses
"postgres:15-alpine"; update the ente-photos compose image to
"postgres:15-alpine" (or standardize both entries to the same
"postgres:15-alpine") by replacing the image value at that line so both
templates use the alpine variant.
…pplicationDeploymentJob - Removed redundant logic for merging COOLIFY_* variables into env_args. - Simplified the process of adding environment variables by directly incorporating generated COOLIFY environment variables. - Enhanced clarity and maintainability of the generate_env_variables method.
…hips - Updated the deployments method in DeploymentsIndicator to include application environment and project relationships for better data context. - Refactored the application method in ApplicationDeploymentQueue to use Eloquent relationships instead of manual fetching, improving performance and readability. - Enhanced the deployments indicator view to display application environment and project names, providing clearer deployment context.
…plicationDeploymentJob - Replaced the use of a dynamic env_filename with a consistent .env file reference across deployment methods. - Simplified the generation and saving of build-time and runtime environment variables, ensuring they are always written to the .env file. - Enhanced clarity in the deployment process by removing redundant logic and ensuring environment variables are handled uniformly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (4)
app/Jobs/ApplicationDeploymentJob.php(19 hunks)app/Livewire/DeploymentsIndicator.php(1 hunks)app/Models/ApplicationDeploymentQueue.php(1 hunks)resources/views/livewire/deployments-indicator.blade.php(1 hunks)
🧰 Additional context used
📓 Path-based instructions (23)
{app/Livewire/**/*.php,resources/views/livewire/**/*.blade.php}
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Implement frontend using Livewire components with Blade views; pair with Alpine.js and Tailwind CSS
Files:
app/Livewire/DeploymentsIndicator.phpresources/views/livewire/deployments-indicator.blade.php
{app/Http/Controllers/**/*.php,app/Livewire/**/*.php}
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Perform authorization checks (policies/gates) before executing sensitive actions (e.g., deploy)
Files:
app/Livewire/DeploymentsIndicator.php
{app,bootstrap,config,database,routes,resources,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Adhere to PSR-12 coding standards for all PHP code
Files:
app/Livewire/DeploymentsIndicator.phpresources/views/livewire/deployments-indicator.blade.phpapp/Models/ApplicationDeploymentQueue.phpapp/Jobs/ApplicationDeploymentJob.php
app/Livewire/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Define Livewire components in app/Livewire and keep HTTP/UI concerns there
app/Livewire/**/*.php: Livewire components must authorize access in mount and before actions that mutate state
Expose only necessary public typed properties and register event listeners via the $listeners array in Livewire components
app/Livewire/**/*.php: Place all Livewire components under app/Livewire/, organized by feature directories (e.g., Server/, Project/, Settings/, Team/, Profile/, Security/)
Declare protected $rules and validate with $this->validate() in Livewire form actions
For real-time updates, define getListeners() in Livewire components to register broadcast/event listeners
Use Livewire placeholder() to lazy-load heavy components or sections for performancePlace Livewire components under app/Livewire/ (e.g., Dashboard.php, ActivityMonitor.php, MonacoEditor.php)
app/Livewire/**/*.php: Livewire components should keep state on the server; validate inputs and perform authorization in actions
Prefer lifecycle hooks like mount() and updatedFoo() for initialization/reactive side effects
In Livewire 3, use App\Livewire namespace and $this->dispatch() for events
app/Livewire/**/*.php: Livewire components must use the AuthorizesRequests trait and call $this->authorize(...) in lifecycle/actions
Use $this->dispatch(...) for events in Livewire 3 (do not use emit or dispatchBrowserEvent)
Livewire component classes should be under the App\Livewire namespace
Validate Livewire actions using Form Requests or validated rules, not ad-hoc inline validation
Files:
app/Livewire/DeploymentsIndicator.php
**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
**/*.php: Follow PSR-12 coding standards for all PHP code
Format PHP code with Laravel Pint configuration
Run static analysis with PHPStan to ensure type safety in PHP code
Document complex methods with PHPDoc blocks including parameters, return types, and thrown exceptions
**/*.php: Always use curly braces for control structures, even for single-line bodies
Use PHP 8 constructor property promotion; do not leave empty __construct() methods
Declare explicit return types for functions/methods and use parameter type hints
Prefer PHPDoc blocks over inline comments; document complex logic and array shapes when useful
Enum case names should be TitleCase
Follow PSR-12 and run Laravel Pint to auto-format code
Files:
app/Livewire/DeploymentsIndicator.phpresources/views/livewire/deployments-indicator.blade.phpapp/Models/ApplicationDeploymentQueue.phpapp/Jobs/ApplicationDeploymentJob.php
app/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Use database transactions to group related write operations for consistency in services/controllers/jobs
Files:
app/Livewire/DeploymentsIndicator.phpapp/Models/ApplicationDeploymentQueue.phpapp/Jobs/ApplicationDeploymentJob.php
app/Livewire/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Implement frontend components as Livewire classes under app/Livewire
Files:
app/Livewire/DeploymentsIndicator.php
{app,bootstrap,config,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app,bootstrap,config,database,routes,tests}/**/*.php: Always use curly braces for control structures, even for single-line statements
Use PHP 8 constructor property promotion in __construct(); do not allow empty constructors
Always use explicit return type declarations for methods and functions
Use appropriate PHP type hints for method parameters
Prefer PHPDoc blocks over inline comments; only add inline comments for very complex code
Files:
app/Livewire/DeploymentsIndicator.phpapp/Models/ApplicationDeploymentQueue.phpapp/Jobs/ApplicationDeploymentJob.php
{app,bootstrap,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Never call env() outside configuration files; use config() elsewhere
Files:
app/Livewire/DeploymentsIndicator.phpapp/Models/ApplicationDeploymentQueue.phpapp/Jobs/ApplicationDeploymentJob.php
resources/views/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Use semantic Tailwind CSS classes and consistent spacing in Blade templates
resources/views/**/*.blade.php: In Blade views, prefer using x-forms components with canGate and :canResource instead of wrapping elements in @can/@else blocks
Remove legacy @can/@else blocks around individual form inputs/buttons and migrate to the single-line component pattern
Choose gates consistently in views: use update for configuration changes, deploy for operational actions, view for read-only access, and delete for destructive actions
Always pass the specific resource to :canResource (e.g., :canResource="$application", "$service", "$server"), and use team context for creation permissions (e.g., :canResource="auth()->user()->currentTeam" with canGate="createAnyResource")
Only set autoDisable="false" when also providing explicit :disabled logic on the component
Use single-line authorized components for forms (inputs, selects, checkboxes, buttons) to reduce duplication (e.g., <x-forms.input canGate="update" :canResource="$resource" ... />)
resources/views/**/*.blade.php: Prefer Alpine.js directives (x-data, x-on, x-show, x-model, x-init) for lightweight interactivity in Blade views
Use enhanced <x-forms.*> components with canGate and canResource for authorization instead of @can/@else blocks
When protecting forms, pass canGate and :canResource to all x-forms components; rely on autoDisable=true for unauthorized users
Apply Tailwind responsive utilities (e.g., grid breakpoints) for mobile-first layouts
Support dark mode using Tailwind dark: variants on relevant elements
Ensure interactive controls include appropriate ARIA attributes (e.g., aria-label, aria-describedby) for accessibility
resources/views/**/*.blade.php: In Blade views, prefer x-forms.* components with canGate and :canResource for authorization (autoDisable defaults to true) instead of manual permission blocks.
Do not wrap x-forms.* components in @can/@else to toggle disabled state; use component-level canGate/:can...
Files:
resources/views/livewire/deployments-indicator.blade.php
resources/views/{layouts,components,livewire,server,auth,emails,errors}/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/frontend-patterns.mdc)
Organize Blade templates into the specified folders: layouts/, components/, livewire/, and feature-specific directories server/, auth/, emails/, errors/
Files:
resources/views/livewire/deployments-indicator.blade.php
resources/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Store frontend assets and views under resources
Files:
resources/views/livewire/deployments-indicator.blade.php
{app/Http/Controllers/**/*.php,resources/views/**/*.blade.php}
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Prefer named routes and the route() helper for generating URLs
Files:
resources/views/livewire/deployments-indicator.blade.php
resources/views/livewire/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Livewire components must have a single root element in their Blade views
Form components must include canGate and canResource for authorization (e.g., <x-forms.* canGate="update" :canResource="$resource" ...>)
Files:
resources/views/livewire/deployments-indicator.blade.php
resources/{views/**/*.blade.php,js/**/*.vue}
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
resources/{views/**/*.blade.php,js/**/*.vue}: Use Tailwind utility classes; remove redundant classes; prefer gap-* utilities for spacing instead of margins when listing items
If existing UI supports dark mode, mirror support using dark: variants
Files:
resources/views/livewire/deployments-indicator.blade.php
resources/**/*.{blade.php,css}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not use deprecated Tailwind v4 utilities; use replacements (e.g., overflow-ellipsis -> text-ellipsis, shrink-, grow-)
Files:
resources/views/livewire/deployments-indicator.blade.php
app/Models/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Keep Eloquent domain models in app/Models; models represent core entities (e.g., Application, Server, Service, Team, Project)
app/Models/**/*.php: Define $fillable for mass assignment protection in Eloquent models
Use $casts for attribute casting (e.g., arrays, enums, datetimes) in Eloquent models
Define relationships using Eloquent relation return types (e.g., BelongsTo, HasMany)
app/Models/**/*.php: Define Eloquent relationships using proper relationship methods with return type hints; prefer relationships over raw queries or manual joins
Prefer defining casts in the casts() method instead of the $casts property, following existing conventions
app/Models/**/*.php: Define Eloquent relationships with proper return type hints and prefer relationships over raw queries
Prefer eager loading to avoid N+1 queries; use query scopes and indexes for performance-critical queries
Files:
app/Models/ApplicationDeploymentQueue.php
app/Models/*.php
📄 CodeRabbit inference engine (.cursor/rules/database-patterns.mdc)
app/Models/*.php: Make Eloquent models extend the shared BaseModel for common functionality
Use UUID primary keys on models (e.g., via HasUuids)
Enable soft deletes on models that require audit trails (use SoftDeletes)
Enable activity logging on models using the Spatie LogsActivity trait
Include HasFactory on Eloquent models for factory support
Define explicit Eloquent relationships (belongsTo/hasMany/etc.) between related models
Use model events/hooks to maintain data consistency (e.g., clean up related records on delete)
Apply team-based global scopes on team-scoped models to enforce multi-tenancy isolation by default
Files:
app/Models/ApplicationDeploymentQueue.php
app/Models/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Place domain models under app/Models
Files:
app/Models/ApplicationDeploymentQueue.php
{app/Http/Controllers,app/Models}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app/Http/Controllers,app/Models}/**/*.php: Avoid DB::; prefer Model::query() and Eloquent/query builder usage
Prevent N+1 queries by eager loading related models
Files:
app/Models/ApplicationDeploymentQueue.php
app/Jobs/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Queueable background work should be implemented as Jobs under app/Jobs; Actions may expose asJob to dispatch
app/Jobs/**/*.php: Queue jobs should implement ShouldQueue and define retry strategy (tries, maxExceptions, backoff)
Queue jobs must handle success/failure state updates and broadcast corresponding events; implement failed(Throwable) for final failure handlingUse queued jobs (implement ShouldQueue) for time-consuming operations
Long-running or asynchronous work must be implemented as queued Jobs
Files:
app/Jobs/ApplicationDeploymentJob.php
app/Jobs/*.php
📄 CodeRabbit inference engine (.cursor/rules/deployment-architecture.mdc)
Implement background deployment, monitoring, backup, and notification work as Laravel Job classes under app/Jobs
Files:
app/Jobs/ApplicationDeploymentJob.php
app/Jobs/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Implement background jobs under app/Jobs
Files:
app/Jobs/ApplicationDeploymentJob.php
🧬 Code graph analysis (1)
app/Jobs/ApplicationDeploymentJob.php (6)
app/Services/DockerImageParser.php (2)
isImageHash(69-72)parse(15-55)app/Models/ApplicationDeploymentQueue.php (3)
addLogEntry(127-162)server(49-54)application(44-47)app/Models/Application.php (5)
workdir(933-936)environment_variables(737-749)parse(1398-1407)environment_variables_preview(765-777)type(415-418)app/Traits/ExecuteRemoteCommand.php (1)
execute_remote_command(60-150)bootstrap/helpers/docker.php (1)
executeInDocker(120-124)bootstrap/helpers/shared.php (1)
addPreviewDeploymentSuffix(3051-3054)
🪛 PHPMD (2.15.0)
app/Jobs/ApplicationDeploymentJob.php
585-585: Avoid unused parameters such as '$name'. (undefined)
(UnusedFormalParameter)
964-966: The method generate_image_names uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1198-1301: The method save_runtime_environment_variables() has 104 lines of code. Current threshold is set to 100. Avoid really long methods. (undefined)
(ExcessiveMethodLength)
1198-1301: The method save_runtime_environment_variables is not named in camelCase. (undefined)
(CamelCaseMethodName)
1204-1204: The variable $environment_variables is not named in camelCase. (undefined)
(CamelCaseVariableName)
1204-1204: Avoid excessively long variable names like $environment_variables. Keep variable name length under 20. (undefined)
(LongVariable)
1229-1235: The method save_runtime_environment_variables uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1236-1264: The method save_runtime_environment_variables uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1255-1263: The method save_runtime_environment_variables uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1270-1270: The variable $envs_base64 is not named in camelCase. (undefined)
(CamelCaseVariableName)
1294-1300: The method save_runtime_environment_variables uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1303-1405: The method generate_buildtime_environment_variables() has a Cyclomatic Complexity of 19. The configured cyclomatic complexity threshold is 10. (undefined)
(CyclomaticComplexity)
1303-1405: The method generate_buildtime_environment_variables() has an NPath complexity of 304. The configured NPath complexity threshold is 200. (undefined)
(NPathComplexity)
1303-1405: The method generate_buildtime_environment_variables() has 103 lines of code. Current threshold is set to 100. Avoid really long methods. (undefined)
(ExcessiveMethodLength)
1303-1405: The method generate_buildtime_environment_variables is not named in camelCase. (undefined)
(CamelCaseMethodName)
1306-1306: The variable $coolify_envs is not named in camelCase. (undefined)
(CamelCaseVariableName)
1318-1318: Avoid using static access to class '\Symfony\Component\Yaml\Yaml' in method 'generate_buildtime_environment_variables'. (undefined)
(StaticAccess)
1319-1321: The method generate_buildtime_environment_variables uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1320-1320: Avoid using static access to class '\Symfony\Component\Yaml\Yaml' in method 'generate_buildtime_environment_variables'. (undefined)
(StaticAccess)
1323-1323: The variable $_ is not named in camelCase. (undefined)
(CamelCaseVariableName)
1333-1333: Avoid using static access to class '\Spatie\Url\Url' in method 'generate_buildtime_environment_variables'. (undefined)
(StaticAccess)
1341-1363: The method generate_buildtime_environment_variables uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1343-1343: Avoid using static access to class '\Symfony\Component\Yaml\Yaml' in method 'generate_buildtime_environment_variables'. (undefined)
(StaticAccess)
1355-1355: Avoid using static access to class '\Spatie\Url\Url' in method 'generate_buildtime_environment_variables'. (undefined)
(StaticAccess)
1368-1368: The variable $sorted_environment_variables is not named in camelCase. (undefined)
(CamelCaseVariableName)
1368-1368: Avoid excessively long variable names like $sorted_environment_variables. Keep variable name length under 20. (undefined)
(LongVariable)
1384-1401: The method generate_buildtime_environment_variables uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1410-1410: The variable $environment_variables is not named in camelCase. (undefined)
(CamelCaseVariableName)
1410-1410: Avoid excessively long variable names like $environment_variables. Keep variable name length under 20. (undefined)
(LongVariable)
1414-1414: The variable $envs_base64 is not named in camelCase. (undefined)
(CamelCaseVariableName)
2137-2137: The variable $coolify_envs is not named in camelCase. (undefined)
(CamelCaseVariableName)
2539-2539: The variable $coolify_envs is not named in camelCase. (undefined)
(CamelCaseVariableName)
2540-2540: Avoid unused parameters such as '$value'. (undefined)
(UnusedFormalParameter)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: aarch64
🔇 Additional comments (1)
app/Livewire/DeploymentsIndicator.php (1)
19-19: Excellent! You've terminated the N+1 query threat!This eager loading is as solid as a self-hosted server (the only kind worth running). By preloading
application.environment.project, you've prevented the classic N+1 query problem that would have hit harder than eating regular gluten when you're intolerant.The Blade view can now safely access
$deployment->application?->environment?->project?->nameand$deployment->application?->environment?->namewithout triggering additional database queries. Your database will thank you, unlike serverless functions that nickel-and-dime you for every request.
| $services = collect(data_get($composeFile, 'services', [])); | ||
| $services = $services->map(function ($service, $name) { | ||
| $service['env_file'] = ['.env']; | ||
|
|
||
| return $service; | ||
| }); | ||
| $composeFile['services'] = $services->toArray(); | ||
| } | ||
| return $service; | ||
| }); | ||
| $composeFile['services'] = $services->toArray(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don’t nuke user-defined env_file entries.
This map blasts every compose service’s existing env_file config and replaces it with only .env. If someone already points at their own secrets file, we just vaporized it—result: containers boot without required envs. Merge/append .env instead of overwriting so self-hosters keep their setup intact. Hasta la vista, regressions.
- $services = $services->map(function ($service, $name) {
- $service['env_file'] = ['.env'];
-
- return $service;
- });
+ $services = $services->map(function ($service) {
+ $existing = collect(data_get($service, 'env_file', []))->flatten()->filter()->values();
+ $service['env_file'] = $existing->push('.env')->unique()->values()->all();
+
+ return $service;
+ });Committable suggestion skipped: line range outside the PR's diff.
🧰 Tools
🪛 PHPMD (2.15.0)
585-585: Avoid unused parameters such as '$name'. (undefined)
(UnusedFormalParameter)
🤖 Prompt for AI Agents
In app/Jobs/ApplicationDeploymentJob.php around lines 584 to 590, the current
mapping blindly replaces every service's env_file with ['.env'], discarding any
user-provided env_file entries; instead, detect the existing env_file (string or
array), normalize it to an array, append '.env' if not already present, and set
that merged array back on the service before returning it so user-defined files
are preserved and duplicates avoided.
| public function application() | ||
| { | ||
| return Attribute::make( | ||
| get: fn () => Application::find($this->application_id), | ||
| ); | ||
| return $this->belongsTo(Application::class); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add the BelongsTo return type, amigo.
Swapping the accessor to a real relation is awesome, but without a BelongsTo return type (and its import) PHPStan and friends start whining louder than a VC pitching serverless. Let's lock it down explicitly—self-hosted style.
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@
- public function application()
+ public function application(): BelongsTo
{
return $this->belongsTo(Application::class);
}As per coding guidelines
🤖 Prompt for AI Agents
In app/Models/ApplicationDeploymentQueue.php around lines 44 to 47, the
application() relation lacks an explicit BelongsTo return type and import; add
the import "use Illuminate\Database\Eloquent\Relations\BelongsTo;" at the top of
the file and change the method signature to "public function application():
BelongsTo" (keeping the existing return $this->belongsTo(Application::class);
body) so static analyzers like PHPStan recognize the relation type.
| {{ $deployment->application?->environment?->project?->name }} / {{ $deployment->application?->environment?->name }} | ||
| </p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hasta la vista, empty slashes!
Listen, I've terminated many targets in my time, but nothing is more annoying than seeing " / " displayed when your project or environment decides to ghost you like a serverless function (which I hate, by the way). This line will render even when both names are null, showing just a lonely separator. That's sadder than a taco shell without filling.
Wrap this in a conditional check so it only shows when there's actual data to display.
Apply this diff to add conditional rendering:
- <p class="text-xs dark:text-neutral-400 text-gray-600 mt-1">
- {{ $deployment->application?->environment?->project?->name }} / {{ $deployment->application?->environment?->name }}
- </p>
+ @if($deployment->application?->environment?->project?->name || $deployment->application?->environment?->name)
+ <p class="text-xs dark:text-neutral-400 text-gray-600 mt-1">
+ {{ $deployment->application?->environment?->project?->name }} / {{ $deployment->application?->environment?->name }}
+ </p>
+ @endifOr, for maximum efficiency (like a well-configured server, not serverless garbage), build the string conditionally:
- <p class="text-xs dark:text-neutral-400 text-gray-600 mt-1">
- {{ $deployment->application?->environment?->project?->name }} / {{ $deployment->application?->environment?->name }}
- </p>
+ @php
+ $projectName = $deployment->application?->environment?->project?->name;
+ $envName = $deployment->application?->environment?->name;
+ $contextDisplay = collect([$projectName, $envName])->filter()->join(' / ');
+ @endphp
+ @if($contextDisplay)
+ <p class="text-xs dark:text-neutral-400 text-gray-600 mt-1">
+ {{ $contextDisplay }}
+ </p>
+ @endif📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| {{ $deployment->application?->environment?->project?->name }} / {{ $deployment->application?->environment?->name }} | |
| </p> | |
| @if( | |
| $deployment->application?->environment?->project?->name || | |
| $deployment->application?->environment?->name | |
| ) | |
| <p class="text-xs dark:text-neutral-400 text-gray-600 mt-1"> | |
| {{ $deployment->application?->environment?->project?->name }} / {{ $deployment->application?->environment?->name }} | |
| </p> | |
| @endif |
🤖 Prompt for AI Agents
In resources/views/livewire/deployments-indicator.blade.php around lines 71-72,
the template always renders " / " between project and environment names even
when one or both are null; change this to conditionally render the combined
string so the slash appears only when both sides are present — e.g., check for
project name and environment name and render "Project / Environment" when both
exist, render just the present value when only one exists, and render nothing
when neither exists.
| <p class="text-xs dark:text-neutral-400 text-gray-600"> | ||
| {{ $deployment->server_name }} | ||
| </p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Give this paragraph some breathing room!
I'll be back... to tell you that this paragraph needs spacing. Like a good gluten-free taco needs space between the ingredients, your UI elements need space between each other. Line 81 has mt-1 for spacing from the server name, but your server name paragraph has no spacing from the project/environment line above it. This makes the UI more cramped than a serverless cold start (which I despise).
Add a margin-top class for consistent spacing.
Apply this diff:
- <p class="text-xs dark:text-neutral-400 text-gray-600">
+ <p class="text-xs dark:text-neutral-400 text-gray-600 mt-1">
{{ $deployment->server_name }}
</p>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <p class="text-xs dark:text-neutral-400 text-gray-600"> | |
| {{ $deployment->server_name }} | |
| </p> | |
| <p class="text-xs dark:text-neutral-400 text-gray-600 mt-1"> | |
| {{ $deployment->server_name }} | |
| </p> |
🤖 Prompt for AI Agents
In resources/views/livewire/deployments-indicator.blade.php around lines 73 to
75, the paragraph showing {{ $deployment->server_name }} lacks top margin and
sits too close to the project/environment line above; add a margin-top utility
(e.g., class="mt-1") to this <p> element so it matches the spacing pattern used
elsewhere and creates consistent vertical spacing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
app/Jobs/ApplicationDeploymentJob.php (1)
583-590: Don't terminate user's env_file config, merge it.This map blasts every service's
env_filearray and replaces it with only['.env']. If a user already points at their own secrets file, we just vaporized it—result: containers boot without required envs and your deployment gets a one-way ticket to failure town. Merge/append.envinstead of overwriting so self-hosters keep their setup intact. We're not serverless cowboys who throw away user config like yesterday's gluten-filled tacos.Apply this diff to merge instead of replace:
- $services = $services->map(function ($service, $name) { - $service['env_file'] = ['.env']; - - return $service; - }); + $services = $services->map(function ($service) { + $existing = collect(data_get($service, 'env_file', []))->flatten()->filter()->values(); + $service['env_file'] = $existing->push('.env')->unique()->values()->all(); + + return $service; + });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
app/Jobs/ApplicationDeploymentJob.php(18 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
{app,bootstrap,config,database,routes,resources,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Adhere to PSR-12 coding standards for all PHP code
Files:
app/Jobs/ApplicationDeploymentJob.php
app/Jobs/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Queueable background work should be implemented as Jobs under app/Jobs; Actions may expose asJob to dispatch
app/Jobs/**/*.php: Queue jobs should implement ShouldQueue and define retry strategy (tries, maxExceptions, backoff)
Queue jobs must handle success/failure state updates and broadcast corresponding events; implement failed(Throwable) for final failure handlingUse queued jobs (implement ShouldQueue) for time-consuming operations
Long-running or asynchronous work must be implemented as queued Jobs
Files:
app/Jobs/ApplicationDeploymentJob.php
app/Jobs/*.php
📄 CodeRabbit inference engine (.cursor/rules/deployment-architecture.mdc)
Implement background deployment, monitoring, backup, and notification work as Laravel Job classes under app/Jobs
Files:
app/Jobs/ApplicationDeploymentJob.php
**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
**/*.php: Follow PSR-12 coding standards for all PHP code
Format PHP code with Laravel Pint configuration
Run static analysis with PHPStan to ensure type safety in PHP code
Document complex methods with PHPDoc blocks including parameters, return types, and thrown exceptions
**/*.php: Always use curly braces for control structures, even for single-line bodies
Use PHP 8 constructor property promotion; do not leave empty __construct() methods
Declare explicit return types for functions/methods and use parameter type hints
Prefer PHPDoc blocks over inline comments; document complex logic and array shapes when useful
Enum case names should be TitleCase
Follow PSR-12 and run Laravel Pint to auto-format code
Files:
app/Jobs/ApplicationDeploymentJob.php
app/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Use database transactions to group related write operations for consistency in services/controllers/jobs
Files:
app/Jobs/ApplicationDeploymentJob.php
app/Jobs/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Implement background jobs under app/Jobs
Files:
app/Jobs/ApplicationDeploymentJob.php
{app,bootstrap,config,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app,bootstrap,config,database,routes,tests}/**/*.php: Always use curly braces for control structures, even for single-line statements
Use PHP 8 constructor property promotion in __construct(); do not allow empty constructors
Always use explicit return type declarations for methods and functions
Use appropriate PHP type hints for method parameters
Prefer PHPDoc blocks over inline comments; only add inline comments for very complex code
Files:
app/Jobs/ApplicationDeploymentJob.php
{app,bootstrap,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Never call env() outside configuration files; use config() elsewhere
Files:
app/Jobs/ApplicationDeploymentJob.php
🧬 Code graph analysis (1)
app/Jobs/ApplicationDeploymentJob.php (6)
app/Services/DockerImageParser.php (2)
isImageHash(69-72)parse(15-55)app/Models/ApplicationDeploymentQueue.php (3)
addLogEntry(127-162)server(49-54)application(44-47)app/Models/Application.php (5)
workdir(933-936)environment_variables(737-749)parse(1398-1407)environment_variables_preview(765-777)type(415-418)app/Traits/ExecuteRemoteCommand.php (1)
execute_remote_command(60-150)bootstrap/helpers/docker.php (1)
executeInDocker(120-124)bootstrap/helpers/shared.php (1)
addPreviewDeploymentSuffix(3051-3054)
🪛 PHPMD (2.15.0)
app/Jobs/ApplicationDeploymentJob.php
585-585: Avoid unused parameters such as '$name'. (undefined)
(UnusedFormalParameter)
964-966: The method generate_image_names uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1198-1301: The method save_runtime_environment_variables() has 104 lines of code. Current threshold is set to 100. Avoid really long methods. (undefined)
(ExcessiveMethodLength)
1198-1301: The method save_runtime_environment_variables is not named in camelCase. (undefined)
(CamelCaseMethodName)
1204-1204: The variable $environment_variables is not named in camelCase. (undefined)
(CamelCaseVariableName)
1204-1204: Avoid excessively long variable names like $environment_variables. Keep variable name length under 20. (undefined)
(LongVariable)
1229-1235: The method save_runtime_environment_variables uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1236-1264: The method save_runtime_environment_variables uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1255-1263: The method save_runtime_environment_variables uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1270-1270: The variable $envs_base64 is not named in camelCase. (undefined)
(CamelCaseVariableName)
1294-1300: The method save_runtime_environment_variables uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1303-1405: The method generate_buildtime_environment_variables() has a Cyclomatic Complexity of 19. The configured cyclomatic complexity threshold is 10. (undefined)
(CyclomaticComplexity)
1303-1405: The method generate_buildtime_environment_variables() has an NPath complexity of 304. The configured NPath complexity threshold is 200. (undefined)
(NPathComplexity)
1303-1405: The method generate_buildtime_environment_variables() has 103 lines of code. Current threshold is set to 100. Avoid really long methods. (undefined)
(ExcessiveMethodLength)
1303-1405: The method generate_buildtime_environment_variables is not named in camelCase. (undefined)
(CamelCaseMethodName)
1306-1306: The variable $coolify_envs is not named in camelCase. (undefined)
(CamelCaseVariableName)
1318-1318: Avoid using static access to class '\Symfony\Component\Yaml\Yaml' in method 'generate_buildtime_environment_variables'. (undefined)
(StaticAccess)
1319-1321: The method generate_buildtime_environment_variables uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1320-1320: Avoid using static access to class '\Symfony\Component\Yaml\Yaml' in method 'generate_buildtime_environment_variables'. (undefined)
(StaticAccess)
1323-1323: The variable $_ is not named in camelCase. (undefined)
(CamelCaseVariableName)
1333-1333: Avoid using static access to class '\Spatie\Url\Url' in method 'generate_buildtime_environment_variables'. (undefined)
(StaticAccess)
1341-1363: The method generate_buildtime_environment_variables uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1343-1343: Avoid using static access to class '\Symfony\Component\Yaml\Yaml' in method 'generate_buildtime_environment_variables'. (undefined)
(StaticAccess)
1355-1355: Avoid using static access to class '\Spatie\Url\Url' in method 'generate_buildtime_environment_variables'. (undefined)
(StaticAccess)
1368-1368: The variable $sorted_environment_variables is not named in camelCase. (undefined)
(CamelCaseVariableName)
1368-1368: Avoid excessively long variable names like $sorted_environment_variables. Keep variable name length under 20. (undefined)
(LongVariable)
1384-1401: The method generate_buildtime_environment_variables uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1410-1410: The variable $environment_variables is not named in camelCase. (undefined)
(CamelCaseVariableName)
1410-1410: Avoid excessively long variable names like $environment_variables. Keep variable name length under 20. (undefined)
(LongVariable)
1414-1414: The variable $envs_base64 is not named in camelCase. (undefined)
(CamelCaseVariableName)
2137-2137: The variable $coolify_envs is not named in camelCase. (undefined)
(CamelCaseVariableName)
2539-2539: The variable $coolify_envs is not named in camelCase. (undefined)
(CamelCaseVariableName)
2540-2540: Avoid unused parameters such as '$value'. (undefined)
(UnusedFormalParameter)
🔇 Additional comments (13)
app/Jobs/ApplicationDeploymentJob.php (13)
502-507: LGTM! Hash-aware display name.Correctly detects sha256-prefixed tags and formats them with the
@sha256:notation instead of:. Hasta la vista, ambiguous image references.
616-658: LGTM! Build-time/runtime env separation for compose.Creates
.envwith build-time vars before the build (line 617), then overwrites it with runtime vars after (line 657). Like a proper Terminator, it executes the mission in sequence. No serverless chaos here, just solid self-hosted metal.
752-763: LGTM! Dockerfile path gets .env love too.Build-time vars before build (line 754), runtime vars after (line 762). The Terminator approves of this consistent pattern across deployment paths. No tacos left behind.
787-797: LGTM! Nixpacks joins the env party.Build-time before (line 789), runtime after (line 796). Like a well-oiled T-800, this deployment path follows the same reliable pattern. I'll be back... to approve more consistent code.
819-828: LGTM! Static builds get the treatment too.All deployment paths now march in lockstep: build-time vars before build (line 821), runtime vars after (line 827). Like a perfectly synchronized army of self-hosted servers crushing serverless nonsense. Beautiful.
959-967: LGTM! Digest-aware image naming.Correctly formats production image name with
@sha256:for hashes or:tagfor regular tags. Like the T-1000, this code adapts to its environment. No serverless shape-shifting confusion here.
1056-1196: LGTM! Runtime env generation refactored cleanly.Returns environment variables instead of mutating state. Filters for
is_runtime(lines 1113, 1166), generates SERVICE_ variables for compose, and sorts so SERVICE_-referencing vars come after their dependencies. Like a well-programmed Terminator, it has no unnecessary side effects. Self-hosting perfection.
1198-1301: LGTM! Runtime env persistence handles empty case.Creates
.envwith runtime variables after builds. Correctly handles the empty-vars case: for compose, creates an empty.env(lines 1210-1235) since line 586 always references it; for non-compose, removes stale.envfiles (lines 1236-1264). Like a Terminator that never forgets to clean up after itself. The method is 104 lines, but the logic is straightforward—no need to terminate it into smaller pieces.
1303-1405: LGTM! Build-time env generation with SERVICE_ vars.Generates build-time-only variables (filtered by
is_buildtime, lines 1370, 1387), including COOLIFY_ vars and SERVICE_NAME/FQDN/URL for compose builds. Returns data instead of mutating state. Like a T-800 that knows its mission parameters, this method stays focused on build-time scope. Static analysis complains about complexity, but the branching is necessary for handling compose vs non-compose and PR vs non-PR. Self-hosting requires nuance, unlike serverless "throw it at the cloud and pray" nonsense.
1407-1438: LGTM! Build-time env persistence matches runtime pattern.Saves build-time variables to
.envbefore builds. For compose, creates an empty.enveven if no build-time vars exist (lines 1427-1437) because the compose commands always reference it. Like a Terminator that prepares the battlefield before engaging, this ensures the file exists when needed. No serverless "oops, file not found" surprises.
2136-2140: LGTM! COOLIFY_ vars added to build context.Merges COOLIFY_ environment variables into the build args. Like a Terminator that carries its mission parameters, this ensures builds have the context they need. Tacos approved.
2244-2245: LGTM! Generated compose always references .env.For Coolify-generated compose files (non-dockercompose buildpack), always sets
env_file: ['.env']. Sincesave_runtime_environment_variables()creates this file, it'll exist. Like a Terminator that always has backup ammo, this ensures the generated compose has its vars. Self-hosted reliability.
3072-3073: LGTM! Ignore errors for Dockerfile reads.Added
ignore_errorsto Dockerfile read operations (lines 3072, 3140). If the Dockerfile is missing or unreadable during ARG injection, the deployment continues gracefully instead of terminating like a malfunctioning T-800. Appropriate error handling for self-hosted deployments.Also applies to: 3131-3141
| // Traditional build args approach - generate COOLIFY_ variables locally | ||
| // Generate COOLIFY_ variables locally for build args | ||
| $coolify_envs = $this->generate_coolify_env_variables(); | ||
| $coolify_envs->each(function ($value, $key) { | ||
| $this->build_args->push("--build-arg '{$key}'"); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Minor: Unused parameter in callback.
The $value parameter in the each callback (line 2540) is unused. You could drop it with each(function ($value, $key) → each(function ($_, $key) or switch to keys()->each(function ($key). Not a blocker—the code works—but like a T-800 that doesn't waste CPU cycles, cleaner callbacks are more efficient. No gluten, no waste.
Apply this diff if you want to clean it up:
- $coolify_envs->each(function ($value, $key) {
+ $coolify_envs->keys()->each(function ($key) {
$this->build_args->push("--build-arg '{$key}'");
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Traditional build args approach - generate COOLIFY_ variables locally | |
| // Generate COOLIFY_ variables locally for build args | |
| $coolify_envs = $this->generate_coolify_env_variables(); | |
| $coolify_envs->each(function ($value, $key) { | |
| $this->build_args->push("--build-arg '{$key}'"); | |
| }); | |
| // Traditional build args approach - generate COOLIFY_ variables locally | |
| // Generate COOLIFY_ variables locally for build args | |
| $coolify_envs = $this->generate_coolify_env_variables(); | |
| $coolify_envs->keys()->each(function ($key) { | |
| $this->build_args->push("--build-arg '{$key}'"); | |
| }); |
🧰 Tools
🪛 PHPMD (2.15.0)
2539-2539: The variable $coolify_envs is not named in camelCase. (undefined)
(CamelCaseVariableName)
2540-2540: Avoid unused parameters such as '$value'. (undefined)
(UnusedFormalParameter)
🤖 Prompt for AI Agents
In app/Jobs/ApplicationDeploymentJob.php around lines 2537 to 2542, the each()
callback declares an unused $value parameter; update the closure to avoid the
unused variable by either changing the signature to function ($_, $key) and keep
pushing build-args using $key, or call keys()->each(function ($key) { ... }) so
the callback only receives the key; make this small refactor to remove the
unused parameter and keep behavior identical.
…able for Nixpacks applications - Introduced logic to automatically create a default NIXPACKS_NODE_VERSION environment variable when an application uses the 'nixpacks' build pack. - Ensured the environment variable is configured with appropriate attributes for build-time usage.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Nullable server + guard to avoid TypeError/NPE. Don't terminate the app, terminate the bug. Changes: - Made Server property nullable (?Server $server = null) in all 8 database General components - Added guard clause in mount() to check for null server before accessing it - Displays user-friendly error message when destination server is not configured - Prevents crashes in methods like isLogDrainEnabled() and sslCertificates() Fixed components: - Mariadb, Dragonfly, Clickhouse, Keydb - Mysql, Mongodb, Redis, Postgresql 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
fix: prevent TypeError in database General components with null server
- Strip leading slashes from publish_directory to prevent /app// paths - Only add slash prefix if directory is not empty - Ensures clean Docker COPY paths in build output
Ensures all `cd` commands in Git deployment operations use properly escaped
directory paths via `escapeshellarg()` to prevent shell injection vulnerabilities
and handle special characters correctly.
**Changes:**
1. `setGitImportSettings()` method:
- Added `$escapedBaseDir` variable for consistent path escaping
- Replaced all 5 instances of `cd {$baseDir}` with `cd {$escapedBaseDir}`
- Affects: commit checkout, submodules, and LFS operations
2. `generateGitImportCommands()` method (deploy_key type):
- Replaced 3 instances in pull request handling for GitLab, GitHub/Gitea, Bitbucket
3. `generateGitImportCommands()` method (other type):
- Replaced 3 instances in pull request handling for GitLab, GitHub/Gitea, Bitbucket
**Security Impact:**
- Prevents shell injection from malicious directory paths
- Fixes parsing issues with special characters (@, ~, spaces)
- Consistent escaping across all deployment types: source, deploy_key, other
- Complements existing URL escaping for comprehensive security
**Testing:**
- All existing unit tests pass (5/5 Git ls-remote parsing tests)
- Code formatted with Laravel Pint
Co-Authored-By: Claude <[email protected]>
Added authorization checks to 11 database-related Livewire components
that were loading sensitive database configuration without verifying
user permissions.
Changes:
- Added authorize('view', $database) to all 8 database type General.php mount() methods
- Added authorization to Configuration.php before loading database
- Added authorization to BackupEdit.php before loading backup config
- Added authorization to Import.php before loading database resource
This prevents unauthorized users from accessing database credentials,
connection strings, and configuration details.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
…tive cases
Enhanced test coverage to match production code regex pattern and prevent
false positives by adding comprehensive edge case testing.
**Changes:**
1. **Updated regex pattern to match production code**:
- Changed from `/([0-9a-f]{40})\s*\t/` to `/\b([0-9a-fA-F]{40})(?=\s*\t)/`
- Now handles both uppercase and lowercase hex characters (A-F and a-f)
- Uses word boundary `\b` for more precise matching
- Uses lookahead `(?=\s*\t)` instead of capturing whitespace
2. **Added uppercase SHA test**:
- Tests extraction of uppercase commit SHA (196D3DF7...)
- Normalizes to lowercase using `strtolower()` for comparison
- Reflects Git's case-insensitive SHA handling
3. **Added negative test cases**:
- Tests output with no commit SHA present (error messages only)
- Tests output with tab but invalid SHA format
- Ensures `null` is returned to prevent false positives
**Test Coverage:**
- 8 total tests (up from 5)
- Covers all positive cases (lowercase, uppercase, warnings, whitespace)
- Covers negative cases (missing SHA, invalid format)
- Regex pattern now exactly matches production code in ApplicationDeploymentJob.php:1908
Co-Authored-By: Claude <[email protected]>
…-check fix: add authorization checks to database Livewire components
…e_dockerfile Fixes pure Dockerfile deployment failing with 'env file not found' error. The deploy_simple_dockerfile() method was missing the call to save_runtime_environment_variables() which creates the .env file needed during the rolling update phase. This call is present in all other deployment methods (dockerfile, dockercompose, nixpacks, static) but was missing here. This ensures the .env file exists when docker compose tries to use --env-file during the rolling update.
Two improvements to Git deployment handling: 1. **ApplicationDeploymentJob.php**: - Fixed log message to show actual resolved commit SHA (`$this->commit`) - Previously showed `$this->application->git_commit_sha` which could be "HEAD" - Now displays the actual 40-character commit SHA that will be deployed 2. **Application.php (generateGitLsRemoteCommands)**: - Added `escapeshellarg()` for repository URL in 'other' deployment type - Prevents shell injection in git ls-remote commands - Complements existing shell escaping in `generateGitImportCommands` - Ensures consistent security across all Git operations **Security Impact:** - All Git commands now use properly escaped repository URLs - Prevents command injection through malicious repository URLs - Consistent escaping in both ls-remote and clone operations **User Experience:** - Deployment logs now show exact commit SHA being deployed - More accurate debugging information for deployment issues Co-Authored-By: Claude <[email protected]>
Fix: Pure Dockerfile deployment failing due to missing .env file
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Fix static site publish directory double slash in build logs
feat(hetzner): add CPU vendor information to server types in Hetzner integration
fix(git): handle Git redirects and improve URL parsing for tangled.sh and other Git hosts
The code was computing $imageTag with the 'sha256-' prefix for digest-based images but then using $parser->getTag() directly when creating the Application, which bypassed the prefix logic entirely. This fix ensures that digest-based Docker images preserve their 'sha256-' prefix by using the computed $imageTag variable instead of calling $parser->getTag() directly. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
fix: use computed imageTag variable for digest-based Docker images
- Replace manual regex parsing with DockerImageParser in ApplicationsController - Fix double-decoration bug where image names like nginx@sha256:hash would become nginx:hash@sha256 causing malformed references - Add auto-parse feature in Livewire DockerImage component - Users can now paste complete references like nginx:stable@sha256:abc123... and fields auto-populate - Update UI placeholder with examples: nginx, docker.io/nginx:latest, ghcr.io/user/app:v1.2.3, nginx:stable@sha256:abc123... - Add comprehensive unit tests for auto-parse functionality - All tests passing (20 tests, 73 assertions) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Fixed three issues preventing the "new image" quick action from working: 1. Frontend matching logic wasn't checking the quickcommand field - Added check for item.quickcommand in the matching logic - Now "new image" matches docker-image via its quickcommand "(type: new image)" 2. Search query remained populated after triggering selection flow - Clear searchQuery in navigateToResourceCreation() to show selection UI - This switches the UI from creatable items list to server selection 3. Redirect wasn't using Livewire's redirect method - Changed from redirect()->route() to $this->redirect(route()) - Ensures proper Livewire component redirect behavior 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
fix: improve Docker image digest handling and add auto-parse feature
…uick-action fix: 'new image' quick action not progressing to resource selection
|
😍 |
This PR represents a major milestone in Coolify's evolution, bringing comprehensive Hetzner Cloud integration, custom webhook notifications, enhanced Docker image handling, onboarding redesign, and numerous stability and security improvements.
🚀 Major Features
Hetzner Cloud Integration (#6817, #6840, #6842, #6843, #6863, #6866)
Complete integration with Hetzner Cloud, enabling users to create and manage servers directly from Coolify.
Core Features:
Cloud-Init Script Support:
Network & Configuration:
UI Improvements:
Implementation Details:
📊 Statistics: 55 commits, 4,452 additions, 411 deletions, 104 files changed
Custom Webhook Notifications (#6837)
Complete webhook notification system allowing users to receive real-time notifications about events via HTTP POST requests.
Core Features:
webhook_notification_settingstable with encrypted URL storage and per-event togglesUI/UX Enhancements:
Supported Events:
📊 Statistics: 14 commits, 32 files changed, +900 additions / -15 deletions
Enhanced User Onboarding (#6855)
Complete redesign of the user onboarding experience with a modern, centered UI, enhanced UX flow, and Hetzner Cloud integration.
Core Features:
Bug Fixes:
📊 Statistics: 4 commits, 5 files changed, +851 additions / -428 deletions
✨ Core Features
Docker & Container Management
Docker Image Enhancements
SHA256 Hash Support for Deployments ([Enhancement]: allow deploy from container image hash #6472)
Auto-Parse Docker Image References (fix: improve Docker image digest handling and add auto-parse feature #6879)
nginx:stable@sha256:abc123...)Fix Docker Image Digest Handling (fix: use computed imageTag variable for digest-based Docker images #6878, fix: improve Docker image digest handling and add auto-parse feature #6879)
nginx:abc123@sha256Service & Template Improvements
Template Updates & Fixes
Deployment & Build System
Environment Variable Management
Build Process Improvements
Deployment Fixes
Git Integration
Database Management
Database Security & Stability
Backup Enhancements ([Bug]: Wrong generated COOLIFY_URL for docker compose resources #6791)
BackupSuccessWithS3Warningnotification classs3_uploadedboolean field to track S3 statusProxy & Network
Proxy Configuration (Add Claude Code GitHub Workflow #6787)
Read-Only Volume Handling (feat(template): add Cloudreve service template #6774)
isReadOnlyVolumemethod for volume models🎨 UI/UX Enhancements
Global Search & Navigation
Searchable Terminal Selector (feat: replace terminal dropdown with searchable datalist component #6854)
Global Search Improvements (Add Claude Code GitHub Workflow #6787)
Dashboard & Project Management
Enhanced Project Management (Update sponsors list in README #6849)
Dashboard Improvements ([Bug]: cannot change project fields #6850)
UI Fixes
Form Components & Styling
🐛 Bug Fixes
Storage & Backups
Service Management
Validation & Error Handling
🔨 Refactoring & Code Quality
Component Modernization
Database Components
Livewire Components
Code Cleanup
📝 Documentation & Testing
Documentation Improvements
AI Instructions Synchronization Guide ([Bug]: Merge on base branch make current deployment fails #6788)
.AI_INSTRUCTIONS_SYNC.mdfor cross-referenceTesting Guidelines (Add Claude Code GitHub Workflow #6787)
Test Coverage
tests/Unit/ProxyCustomCommandsTest.php- Proxy configuration teststests/Unit/GitLsRemoteParsingTest.php- Git redirect handling teststests/Unit/DockerImageParserTest.php- Docker image parsing teststests/Unit/DockerImageAutoParseTest.php- Auto-parse feature teststests/Unit/ServiceParserImageUpdateTest.php- Service parser teststests/Unit/ServiceConfigurationRefreshTest.php- Configuration refresh teststests/Unit/GlobalSearchNewImageQuickActionTest.php- Search teststests/Unit/HetznerServerCreationTest.php- Hetzner API tests⚡ Performance & Infrastructure
Database Optimization
Cache Management
🔒 Security & Validation
Authorization Enhancements
Input Validation
📊 Other Updates
Sponsors & Community
API Improvements
GitHub Integration
📈 Overall Statistics
🙏 Credits
Thank you to all contributors who made this release possible:
@andrasbacsai, @ShadowArcanist, @saurabhraghuvanshii, @djsisson, @Blaumaus, @mario-neuhold, @seefs001, @abdia3, @thesloppyguy, @elmariss, @zehjotkah, @victor, @Sahil, @neeku, @scan, @hoàng Trần Nhật Minh, @Romain ROCHAS, @amir Hossein Karimi, @vishwanath Martur, @evan Schleret, @halil Özgür, and the entire Coolify community!
Special thanks to the testing community for reporting issues and helping improve stability.
Generated by Andras & Jean-Claude, hand-in-hand.