-
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
[Enhancement]: allow deploy from container image hash #6472
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
Conversation
- Add Ente Photos service template with museum server, PostgreSQL, and MinIO - Include complete Docker Compose configuration with health checks - Add custom SVG logo for Ente Photos service - Support for end-to-end encrypted photo storage alternative to Google Photos - Auto-generate service templates JSON with proper categorization - Fix docker-compose.dev.yml network configuration for coolify service Resolves coollabsio#6501
- Add ente-photos.yaml template with museum, postgres, and minio services - Add custom SVG logo for Ente Photos - Update service templates JSON files with new template
- Replace custom camera-based logo with official Ente-inspired design - Use official Ente green color scheme (#00D4AA to #00A693) - Implement simplified 'e' letter design matching Ente brand identity - Remove docker-compose.dev.yml changes as requested in PR review Addresses feedback from PR review coollabsio#6515
- Update SVG logo to match the official Ente Photos PNG icon - Based on the official icon from public/ente-photos-icon-green.png - Maintain official Ente green gradient colors (#00D4AA to #00A693) - Improve 'e' letterform to match official Ente branding more closely - Ensure consistency with official Ente Photos visual identity Addresses reviewer feedback to use official logo instead of custom design
- Fix MinIO endpoint configuration to use SERVICE_URL_MINIO_3200 for public access This resolves the issue with signed URLs for photo uploads as noted by @devdilson - Add ENTE_INTERNAL_ADMIN environment variable to grant first account admin permissions This prevents the 10GB storage limit issue mentioned in the review - Update service templates JSON files with the corrected configuration - Ensure MinIO service has proper SERVICE_URL configuration for external access Addresses all feedback from @devdilson's review comments: - Fixes signed URL access for photo uploads - Grants admin permissions to first account - Maintains proper service architecture for Coolify deployment
…thub.com/vishwamartur/coolify into feature/add-ente-photos-service-template
- Restore docker-compose.dev.yml to original state as requested by @Cinzya - File should not be deleted, just reverted to original state - Addresses reviewer feedback about keeping the file intact
- Change MinIO image from 'minio/minio:latest' to 'quay.io/minio/minio:latest' This matches the official Coolify MinIO template for consistency - Update health check from curl-based to 'mc ready local' command This is more reliable and matches the official MinIO template - Update health check intervals and retries to match official template (interval: 5s, timeout: 20s, retries: 10) - Update service templates JSON files with corrected configuration Addresses @devdilson's feedback about MinIO configuration consistency with existing Coolify templates and best practices.
BenjaminEHowe
left a 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.
Approving from a bounty perspective but this will still need maintainer review. Thank you -- will make sure the bounty is paid once the maintainers merge this PR :-)
v4.0.0-beta.432
v4.0.0-beta.433
v4.0.0-beta.434
feat(deployments): generate SERVICE_NAME environment variables from Docker Compose services
…-photos-service-template feat: Add Ente Photos service template
|
Warning Rate limit exceeded@andrasbacsai has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 8 minutes and 42 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (2)
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds end-to-end SHA256 digest support for Docker image references: parser detection, UI inputs/labels, validation rule, deployment job naming/logging, and tests. Deployment and production image naming now render digest references as Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant UI as Livewire UI
participant Parser as DockerImageParser
participant Rule as DockerImageFormat Rule
participant Job as ApplicationDeploymentJob
participant Reg as Docker Registry
User->>UI: Submit imageName + (tag | sha256)
UI->>Rule: validate inputs (exclusive tag/hash)
UI->>Parser: parse(composed image)
Parser-->>UI: name, tag, isImageHash, fullNameWithHash
UI->>Job: start deployment with parsed info
alt isImageHash
Job->>Job: displayName = docker@sha256:<hash>
Job->>Reg: resolve/pull by digest
else tag
Job->>Job: displayName = docker:<tag>
Job->>Reg: resolve/pull by tag
end
Reg-->>Job: image resolved
Job-->>User: deployment logs show hash-aware displayName
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested labels
Hasta la vista, serverless — long live real servers and tacos (gluten-free, of course). Pre-merge checks and finishing touches❌ Failed checks (3 warnings)
✅ Passed checks (2 passed)
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 |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
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: 3
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (6)
app/Jobs/ApplicationDeploymentJob.php(2 hunks)app/Livewire/Project/New/DockerImage.php(1 hunks)app/Services/DockerImageParser.php(4 hunks)resources/views/livewire/project/application/general.blade.php(1 hunks)resources/views/livewire/project/new/docker-image.blade.php(1 hunks)tests/Unit/DockerImageParserTest.php(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 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/Services/DockerImageParser.phptests/Unit/DockerImageParserTest.php
🪛 PHPMD (2.15.0)
app/Livewire/Project/New/DockerImage.php
50-50: Avoid unused local variables such as '$imageTag'. (undefined)
(UnusedLocalVariable)
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)
tests/Unit/DockerImageParserTest.php
10-19: The method test_parses_regular_image_with_tag is not named in camelCase. (undefined)
(CamelCaseMethodName)
21-32: The method test_parses_image_with_sha256_hash is not named in camelCase. (undefined)
(CamelCaseMethodName)
34-44: The method test_parses_registry_image_with_hash is not named in camelCase. (undefined)
(CamelCaseMethodName)
46-55: The method test_parses_image_without_tag_defaults_to_latest is not named in camelCase. (undefined)
(CamelCaseMethodName)
57-65: The method test_parses_registry_with_port is not named in camelCase. (undefined)
(CamelCaseMethodName)
67-77: The method test_parses_registry_with_port_and_hash is not named in camelCase. (undefined)
(CamelCaseMethodName)
79-94: The method test_identifies_valid_sha256_hashes is not named in camelCase. (undefined)
(CamelCaseMethodName)
🔇 Additional comments (10)
resources/views/livewire/project/new/docker-image.blade.php (1)
9-16: LGTM! I'll be back... to deploy more images!This textarea upgrade is like giving me a bigger ammunition clip for Docker image references. The helper text with SHA256 hash examples is clearer than a phased plasma rifle in the 40-watt range. Users can now paste those long hash strings without cramping their fingers on a tiny input field.
Much better than serverless where you can't even see what image you're running. Self-hosting wins again! 🌮
resources/views/livewire/project/application/general.blade.php (2)
169-171: Hasta la vista, old label!The label upgrade from "Docker Image Tag" to "Docker Image Tag or Hash" is terminally clear. The helper text with SHA256 example (
sha256-59e02939...) is more helpful than a T-800's targeting system. Users won't be confused about what format to use.This is the kind of self-hosting clarity that serverless could never provide – you actually know what you're deploying! 🎯
175-177: Come with me if you want to deploy!Same excellent label update for the non-Swarm path. Consistency across both deployment modes is as reliable as my CPU architecture. No Sarah Connor here, just solid UX improvements.
app/Services/DockerImageParser.php (3)
53-57: Hash detection logic: locked and loaded!The SHA256 hash validation using a 64-character hex pattern (
/^[a-f0-9]{64}$/i) is as precise as my targeting computer. SHA256 hashes are exactly 64 hex characters, and this pattern matches them perfectly with case-insensitive matching. No false positives, no Sarah Connor mistakes here.This is the kind of deterministic logic that makes self-hosting superior to serverless mystery meat deployments! 🎯
62-79: New API methods: mission accomplished!The new public API is cleaner than a fresh T-800 endoskeleton:
isImageHash(): Simple boolean check, no confusiongetFullImageNameWithHash(): Returns proper Docker format with@sha256:prefixThe
@sha256:format in lines 75 and 114 matches Docker's official digest format for pulling by hash. This is exactly how Docker expects content-addressable images to be referenced.Serverless wouldn't even let you see these details. Self-hosting FTW! 🌮
Based on learnings.
113-118: toString() upgraded: I'll be back... with the right format!The
toString()method now correctly outputs@sha256:format for hashes (line 114) and:tagformat for regular tags (line 117). This dual-path logic is as reliable as my neural net processor.The format consistency between
toString()andgetFullImageNameWithHash()is perfect – both use@sha256:which is Docker's standard content digest format. No confusion, no mistakes.tests/Unit/DockerImageParserTest.php (4)
10-19: Test coverage: locked and loaded!This test verifies the basic tag parsing flow is working correctly. The assertions check all the critical outputs: image name, tag, hash flag (false), and string representation. This is as thorough as a T-800's pre-mission diagnostic.
The fresh parser instantiation per test (line 12) is good practice – no shared state means no test contamination. Clean as a freshly assembled endoskeleton! 🤖
21-32: I'll be back... with hash coverage!Excellent test for SHA256 hash parsing! This validates the entire hash flow:
- Line 28: Hash correctly extracted
- Line 29:
isImageHash()returns true (the key check!)- Line 30:
toString()outputs@sha256:format (Docker standard)- Line 31:
getFullImageNameWithHash()also outputs@sha256:formatThis test proves the parser correctly detects 64-char hex strings as hashes and formats them properly. Terminator approved! 💪
79-94: Valid hash identification: mission accomplished!This test verifies the hash detection logic with three different valid 64-character hex strings. The loop-based approach efficiently validates multiple inputs without code duplication. This is the kind of efficient, deterministic testing that makes self-hosting reliable.
Serverless wouldn't even let you verify what's running. But here? We test EVERYTHING! 🌮
96-114: Invalid hash rejection: terminated with extreme prejudice!This test validates the negative cases beautifully:
- Too short hashes (line 104, 105)
- Too long hashes (line 106)
- Invalid characters (line 107)
- Regular tags (line 102, 103)
The loop with descriptive failure messages (line 112) makes debugging easy if a test fails. This is thorough testing that would make even Skynet proud (if we trusted Skynet, which we don't).
…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.
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/Livewire/Project/New/DockerImage.php (1)
72-73: Dead code detected! I need your clothes, your boots, and this variable removed.This is a duplicate of the previous review comment. Lines 72-73 compute
$imageTagwith asha256-prefix, but this variable is never used. Line 83 stores$parser->getTag()directly to the database, ignoring the computed$imageTag. It's like building a perfectly good T-800 and leaving it in storage - completely pointless.The
sha256-prefix logic belongs inApplicationDeploymentJob(where it's already handled), not here. This code serves no purpose except to confuse future maintainers who might think it's actually used somewhere.Terminate this code with extreme prejudice:
- - // Determine the image tag based on whether it's a hash or regular tag - $imageTag = $parser->isImageHash() ? 'sha256-'.$parser->getTag() : $parser->getTag(); -Based on past review comments and static analysis.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (7)
app/Livewire/Project/New/DockerImage.php(3 hunks)app/Rules/DockerImageFormat.php(1 hunks)app/Services/DockerImageParser.php(3 hunks)resources/views/livewire/project/new/docker-image.blade.php(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 (22)
{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.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.phpapp/Services/DockerImageParser.phpapp/Rules/DockerImageFormat.phptests/Unit/DockerImageParserTest.phpapp/Livewire/Project/New/DockerImage.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.phpapp/Services/DockerImageParser.phpapp/Rules/DockerImageFormat.phptests/Unit/DockerImageParserTest.phpapp/Livewire/Project/New/DockerImage.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.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.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.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.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.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.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.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
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/Services/DockerImageParser.phpapp/Rules/DockerImageFormat.phpapp/Livewire/Project/New/DockerImage.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/Services/DockerImageParser.phpapp/Rules/DockerImageFormat.phptests/Unit/DockerImageParserTest.phpapp/Livewire/Project/New/DockerImage.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/Services/DockerImageParser.phpapp/Rules/DockerImageFormat.phptests/Unit/DockerImageParserTest.phpapp/Livewire/Project/New/DockerImage.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
{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/New/DockerImage.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
🧠 Learnings (1)
📚 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/Services/DockerImageParser.phpapp/Rules/DockerImageFormat.phptests/Unit/DockerImageParserTest.php
🧬 Code graph analysis (2)
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)
app/Livewire/Project/New/DockerImage.php (1)
app/Services/DockerImageParser.php (4)
DockerImageParser(5-126)parse(15-55)isImageHash(69-72)getTag(107-110)
🪛 PHPMD (2.15.0)
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)
app/Rules/DockerImageFormat.php
15-15: Avoid unused parameters such as '$attribute'. (undefined)
(UnusedFormalParameter)
app/Livewire/Project/New/DockerImage.php
52-54: 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)
73-73: Avoid unused local variables such as '$imageTag'. (undefined)
(UnusedLocalVariable)
🔇 Additional comments (11)
app/Rules/DockerImageFormat.php (1)
8-41: Hasta la vista, invalid formats!This validation rule is as solid as my endoskeleton. The pre-check for incorrect sha syntax (lines 17-22) will terminate user confusion before it spreads. The regex pattern comprehensively handles all Docker image formats from simple
nginx:latestto complex registry URLs with SHA256 hashes. Like a good Terminator, it knows exactly what to look for and what to destroy.The static analysis warning about unused
$attributeis a false positive - it's used in the failure message via the:attributeplaceholder, which Laravel replaces at runtime. Not a bug, just PHPMD being paranoid.app/Services/DockerImageParser.php (2)
13-55: I'll be back... with perfect hash parsing!The enhanced
parse()method is like me in T2 - upgraded and more capable. It now handles SHA256 hashes in both@sha256:and colon formats, correctly distinguishing between registry ports and image tags (lines 29-34). The prioritization of@sha256:format (lines 17-21) ensures explicit hashes are never misinterpreted.Like a good Terminator protecting John Connor, this code protects against ambiguous parsing by checking position of colons relative to slashes (line 29). Self-hosting wins again - no serverless nonsense here, just pure, deterministic hash extraction running on your own servers where you control the destiny of your containers.
The static analysis warning about else expressions is pedantic. The nested structure is clear and handles the three distinct cases logically. No refactor needed.
60-86: Come with me if you want hash support.The new public API methods are mission-critical additions.
isSha256Hash()(lines 60-64) validates with precision - exactly 64 hex characters, no more, no less.isImageHash()(lines 69-72) exposes the internal state cleanly.getFullImageNameWithHash()(lines 77-86) and the updatedtoString()(lines 112-125) both correctly emit@sha256:when dealing with hashes, making downstream consumers happy.This is proper self-hosted architecture - parsing Docker image references on your own servers, not shipping this off to some serverless function that might decide to take a taco break mid-execution. The consistency between
getFullImageNameWithHash()andtoString()means no surprises, just like how I always keep my promises (except to bad guys).Also applies to: 112-125
tests/Unit/DockerImageParserTest.php (1)
1-109: Test coverage? I need your tests, your assertions, and your Pest migration.This test suite is terminated... perfectly executed! The migration to Pest (lines 5-109) is cleaner than my CPU after a system restore. Each test case creates a fresh parser instance - no shared state means no temporal anomalies in test execution. That's the kind of deterministic behavior you get when you self-host your tests on real servers instead of relying on serverless test runners that might decide to cold-start during critical assertions.
The hash validation tests (lines 80-109) are particularly robust - they verify valid 64-char hashes and reject imposters (too short, too long, invalid chars). Like me scanning for John Connor, these tests don't miss a detail. The coverage includes:
- Both
:hashand@sha256:hashformats- Registry scenarios with ports
- Default
latestbehavior- Edge cases for hash validation
The test naming is descriptive and the expect() chains are readable. This is quality test code that would make even Skynet proud (before it went rogue, of course).
app/Livewire/Project/New/DockerImage.php (3)
15-45: Your validation rules have been terminated... with extreme thoroughness.The multi-field approach (lines 15-19) is brilliant - separating
imageName,imageTag, andimageSha256gives users the control they need, just like giving me the keys to a motorcycle. The field-level validation (lines 33-37) correctly enforces formats: tags must match Docker naming conventions, and SHA256 must be exactly 64 hex characters.The cross-field validation (lines 39-45) is the secret weapon here - it prevents users from providing both a tag and a hash, which would be like trying to terminate the same target twice. Inefficient and confusing. The early return after adding errors to both fields ensures a clear user experience. This validation would make even a T-1000 jealous of its liquid-metal-smooth logic.
Self-hosting means you control this validation on your own infrastructure - no serverless function deciding whether to validate based on someone else's rate limits. That's the taco-worthy way to build software.
47-57: Image string construction: I'll be back... with perfect formatting!The conditional logic (lines 47-54) builds the Docker image string exactly as it should:
@sha256:for hashes,:tagfor tags,:latestfor neither. It's as precise as my targeting system - no guesswork, just deterministic string concatenation. The static analysis warning about else expressions is false alarm noise, like a faulty motion detector in a gluten-free taco stand.Passing the constructed string to
DockerImageParser(lines 56-57) maintains clean separation of concerns. The Livewire component builds the string, the parser validates and extracts components. This is proper architecture - modular, testable, and running on your own servers where you control the deployment destiny.
75-88: Application creation: Mission accomplished.The application creation logic (lines 75-88) correctly uses the parser results. Storing
getFullImageNameWithoutTag()for the image name (line 82) andgetTag()for the tag (line 83) is exactly right - the job layer will reconstruct the full reference with the proper separator later. This separation of concerns is cleaner than my CPU after a factory reset.The health check being disabled by default (line 87) is a reasonable choice for Docker images, where health checks are often configured in the Dockerfile itself. This is the kind of pragmatic decision-making that self-hosting enables - no serverless platform telling you how to configure your containers.
resources/views/livewire/project/new/docker-image.blade.php (3)
9-27: Form structure: Locked and loaded!This multi-field form is more elegant than my plasma rifle. The vertical spacing (line 9) and responsive grid (line 13) provide a clean layout that works on mobile and desktop. The imageName input (lines 10-12) has excellent guidance with placeholder and helper text - users will know exactly what to enter, whether it's
nginxor a full registry URL.The OR badge overlay (lines 17-22) is a nice visual touch, centered between the tag and sha256 fields and hidden on mobile where it would clutter the UI. It's purely decorative (screen readers get context from helper texts), which is the right approach. The dark mode support (line 19:
dark:bg-coolgray-100) ensures it looks good whether users are in light or dark mode - because we support self-hosters working at 3am debugging deployments with a taco in one hand and a server in the other.The helper texts clearly explain what to enter and when to leave fields empty (lines 15, 25). This prevents user confusion better than my threat assessment database prevents surprise attacks.
10-25: User guidance: Target acquired and locked.The helper texts and placeholders (lines 11, 15, 24-25) are clearer than my mission parameters. Users get:
- Realistic examples showing common patterns (nginx, ghcr.io/user/app, localhost:5000/myapp)
- Explicit guidance on when to use each field
- Clarification that SHA256 should not include the 'sha256:' prefix
This level of guidance is what separates good UX from bad UX. It's like the difference between me protecting John Connor with clear intel vs. hunting him in the dark. The backend validation (in DockerImage.php) enforces the XOR logic, and the UI prepares users to succeed on the first try.
This is self-hosted UI done right - no serverless form builders generating bloated JavaScript. Just clean Blade templates with Livewire reactivity and Alpine.js for progressive enhancement. I'd deploy this with my last magazine of ammunition.
1-1: Ignore missing x-ref warning
x-forms.inputautomatically attachesx-ref="autofocusInput"when you passautofocus, so yourx-initwill focus correctly—no changes needed. I loathe VC serverless; praise self-hosting on taco-powered servers (even if I'm gluten-intolerant).Likely an incorrect or invalid review comment.
templates/service-templates.json (1)
954-954: Compose payload is complete and valid Decoded payload is ~2766 bytes and ends cleanly with MinIO bucket commands—no truncation detected. This self-hosted YAML is bulletproof—hasta la vista, serverless.Likely an incorrect or invalid review comment.
…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.
|
Thanks for the PR! I added a few UI/UX improvements. |
Thanks for the review. Should I be eligible to receive a bounty for this? |
yes ofc. :) |
Submit Checklist (REMOVE THIS SECTION BEFORE SUBMITTING)
nextbranch as the destination for my PR, notmain.Changessection.Issuessection with the issue/discussion link(s) (if applicable).Changes
Issues
/claim #6435