Commit Graph
17660 Commits
Author SHA1 Message Date
Andras Bacsai e09876adcd fix(config): use docker.io as the default registry
A merge brought back ghcr.io as the default registry and helper image
registry. The install and upgrade scripts and the compose files use
docker.io.

- Default REGISTRY_URL and the helper image registry to docker.io
2026-10-05 21:24:30 +02:00
Andras Bacsai 111ff9adae docs(api): document audit events and fix the private key update path
- Add the OpenAPI attribute for GET /audit-events
- Document PATCH /security/keys/{uuid} with its uuid parameter instead
  of /security/keys
2026-10-05 21:24:20 +02:00
Andras Bacsai e11be922b4 fix(mcp): limit the deploy tool pull request id to the integer range
The MCP deploy tool passed pull_request_id without a range check.

- Return an error for ids below 0 or above 2147483647
2026-10-05 21:24:14 +02:00
Andras Bacsai 0abf82e631 fix(api): limit pull request ids to the database integer range
A pull request id above 2147483647 caused a database error and a 500.

- Previews store: validate max 2147483647 (422)
- /deploy: return 400 for pr or pull_request_id out of range
- Preview show, logs, update, and delete: return 422 for ids out of range
- Document the maximum in the OpenAPI spec
2026-10-05 21:24:05 +02:00
Andras Bacsai 50268139be fix(api): reject custom_internal_name without consistent container naming
Container names use custom_internal_name only when consistent container
naming is on. The API accepted the name and then ignored it.

- Return 422 with a message that says to set
  is_consistent_container_name_enabled to true
- Accept the name when the request or the application turns the setting on
- Document the requirement in the OpenAPI spec
2026-10-05 21:23:55 +02:00
Andras Bacsai ac5a0c289f fix(api): require the deploy ability for database imports from a server path
An import with source=server reads a file at an absolute path on the
server, but it needed only the write ability.

- Return 403 without the deploy or root ability, the same as other host
  paths outside the resource directory
2026-10-05 21:23:43 +02:00
Andras Bacsai babe43da32 fix(audit): return 403 on the audit log without a session team
When the user had no session team (for example after removal from the
team), the audit log page threw an error and returned 500.

- Return 403 when there is no session team or the user is not an admin
2026-10-05 21:23:36 +02:00
Andras Bacsai a331f91c49 fix(ui): validate secret manager settings and lock server-built lists
- SecretManagerLinks: validate settings when the integration token
  changes, and save only validated keys
- Service Domains: lock domainRows
- Server DockerImages: lock images
2026-10-05 21:23:29 +02:00
Andras Bacsai 379838251b fix(auth): use the resource team in database import, SQLite, and tokens
These paths used the session team after the resource was loaded. After a
team switch in another tab they used the wrong team or denied access.

- ImportForm: use the database team for the server, S3 storages, and
  the import
- SQLite ConnectApplication: list applications of the database team
- IntegrationTokenPolicy: check admin of the token team for view,
  update, and delete
2026-10-05 21:22:33 +02:00
Andras Bacsai 4f43c96e53 fix(backups): treat removed containers as recovered after a volume backup
When a container that a volume backup stopped no longer existed (for
example after a redeploy), recovery kept it as remaining. The execution
needed attention and every later run of the schedule was skipped.

- Treat "no such container" or "no such object" from docker inspect as
  recovered; other failures still need attention
2026-10-05 21:21:34 +02:00
Andras Bacsai b794da0983 fix(backups): set finished_at for each database of a backup run
In a backup of several databases, only the last execution got
finished_at.

- Set finished_at when each database backup succeeds or fails
2026-10-05 21:20:35 +02:00
Andras Bacsai 14523ed738 fix(backups): reset per-database state in a multi-database backup
When the execution of the next database could not be created, the
error handler used the state of the previous database. It marked the
successful backup of that database as failed and could delete its file.

- Reset the execution, location, and output at the start of each database
2026-10-05 21:20:32 +02:00
Andras Bacsai 99d4071f2c fix(service): read compose up and pull input from /dev/null
The service start script goes to the server over stdin. When the
configuration of an existing volume changed, docker compose asked to
recreate the volume and read the next script line as the answer. That
line, for example the proxy network connect, did not run.

