Repository navigation
Conversation
Socialite's GitLab provider fetches the user from /api/v3/user, which GitLab removed in 11.0 (410 Gone). Add App\Auth\GitlabProvider that reads /api/v4/user with a bearer token and register it in the socialite helper, for both gitlab.com and self-hosted base URLs. Environment variable copyValue now checks the 'update' policy on the variable instead of the member role of the current team, so members can no longer copy values after switching to a team they own. Remove the redundant member check from ShowHardcoded. Add tests for the GitLab v4 user lookup and the team-switch copy case.
Numeric coolify.{type}Id labels can collide with resources on another
Coolify instance managing the same server, so they no longer select or
resolve container owners. Drop the legacyId fallback from container
lookups in DeleteService and ComplexStatusCheck.
Legacy application containers without a UUID label are now resolved by
their compose service name, which starts with the application UUID.
A plain pipe into the compressor only reported the compressor's exit status, so a failed dump still produced a small, valid archive. Add pipeToFileKeepingExitStatus() to propagate the source's exit status in POSIX sh and use it for all compressed dump commands. - Delete the partial local backup file on any failed backup, not only for ClickHouse, since untracked files are never removed by retention - Wait up to 10s for locks when running VACUUM INTO for SQLite backups - Refuse SQLite restores unless the file has a SQLite header, so an empty backup no longer wipes the database - Add tests for dump exit status handling and SQLite restore validation
GET /applications/{uuid}/logs ignored service_name and always returned
logs from the first container, so 'coolify app logs --service' could show
logs from the wrong Compose service. When service_name is present, select
the container whose labels contain the matching
com.docker.compose.service entry and 404 when nothing matches.
DeleteResourceJob no longer restores a service and rethrows when remote cleanup fails. The resource is always removed from Coolify, and the team gets a notification that Docker resources may remain on the server. No notification is sent when the server itself was already deleted. removeSubresourceContainer now returns false instead of throwing when the server is not functional. Deleting a service application or database then shows a warning that the container is removed on the next service start. StopService handles a missing destination server, environment, project, or team without throwing. The danger zone warning now shows for any resource whose server is unreachable, not only services.
Mark DNS proposals, conflicts and server IP properties as #[Locked] so clients cannot tamper with them. Re-resolve the zone per hostname, lowercase hostnames, validate record content server-side and use the resource's team id for DNS lookups and jobs. Move modal-confirmation submitAction parsing into a tested JS helper that strips quotes and keeps commas, parentheses and escaped quotes inside quoted arguments. Pass the hostname to replaceManagedDnsRecord through it instead of Js::from. Rework member-permission tests to open the real DNS dialog rather than setting locked properties directly.
SSH: sshd runs the remote command with the user's login shell, which can be fish or csh/tcsh. Those shells cannot parse POSIX `if ... fi`, so the bash/sh fallback wrapper now runs inside `sh -c "..."`. Unit tests run the wrapper under every login shell that is installed and check that it stays one simple sh command. Secret managers: the SecretManagerLinks component now lists and resolves tokens by the resource's team instead of the session team. A team switch in another tab can no longer link a token from a different team. SecretManagerLink::fetchSecrets() also throws when the linked token does not belong to the resource's team, so no request is sent with it. Also adds a lesson note: remove the SSH mux file before live SSH or login-shell tests.
Hardcoded variables parsed from docker-compose are now redacted in the environment variable list unless the user can update the resource. The value is nulled server-side and flagged with is_value_hidden, so it no longer reaches the Livewire snapshot or rendered HTML. ShowHardcoded gets a locked isValueHidden property. When it is set, the copy button is hidden and the details modal shows "Hidden (only admins can view)" in place of the value. Previously the view checked member role only. Add tests covering redaction for members and visibility for owners.
Git source HTTP clients previously disabled redirects entirely, so API
calls for renamed repositories (e.g. GitHub 301 to /repositories/{id})
failed. Add SafeExternalUrl::sameOriginRedirectOptions() and use it in
the GitSource HTTP macro to follow up to five strict redirects that stay
on the same scheme, host and port.
A redirect to a different origin gets a RequestException, because the
DNS pin covers only the original host and port. This blocks SSRF via
redirects to metadata or attacker hosts. Authorization headers and the
original request method and body are kept on same-origin redirects.
Tests cover following same-host redirects, keeping POST on a redirect,
refusing cross-host/scheme/port redirects and the five-redirect cap.
…oollabsio#12048) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ers (coollabsio#12054) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Pushes to main published three tags per commit (sha-<sha>, sha-<sha>-amd64, sha-<sha>-aarch64). Publish the per-arch images under rolling main-amd64/main-aarch64 tags instead, and keep one sha-<sha> manifest per commit next to a rolling main tag. Serialize runs so concurrent pushes cannot mix architectures, and label images with the source revision. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Accept Compose variables ($NAME, ${NAME}, ${NAME-default},
${NAME:-default}) in the `name:` of an external volume, and in the old
`external: {name: x}` syntax. Docker Compose resolves them from the
deployment .env. Coolify never removes external volumes, so it does not
need the resolved name.
The volume key must still be a literal Docker volume name, because
Compose does not resolve variables in keys. Names that are unsafe or use
unsupported syntax are still rejected, for example command substitution,
spaces, escaped dollars, and ${VAR:?err}.
Add tests for application and service parsing, legacy volume rows, the
StackForm save, legacy Compose parsing, and the rejected cases.
- database import: add keep_owners (restore PostgreSQL owners and privileges) and sqlite_database (pick the target SQLite file) to the API, OpenAPI spec, and import form - oauth: require password confirmation and support team selection on OAuth login - remote process: send team broadcast events to the team of the server that ran the process instead of the causer's user id - servers API: handle the legacy build server setting - compose: support parent bind paths and volume driver options - dns: improve record hints and provider management - notifications: fix throttling and missing backup notifications - ui: rework the confirmation modal - add feature and unit tests for the new behavior
Before Coolify kept `driver`, `driver_opts` and `labels` of renamed Compose volumes, Docker created those volumes without them. Applying the options now would make Docker Compose ask to recreate the volumes on every deployment. - Add `ignores_compose_driver_options` column to local_persistent_volumes and mark all volumes that exist at upgrade time - Parsers now use composeRenamedVolumeDeclarationFor() so flagged volumes keep the old name-only top-level declaration - Legacy application parsers (v1/v2) always emit name-only declarations - Reset the flag when a volume is replicated, since a clone is a new Docker volume - Include the flag in server transfer export/import; bundles without it default to true - Storages UI shows which volumes ignore driver options and allows deleting them so the options apply on recreation - Add tests for parsers, cloning and server transfer
GitLab, Authentik, Zitadel, Clerk and Azure identities were keyed by the provider name only, so a user with the same subject on another instance could sign in as the linked user after the base URL or tenant changed. The issuer column now stores the normalized instance, existing rows are backfilled from the current settings, and oauth:rekey handles host renames.
… expires A user who accepted another team's invitation but had not set a password yet was deleted, with their team data. Now only users in no team except their own personal team are deleted.
…on changes Changing the Vault base URL or namespace, or the Infisical base URL or client ID, sent the stored secret to the new settings. The secret must now be entered again, and base URL changes are audit logged.
…kups Coolify copies acme.json to a timestamped backup before every change and keeps the last 10. The proxy page lists the backups with Restore and Delete for team admins, and the restore dialog can restart the proxy right away.
Entries such as ${HTTP_PORT:-80}:80 blocked proxy start, save and restart.
Defaults are used for the conflict check and unresolved entries are skipped.
… multi-server runs - Decide whether to start a queued deployment inside the application and server lock, so two requests cannot start the same app twice. - Send the multi-server summary when the last child is cancelled. - Show the registry message when an inline Dockerfile image is missing on a deployments-only additional server.
A queued start or restart whose reservation expired no longer runs. Failed queued starts are recorded as failed activities and release the reservation.
…er lookups - Align the traffic window to the minute so the 60 s cache is used. - Skip only an unsafe key instead of hiding the whole server. - Look up unknown container owners in one query per push.
…ne, use random clone dirs - Resolve relative LocalFileVolume paths against the resource directory. - Create cloned volumes with the source driver and options. - Stage clone archives for non-root users in a mktemp directory (mode 700) instead of a predictable path in /var/tmp.
…rottles - The S3 revalidation job stops within its time budget and continues from a cursor on the next run. - An hourly sweep deletes throttle rows whose subject no longer exists.
The signoz and plausible template updates changed the count from 94 to 91.
- Update tests whose expectations no longer matched intended changes (GitHub App redirect, wildcard domains, container IDs, nightly install folders, localhost metadata, Sentinel restart on save) - Seed the instance settings the 2FA profile test needs - Run the global Pest hooks for all test folders and release the Laravel application after each test, so tests do not leak state - Replace a class alias mock that broke later tests - Generate factory names that always pass name validation; Faker names with apostrophes or short words made form tests fail at random
Keep reserved jobs active and bound missing Horizon records by the server's deployment timeout. Add regression coverage for active and finished jobs. Use UTC PostgreSQL sessions and bump the release version to 4.4.1.
Count running scheduled tasks, database backups, and volume backups, excluding runs older than their job timeout. Report scheduled job counts and keep the progress check active while any scheduled jobs are running.
Default to sequential dispatch on self-hosted instances and concurrent per-type dispatch on Coolify Cloud. Allow SCHEDULED_JOBS_DISPATCH_MODE to override the default, falling back for invalid values. Cover defaults, overrides, and fallback behavior in scheduler tests.
Send success and failure notifications through enabled backup channels. Route successful backups with warnings through failure channels.
Check enabled volume backup schedules hourly and notify teams when no execution occurs within the configured number of days. Expose the alert threshold in the UI and API, with alerts disabled by default. Route volume backup results and warnings to the appropriate Telegram backup threads.
Allow full, anonymized, or disabled IP recording per server through the UI and API, and pass the selected mode to Sentinel. Adapt traffic breakdowns to the effective IP mode, including views that aggregate multiple servers.
Sentry self-hosted (getsentry/self-hosted 26.8.0) could not be deployed as a Docker Compose application. Three separate problems blocked it: - YAML collection aliases: the first fix raised the limit to 256 only in Application::oldRawParser(). The safety check added in v4.4.0 (validateDockerComposeForInjection) and all other Compose parse calls still used the Symfony default of 128, so the Sentry file (133 aliases) failed with "Maximum number of collection aliases (128) exceeded". Add parseDockerComposeYaml() and use it for every Compose parse. - Argument list too long: the deployment job sent the generated Compose file as base64 inside the SSH command. Linux limits one argument to 128 KiB, and the Sentry file is about 370 KB. execute_remote_command() now accepts an 'input' key that streams content over SSH stdin, and the job writes the Compose file with it. - A list-style build arg without a value (build.args: [SENTRY_IMAGE]) merged into a map environment kept its numeric key, so Docker Compose rejected the file with "non-string key in ...environment: 0". It now becomes NAME with no value, as in Compose. Closes coollabsio#11725
Combine Sentinel overflow rows into one unlinked "Other paths" row. Show domains beside paths and include them in Livewire row keys. Add regression coverage for overflow aggregation across app keys.
…io#11781) Co-authored-by: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com>
Add an authorized update button with activity logs to pull the latest image and recreate the tunnel container in the background. Persist new Compose files under /data/coolify/cloudflared and support existing /tmp configurations. Cover updates, missing configuration, and member restrictions with tests.
Replace datalist and searchable-listbox components with the shared listbox and migrate form fields. Deduplicate superseded Livewire updates to prevent repeated array update hooks, with regression coverage.
The delete guard compared an environment variable's key against the keys of
services.*.environment. In `FOO: ${BAR}` the key `FOO` is the name the
container sees, not a reference to a Coolify variable, so every left-hand
name in a compose file became undeletable — the UI refused with "remove it
from the Docker Compose file first" for variables the file never referenced.
The companion check, str_contains($value, '$'.$key), could not match the
${VAR} form at all, since `$VAR` is not a substring of `${VAR}`. Real
references were therefore missed, and references outside
services.*.environment (build.args, labels) were never scanned.
Match `$KEY`, `${KEY}` and `${KEY:-default}` against string values only,
walking the whole compose tree, with a boundary so `FFP_ENCRYPTION_KEY` no
longer matches inside `${API_FFP_ENCRYPTION_KEY}`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Oct 9, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Once
infisical-integrationis resolved, fork-sync on v4.4.2 (#20) conflicts next on this patch, inapp/Traits/EnvironmentVariableProtection.php.Cause: upstream commit
81045b2dc("deploy large Compose files such as Sentry self-hosted") replacedYaml::parse($dockerCompose)with the newparseDockerComposeYaml($dockerCompose)helper, which raises the YAML alias limit. That is the same line this patch restructures.Resolution
git rebase --onto v4.4.2 <old-base>. I kept the patch's values-only reference check unchanged and switched its parse call toparseDockerComposeYaml(), so upstream's large-Compose fix is preserved. Upstream's bug (matching on keys, which blocks deletion of every left-hand name) is still present in v4.4.2, so the patch is still needed. The diff against v4.4.2 is the same single file, +36/−20.Verification
php -lis clean.fork-cdn-hardeningandinfisical-integration.Force-push this onto
patch/env-var-delete-guardyourself once it's reviewed.🤖 Generated with Claude Code
https://claude.ai/code/session_01HLUygtSre2fFuUUhyQZaip
Generated by Claude Code