This commit addresses a critical security issue where malicious Docker Compose
data was being saved to the database before validation occurred.
Problem:
- Service models were saved to database first
- Validation ran afterwards during parse()
- Malicious data persisted even when validation failed
- User saw error but damage was already done
Solution:
1. Created validateDockerComposeForInjection() to validate YAML before save
2. Added pre-save validation to all Service creation/update points:
- Livewire: DockerCompose.php, StackForm.php
- API: ServicesController.php (create, update, one-click)
3. Validates service names and volume paths (string + array formats)
4. Blocks shell metacharacters: backticks, $(), |, ;, &, >, <, newlines
Security fixes:
- Volume source paths (string format) - validated before save
- Volume source paths (array format) - validated before save
- Service names - validated before save
- Environment variable patterns - safe ${VAR} allowed, ${VAR:-$(cmd)} blocked
Testing:
- 60 security tests pass (176 assertions)
- PreSaveValidationTest.php: 15 tests for pre-save validation
- ValidateShellSafePathTest.php: 15 tests for core validation
- VolumeSecurityTest.php: 15 tests for volume parsing
- ServiceNameSecurityTest.php: 15 tests for service names
Related commits:
- Previous: Added validation during parse() phase
- This commit: Moves validation before database save
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Previously, the bash escaping functions (`escapeBashEnvValue()` and `escapeBashDoubleQuoted()`) had strict string type hints that rejected null values, causing deployment failures when environment variables had null values.
Changes:
- Updated both functions to accept nullable strings (`?string $value`)
- Handle null/empty values by returning empty quoted strings (`''` for single quotes, `""` for double quotes)
- Added 3 new tests to cover null and empty value handling
- All 29 tests pass
This fix ensures deployments work correctly even when environment variables have null values, while maintaining the existing behavior for all other cases.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit addresses two critical issues with Docker Compose service management:
## Issue 1: Duplicate Services Created on Image Change
When changing the image in a docker-compose file, the parser was creating new
ServiceApplication/ServiceDatabase records instead of updating existing ones.
**Root Cause**: The parsers used `firstOrCreate()` with `['name', 'image', 'service_id']`,
meaning any image change would create a new record.
**Fix**: Remove `image` from `firstOrCreate()` queries and update it separately after
finding or creating the service record.
**Changes**:
- `bootstrap/helpers/parsers.php` (serviceParser v3): Fixed in presave loop (lines 1188-1203)
and main parsing loop (lines 1519-1539)
- `bootstrap/helpers/shared.php` (parseDockerComposeFile v2): Fixed null check logic
(lines 1308-1348)
## Issue 2: UI Not Refreshing After Changes
When compose file or domain was modified, the Configuration component wasn't receiving
events to refresh its data, requiring manual page refresh to see updates.
**Root Cause**: The Configuration component wasn't listening for refresh events dispatched
by child components (StackForm, EditDomain).
**Fix**: Add event listeners and dispatchers to enable real-time UI updates.
**Changes**:
- `app/Livewire/Project/Service/Configuration.php`: Added listeners for `refreshServices`
and `refresh` events (lines 36-37)
- `app/Livewire/Project/Service/EditDomain.php`: Added `refreshServices` dispatch (line 76)
- Note: `app/Livewire/Project/Service/StackForm.php` already had the dispatch
## Tests Added
- `tests/Unit/ServiceParserImageUpdateTest.php`: 4 tests verifying no duplicates created
- `tests/Unit/ServiceConfigurationRefreshTest.php`: 4 tests verifying event dispatching
All 8 new tests pass, and all existing unit tests continue to pass.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Introduced a new notification class, BackupSuccessWithS3Warning, to alert users when local backups succeed but S3 uploads fail.
- Updated DatabaseBackupJob to track local backup success and handle S3 upload errors, improving error reporting and user notifications.
- Modified ScheduledDatabaseBackupExecution model to include a new s3_uploaded boolean field for tracking S3 upload status.
- Adjusted views and validation logic to reflect changes in backup execution status and S3 handling.
- Added tests to ensure the new s3_uploaded column is correctly implemented and validated.
- Added a new function to extract custom proxy commands from existing Traefik configurations before regenerating the proxy configuration.
- Updated the proxy configuration generation logic to include these custom commands, ensuring they are preserved during regeneration.
- Introduced unit tests to validate the extraction of custom commands and handle various scenarios, including invalid YAML and different proxy types.
- Changed the .env file reference to use a build-time .env file located in /artifacts, preventing it from being included in Docker images.
- Introduced a new method to wrap Docker build commands with environment variable exports, enhancing the handling of build-time variables.
- Updated logging messages for clarity regarding the creation and usage of the build-time .env file.
- Added functionality to generate environment variables for each service defined in the Docker Compose file, transforming service names into uppercase and replacing special characters.
- Updated the service parser to merge these generated variables with existing environment variables, enhancing deployment configuration.
- Introduced new helper functions to generate Docker build arguments and environment flags, accommodating multiline variables with proper escaping.
- Updated the ApplicationDeploymentJob to utilize these new functions, improving the handling of environment variables during deployment.
- Added comprehensive tests to ensure correct behavior for multiline variables and special characters.
- Updated validation rules for 'custom_user' and 'custom_port' fields to be nullable in the GithubController.
- Refactored API request handling in GithubController, GithubPrivateRepository, and helper functions to use a consistent Http::GitHub method with timeout and retry logic.
- Improved error handling for repository and branch loading processes.
This change introduces automatically generated `SERVICE_NAME_<SERVICE>`
environment variables for each service within a Docker Compose deployment.
This allows services to reliably reference each other by name, which is particularly
useful in pull request environments where container names are dynamically suffixed.
- The application parser now generates and injects these `SERVICE_NAME` variables
into the environment of all services in the compose file.
- `ApplicationDeploymentJob` is updated to correctly handle and filter these
new variables during deployment.
- UI components and the `EnvironmentVariableProtection` trait have been updated
to make these generated variables read-only, preventing accidental modification.
This commit introduces two new helper functions to standardize resource naming
for pull request deployments:
- `addPreviewDeploymentSuffix()`: Generates a consistent suffix format (-pr-{id})
for resource names in preview deployments
- `generateDockerComposeServiceName()`: Creates SERVICE_NAME environment variables
for Docker Compose services
- Added functionality for users to request an email change, including generating a verification code and setting an expiration time.
- Implemented methods in the User model to handle email change requests, code validation, and confirmation.
- Created a new job to update the user's email in Stripe after confirmation.
- Introduced rate limiting for email change requests and verification attempts to prevent abuse.
- Added a new notification for email change verification.
- Updated the profile component to manage email change requests and verification UI.
- If you set a low local backup retention, for example 2 backups for local backup retention and 10 backups for S3, then the S3 backups were never deleted, not even after 10 days. This was because we check the file paths based on the backup executions table, and as soon as a backup was deleted locally, the execution was removed, which meant after 10 days for s3 there where no backups older then 10 days just the 2 local backups which is just wrong. Now we only delete a backup execution if it has been removed from both locations.
- Also added a nice little UI element to see where your backup is available.
Updated the default Nginx configuration function to enhance clarity and maintainability. Removed unnecessary redirection logic and added explicit handling for 404 errors, ensuring a more robust error management strategy. This refactor simplifies the configuration while maintaining essential functionality, contributing to a cleaner and more efficient setup.
- Replace `! $type` checks with `blank($type)` for consistency
- Modify email settings configuration to handle null/disabled states
- Ensure proper fallback and configuration of email providers
- Increase UUID length for better uniqueness
- Add server existence check before validation
- Implement cleanup of temporary compose file in finally block
- move date and duration functions to a shared function
- remove duplicate code
- redesigned the deployment executions tab
- added start and end times for backups, scheduled tasks, deployments and docker cleanup executions
- calculated the duration for backups, scheduled tasks, deployments and Docker cleanup executions
- redesigned status badges with colors to make it easier to see your current status
- removed dependency on dayjs
- fixed calculation of execution time was sometimes incorrect
- feat: add storage retention to local storage as well
- fix: UI input for max storage now allows exact decimals so MB input is now also possible
- fix: Database column is now decimal instead of integer
- fix: variable naming of storage check no longer overwrites $backup - renamed it to $backupExecution
- fix: Delete folder and parent folder if folders are empty when deleting local backups.
- fix: Do not remove executions from DB until both S3 and local backups have been deleted and successfully processed otherwise backups will never be deleted from s3.
- fix: Server ID could be null
- Removed the private property for application deployment queue ID in ApplicationDeploymentJob and utilized constructor property promotion.
- Added a tags method in ApplicationDeploymentJob to properly identify the worker running the job.
- Updated HorizonServiceProvider to handle cases where the deployment queue ID is blank, preventing potential errors during job processing.
- Cleaned up the isAnyDeploymentInprogress function by removing unnecessary whitespace.
- Simplified the job status retrieval process by consolidating logic into a single `getJobStatus` function.
- Removed redundant checks and methods from the `CustomJobRepositoryInterface` and `CustomJobRepository`.
- Updated the `getHorizonJobStatus` method in `ApplicationDeploymentQueue` to directly utilize the new `getJobStatus` function.
- Enhanced the `isThereAJobInProgress` method to improve clarity and maintainability.
- Updated the isAnyDeploymentInprogress function to check for running jobs based on the current hostname.
- Enhanced the logic to return true if any job status is 'unknown' and to provide a clearer output regarding the number of deployments in progress.
- Modified the cloud_upgrade.sh script to loop until the deployment status check confirms no ongoing deployments before proceeding with the upgrade.
- Introduced `environment_uuid` as a required field in various API endpoints and schemas.
- Updated descriptions to clarify that either `environment_name` or `environment_uuid` must be provided.
- Modified routes and controller methods to accommodate the new UUID parameter.
- Adjusted frontend components to utilize `environment_uuid` for better consistency and clarity.
- Removed deprecated fields related to environment handling.
This change enhances the API's flexibility in identifying environments, improving overall usability.