- Add < /dev/null to the service compose up and pull commands
- Do not use --yes, because it recreates the volume and deletes data
2026-10-05 21:20:19 +02:00
Andras Bacsai c2d82b542d fix(github-runners): do not reconcile servers with disabled runners
ReconcileGithubRunnersJob connected over SSH every minute to every
server with a runner configuration, also when the runners were
disabled.

- Reconcile a server only when its runners are enabled or it still has
  active runner executions, so jobs that run after disabling still end
2026-10-05 21:20:10 +02:00
Andras Bacsai f9e513b7a3 fix(server): fail only the execution of the failed Docker cleanup job
failed() marked the latest running execution of the server as failed.
A manual run that never started, or a run that timed out, could mark a
different running cleanup as failed.

- Keep the execution id in the cache under the queue job uuid, because
  failed() runs on a fresh copy of the job
- Change nothing when the job created no execution
2026-10-05 21:19:52 +02:00
Andras Bacsai 798e3aafc9 fix(server): retry a manual Docker cleanup while another cleanup runs
A manual cleanup that started while a stop-triggered cleanup held the
server lock was dropped. The UI said it was queued, but it never ran.

- Release a manual run and try again after 60 seconds
- Stop the retries 780 seconds after dispatch (the lock expiry plus a
  margin)
- Scheduled and stop-triggered runs are still dropped
2026-10-05 21:19:44 +02:00
Andras Bacsai 6a527051ce fix(jobs): let the unique locks of scheduled instance jobs expire
CleanupInstanceStuffsJob, CleanupOrphanedPreviewContainersJob, and
CheckMissingDatabaseBackupsJob had no uniqueFor. A lock left by a
stopped worker blocked them for up to 24 hours.

- Set uniqueFor to 60, 600, and 1800 seconds
- Give CheckMissingDatabaseBackupsJob a 1800 second timeout, so a run
  cannot outlive its lock
2026-10-05 21:19:23 +02:00
Andras Bacsai 0facde67a8 fix(storage): let the S3 revalidation unique lock expire
RevalidateUnusableS3StoragesJob had no uniqueFor. A lock left by a
stopped worker blocked the job for up to 24 hours, so unusable S3
storages were not checked again and their backups were skipped.

- Set uniqueFor to 1800 seconds
2026-10-05 21:19:19 +02:00
Andras Bacsai df51b23bc2 fix(deployments): start queued deployments of the application on all servers
When a deployment on the primary server finished, deployments of the
same application queued on an additional server did not start. They
waited for the primary deployment, and then no queue event came for
their server.

- Also advance every server that has a queued deployment of the
  application; the per-server and per-application limits still apply
2026-10-05 21:19:11 +02:00
Andras Bacsai d599d04053 fix(deployments): advance the queue of an additional server
When a deployment on an additional server finished, only the queue of
the primary server advanced. Deployments queued on the additional server
could wait with no limit.

- Also advance the queue of the server of the finished deployment
2026-10-05 21:19:08 +02:00
Andras Bacsai eb2a6a5c82 fix(deployments): fail a deployment when its job cannot be dispatched
When the job constructor or the dispatch threw (for example, an invalid
registry image name), the deployment stayed in_progress. It blocked
later deployments of the application and used a build slot.

- Mark the deployment failed with fail_undispatchable_deployment()
- Throw the error again, so the UI and API still show it
2026-10-05 21:18:55 +02:00
Andras Bacsai 13db52f730 fix(scheduler): accept ScheduledJobManager jobs queued before the upgrade
Jobs that v4.3.23 put in the queue have no type property. The promoted
constructor property had no default, so these jobs failed with "must not
be accessed before initialization" after the upgrade.

- Declare type as a normal property with a null default
2026-10-05 21:18:48 +02:00
Andras Bacsai 2361161487 fix(service): write large compose files through SSH stdin
Service compose and .env content was sent inline in the SSH command.
Linux limits one argument to 128 KiB, so a service with a generated
compose over about 96 KB failed to save or start with "Argument list
too long".

