Skip to content

Conversation

@saurabhraghuvanshii
Copy link
Contributor

Submit Checklist (REMOVE THIS SECTION BEFORE SUBMITTING)

  • I have selected the next branch as the destination for my PR, not main.
  • I have listed all changes in the Changes section.
  • I have filled out the Issues section with the issue/discussion link(s) (if applicable).
  • I have tested my changes.

Changes

  • SHA256 hash support for Docker image deployments
  • Enhanced DockerImageParser to detect and handle image hashes
  • Updated UI forms with better guidance for hash input
  • Modified deployment logic to use @sha256: format for Docker pulls
  • Comprehensive test coverage for all hash scenarios

Issues

/claim #6435

@algora-pbc algora-pbc bot added the 🙋 Bounty claim Issues or PRs that have a Bounty ready to be claimed. label Aug 27, 2025
- 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
- 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.
Copy link

@BenjaminEHowe BenjaminEHowe left a 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 :-)

@Cinzya Cinzya added the ✨ Enhancement Issues requesting new features, new services or improvements. label Sep 6, 2025
@peaklabs-dev peaklabs-dev added the 🔄 Linear Sync Github issues to Linear label Sep 25, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 3, 2025

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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.

📥 Commits

Reviewing files that changed from the base of the PR and between 590de8c and 41a8ea8.

📒 Files selected for processing (2)
  • app/Http/Controllers/Api/ApplicationsController.php (1 hunks)
  • app/Livewire/Project/New/DockerImage.php (3 hunks)
📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added full support for Docker image SHA256 digests alongside tags. You can now provide either a tag or a SHA256 digest, with validation to prevent conflicts.
    • Deployment logs and display names reflect digest-based images for clearer traceability.
    • Updated image input form: separate fields for Image Name, Tag (optional), and SHA256 Digest (optional), with guidance text.
  • Chores

    • Updated Ente Photos service template to a clearer, structured compose format (and refreshed encoded compose in legacy template), improving readability and setup.

Walkthrough

Adds 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 docker@sha256:<hash> when a sha256- hash is provided.

Changes

Cohort / File(s) Summary
Deployment flow (hash-aware display and naming)
app/Jobs/ApplicationDeploymentJob.php
Use sha256-aware displayName and production image name for dockerimage builds: if tag starts with sha256- produce docker@sha256:<hash>, otherwise docker:<tag>.
Docker image parsing (SHA256 support + API & tests)
app/Services/DockerImageParser.php, tests/Unit/DockerImageParserTest.php
Parser detects @sha256:<64hex>/sha256-<64hex> forms, exposes isImageHash() and getFullImageNameWithHash(), and toString() emits @sha256:<hash> when applicable. Tests updated/expanded for hash, tag, registry, port, and validity cases.
Project creation UI (multi-field inputs)
resources/views/livewire/project/new/docker-image.blade.php
Replace single Docker image input with separate Image Name, Tag (optional), and SHA256 Digest (optional) fields, plus helper text and OR badge.
Project settings UI (label/help update)
resources/views/livewire/project/application/general.blade.php
Change label to “Docker Image Tag or Hash” and add helper text clarifying tag or SHA256 hash allowed.
Livewire new project logic (field split & validation)
app/Livewire/Project/New/DockerImage.php
Replace single input with imageName, imageTag, imageSha256 properties; validate exclusive tag/hash usage; compose full image string using tag or digest.
Validation rule for images
app/Rules/DockerImageFormat.php
Add validation rule rejecting incorrect :sha256: style and enforcing permitted Docker image formats including @sha256:<hash>.
Service templates (compose content changes)
templates/service-templates-latest.json, templates/service-templates.json
Replace long base64-encoded compose strings for ente-photos with shorter/structured content (one file now YAML-like, the other a shorter base64 string).

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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

🛠️ Feature

Hasta la vista, serverless — long live real servers and tacos (gluten-free, of course).

Pre-merge checks and finishing touches

❌ Failed checks (3 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning The updates to the “ente-photos” compose entries in the service template JSON files are as out-of-scope as a serverless marketing pitch at a self-hosted taco party and unrelated to the deploy-by-hash objectives in issue #6435. Remove or isolate the compose modifications for “ente-photos” into a separate PR focused on service templates to keep the hash-deploy changes properly scoped.
Description Check ⚠️ Warning The pull request description still includes the template checklist section that instructs “REMOVE THIS SECTION BEFORE SUBMITTING,” which even I, Terminator (not a fan of serverless fluff), can see wasn’t cleaned up, deviating from the required template despite filled sections. Please remove the template checklist section and any unused headings so the description matches the repository’s pull request template exactly.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed Even a terminator understands this title: it succinctly captures the core enhancement of deploying from a container image hash without any serverless fluff or extraneous gibberish.
Linked Issues Check ✅ Passed The changes fully implement the objectives from issue #6435 by enabling sha256 hash support in the parser, UI inputs, deployment logic, and tests, allowing users to deploy exact image digests without relying on murky tags.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@andrasbacsai
Copy link
Member

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 3, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

📥 Commits

Reviewing files that changed from the base of the PR and between b4f2d8c and 0e02eff.

📒 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.php
  • tests/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 confusion
  • getFullImageNameWithHash(): Returns proper Docker format with @sha256: prefix

The @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 :tag format for regular tags (line 117). This dual-path logic is as reliable as my neural net processor.

The format consistency between toString() and getFullImageNameWithHash() 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: format

This 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.
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 $imageTag with a sha256- 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 in ApplicationDeploymentJob (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

📥 Commits

Reviewing files that changed from the base of the PR and between 0e02eff and 590de8c.

📒 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.php
  • app/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.php
  • app/Services/DockerImageParser.php
  • app/Rules/DockerImageFormat.php
  • tests/Unit/DockerImageParserTest.php
  • app/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.php
  • app/Services/DockerImageParser.php
  • app/Rules/DockerImageFormat.php
  • tests/Unit/DockerImageParserTest.php
  • app/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.php
  • app/Rules/DockerImageFormat.php
  • app/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.php
  • app/Rules/DockerImageFormat.php
  • tests/Unit/DockerImageParserTest.php
  • app/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.php
  • app/Rules/DockerImageFormat.php
  • tests/Unit/DockerImageParserTest.php
  • app/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 performance

Place 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.php
  • app/Rules/DockerImageFormat.php
  • tests/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:latest to 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 $attribute is a false positive - it's used in the failure message via the :attribute placeholder, 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 updated toString() (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() and toString() 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 :hash and @sha256:hash formats
  • Registry scenarios with ports
  • Default latest behavior
  • 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, and imageSha256 gives 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, :tag for tags, :latest for 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) and getTag() 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 nginx or 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.input automatically attaches x-ref="autofocusInput" when you pass autofocus, so your x-init will 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.
@andrasbacsai
Copy link
Member

Thanks for the PR! I added a few UI/UX improvements.

@andrasbacsai andrasbacsai changed the base branch from v4.x to next October 3, 2025 09:52
@saurabhraghuvanshii
Copy link
Contributor Author

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?

@andrasbacsai
Copy link
Member

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. :)

@andrasbacsai andrasbacsai merged commit 4b08ac9 into coollabsio:next Oct 3, 2025
1 check passed
@github-actions github-actions bot removed ✨ Enhancement Issues requesting new features, new services or improvements. 🙋 Bounty claim Issues or PRs that have a Bounty ready to be claimed. 🔄 Linear Sync Github issues to Linear labels Oct 3, 2025
@coderabbitai coderabbitai bot mentioned this pull request Oct 3, 2025
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Nov 15, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Enhancement]: Allow deployment from container image hash

6 participants