Anonymize the audit events of a deleted user, store only the ID and
name of other users, and drop the metadata copy of actor_email.
Store URLs without query strings, registries without user info, and
the exception class instead of raw SSH errors.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Set env var version and compose parsing version while creating, so a create writes one row
- Record no rows for the auto-created preview copy of an env var
- Record env and application API updates only with the fields that really changed
- Store no change data for new env vars, and null for empty change data
- Store metadata team_id as an integer
- Drop the unused level and resource indexes of audit_events
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Return 429 after 30 failed (401/403/404) requests per minute for one
token or IP, also for unknown API routes (API_FAILED_REQUEST_RATE_LIMIT)
- Notify the team once a day when a token reaches the limit
- Deduplicate ability_denied and scope_denied audit events for 5 minutes
- Send Retry-After: 300 when the server is not functional
- Send Retry-After: 3600 when the push token cannot be decrypted
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Preview containers (-pr-<id>) came and went with pull requests and
invalidated the build cache of every app on the network. A build server
got the IPs of the deployment server network, which it cannot reach.
Add a per-app setting to turn off network hosts during the build.
Closes#12452
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Reply 410 for deleted servers and 402 for unpaid teams, with Retry-After
- Remove the Sentinel container of unpaid servers once a day, and before a server is deleted
- Record server_not_found and subscription_unpaid push failures once per hour
- Audit scheduled task API updates only for fields that really changed
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ServerValidated and ServerPatchCheckFinished used broadcastAs(), so Echo
listeners without a leading dot never matched them. Close the validation
dialog that a background job opened when the job finishes.
Add gitea_app_uuid to the allowed fields for application create and
update endpoints, with string validation on update, so Gitea App
sources can be set through the API.
Add a test checking that a closed GitLab merge request on the manual
webhook closes the matching preview and loads only applications of
that repository.
BuildKit keys every RUN step on the --add-host names, so a container
that joins or leaves the network between two builds rebuilt all layers.
Leave out database backup and S3 import helpers, Sentinel, and the
proxy error page container.
Closes#12452
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Updating the image of a service named like "api.test" wrote a nested
"test" key into the "api" service, because data_get/data_set split the
name on dots. Use array key paths instead. Also refuse service names that
Docker cannot use as a container name prefix, with a clear error on save.
Closes#12456
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The API and MCP saved names and descriptions that the UI rejects, so the
resource could not be saved in the UI after that. Applications, services,
databases, servers, and private keys now use the UI name and description
rules on create and update, with the UI error messages.
Closes#12466
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add GET /gitea-apps, POST /applications/private-gitea-app, and
gitea_app_uuid in PATCH /applications/{uuid}, with OpenAPI docs and MCP tool support.
Closes#12459
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GitHub rejects new RSA SSH keys smaller than 3072 bits, and phpseclib
made 2048-bit keys by default, so new RSA deploy keys from Coolify
could not authenticate.
Closes#12461
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Read compound and fractional durations (1m30s, 1.5m), quoted values,
only the flags before CMD, the escape parser directive, and NONE with
flags. Zero and sub-second values no longer become 0 seconds.
Closes#12455
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Compute accent text per page and sidebar surface to reach 4.5:1, move fill shades away from their text, pick the fill text by exact WCAG contrast, show the real fill in the preview, and use the theme surface for light custom wells.
Closes#12468
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Account menu entries, including Log out, now follow the sidebar text color
when a custom theme sidebar uses the other light/dark scheme than the page.
In the 3D style, the current page label keeps the sidebar text color,
because that row has no Selected fill.
Closes#12467
Remove the obsolete -webkit-overflow-scrolling: touch rule from the
table and log scroll containers in app.css, and the matching inline
styles from the scrollable bodies of modals, dialogs, the global
search create modals, the domain settings, subscription and upgrade
views. Modern iOS Safari scrolls with momentum by default, so these
declarations no longer did anything.
- Add a hint to failed command messages when the exit code is 255,
which explains that the SSH connection to the server closed before
the command finished.
- Return no services from applicationParser and serviceParser when the
compose `services` key is empty or is not a map, so parsing does not
fail.
- Move Server::getIp() out of the sshEndpointInUse() docblock, where it
was misplaced and broke the class.
- Add tests for the SSH hint, for services keys that are not maps, and
for saved compose variable values that must survive a redeploy
(#6995).
The deploy endpoint now checks the deploy permission before it creates a
preview or changes its image tag, not only before it queues the deployment.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Add an albums service for public links, with its own domain
- Pull images from ghcr.io/ente (ghcr.io/ente-io denies pulls)
- Generate a URL-safe JWT secret, so Museum can decode it
- With S3: use the routed MINIO_SERVER_URL as the S3 endpoint, allow
all CORS origins, and drop the SMTP defaults
Closes#7405
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Odoo keeps its data in databases that the user creates in Odoo, so the
POSTGRES_DB=postgres database that the backup used was empty. Also show the
sections of the edit backup schedule modal without nested cards.
Closes#7555
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A locked variable used by Docker Compose could not be changed, unlocked,
or deleted, so a lock by mistake had no fix in the UI. A locked value can
now be replaced without showing it. The lock is permanent in the UI, the
API, and MCP, and Lock asks for confirmation.
Closes#6803
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Containers without the Coolify default variables sent no project,
environment, or service to the drain. The fluentd driver now also sends
the Coolify container labels; the built-in configs use them as a
fallback and add coolify.service_name.
Closes#8415
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Variables saved before exact escaping wrote JSON objects and arrays
without quotes. A multi-line JSON value broke the .env file, so Docker
Compose stopped the deployment. These values now use exact escaping,
which gives the container the same value as before beta.463.
Closes#8279
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Read the running version from the container that answers the status request, not from the old page state, so the modal shows success as soon as the new version is up. Hide all Livewire error pages while an upgrade runs.
Closes#8024
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Containers without sh (distroless or scratch images) could not run
scheduled tasks, because Coolify always ran the command with sh -c.
Turn off "Run in a shell" to split the command into arguments and run
it directly. The option is also in the API, the MCP tools, and the
server transfer.
Closes#8244
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The queue counted every running deployment against the deployment server,
and the job picked a build server at random. So the deployment server
limit capped builds on build servers, and the build server limit was
never read. Count each build on the server that runs it, reserve a build
server with a free slot when the deployment starts, and start waiting
deployments of other servers when a build server slot is freed.
Closes#7649