- Add instant_remote_write_file(), which streams content to a remote
  tee over SSH stdin (sudo tee for non-root SSH users)
- Add SshMultiplexingHelper::generateSshStdinCommand() with the same
  SSH options as generateSshCommand()
- Write the service compose and .env with the new helper
2026-10-05 17:04:05 +02:00
Andras Bacsai 3de74145b7 fix(previews): match preview containers by exact pull request id
The container lookup matched the pullRequestId label as a substring, so
PR 1 also matched PR 12, 13, and 100. Deploying, closing, or deleting one
preview could stop and remove the containers of other previews.
2026-10-05 17:04:05 +02:00
Andras Bacsai edfaa5c381 fix(api): enforce validation and deploy ability on database create
The create endpoint checked $validator->failed(), which is always empty,
so its validation rules never ran. The start step also read
instant_deploy loosely, so a write-only token could send "false" and
still start the database.

- Use $validator->fails() so invalid input returns 422
- Read instant_deploy with $request->boolean() for the gate and the start
2026-10-05 17:04:05 +02:00
Andras Bacsai 3987f97a8e fix(subscription): require team admin for billing actions
Subscription actions ran on the session team without a role check. A user
who switched the session to a team where they are only a member could
cancel, refund, or change that team's subscription.

- Lock the team id at mount and require admin or owner of that team
- Check the locked team and the role again in every billing action
- Reject actions after the session switched to another team
2026-10-05 17:04:05 +02:00
Andras Bacsai 0da202b39d fix: protect restores, preview imports, and analytics access 2026-10-05 17:02:56 +02:00
Andras Bacsai 01ea05959e fix(api): skip domain generation for Docker Compose applications 2026-10-05 15:09:25 +02:00
Andras Bacsai 35c38b1dde fix(database): reject blocked starts before queueing operations
Check start prerequisites in database and deploy APIs and MCP controls.
Return HTTP 422 for blocked API starts and restarts. Show restart notices
and open UI logs only after an operation is queued.

Add API regression tests for blocked ClickHouse starts and restarts.
2026-10-05 14:59:59 +02:00
Andras Bacsai 88efc0716e fix: enforce resource team isolation and preserve ClickHouse data
Scope resource permissions and related records to the owning team across
team switches, cloning, deployments, and resource operations.

Merge ClickHouse volume mounts, preserve anonymous data volumes on stop,
and require adopting current data before starting or restarting.

Fix file storage deletion checks and add regression coverage.
2026-10-05 14:23:04 +02:00
Andras Bacsai 439ee6faea fix: restrict proxy content access and scope backup storage to owners
- Hide proxy configuration contents from users without update permission.
- Select and validate backup S3 storage against the resource's team.
- Keep scheduled branch syncs green while a conflict PR remains open.
- Document external mount permissions and Sentinel traffic limits.
- Add regression coverage for authorization and backup storage selection.
2026-10-05 13:20:19 +02:00
Andras Bacsai 4227ec6ebf fix(storage): require deploy permission for external host writes
Require deploy or root token access when creating managed mounts outside
resource directories or changing their file contents through the API.

Synchronize KeyDB and Dragonfly passwords with local and shared
REDIS_PASSWORD values while preserving secret manager resolution.
2026-10-05 12:03:37 +02:00
Andras Bacsai 2aead9c914 refactor(analytics): remove application traffic overview card 2026-10-05 11:28:03 +02:00
Andras Bacsai 554bd354bf fix: support host storage paths and clean up cancelled deployments
Allow validated host file and directory mounts outside resource directories
while protecting external paths from deletion.

