Expose GitHub app secrets and file storage content only when the request has sensitive read access. Hide LocalFileVolume content by default and resolve application UUIDs from route parameters.
Require admin team membership for destination mutations, return invalid-token
responses for tokenless requests, and remove standalone Docker networks when
deleting destinations.
PHP's FILTER_VALIDATE_URL rejects underscores in the host, so domains
like https://myapp_service.example.com were rejected by the API and
never got a Let's Encrypt certificate. Add an isValidDomainUrl() helper
that validates a copy with underscores replaced by hyphens, and route
domain validation in the Applications and Services API controllers
through it.
Fixes#10597
Require read:sensitive for nested server logdrain and sentinel fields in
application and database API responses.
Limit deployment configuration column migration SQL to PostgreSQL.
Skip Docker healthcheck configuration when standalone database health checks are disabled, and document default health check settings in the database API schema.
Add configurable health check settings for standalone databases and apply them to generated Docker Compose services. Allow disabling health checks and cover the behavior with feature tests.
Ignore health status changes in Sentinel push deduplication when the container lifecycle state is unchanged.
Scope stale resource checks to Sentinel servers whose heartbeat is stale, and avoid refreshing resource last_online_at on unchanged statuses.
The endpoint validated private_key_uuid but dropped it from the update,
so the request silently no-op'd. Resolve the UUID to a team-scoped
PrivateKey and include private_key_id in the update payload.
The ownedByCurrentTeamAPI scope was added to StandaloneDocker/SwarmDocker
*after* 4.0.0-beta.470 — running containers on that beta hit a
BadMethodCallException. Rewrites all team scoping to use
whereHas('server', whereTeamId) which works against any v4.x of
Coolify (StandaloneDocker.server_id -> Server.team_id has been there
since the multi-team change).
Also guards attachedTo() with method_exists and falls back to a manual
attached-resource check covering applications + every standalone DB
relation, so delete() doesn't crash on older versions either.
Initial draft called auth()->user()->currentTeam() which returns null in
the API context (Sanctum tokens don't carry the per-user currentTeam
state — that's a session/Livewire concept). Other Api controllers
(ServersController, ScheduledTasksController, etc.) use the canonical
helper getTeamIdFromToken() with a null guard returning 403.
This swap makes all five endpoints work against a real token.
The Destinations section is exposed in the Coolify UI but not via the
REST API. The destination_uuid field is required when creating
applications via create-public-application, but no way to enumerate or
create destinations programmatically existed — this blocks IaC tools
(e.g. an Aspire publisher targeting Coolify).
Adds, scoped to the existing v1 auth:sanctum + ApiAllowed + api.sensitive
group:
GET /api/v1/destinations
GET /api/v1/destinations/{uuid}
DELETE /api/v1/destinations/{uuid}
GET /api/v1/servers/{server_uuid}/destinations
POST /api/v1/servers/{server_uuid}/destinations
The controller uses the existing inline-Validator convention (no Form
Request classes per the API surface's house style), reuses
StandaloneDocker::ownedByCurrentTeamAPI / SwarmDocker::ownedByCurrentTeamAPI
for team scoping (matching ScheduledTasksController etc.), and respects
the `attachedTo()` guard on delete.
No migrations needed — both standalone_dockers and swarm_dockers tables
already carry uuid/name/network/server_id/timestamps.
OpenAPI @OA\ annotations omitted in this commit to keep the diff
minimal; a follow-up can add them in the style of ServersController.
Move Sentinel push handling into a controller and dispatch server update jobs only when container state changes or the force interval elapses. Add opt-in PostgreSQL read/write replica configuration and tune periodic proxy network and storage checks to reduce unnecessary work.
Add feature coverage for replica config, Sentinel push deduplication, deployment log scrolling, and server update job optimizations.
Decode base64 custom_nginx_configuration before model assignment so it is not double-encoded, and allow null values when clearing the setting. Add API coverage for create, update, invalid input, and clearing behavior.
Add model-level hidden fields for secrets, tokens, keys, notification
credentials, deployment logs, and environment values. Allow explicit
read:sensitive API access to reveal gated private keys and deployment logs,
and cover the behavior with feature and unit tests.
Require Docker buildx before Railpack builds, normalize environment
variable keys before validation, and align private deploy key API docs with
the supported dockerfile build pack.
Drop the unstable applications/dockercompose route and controller path now that
service creation is handled by POST /api/v1/services. Add coverage to ensure the
deprecated endpoint stays unregistered while the services endpoint remains
available.
Only eager load nested server settings for service responses when the API token has read:sensitive, preventing read-only tokens from exposing sentinel fields while preserving sensitive access.
Add compose PR fields to the Application hidden attributes and allow database list queries to eager load nested server settings when sensitive access is permitted.
- `/mcp/enable` and `/mcp/disable` now use POST (state-mutating ops)
- `ListServices` queries DB directly instead of loading all projects into memory
- `ListApplications` validates tag arg rejects empty string (not just falsy)
$request->input('force') ?? false reads "false" as a non-empty string,
which PHP coerces to true. Replace with $request->boolean() which uses
filter_var(FILTER_VALIDATE_BOOLEAN), correctly mapping "false" -> false.
Add `exposeNestedServerSecrets()` to Applications, Databases, and
Services controllers so that `read:sensitive`/`root` tokens see
sentinel and logdrain fields on eager-loaded Server + ServerSetting
relations.
ServicesController handles both single models and Eloquent Collections
(listing endpoint passes a Collection per project).
Tests tightened to use JSON-key assertions (`"field":`) to avoid false
positives from field names appearing in values.
Models now declare $hidden for passwords, tokens, db URLs, and compose
fields. API controllers flip from makeHidden-on-deny to makeVisible-on-
allow (can_read_sensitive=true), fixing fields that were never hidden.
Also adds missing fields (mysql/mariadb passwords, logdrain keys, etc.)
to privileged disclosure lists.
Tests added: Feature/Security/ApiSensitiveFieldsTest and
Unit/Models/SensitiveFieldsHiddenTest cover all affected models and
controllers.
Add Model Context Protocol server exposing Coolify infrastructure data
to AI assistants. Includes tools for listing/fetching servers, projects,
applications, databases, and services, scoped to authenticated team tokens.
- Add CoolifyServer with 10 read-only tools (list/get for all resource types)
- Add BuildsResponse and ResolvesTeam traits for shared tool logic
- Add EnsureMcpEnabled middleware guarding /mcp routes
- Add enable/disable MCP API endpoints (root-only)
- Add is_mcp_server_enabled toggle in instance settings and advanced UI
- Add migration for is_mcp_server_enabled column
- Add feature tests for MCP endpoints and toggle API
- Scrub sensitive keys (passwords, tokens, raw IDs) from all responses
Introduce a dedicated `audit` log channel (daily rotation, configurable retention via
LOG_AUDIT_DAYS) and a small `auditLog()` / `auditLogWebhookFailure()` helper used to
record state-changing API operations and webhook events.
Instrumented:
- API mutation endpoints (create / update / delete / start / stop / restart) across
applications, services, databases (incl. backups, env vars, storage), servers,
projects + environments, scheduled tasks, private keys, GitHub apps, cloud provider
tokens, Hetzner server provisioning, instance enable/disable.
- Webhook signature verification outcomes for GitHub, GitLab, Bitbucket, Gitea and
Stripe, plus the Sentinel push endpoint.
- Authentication and authorization outcomes via the global exception handler and
the `ApiAbility` middleware (unauthenticated, ability-denied, policy-denied).
The helper is wrapped in try/catch so logging failures never affect the request
path. Successful operations log at `info`; suspicious/denied requests log at
`warning`. Operators wanting a failures-only feed can set `LOG_AUDIT_LEVEL=warning`.
Includes a feature test suite covering the helper, the webhook providers and the
new auth/authorization log paths.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add ValidationPatterns helpers for database identifiers and passwords,
apply them across database Livewire components and the API controller,
encode MongoDB init script values via json_encode, and pass the MySQL
user through escapeshellarg when generating SSL chown commands.
Replace exception text in 5xx JSON responses with stable, action-specific
messages so API consumers get a consistent payload regardless of which
underlying client (Guzzle, PDO, filesystem) raised the exception. The
previous responses concatenated the raw upstream error, which produced
inconsistent messages and unnecessary noise for clients trying to parse
errors programmatically.
Touched endpoints:
- GET /api/v1/hetzner/{locations,server-types,images,ssh-keys}
- POST /api/v1/servers/hetzner
- DELETE /api/v1/databases/{uuid}/backups/{uuid}
- DELETE /api/v1/databases/{uuid}/backups/{uuid}/executions/{uuid}
- /download/backup/{uuid}
The RateLimitException branch and AuthenticationException flow keep their
existing curated messages.
Adds Pest coverage for the four Hetzner GET endpoints to lock the response
shape on upstream failure.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Tighten validation on volume name and host path inputs across Livewire + API storage endpoints and escape shell arguments in volume clone and compose preview cleanup paths.
Replace `ownedByCurrentTeam()` (session-based) with `ownedByCurrentTeamAPI($teamId)`
(explicit team ID) when resolving S3 storage in create_backup and update_backup.
Session-based team resolution is unreliable in API context where auth is token-based.
Add `S3Storage::ownedByCurrentTeamAPI(int $teamId)` scope and update feature tests
to use real model instances instead of Mockery mocks.
- Validate content (required string, min:10, max:2000) in OtherController@feedback
- Register 'feedback' named rate limiter (3/min per user or IP) in RouteServiceProvider
- Apply throttle:feedback middleware to POST /api/feedback
- Forward to Discord with allowed_mentions.parse=[] and a 5s HTTP timeout
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Use find_destination_for_current_team helper across resource creation
flows and the destination controller. Pass full destination objects to
database creation helpers instead of UUIDs so team relationships are
resolved consistently before the resource is created or linked.
Add feature tests covering destination, backup storage, and resource
proof lookups across teams.
Add `DELETE /api/v1/applications/{uuid}/previews/{pull_request_id}` to
cancel active deployments, stop containers, and delete the preview
record via `CleanupPreviewDeployment`. Includes OpenAPI annotations,
input validation, and full feature test coverage.
Replace all uses of `forceFill`, `forceCreate`, and `forceFill` with their
non-force equivalents across models, actions, controllers, and Livewire
components. Add explicit `$fillable` arrays to all affected Eloquent models
to enforce mass assignment protection.
Add ModelFillableCreationTest and ModelFillableRegressionTest to verify that
model creation respects fillable constraints and prevent regressions.
Add logic to populate docker_compose_domains in applicationParser
for dockercompose build packs, ensuring proper domain handling
for KEY-based SERVICE_FQDN variables.