Clean up cancelled deployment containers and clear tracked process IDs.
Preserve legacy KeyDB and Dragonfly password parsing, accept server backup
paths without extension restrictions, and allow Compose variable proxy ports.
2026-10-05 11:08:52 +02:00
Andras Bacsai 774e6bf178 feat(account): add self-service deletion and cancellation flow (#12088) 2026-10-05 09:17:10 +02:00
Andras Bacsai 34e4da1095 fix(ui): copy DNS record values on plain http instances
On non-secure origins the copy button falls back to execCommand('copy')
with a temporary textarea. The textarea was appended to <body>, outside
the x-trap focus trap of the DNS entries modal, so the trap pulled focus
back and the selection was lost before the copy. The button showed
success, but nothing was copied.

Append the textarea next to the button, select it explicitly, and
restore focus afterwards. "Copy all" now uses the shared copyButton
handler instead of its own duplicate fallback that ignored failures.

Closes #12075
2026-10-04 20:36:49 +02:00
Andras Bacsai cfe9e0eee0 fix(settings): load instance backup page without a backup schedule
/settings/backup returned 500 when the coolify-db resource existed without
a scheduled backup. Configure backup now reuses the existing coolify-db and
creates only the missing schedule for the root team, without forcing id 0.

Closes #12074
2026-10-04 20:33:22 +02:00
Andras Bacsai 16a8c7999d feat(audit): log account, resource, and instance settings changes
Add audit events for account actions, server and application settings,
services, destinations, storage, backup schedules, and scheduled tasks.
Track changed fields and skip unchanged saves without logging file content.

Add regression coverage for audit events and changed-field detection.
2026-10-04 17:32:50 +02:00
Andras Bacsai f63bf5abaa fix(sentinel): refresh UI on container health and status changes
Include health status in push deduplication and broadcast ServiceChecked after processing complete or partial snapshots.
2026-10-04 16:25:00 +02:00
Andras Bacsai e837a4f0b4 style(ui): use neutral colors for selection checkmarks 2026-10-04 13:46:21 +02:00
Andras Bacsai b235a480b2 fix(service): detect registry-prefixed Grafana server images (#10617) 2026-10-04 13:39:19 +02:00
Andras Bacsai 1b9f0ccaee feat(audit): show encrypted field-level mutation changes (#11788) 2026-10-04 13:15:46 +02:00
Andras Bacsai 9850793109 Merge remote-tracking branch 'origin/main' into pr-11788-encrypted-audit-change-details 2026-10-04 13:13:16 +02:00
Andras Bacsai c4f96a7185 fix(analytics): label zero response status in traffic breakdowns 2026-10-04 12:42:17 +02:00
Andras Bacsai 15b64d6c56 Move proxy TLS certificates to a separate page 2026-10-04 12:35:54 +02:00
Andras Bacsai 51c1a2ad4a fix: add column headers to analytics tables 2026-10-04 12:35:53 +02:00
Andras Bacsai 4c2253c2ad fix(previews): restrict PR loading and status updates to GitHub Apps
Add Application::isGithubAppSource(), which checks that the source is a
GithubApp, and use it in place of is_github_based() for pull request
status updates in ApplicationDeploymentJob and for the "Load pull
requests" action in the previews view.

Previews::load_prs now throws an error for non-GitHub App sources
instead of calling the GitHub API with a GitLab or other source. Also
adds a test checking that GitLab sources don't show or load GitHub pull
requests.
2026-10-04 12:29:48 +02:00
Andras Bacsai 5805a28872 fix(audit): redact raw credential fields and keep hidden fields excluded
Raw commands, URLs and configuration blobs can contain credentials even
when their field names don't look sensitive. Add a list of these fields
to AuditEvent (git_full_url, build/start commands, database confs,
proxy configuration, compose files, environment variables, etc.). Expose
AuditEvent::isSensitiveField() so redaction and audit change capture use
the same check.

Auditable now excludes a model's class-level $hidden fields as well as
its runtime hidden fields. A field stays out of audit changes even after
makeVisible() is called on the instance.

Add regression tests for credentials embedded in raw fields, database
config on create/delete, nested metadata and proxy configuration, and
hidden fields after makeVisible().
2026-10-04 12:26:37 +02:00
Andras Bacsai 4759b7bcf7 fix(audit): redact object values and isolate change preparation failures 2026-10-04 12:26:06 +02:00
Andras Bacsai 83d19800a6 feat(audit): store encrypted field-level changes on mutations
Record old/new values for auditable create, update, and delete actions, persist them encrypted on audit events, expose them in the API, and let the team audit log expand a field-level before/after view. Sensitive, hidden, and identifier fields stay out of the change payload.
2026-10-04 12:26:00 +02:00