Commit graph

1031 commits

Author SHA1 Message Date
Andras Bacsai
a07cee7ad6 fix(github): support custom webhook override 2026-05-27 09:05:55 +02:00
Andras Bacsai
499a8666db fix(github): allow custom webhook endpoint input 2026-05-27 08:37:10 +02:00
Andras Bacsai
9b996b4dc9 chore: inspect commit message guidance 2026-05-27 07:14:54 +02:00
Andras Bacsai
d443758b03 fix(github): allow system-wide private apps across teams
Use the shared GitHub app scope when listing and loading private apps so system-wide apps owned by another team remain available. Update coverage for mounting and loading repositories through those apps.
2026-05-26 17:36:02 +02:00
Andras Bacsai
9f29df4cc3 fix(sentinel): accept empty container heartbeats
Allow Sentinel pushes with an empty containers array so servers with no
running containers still refresh their heartbeat and enqueue an update.
2026-05-26 17:31:27 +02:00
Andras Bacsai
081bd6ef8c fix(seeding): ensure root user joins root team
Create the root team before production seeding depends on it, reuse the
existing root team when creating root users, and cover the production seeder
flow with a feature test.
2026-05-26 17:05:54 +02:00
Andras Bacsai
6da907f1c8 chore: inspect commit message guidance 2026-05-26 15:35:09 +02:00
Andras Bacsai
0c6a233b27 fix(deployment): unregister Livewire morph hook on teardown
Store the morph.updated cleanup callback and invoke it during Alpine destroy so deployment log search hooks do not survive component teardown.
2026-05-26 14:57:20 +02:00
Andras Bacsai
b751628545 fix(database): normalize read/write host lists
Trim comma-separated database host values and fall back to DB_HOST or the default host when write hosts are empty. Add unit coverage for read/write host parsing.
2026-05-26 14:52:25 +02:00
Andras Bacsai
8e033c5bc3 fix(destination): promote networks atomically
Wrap destination promotion in a transaction so the main destination swap and additional network updates stay consistent. Add coverage for promoting an owned team network while preserving the previous main destination as an additional network.
2026-05-26 14:50:29 +02:00
Andras Bacsai
f44ace3965 fix(destination): validate network server pairing
Ensure destination attach and promote operations only accept networks that belong to the selected server, preventing mismatched same-team server/network pairs.
2026-05-26 14:48:36 +02:00
Andras Bacsai
097efd14ce fix(storage): clear stale disk usage cache
Forget cached storage threshold state when reported disk usage drops below the alert threshold, allowing future threshold crossings to dispatch a fresh storage check.
2026-05-26 14:45:49 +02:00
Andras Bacsai
43884823c6 chore(ssh): remove stale mux cleanup job
Drop the scheduled stale multiplexed connection cleanup job, its SSH mux
health/orphan config, and the tests that covered that cleanup path.
2026-05-26 14:40:38 +02:00
Andras Bacsai
b5be9fe9e8 fix(sentinel): lock push dedupe decisions
Guard Sentinel push hash checks and cache updates with a server-scoped atomic cache lock to prevent concurrent duplicate dispatches.
2026-05-26 14:12:56 +02:00
Andras Bacsai
7677fac2f5 fix(sentinel): validate push containers payload
Reject malformed sentinel push payloads before updating heartbeat state,
dispatching jobs, or writing deduplication cache entries.
2026-05-26 14:07:41 +02:00
Andras Bacsai
ed3780b2a7 fix(schedule): run stale multiplex cleanup on crons queue
Dispatch CleanupStaleMultiplexedConnections through the crons queue and
cover the scheduled job queue assignment with a feature test.
2026-05-26 13:51:22 +02:00
Andras Bacsai
ebf23f4874 fix(ssh): escape scp source and destination
Quote SCP operands when building commands to prevent shell injection through source or destination paths, and cover the escaping behavior in the SSH command injection tests.
2026-05-26 13:48:10 +02:00
Andras Bacsai
8a40c4e348 chore(sync-bunny): remove GitHub release sync paths
Drop the unused GitHub release and version sync options from sync:bunny,
leaving the command focused on BunnyCDN template, release, and nightly syncs.
Update the nightly test to assert it does not invoke gh or git.
2026-05-26 11:51:38 +02:00
Andras Bacsai
21db1fd374 fix(sync-bunny): sync nightly CDN files to nested paths
Write nightly versions and releases under json/nightly in the CDN repo, and cover both release and versions-only sync flows with feature tests.
2026-05-26 11:41:04 +02:00
Andras Bacsai
8e6e3551f3
fix(ui): improve configuration changes modal values, colors and spacing (#10365) 2026-05-26 11:09:54 +02:00
Andras Bacsai
27b76a4e97 Merge remote-tracking branch 'origin/next' into fix/form-state 2026-05-25 16:08:19 +02:00
Andras Bacsai
33e172ac24 fix(backups): revalidate S3 storage on scheduled backup submit
Check the selected S3 storage against the database at submit time so
stale Livewire state cannot schedule backups with storage that was
reassigned or marked unusable after the component mounted.
2026-05-23 21:06:22 +02:00
Andras Bacsai
a4d75ff0e2 fix(backups): validate S3 storage before backup scheduling
Prevent scheduled database backups from enabling S3 uploads without a valid team-owned storage configuration, and preserve the previous S3 storage ID in missing-storage error messages.

Add coverage for backup edit/create validation and S3 upload failure messaging.
2026-05-23 13:06:36 +02:00
Andras Bacsai
ffe8cfd76f fix(changelog): use configurable GitHub releases source
Default changelog pulls to the GitHub raw releases JSON and cover the
configured URL, file writing, and draft-release filtering with feature tests.
2026-05-22 18:39:37 +02:00
Andras Bacsai
a058786509 fix(ssh): remove mux first-use lock wrapper
Rely on OpenSSH lazy multiplexing directly for SSH and SCP commands,
removing the shell lock wrapper and related readiness checks.
2026-05-22 18:27:40 +02:00
Andras Bacsai
a13fb3cf00 fix(ssh): verify mux readiness before reusing socket
Use ssh -O check in the first-use mux lock flow so commands only reuse a multiplexed socket after the control master is actually ready.
2026-05-22 18:22:22 +02:00
Andras Bacsai
5c67766f41 fix(ssh): serialize initial mux connection creation
Wrap first-use SSH and SCP multiplexed commands with a lock to avoid racing while the control socket is created. Also detect native OpenSSH mux master process names during stale connection cleanup and cover both orphaned and duplicate mux processes with tests.
2026-05-22 18:17:37 +02:00
Andras Bacsai
54a020cf1b fix(ssh): rely on lazy multiplexed connections
Remove explicit SSH master pre-warming and lock handling so OpenSSH manages ControlMaster creation lazily from real ssh/scp commands. Add cleanup for duplicate mux processes and update coverage around mux command options and stale process cleanup.
2026-05-22 18:01:53 +02:00
ShadowArcanist
bd744eb8dd
fix(ui): configuration changes modal values, colors and spacing 2026-05-22 21:22:50 +05:30
Andras Bacsai
57d879263d fix(ssh): prevent orphaned multiplexed connections
Serialize multiplexed SSH master creation per server to avoid concurrent workers spawning orphaned processes. Enable scheduled cleanup for stale mux connections and add guarded orphan process reaping with tests.
2026-05-22 17:31:38 +02:00
Andras Bacsai
b35524bdf8 Merge remote-tracking branch 'origin/next' into improve-github-app-setup-flow 2026-05-22 17:04:47 +02:00
Andras Bacsai
182df1cb07 fix(logs): keep stream polling active without collapsible panel
Move log stream polling off the loading indicator so non-collapsible log panels continue polling while streaming, and cover the behavior with a Livewire feature test.
2026-05-22 17:00:08 +02:00
Andras Bacsai
5a7408a919 fix(github): improve GitHub App setup and installation flow
- resolve the GitHub App by a stable identifier during installation
  callbacks so installing and re-installing keeps working over the
  full lifetime of the App
- verify the installation id received from the callback against the
  GitHub API before persisting it
- support re-installing an already configured GitHub App instead of
  blocking it
- require an authenticated session and rate limit the setup callback
  routes
- extend manifest setup state validity to match GitHub's manifest
  code lifetime

Adds feature coverage for the GitHub App setup and installation
callbacks.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 16:34:36 +02:00
Andras Bacsai
fcd63f40eb fix(queue): route scheduled jobs through crons helper
Centralize scheduled job queue selection with crons_queue() and use it for scheduler, task, and database backup jobs so cloud runs on crons while self-hosted stays on high.
2026-05-22 16:26:15 +02:00
Andras Bacsai
e2199f1223 fix(queue): route cloud jobs to dedicated queues
Use config-based queue selection for deployment and scheduled jobs so cloud dispatches deployments to `deployments` and scheduled jobs to `crons`, while self-hosted keeps using `high`.

Add coverage for deployment queue helper, start action routing, and scheduled job manager routing.
2026-05-22 16:11:24 +02:00
Andras Bacsai
809d9b21fa fix(webhook): match manual webhook repositories case-insensitively
Git hosts treat owner/repo names case-insensitively, but the exact
repository match used a case-sensitive comparison, so a payload whose
casing differed from the stored git remote would fail to match and
skip a legitimate deployment.

Lowercase both canonical repository paths before comparing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 15:59:20 +02:00
Andras Bacsai
c1518ba1c0 fix(webhook): match manual webhook repositories exactly
The manual webhook handlers selected target applications with a
`git_repository LIKE %full_name%` substring query, so a payload
repository name could match unintended applications when repository
names overlap.

Add a `MatchesManualWebhookApplications` trait that validates the
incoming `owner/repo` value and matches `Application.git_repository`
by exact normalized path. Github, Gitlab, Gitea and Bitbucket manual
handlers now use it, reject invalid repository input early, and return
a consistent generic webhook failure payload.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 15:32:44 +02:00
Andras Bacsai
00ce43a9d0
Refine service resource routing (#10358) 2026-05-22 13:40:18 +02:00
Andras Bacsai
beaad0a722 Refine service resource routing 2026-05-22 13:39:26 +02:00
Andras Bacsai
7f135e0f6d Harden token permission handling 2026-05-22 13:12:17 +02:00
Andras Bacsai
e9b8320d5f Fix source selection flow 2026-05-22 13:00:53 +02:00
Andras Bacsai
783344c875
fix(environment): scope DeleteEnvironment lookups to current team (#10349) 2026-05-22 12:57:57 +02:00
Andras Bacsai
59111e8cf3 fix(destination): scope server and network selection to current team
Resolve the server and network in Destination::addServer() and
::promote() through ownedByCurrentTeam() before use, authorize the
update against the resource, and pass the validated IDs into
attach()/detach()/update(). Errors are routed through handleError()
to match the sibling removeServer() method.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 12:53:14 +02:00
Andras Bacsai
36526928df feat(sentinel): deduplicate metrics push processing
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.
2026-05-22 12:48:48 +02:00
Andras Bacsai
df166ac689 fix(environment): scope DeleteEnvironment lookups to current team
Scope DeleteEnvironment::mount() and delete() lookups through
Environment::ownedByCurrentTeam() so an environment_id that belongs to
another team resolves to a 404 instead of loading the foreign record.
Mark $environment_id as #[Locked] so the public Livewire property can no
longer be reassigned from the client.

Add tests/Feature/DeleteEnvironmentTeamScopingTest.php covering mount,
delete, the #[Locked] guard, and the team-scoped helper for both the
cross-team and own-team cases.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 12:37:48 +02:00
Andras Bacsai
5dda39e588 fix(source): scope private key and source selection to current team
The Source component now resolves the supplied private key and Git
source IDs through team-scoped queries before persisting them, so a
selection can only ever reference a resource owned by the current
team. The source type is additionally restricted to the supported
GitHub/GitLab app classes.

The privateKeyId property is marked #[Locked] so it can only change
through the dedicated handler rather than a direct property update.

Adds feature tests covering team-scoped selection of private keys and
Git sources.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 12:30:00 +02:00
Andras Bacsai
b124397613 fix(schedule): prevent duplicate SSL certificate regeneration
Run RegenerateSslCertJob on one server only and add coverage to ensure scheduled production jobs use onOneServer.
2026-05-21 19:19:43 +02:00
Aditya Tripathi
7a3fcd37d5 fix(livewire): scope DatabaseProxyStopped to proxy fields, harden status trait
Clickhouse, Dragonfly, and Keydb still called syncData() inside the
DatabaseProxyStopped broadcast handler, clobbering in-progress edits to
name/description/credentials. Refresh only is_public/public_port/
public_port_timeout instead, matching the pattern used elsewhere.

Also null-guard HasDatabaseStatusInfo::getListeners() against an absent
Auth::user()/currentTeam(), add explicit return types on getListeners()
and render(), and convert inline comments in the SSL refresh test to a
PHPDoc block.
2026-05-21 10:24:49 +00:00
Aditya Tripathi
e7e65831a7 fix(livewire): preserve wire:dirty across DB status broadcasts
The earlier refreshStatus fix kept user-typed values intact but Livewire still
absorbed deferred wire:model values into the snapshot on every broadcast-
triggered roundtrip, clearing the unsaved-changes indicator and making the form
look auto-saved. Move all status-derived display (DB URLs, SSL toggle/mode,
cert expiry) out of each DB General form into a sibling StatusInfo Livewire
component, so the form never roundtrips on broadcasts.

Shared scaffolding lives in App\Traits\HasDatabaseStatusInfo plus an x-database-
status-info Blade component, leaving each per-DB StatusInfo class as a ~20-50
line declaration of label, SSL mode options, and SSL save hooks. Parents
dispatch databaseUpdated from save methods so the sibling refreshes after writes.

Tests cover the architecture (no DB form subscribes to status broadcasts) and
the sibling's refresh-on-status-change behavior.
2026-05-21 08:31:08 +00:00
Aditya Tripathi
b9f773c1d9 fix(livewire): stop broadcast handlers from wiping in-progress form input 2026-05-20 19:04:43 +00:00
Andras Bacsai
65c0c92c02 fix(destinations): handle empty and server-scoped destinations
Build the global destinations list from actual destination records so empty
servers do not render duplicate empty states. Allow creating Docker destinations
for a selected team server outside the global usable list, authorize swarm
creation correctly, and store discovered swarm network names from the selected
network. Add feature coverage for empty states, selected-server mounting, and
swarm destination creation.
2026-05-19 12:50:08 +02:00
Andras Bacsai
fde500a347 fix(templates): require Docmost mail driver
Require MAIL_DRIVER to be set before Docmost starts and add a unit test to keep the compose template and generated service templates in sync.
2026-05-15 13:36:02 +02:00
Julien Bouquillon
89d7672253 feat(api): add is_preview_deployments_enabled on applications 2026-05-13 13:09:18 +02:00
Andras Bacsai
d1126c02a9 fix(deployments): filter generated compose service env vars
Exclude generated Docker Compose SERVICE_FQDN, SERVICE_URL, and SERVICE_NAME variables from runtime, build-time, and build arg environments so stale stored values cannot override generated service names for preview deployments.
2026-05-13 11:59:45 +02:00
Andras Bacsai
a54e70b4e0 fix(deployments): skip registry image tag for previews
Only push the configured Docker registry image tag for production deployments, and cover preview and missing-tag cases with unit tests.
2026-05-13 11:49:15 +02:00
Andras Bacsai
fb13a6cdc0 fix(api): expose cloud tokens with sensitive read access
Show cloud provider token values only when the API request has sensitive
read permission, and cover read, read:sensitive, and root token behavior.
2026-05-13 11:29:48 +02:00
Andras Bacsai
6ab88c46b2 Merge remote-tracking branch 'origin/next' into audit-policies 2026-05-13 11:15:29 +02:00
Andras Bacsai
4ff3e4b2be
feat(deployments): track application configuration diffs (#10183) 2026-05-13 10:49:53 +02:00
Andras Bacsai
1522c510cf fix(api-tokens): mark expiration warning after notification
Ensure failed token expiration warning notifications do not persist the warning marker, allowing the job to retry later.
2026-05-13 10:28:32 +02:00
Andras Bacsai
df4d9f8069 fix(applications): use preview environment variable query
Call the preview environment variable relationship as a query when building the legacy configuration hash, and cover preview deployments with a regression test.
2026-05-13 10:28:18 +02:00
Andras Bacsai
3911a0305c fix(api-tokens): persist expiration warning state
Track when expiration warnings are sent on personal access tokens so repeated job runs or cache flushes do not send duplicate notifications.
2026-05-13 10:11:40 +02:00
Andras Bacsai
0ecd488d6a fix(applications): refresh pending configuration changes
Dispatch configuration change events after saving application source and advanced settings, and refresh the configuration checker before showing redeploy diffs.
2026-05-13 10:04:17 +02:00
Andras Bacsai
f8849aba73 feat(deployments): track application configuration diffs
Store deployment configuration snapshots on application deployment queues and compare them against the current application state. Surface grouped pending changes in the configuration checker and use build-impact diffs to decide when an existing image can skip the build step.
2026-05-13 09:58:58 +02:00
Andras Bacsai
d8972e97c9 fix(previews): clean up closed PR previews after update failures
Catch and report failures while updating closed pull request status so preview deployment cleanup still runs for closed GitHub pull request webhooks.

Add coverage for cleanup continuing when GitHub comment cleanup fails.
2026-05-13 09:31:28 +02:00
Andras Bacsai
63c2d31ca0 feat(applications): add configurable stop grace period
Add centralized stop grace period resolution for application settings and use it across manual stops, preview stops, and deployments. Validate the Livewire advanced setting against shared min/max constants and cover persistence, fillable creation, and fallback behavior with tests.
2026-05-11 23:43:53 +02:00
Andras Bacsai
d1220895d9 Merge remote-tracking branch 'origin/next' into feat/configurable-stop-grace-period 2026-05-11 23:20:31 +02:00
Andras Bacsai
6f3bb47682
fix(applications): decode custom nginx API payloads (#10067) 2026-05-11 22:24:55 +02:00
Andras Bacsai
a42613168d fix(applications): store custom nginx config from API correctly
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.
2026-05-11 22:22:01 +02:00
Andras Bacsai
9bb40f3ccb fix(deployment): avoid shared preview tags for HEAD commits
Use the deployment UUID when preview deployments are built from HEAD so each deployment gets distinct production and build image tags.
2026-05-11 22:11:08 +02:00
Andras Bacsai
2253c40e01 fix(deployment): include commit in preview image tags
Generate pull request preview image tags with both the PR id and commit
so different commits on the same PR do not reuse the same image tag. Sanitize
and truncate generated tags to stay within Docker tag limits.
2026-05-11 22:05:07 +02:00
Andras Bacsai
81a3bb0f07 fix(api): hide sensitive fields by default
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.
2026-05-11 21:18:07 +02:00
Andras Bacsai
c175d3d282 Merge remote-tracking branch 'origin/next' into audit-policies 2026-05-11 21:13:57 +02:00
Andras Bacsai
b29bdce73a Merge remote-tracking branch 'origin/next' into api-sensitive-data-scrubber 2026-05-11 17:34:48 +02:00
Andras Bacsai
ab1958d741 fix(railpack): fail fast when buildx is unavailable
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.
2026-05-11 17:31:29 +02:00
Andras Bacsai
0395db30f0 fix(railpack): align example ports and smoke checks
Update Railpack seed examples to use the expected Flask start command and Go/Rust exposed ports. Adjust smoke coverage to run Symfony by default and accept reachable 4xx responses, and extend seeder tests for per-example branch and port assertions.
2026-05-11 17:13:55 +02:00
Andras Bacsai
0f904d792b Merge remote-tracking branch 'origin/next' into feat/railpack 2026-05-11 17:03:25 +02:00
Andras Bacsai
ff149b8daa fix(stripe): ignore missing subscriptions in webhook jobs
Avoid failing Stripe webhook processing when local subscriptions are missing, and cover ignored invoice/payment/subscription events with feature tests.
2026-05-11 16:56:00 +02:00
Andras Bacsai
db7d0f0bfb Merge remote-tracking branch 'origin/next' into feat/railpack 2026-05-11 16:26:50 +02:00
Andras Bacsai
d96e253230 fix(ui): align deployment indicator with collapsed sidebar
Move the deployments indicator inside the app layout state scope so it can react to the sidebar collapsed state, and add a layout test covering the responsive positioning.
2026-05-11 16:25:15 +02:00
Andras Bacsai
b5ff124446 fix(env): validate Docker-compatible variable keys
Add shared environment variable key validation and normalization for Livewire forms and models, allowing Docker-compatible keys while rejecting invalid entries such as keys containing equals signs. Also quote Railpack build environment and secret arguments safely.
2026-05-11 15:43:09 +02:00
Andras Bacsai
d5946dcfca fix(railpack): include scoped env vars in builds
Build Railpack variables from generic build-time vars plus Railpack-specific vars, filter unrelated buildpack control vars, and ensure curl/wget deploy apt packages are present. Add coverage for standard and preview deployments.
2026-05-11 13:29:21 +02:00
Andras Bacsai
6ee75cfa65 fix(api): remove deprecated docker compose application endpoint
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.
2026-05-11 13:20:05 +02:00
Andras Bacsai
12aba41d9a fix(api): gate service server secrets by sensitive scope
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.
2026-05-11 11:53:22 +02:00
Andras Bacsai
c97f916052 fix(api): hide application compose PR fields
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.
2026-05-11 11:46:05 +02:00
Andras Bacsai
ffa494d391 Merge remote-tracking branch 'origin/next' into api-sensitive-data-scrubber 2026-05-11 11:36:24 +02:00
Andras Bacsai
9f380b8495 Merge remote-tracking branch 'origin/next' into feat/railpack 2026-05-11 10:58:13 +02:00
Andras Bacsai
c6ac52dc38 fix(env): generate encoded secrets from raw random bytes
Use random_bytes before hex and base64 encoding so generated env values
match the expected decoded byte lengths. Add Pest coverage for HEX and
REALBASE64 magic variables.
2026-05-09 14:49:39 +02:00
Andras Bacsai
fe934dd139 Merge remote-tracking branch 'origin/next' into feat/railpack 2026-05-06 14:33:22 +02:00
Andras Bacsai
c553b6aef9 Merge remote-tracking branch 'origin/next' into api-sensitive-data-scrubber 2026-05-06 14:33:19 +02:00
Andras Bacsai
29d41ba041 Merge remote-tracking branch 'origin/next' into 9916-investigate-undefined-relationship 2026-05-06 14:32:16 +02:00
Andras Bacsai
0888198a81 Merge remote-tracking branch 'origin/next' into api-sensitive-data-scrubber 2026-05-05 22:09:34 +02:00
Andras Bacsai
45f65481e6 fix(mcp): change enable/disable endpoints from GET to POST and fix service/app listing
- `/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)
2026-05-05 22:07:58 +02:00
Andras Bacsai
22a2c05a1d test(railpack): add API, Livewire UI tests and e2e smoke script
Add feature tests covering railpack build pack via REST API and
Livewire UI components, plus a bash smoke test that deploys seeded
railpack-* example apps against the local dev stack and verifies
COOLIFY_*, SOURCE_COMMIT, and RAILPACK_* env vars land correctly.
2026-05-05 15:32:43 +02:00
Andras Bacsai
1849b5903e refactor(scheduled-task): simplify server() with nullsafe operators and add return type
Replace nested null checks with nullsafe operator chains, add ?Server
return type, drop unreachable database branch, and cover all paths with
feature tests.
2026-05-04 12:26:15 +02:00
Andras Bacsai
b6ca6b1b20 feat(railpack): expose COOLIFY_* vars at build time and generalize buildpack control flag
Mirrors Nixpacks behavior: inject COOLIFY_* and SOURCE_COMMIT into
railpack build variables so apps (e.g. SPAs baking public URLs) can
read them via /run/secrets/<KEY>.

Rename is_nixpacks → is_buildpack_control to cover both NIXPACKS_ and
RAILPACK_ prefixed keys. Update the env variable view and appends list
accordingly.

Promote generate_coolify_env_variables to protected for testability.
2026-04-30 18:31:41 +02:00
Andras Bacsai
ea0ade442b Merge remote-tracking branch 'origin/next' into api-sensitive-data-scrubber 2026-04-30 16:45:34 +02:00
Andras Bacsai
ace643d3d8 fix(railpack): query buildtime env vars directly instead of via computed attribute
Replace `railpack_environment_variables_collection()` helper (which returned
pre-filtered Eloquent attribute collections) with inline queries on
`environment_variables()` / `environment_variables_preview()` filtered by
`is_buildtime`. This ensures Railpack build variables are sourced from the
same query path as the rest of the deployment pipeline and avoids relying on
a now-removed accessor that silently included all railpack vars regardless of
build context.
2026-04-30 16:38:58 +02:00
Andras Bacsai
ec71d33f5e fix(railpack): pin frontend image version via config constant
Remove RAILPACK_FRONTEND_IMAGE env var from helper Dockerfile and resolve
the image ref at runtime using a new `railpack_version` constant in config.
Eliminates Docker build-time env interpolation for BUILDKIT_SYNTAX arg.
2026-04-30 16:27:08 +02:00
Andras Bacsai
a51f114a70 fix(standalone-docker): include keydb, dragonfly, clickhouse in databases()
Add missing DB types to StandaloneDocker::databases() concat chain and
cover all 8 standalone database types with feature tests.
2026-04-30 15:01:48 +02:00
Andras Bacsai
79174b749d refactor(helpers): extract STANDALONE_DATABASE_MODELS registry, add tests
Replace 8× repeated per-type if-blocks in `queryDatabaseByUuidWithinTeam`
and `queryResourcesByUuid` with a single loop over the new
`STANDALONE_DATABASE_MODELS` constant.

Add unit tests to guard the registry against drift (keys mirror
`DATABASE_TYPES`, every entry is a valid Eloquent model with `team()`),
and feature tests covering team-ownership, wrong-team, and unknown-UUID
cases for `queryDatabaseByUuidWithinTeam`.
2026-04-30 14:48:48 +02:00
Andras Bacsai
0f830b31f3 Merge remote-tracking branch 'origin/next' into mcp-server-instance-toggle 2026-04-30 14:48:35 +02:00
Andras Bacsai
8dc79f4ed6 fix(api): expose nested server secrets for privileged tokens
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.
2026-04-30 11:49:15 +02:00
Andras Bacsai
8e91d627a3 Merge remote-tracking branch 'origin/next' into feat/railpack 2026-04-30 11:47:06 +02:00
Andras Bacsai
f9b3f89757 Merge remote-tracking branch 'origin/next' into suppress-horizon-job-failures 2026-04-30 11:42:52 +02:00
Andras Bacsai
e828058755 Merge remote-tracking branch 'origin/next' into api-sensitive-data-scrubber 2026-04-30 11:30:50 +02:00
Andras Bacsai
d057ce5172 Merge remote-tracking branch 'origin/next' into mcp-server-instance-toggle 2026-04-30 11:30:45 +02:00
Andras Bacsai
8b7dbbafb2 fix(api): hide sensitive fields by default, expose via makeVisible for privileged tokens
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.
2026-04-30 11:28:06 +02:00
Andras Bacsai
4575106f53 feat(sentinel): embed server UUID in encrypted sentinel token
Replace random string with encrypted JSON payload containing
server_uuid, binding token to its server for validation.
Remove double-encrypt test no longer relevant to new token format.
2026-04-30 08:21:30 +02:00
Andras Bacsai
00d6e83e7f fix(sentinel): auto-regenerate invalid or undecryptable tokens
Replace hard validation error with self-healing token logic. Tokens that
are null, empty, or fail decryption are now regenerated automatically
rather than crashing sentinel startup or metrics reads.

Token format changed from encrypted JSON payload to a plain 64-char
random string (Str::random), eliminating double-encryption issues and
simplifying the validation regex to cover the new character set.

New `ensureValidSentinelToken()` method on ServerSetting centralises
the get-or-regenerate contract; both StartSentinel and HasMetrics now
delegate to it. HasMetrics logs a warning when regeneration occurs so
operators know a sentinel container restart is required.

`isValidSentinelToken()` now accepts `?string` (null → false).

Adds feature tests covering: null/empty/undecryptable stored values,
idempotent return of valid tokens, RuntimeException only when
regeneration itself produces an invalid token, no double-encryption of
newly generated tokens, and cast round-trip consistency.
2026-04-29 16:44:12 +02:00
Andras Bacsai
fc3ce85f88 feat(horizon): suppress failed job entries for deployment/timeout errors on cloud
On cloud, DeploymentException and TimeoutExceededException are expected
failure modes that pollute the Horizon failed jobs UI. Listen to JobFailed
events and scrub the entry via JobRepository::deleteFailed so operators
are not alerted for noise failures. Self-hosted instances are unaffected.
2026-04-29 15:40:01 +02:00
Andras Bacsai
b8e311622a Merge remote-tracking branch 'origin/next' into feat/railpack 2026-04-29 15:22:47 +02:00
Andras Bacsai
6d1d699595 fix(deployments): resolve commit from app git_commit_sha when not explicitly set
Change `commit` param from `string 'HEAD'` default to `?string null`, then
resolve priority: explicit param > app `git_commit_sha` > `'HEAD'` fallback.

Add feature tests covering all four resolution paths.
2026-04-29 10:59:32 +02:00
Andras Bacsai
7ab16ad7b5 feat(mcp): add MCP server with read-only tools for Coolify resources
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
2026-04-29 10:30:43 +02:00
Andras Bacsai
46180dbbf9 feat(webhook): skip deployment on [skip ci]/[skip cd] commit markers
Add DetectsSkipDeployCommits trait with two strategies: shouldSkipDeploy
(all commits must contain the marker) for push events, and
shouldSkipDeployAny (any single marker triggers skip) for PR/MR titles
and latest-commit signals.

Apply trait to Bitbucket, Gitea, GitHub, GitLab webhook controllers and
ProcessGithubPullRequestWebhook job. PRs pass pullRequestTitle through
to the job constructor for evaluation.
2026-04-29 09:12:24 +02:00
Andras Bacsai
9717d9ff5a Merge remote-tracking branch 'origin/next' into feat/railpack 2026-04-29 08:56:23 +02:00
Andras Bacsai
eaaf258f25 fix(service): block UI editing of file volumes exceeding 5 MiB
Large host files mounted via Docker volumes caused the storages page to
become unusable — full file content was stored in the encrypted mediumText
column and serialised into the Livewire payload, crashing the browser.

- Add MAX_CONTENT_SIZE (5 MiB), BINARY_PLACEHOLDER, and TOO_LARGE_PLACEHOLDER
  constants to LocalFileVolume
- Check remote file size via stat/wc before cat in loadStorageOnServer and
  saveStorageOnServer; store placeholder instead of content when limit exceeded
- Expose is_too_large computed attribute (appended for Livewire serialisation)
- Guard submit, instantSave, and syncData in FileStorage Livewire component
- Truncate oversized content in Storage::refreshStorages to prevent payload bloat
- Show distinct warning banner in file-storage blade; mark textarea readonly and
  hide Save/Convert buttons for too-large files
- Add unit tests covering constants, computed flags, and toArray serialisation

Fixes #4701
2026-04-28 22:36:56 +02:00
Andras Bacsai
19994a0a13 test(api): add feature tests for server connection_timeout API
Tests cover PATCH update success, out-of-range, above-max, and
non-integer validation for the connection_timeout field.
2026-04-28 22:20:15 +02:00
Andras Bacsai
6293b14586 feat(server): add configurable SSH connection timeout per server
Add `connection_timeout` field to server settings, allowing per-server
override of the global SSH connection timeout constant.

- Migration adds `connection_timeout` integer column (default 10s)
- `ServerSetting` model exposes and casts the new field
- `SshMultiplexingHelper::getConnectionTimeout()` resolves per-server
  value with fallback to `constants.ssh.connection_timeout`
- All SSH/SCP command builders use the new resolver instead of the
  global config directly
- Livewire `Show` component binds `connectionTimeout` with validation
  (1–300 seconds) and syncs to/from the model
- UI input added to server settings form with helper text
- Feature tests cover default, persistence, resolver, and fallback
2026-04-28 15:39:36 +02:00
Jan Thiel
6637159d7b feat(hetzner): add support for enabling backups during server creation 2026-04-28 15:37:26 +02:00
Andras Bacsai
b8226be774 refactor(server): dispatch event for reachability notifications, drop retry loop
Move reachability notification triggering out of isReachableChanged into
a dedicated ServerReachabilityChanged event dispatched by
ServerConnectionCheckJob. Remove the blocking 3-attempt sleep loop from
isReachableChanged — unreachable_count threshold alone now gates the
Unreachable notification. Add feature and unit tests covering all
notification dispatch paths.
2026-04-28 15:28:22 +02:00
Andras Bacsai
a2096c6f68 feat(observability): add structured audit log channel for API and webhook events
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>
2026-04-28 14:50:37 +02:00
Andras Bacsai
b3339d1034 feat(railpack): add buildpack control var filtering and dev seeder
Extract NIXPACKS_/RAILPACK_ prefix filtering into a reusable
`scopeWithoutBuildpackControlVariables` query scope on EnvironmentVariable.
Apply scope consistently to runtime vars, runtime preview vars, and
buildtime var generation in ApplicationDeploymentJob.

Refactor `generate_railpack_env_variables` to return a Collection.
Add `RAILPACK_FRONTEND_IMAGE` constant and bake it into the
coolify-helper Dockerfile as a build arg.

Add DevelopmentRailpackExamplesSeeder (dev/local env only) for
seeding example Railpack apps, wired into DatabaseSeeder.

Add tests:
- ApplicationDeploymentControlVarFilteringTest: verifies control vars
  are excluded from runtime and buildtime envs
- DevelopmentRailpackExamplesSeederTest: verifies seeder behavior
- ApplicationDeploymentRailpackEnvParityTest: parity checks for env
  handling across build/runtime paths
2026-04-28 14:37:31 +02:00
Andras Bacsai
5cef7cc092 Merge remote-tracking branch 'origin/next' into feat/railpack 2026-04-28 14:36:54 +02:00
Andras Bacsai
cabcd8f699 fix(terminal): add idle timeout, reconnect replay, and scrollback preservation
- Kill PTY and notify client after 30 min of inactivity (IDLE_TIMEOUT_MS)
- Buffer client messages during async auth/IP fetch to prevent race-condition
  message loss on fast reconnects
- Replay last sent command after transient reconnect so PTY respawns without
  user interaction
- Preserve scrollback on disconnect/reconnect; write visible timestamp markers
  instead of wiping term state
- Handle idle-timeout sentinel on client with user-facing error message
2026-04-28 12:26:31 +02:00
Andras Bacsai
9408620d5f fix(terminal): add WS heartbeat and fix proxy idle disconnects
Proxies (Cloudflare, nginx) drop idle WebSocket connections before the
application notices, leaving clients typing into dead sockets.

- Add server-side ping/pong heartbeat (30s) in terminal-server.js;
  terminate unresponsive clients instead of letting connections go stale
- Move client keepAlive interval start to the connect event so it
  restarts correctly after reconnects
- Remove hidden-tab keepalive short-circuit — server pings now own
  liveness; suppressing client pings while hidden masked proxy drops
- Fix clearAllTimers to use clearTimeout for one-shot timers
- On visibility resume, probe with a 5s timeout instead of the default
  35s so half-open sockets are detected quickly
- Bump coolify-realtime to 1.0.14 across all compose files
2026-04-28 10:35:32 +02:00
Andras Bacsai
b4e139929e Merge remote-tracking branch 'origin/next' into fix/oauth-email-normalization 2026-04-27 14:56:16 +02:00
Hendrik Kleinwaechter
60d8aba323 feat: configurable stop grace period for applications
Adds stop_grace_period to application settings (seconds, 1-3600, default 30).
Used in place of the hardcoded docker stop -t 30 in the four places that
stop application containers: rolling update shutdown, manual stop, stop on
another server, and preview deployment stop.

Non-positive values fall back to the default via ($val > 0) ? $val : default,
with tests covering 0 and -10 so the cast does not blow up if a bad value
ever lands in the db.

Picks up Jack Coy's work from #7125 which went dormant. His commits are
squashed here with credit below.

Co-authored-by: Jack Coy <jackman3000@gmail.com>
2026-04-22 21:18:18 +02:00
Andras Bacsai
e1aac50b74
refactor(validation): tokenize shell-safe command pattern (#9684) 2026-04-20 22:04:36 +02:00
Andras Bacsai
817128c5af refactor(validation): tokenize shell-safe command pattern
Replace the flat character-class regex for SHELL_SAFE_COMMAND_PATTERN with
a token-aware alternation. The parser now recognizes explicit tokens
(`&&`, `||`, balanced single/double quotes, whitespace, and an unquoted
safe-char run) instead of a bag of characters, which lets us extend the
accepted grammar without loosening the guarantees.

New surface area, with tests:
- logical OR chaining (`make build || make clean`)
- shell globs and bang (`rm *.tmp`, `cp src/?.js dist/`, `! grep -q foo`)
- single-quoted arguments are now treated as balanced runs rather than
  rejected per-character

Preserved surface area:
- && chaining, balanced "..." and '...' quotes, the previous safe path /
  argument characters, and the existing error-path contract in
  ApplicationDeploymentJob::validateShellSafeCommand().

Also refreshes the user-facing validation messages in General.php so the
allow/deny list shown on failure matches the new grammar.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 22:00:41 +02:00
Andras Bacsai
f0e955bf45 refactor(database): escape postgres_user in SSL chown command
Apply escapeshellarg() to the Postgres username before interpolating it
into the chown command used to fix SSL certificate ownership, matching
the handling already in place for StartMysql. This keeps the sink-side
escaping consistent across database actions, independent of upstream
input validation.

Also adjusts an assertion in DatabaseSslCredentialEscapingTest to match
the actual double-escaped output of executeInDocker, and adds Postgres
regression cases for subshell and semicolon payloads.
2026-04-20 21:41:48 +02:00
Andras Bacsai
a05d4e3a4b fix(database): tighten Postgres init script filename handling
Validate new init-script filenames against path traversal and shell
metacharacters via a new validateFilenameSafe() helper, and harden the
write/delete paths with basename() + escapeshellarg() so legacy rows
still deploy and can be cleaned up without regressions.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 21:26:34 +02:00
Andras Bacsai
90ddbb3572 feat(security): support expiration on API tokens with warning notifications
Add optional expiration to personal API tokens. Users pick a duration
(1/7/30/60/90 days or Never) at creation time. Expired tokens are
rejected by Sanctum, pruned hourly by sanctum:prune-expired, and a
team notification fires ~24h before expiry so owners can rotate
before API calls start failing.

- ApiTokens Livewire component stores expires_at from expiresInDays
- Rework issued-tokens UI from card grid to table (matches other views)
- New ApiTokenExpirationWarningJob scheduled hourly (idempotent via RateLimiter)
- New ApiTokenExpiringNotification (email/discord/telegram/slack/pushover)
- api_token_expiring added to alwaysSendEvents so users cannot silence
  expiry warnings from the per-event notification toggle UI
- sanctum:prune-expired cadence moved from daily to hourly

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 14:28:38 +02:00
Andras Bacsai
40a9881ef2 fix(database): skip credential pattern validation for unchanged values
Pattern enforcement now conditional on field being dirty (changed vs
saved value). Prevents false validation failures when existing records
hold legacy credential formats that pre-date the stricter regex rules.
2026-04-20 13:58:44 +02:00
Andras Bacsai
03313e54cc fix(database): enforce credential format validation and sanitize init/SSL arguments
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.
2026-04-20 13:58:36 +02:00
Andras Bacsai
2264a2ef76 docs(tests): replace advisory ID with descriptive comment in healthcheck injection test 2026-04-20 13:28:55 +02:00
Andras Bacsai
64753b4136 fix(database): prevent command injection in healthcheck via CMD exec-form
Replace CMD-SHELL string interpolation with CMD exec-form arrays in
healthcheck configs for PostgreSQL, Dragonfly, KeyDB, and ClickHouse.

CMD-SHELL passes the string to /bin/sh -c, allowing command injection
through user-controlled fields (username, password, dbname). CMD
exec-form bypasses the shell entirely — each value is a discrete argv
element.

Fixes GHSA-gvc4-f276-r88p.

Adds regression tests covering semicolon, pipe, backtick, $(),
background operator, redirect, newline, and null-byte injection vectors.
2026-04-20 13:17:15 +02:00
Andras Bacsai
bb0c3501ef refactor(cli): validate --date and escape shell args on logs:scheduled
Reject malformed --date values with a clear error before building any
shell command, and wrap every interpolated value (log paths, filter
expression, line count) in escapeshellarg() so filter options and date
values can no longer break out of the tail/grep pipeline.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 12:09:48 +02:00
Andras Bacsai
49b5472961 refactor(auth): upgrade email verification hash to sha256
Move the email-verification URL hash from sha1 to sha256 and verify it
directly in the controller using hash_equals, instead of going through
Laravel's EmailVerificationRequest (which only compares against sha1).
The signed URL still carries the authoritative HMAC; the hash upgrade
keeps the identity binding aligned with modern hashing guidance.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 12:09:48 +02:00
Andras Bacsai
9b37a1a7eb refactor(auth): drop implicit email verification on invitation link login
The invitation-link login path previously marked the account as
email-verified as a side effect of authenticating, without the user ever
proving control of the mailbox. Remove that branch so every account
goes through the standard signed-URL verification flow.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 12:09:48 +02:00
Andras Bacsai
e373037a2a test: remove GHSA advisory IDs from test descriptions and comments
Strip advisory identifiers (GHSA-*) from describe blocks, test
docblocks, and inline comments. Replace with plain descriptive
labels. Also clean up FQCNs to use imported class names and minor
style fixes (string concatenation spacing).
2026-04-20 12:07:42 +02:00
Andras Bacsai
ea639dab8f
refactor(api): return stable generic error messages for 5xx responses (#9669) 2026-04-20 11:53:20 +02:00
Andras Bacsai
fe8b3412d3
refactor(settings): harden dev_helper_version validation and escape build args (#9670) 2026-04-20 11:52:48 +02:00
Andras Bacsai
03a35faf2c
refactor(storage): tighten S3 endpoint URL validation (#9668) 2026-04-20 11:51:51 +02:00
Andras Bacsai
6a5fd40a5c refactor(policies): add uploadBackup ability and enforce it on backup upload endpoint
Introduce a dedicated `uploadBackup` ability on Application, Database,
Service, and ServiceDatabase policies (admin/owner only) and call
`$this->authorize('uploadBackup', $resource)` in `UploadController::upload`
so the backup-upload endpoint goes through the same policy layer as the
rest of the authorization refactor. Adds Pest coverage for each policy
variant plus HTTP-level checks.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 11:51:35 +02:00
Andras Bacsai
dc9322b11f refactor(settings): validate dev_helper_version and escape build args
Constrain dev_helper_version to Docker tag grammar
([A-Za-z0-9_][A-Za-z0-9_.-]{0,127}), re-validate before triggering the
helper image build, and interpolate the image reference via
escapeshellarg() when composing the docker build command.
2026-04-20 11:51:27 +02:00
Andras Bacsai
4d83688896 refactor(api): return generic error messages for upstream and storage failures
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>
2026-04-20 11:50:30 +02:00
Andras Bacsai
297e9c41e1 refactor(storage): tighten S3 endpoint URL validation
Reuse the existing SafeWebhookUrl rule on the S3 Storage endpoint field so
the create and edit forms go through the same URL-normalization path as
webhook settings. Adds a matching guard inside S3Storage::testConnection()
so background callers (scheduled backups, database import reuse) also
validate the endpoint before building the S3 client.

Also fixes an IPv6-bracket edge case in SafeWebhookUrl so `http://[::1]`
style hosts are normalized before the filter_var IP check — the rule's
own loopback test was already asserting this behaviour.
2026-04-20 11:50:19 +02:00
Andras Bacsai
af0a8badb3 refactor(backup): validate database backup upload file type and size
Add allowlist of backup file extensions (sql, sql.gz, tar, tgz, zip,
dump, bak, bson, archive, bz2, xz, and compound variants) and enforce
a 10 GiB maximum file size on the backup upload endpoint. Validation
runs early on each chunk using the dropzone metadata and again on the
assembled file. Also drops the unused createFilename helper and the
commented-out S3 block.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 11:45:00 +02:00
Andras Bacsai
410a9a6195 refactor(volumes): validate input and escape shell args
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.
2026-04-20 11:27:10 +02:00
Andras Bacsai
1f9dd5326f Merge remote-tracking branch 'origin/next' into audit-policies
# Conflicts:
#	tests/Feature/DatabaseBackupCreationApiTest.php
2026-04-19 17:40:12 +02:00
Andras Bacsai
a1b2ab124a
fix(api): use explicit team ID for S3 storage lookup in backup endpoints (#9655) 2026-04-19 15:28:13 +02:00
Andras Bacsai
5019c8db92 fix(api): use explicit team ID for S3 storage lookup in backup endpoints
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.
2026-04-19 15:26:47 +02:00
Andras Bacsai
43f33d94ad Merge remote-tracking branch 'origin/next' into audit-policies
# Conflicts:
#	app/Http/Controllers/Api/SecurityController.php
#	app/Http/Controllers/Api/ServersController.php
#	app/Livewire/Admin/Index.php
#	app/Livewire/Destination/Show.php
#	app/Livewire/NavbarDeleteTeam.php
#	app/Livewire/Project/Application/Previews.php
#	app/Livewire/Project/DeleteProject.php
#	app/Livewire/Project/Shared/ResourceOperations.php
#	app/Livewire/Server/Resources.php
#	app/Livewire/Server/ValidateAndInstall.php
#	app/Livewire/Storage/Show.php
#	resources/views/livewire/dashboard.blade.php
#	resources/views/livewire/project/application/heading.blade.php
#	resources/views/livewire/project/database/heading.blade.php
#	resources/views/livewire/project/service/heading.blade.php
#	resources/views/livewire/project/shared/environment-variable/show.blade.php
#	resources/views/livewire/project/shared/scheduled-task/show.blade.php
#	tests/Feature/Security/TrustHostsMiddlewareTest.php
2026-04-19 15:19:37 +02:00
Andras Bacsai
0620496c5f fix(server): exclude persistent resources from container prune
Prevent docker container prune from removing containers labeled as
database, application, or service types. Previously only proxy containers
were excluded, risking accidental cleanup of active resources.
2026-04-19 15:17:47 +02:00
Andras Bacsai
371e883c75
refactor(api): validate and throttle feedback endpoint (#9653) 2026-04-19 14:50:03 +02:00
Andras Bacsai
5bf4bb9e80
feat(api): add DELETE endpoint for preview deployments by PR id (#9614) 2026-04-19 14:43:32 +02:00
Andras Bacsai
e7bbd45408 refactor(api): validate and throttle feedback endpoint
- 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>
2026-04-19 14:41:47 +02:00
Andras Bacsai
bafb9a5a8b refactor(webhook): encrypt manual webhook secrets and tighten HMAC verification
- Auto-generate a 40-char random secret for each manual_webhook_secret_* column on Application creation so new apps are never left with an empty secret.
- Add encrypted cast for the four webhook-secret columns; backfill migration re-encrypts existing plaintext values and fills missing ones.
- Reject webhook deliveries when the stored secret is empty (GitHub, GitLab, Bitbucket, Gitea manual endpoints).
- Bitbucket: require the sha256 algorithm prefix on X-Hub-Signature instead of trusting the client-supplied algo.
- GitLab: drop the ?? '' fallback on the token comparison.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-19 12:52:23 +02:00
Andras Bacsai
33518b24a2
refactor: tighten team scoping on resource creation and admin nav (#9651) 2026-04-19 12:01:11 +02:00
Andras Bacsai
f77cc91b83 refactor(admin): use named routes for admin index navigation
Replace Referer-based redirects in Admin Index back() and switchUser()
with named routes (admin.index and dashboard) for consistent navigation
behavior independent of the request header.

Add tests verifying back() returns to admin.index, switchUser routes to
the dashboard, and the Referer header is no longer consulted.
2026-04-19 11:58:52 +02:00
Andras Bacsai
a478ac66eb refactor: scope destination and resource lookups by current team
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.
2026-04-19 11:55:12 +02:00
Jan Thiel
a4b27641c8 feat(hetzner): add endpoints and UI for attaching firewalls and internal networks to the Server Creation dialog 2026-04-19 06:12:50 +02:00
Andras Bacsai
bceb5f28dc feat(applications): add DELETE endpoint for preview deployments by PR id
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.
2026-04-17 13:29:11 +02:00
Andras Bacsai
451b7376ed Merge remote-tracking branch 'origin/next' into feat/railpack 2026-04-17 07:01:27 +02:00
Andras Bacsai
3a8f52ce16 fix(team): mark servers unreachable when subscription ends
Set unreachable_count to 3 and unreachable_notification_sent to true
on all team servers in subscriptionEnded(), so the existing cleanup
command can pick them up after the 7-day grace period.

Also adds feature tests for the subscription-ended cleanup flow and
casts server IP to string in existing unreachable server tests to fix
type comparison.
2026-04-15 15:12:29 +02:00
Andras Bacsai
3fa4ea9ad3
fix(git): preserve ssh scheme URLs with custom ports (#9425) 2026-04-14 15:31:31 +02:00
Andras Bacsai
16d9c02e73 fix(install): use Rocky Linux RHEL Docker repository
Add a Rocky-specific Docker install path to the stable and nightly install scripts, using Docker's documented RHEL repository flow. Include a unit test to lock in the Rocky repo selection and command set.
2026-04-14 10:31:01 +02:00
Andras Bacsai
0627db5342 Merge remote-tracking branch 'origin/next' into feat/railpack 2026-04-10 12:20:09 +02:00
Andras Bacsai
0d8a95473a fix(ui): improve responsive project headings and controls
Refine mobile layout for project resource pages by making breadcrumbs and status blocks responsive, improving dropdown and checkbox touch behavior, and adding support for custom modal triggers. Add feature tests covering breadcrumb visibility and responsive checkbox layout.
2026-04-09 19:51:31 +02:00
Andras Bacsai
33f260a655 fix(deployments): use full-height deployment logs layout
Adjust the deployment view container classes so the logs panel fills the available viewport height instead of capping at 30rem. Add a feature test to lock in the full-height layout classes and prevent regressions.
2026-04-09 19:27:19 +02:00
Andras Bacsai
3c51b1aacc fix(railpack): pass command overrides through supported prepare/build args
Use Railpack's install env handling and dedicated CLI flags for build/start overrides, and forward install commands into docker build secrets so image builds stay aligned with prepare-time configuration. Update the railpack config test to cover the new command format.
2026-04-09 19:01:52 +02:00
Andras Bacsai
d7e1b7ec37 feat(railpack): add config merging, beta badge, and nodejs seeder example
- Implement railpack.json + generated config deep merging logic in
  ApplicationDeploymentJob with JSON validation and assoc array checks
- Label Railpack as "Beta" in all build pack selectors and show a
  visible beta badge when railpack is selected in new-app forms
- Add railpack-nodejs Fastify example to ApplicationSeeder
- Add ApplicationSeederTest and ApplicationDeploymentRailpackConfigTest
  covering config merge behavior and seeder correctness
2026-04-09 18:45:42 +02:00
Andras Bacsai
0649a424b8 fix(buildpack): revert default build pack to nixpacks and reorder selector
Change default build_pack from railpack back to nixpacks in all new
application flows (GithubPrivateRepository, GithubPrivateRepositoryDeployKey,
PublicGitRepository) and reorder the build pack dropdown so Nixpacks
appears before Railpack across all relevant views.

Add feature tests covering the nixpacks default and selector ordering.
2026-04-09 17:48:17 +02:00
Tristan Rhodes
519a186e84 fix: normalize oauth emails before matching users 2026-04-09 09:38:56 -06:00
Andras Bacsai
f573ad28a0 Merge remote-tracking branch 'origin/next' into feat/railpack 2026-04-09 17:12:26 +02:00
Andras Bacsai
7d2c776ae7 fix(team): transfer instance-wide sources to root team on deletion
Instead of nullifying source references on applications when a team is
deleted, transfer instance-wide GitHub/GitLab apps to the root team
(team_id=0) so they remain available to other teams that depend on them.

Non-instance-wide sources are still deleted along with the team.
2026-04-09 14:51:52 +02:00
Andras Bacsai
ad662e5560 Merge remote-tracking branch 'origin/next' into 8172-investigate-user-delete-bug 2026-04-09 14:51:22 +02:00
Andras Bacsai
dbd2b68a08 fix(upgrade): clear stale upgrade flag when version is already current
Refactor upgrade state initialization into a shared `refreshUpgradeState()`
method used by both `mount()` and `checkUpdate()`. The method now uses
`version_compare` to validate upgrade availability and clears the
`new_version_available` flag in InstanceSettings when the current version
is already equal to or newer than the latest version, preventing stale
upgrade notifications from persisting after a successful update.
2026-04-09 14:31:12 +02:00
Andras Bacsai
02558d8672 Merge remote-tracking branch 'origin/next' into pr-7774-fix-upgrade-notification-modal 2026-04-09 14:16:28 +02:00
Andras Bacsai
e012e98a34 Merge remote-tracking branch 'origin/next' into 8172-investigate-user-delete-bug 2026-04-09 14:08:54 +02:00
Andras Bacsai
e36ae82d9d fix(validation): allow quoted shell args in docker options
Permit single-quoted arguments in SHELL_SAFE_COMMAND_PATTERN while
keeping dangerous metacharacters blocked, and add security test cases
for quoted --entrypoint and --hostname values.
2026-04-08 14:21:49 +02:00
Iisyourdad
d2ada90a47 fix(git): harden ssh URL normalization 2026-04-07 22:41:15 -05:00
Andras Bacsai
8f7bb449da Merge remote-tracking branch 'origin/next' into 8172-investigate-user-delete-bug 2026-04-05 18:15:54 +02:00
Andras Bacsai
3f564f9b2e fix(user-deletion): handle GitHub app sources across team cleanup
Limit team cleanup to apps owned by the deleted team and nullify cross-team application source references before deleting team-owned sources. Adds feature tests covering user deletion with GitHub app-backed applications, preserving system-wide apps, and nullifying external source links.
2026-04-05 18:08:06 +02:00
Iisyourdad
f877985e56 fix(git): preserve ssh scheme URLs with custom ports 2026-04-04 14:49:34 -05:00
Andras Bacsai
ffb5045c6a fix(backups): enforce retention and clean up stale executions
Add `WithoutOverlapping` middleware to `DatabaseBackupJob` keyed by backup ID
with timeout-based lock expiry to prevent concurrent runs.

Mark long-running backup executions as failed when they exceed the stale
time threshold, and add periodic retention enforcement in
`CleanupInstanceStuffsJob` with cache-based throttling.

Also add float casts for retention max-storage fields on
`ScheduledDatabaseBackup` and comprehensive feature tests covering
overlap middleware, stale detection, casts, and retention behavior.
2026-04-03 11:33:21 +02:00
Andras Bacsai
7542c71dc4 Merge remote-tracking branch 'origin/next' into 2731-investigate-failed-git-clone 2026-04-03 09:05:13 +02:00
Andras Bacsai
968508583d fix(project): handle slash branches in public repo URLs
Parse `/tree/...` URLs by first capturing the full branch candidate, then
iteratively resolving valid branch names for GitHub API lookups and deriving
the remaining path as base directory. Also adjust env var editor/input view
classes (`font-sans`, `w-full`) and add/extend feature tests for both branch
parsing and multiline toggle rendering.
2026-04-01 09:11:56 +02:00
Andras Bacsai
c2a3be152e test(upgrade): add mount tests for cached and fallback versions
Covers Upgrade Livewire component mount behavior for:
- initializing latest version from cached versions data
- falling back to 0.0.0 when versions cache is unavailable
2026-03-31 17:28:24 +02:00
Andras Bacsai
2abb073b52 Merge remote-tracking branch 'origin/next' into 9076-investigate-pre-deployment 2026-03-31 16:49:43 +02:00
Andras Bacsai
da5b003971 Merge remote-tracking branch 'origin/next' into unreachable-server-backoff 2026-03-31 16:46:22 +02:00
Andras Bacsai
3961077b90 feat(forms): make textarea monospace opt-in and improve multiline toggle
Add `monospace` prop to Textarea component so font-mono is no longer
applied by default. Apply it explicitly to env variable editors, private
key fields, and shared variable forms where monospace is appropriate.

Use Alpine.js x-data/x-model to make the multiline toggle reactive
without a full Livewire round-trip. Add wire:key on the input/textarea
wrappers to force proper DOM replacement when switching modes.
2026-03-31 15:37:42 +02:00
Andras Bacsai
acb716cb90 fix(shared-variables): support direct mount params and comment field for server variables
Allow SharedVariables Livewire components (Environment, Project, Server)
to accept UUID parameters directly via mount() instead of relying solely
on route parameters. This enables Livewire component testing without a
live route context.

Also adds comment field support when saving/updating server shared
environment variables, guards PostgreSQL-specific migration statements
from running under SQLite (test environment compatibility), and expands
the feature test suite with server shared variable scenarios including
inline comment preservation and update behaviour.
2026-03-31 14:58:01 +02:00
Andras Bacsai
466eb8504e refactor(models): extract defaultStandaloneDockerAttributes method on Server
Extract duplicated inline StandaloneDocker attribute arrays in the
Server boot lifecycle into a dedicated method, eliminating repetition
between the root-server (id=0) and normal-server paths.

Also harden the shared_environment_variables migration by wrapping
DDL statements in DB::transaction() and using DROP CONSTRAINT IF EXISTS
to make the migration safely re-runnable.

Add unit test covering the extracted method to verify uuid is always
present in bootstrap attributes.
2026-03-31 14:44:45 +02:00
Andras Bacsai
1a603a10ed fix(models): replace forceFill/forceCreate with fill/create and add fillable guards
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.
2026-03-31 13:45:31 +02:00
Andras Bacsai
7638912fdc fix(github): reset branch state when refreshing repositories
Clear `branches` and `total_branches_count` in `loadRepositories` to avoid stale branch data after repo refreshes. Update the Livewire view to use the shared loading button pattern for refresh/load actions, and expand feature coverage for repository refresh behavior and refresh button visibility.
2026-03-31 12:50:19 +02:00
Andras Bacsai
25c0c88eb2 Merge remote-tracking branch 'origin/next' into feat/refresh-repos 2026-03-31 12:37:38 +02:00
Andras Bacsai
2692496726 fix(database): refresh SSL/status state and harden clone writes
Handle database status updates more reliably by listening for `ServiceChecked`
and using explicit `refresh()` handlers in Livewire database components.

Also switch guarded clone/create paths to `forceFill`/`forceCreate` in helper
flows to avoid missing persisted attributes during app/service cloning.

Update log/terminal font stacks to Geist (with bundled variable fonts) and add
coverage for SSL status refresh, persistent volume UUID cloning, and log font
styling.
2026-03-31 09:29:36 +02:00
Bakr Elsherif
2af16cd25e
Merge branch 'next' into next 2026-03-31 00:38:18 +03:00
Andras Bacsai
f09115afdc Merge remote-tracking branch 'origin/next' into feat/refresh-repos 2026-03-30 17:30:14 +02:00
Tobias Thiele
7f46b2ed71 Populate docker_compose_domains for dockercompose apps
Add logic to populate docker_compose_domains in applicationParser
for dockercompose build packs, ensuring proper domain handling
for KEY-based SERVICE_FQDN variables.
2026-03-30 14:59:20 +02:00
Andras Bacsai
61f47cc7ee feat(deployments): support Docker image tags for preview deployments
Add end-to-end support for `docker_registry_image_tag` in preview and deployment queue flows.

- Extend deploy API to accept `pull_request_id` alias and `docker_tag` for preview deploys
- Persist preview-specific Docker tags on `application_previews` and `application_deployment_queues`
- Pass tag through `queue_application_deployment()` and de-duplicate queued jobs by tag
- Update deployment job logic to resolve and use preview Docker tags for dockerimage build packs
- Update Livewire previews UI/state to manage per-preview tags and manual preview/tag inputs
- Add migration for new tag columns and model fillable/casts updates
- Add feature and unit tests covering API behavior and tag resolution
2026-03-30 13:35:35 +02:00
Andras Bacsai
3fddc795f6
refactor: define explicit fillable attributes on all Eloquent models (#9282) 2026-03-30 13:11:58 +02:00
Andras Bacsai
850c37bedd fix(database): auto-generate missing CA cert on SSL regeneration
Prevent null CA certificate access during database SSL certificate regeneration
across KeyDB, MariaDB, MongoDB, MySQL, PostgreSQL, and Redis components.

If no CA certificate exists, attempt to generate one and re-query; if still
missing, dispatch a clear error and stop regeneration gracefully.

Add `SslCertificateRegenerationTest` coverage for missing-CA and CA-query
scenarios to prevent regressions.
2026-03-30 13:10:49 +02:00
Andras Bacsai
1da1f32f0e refactor: use forceCreate() for internal model creation
Replace create() with forceCreate() across internal model creation operations to bypass mass assignment protection. This is appropriate for internal code that constructs complete model state without user input.

Add InternalModelCreationMassAssignmentTest to ensure internal model creation behavior is properly tested. Optimize imports by using shortened Livewire attribute references and removing unused imports.
2026-03-30 13:04:11 +02:00
Michael Jathe
2b573ef5ec
Merge branch 'next' into feat/api/tag-management 2026-03-30 10:04:00 +02:00
Andras Bacsai
09f1c71a76 Merge remote-tracking branch 'origin/next' into refactor/sync-model-attributes 2026-03-30 08:14:32 +02:00
Andras Bacsai
c0c0349880 refactor(models): add fillable attributes for database configuration options
Add explicit fillable attributes to Service and all Standalone* database models
for new configuration options: public_port_timeout, enable_ssl, ssl_mode,
is_log_drain_enabled, is_include_timestamps, and custom_docker_run_options.

Add tests to MassAssignmentProtectionTest to verify these attributes are
properly protected by mass assignment protection across all relevant models.
2026-03-30 08:11:23 +02:00
Andras Bacsai
4ec9b7ef69 fix(clone): include uuid field when cloning persistent volumes
Ensure that the uuid field is preserved during clone operations for persistent
volumes across all clone methods (CloneMe, ResourceOperations, and the clone_application
helper). This prevents UUID conflicts and ensures cloned volumes receive new unique
identifiers as intended.

Adds test coverage validating that cloned persistent volumes receive new UUIDs
distinct from the original volumes.
2026-03-30 00:06:45 +02:00
Andras Bacsai
f267a28cb2
fix: harden GetLogs Livewire component properties (#9229) 2026-03-29 21:29:23 +02:00
Andras Bacsai
7b3b6fa6ef
fix(application): persist redirect value in setRedirect (#9279) 2026-03-29 21:03:14 +02:00
Andras Bacsai
b3256d4df1 fix(security): harden model assignment and sensitive data handling
Restrict mass-assignable attributes across user/team/redis models and
switch privileged root/team creation paths to forceFill/forceCreate.

Encrypt legacy ClickHouse admin passwords via migration and cast the
correct ClickHouse password field as encrypted.

Tighten API and runtime exposure by removing sensitive team fields from
responses and sanitizing Git/compose error messages.

Expand security-focused feature coverage for command-injection and mass
assignment protections.
2026-03-29 20:56:04 +02:00
Andras Bacsai
3fde1e0f9f fix(application): persist redirect value in setRedirect
Assign the selected redirect option before validation so valid changes are saved.
Add feature tests to verify redirect persistence and rejection when no www domain exists.
2026-03-29 20:50:03 +02:00
Andras Bacsai
a5840501b4 fix(forms): use Alpine state for password visibility toggles
Replace shared `changePasswordFieldType` JS with component-local Alpine logic
across input, textarea, and env-var-input components. This keeps toggle
behavior consistent, resets visibility on `success` events, and preserves
`truncate` styling only when showing plaintext on enabled fields.

Also adds `PasswordVisibilityComponentTest` to verify Alpine bindings are
rendered and legacy handler references are removed.
2026-03-29 20:47:36 +02:00
Andras Bacsai
9e96a20a49
fix: add validation and escaping for Docker network names (#9228) 2026-03-29 20:46:39 +02:00
Andras Bacsai
1027c73d0f
refactor: scope server and project queries to current team (#9230) 2026-03-29 20:28:21 +02:00
Michael Jathe
23d5b854e9 feat(api): add tag management endpoints for applications, databases, and services
Add CRUD tag endpoints (GET/POST/DELETE) as sub-resources for applications,
databases, and services. Add team-level GET /tags endpoint. Extend all
resource creation endpoints to accept an optional tags array.

Uses a shared HandlesTagsApi trait to avoid duplication across controllers.
Tags are race-safe via syncWithoutDetaching(), garbage-collected when orphaned,
and sanitized (strip_tags + lowercase).
2026-03-29 16:02:05 +02:00
Andras Bacsai
3ba4553df5 fix(security): enforce team-scoped project/env lookups in onboarding
Use firstOrFail() for team-scoped project and environment lookups across
new-project Livewire flows so missing or cross-team UUIDs fail closed.
Also dispatch an error when boarding selects a non-owned project, and
update IDOR feature tests for the new error/exception behavior.
2026-03-29 15:55:03 +02:00
Andras Bacsai
96ae9ade23
fix: add input validation for install/build/start command fields (#9227) 2026-03-29 15:48:30 +02:00
Bakr
8ad65a0ef8 eat(api): add service-applications API to manage service applications 2026-03-29 06:03:47 +03:00
Andras Bacsai
72118d61f9 feat(databases): add public port timeout configuration
Add support for configuring public port timeout on databases via API:
- Add public_port_timeout field to schema documentation with 3600s default
- Add validation rules (integer|nullable|min:1)
- Update all database type configurations to support the field
- Add comprehensive test coverage for the feature
2026-03-28 17:08:02 +01:00
Andras Bacsai
3b2e6e11f1
refactor: use random_int() for email change verification codes (#9226) 2026-03-28 15:18:00 +01:00
Andras Bacsai
377ce24b6d
Add URL validation for notification webhook fields (#9224) 2026-03-28 14:39:27 +01:00
Andras Bacsai
0b8c75f8ed fix(webhooks): add validation to block unsafe webhook URLs
Prevent server-side request forgery (SSRF) attacks by validating webhook URLs before sending requests. Blocks loopback addresses, cloud metadata endpoints, and localhost URLs.

- Add SafeWebhookUrl rule validation in SendWebhookJob.handle()
- Log warning when unsafe URLs are rejected
- Add comprehensive unit tests covering valid and invalid URL scenarios
2026-03-28 14:23:08 +01:00
Andras Bacsai
91ab0b38d6
refactor: move admin route into middleware group (#9225) 2026-03-28 14:18:16 +01:00
Andras Bacsai
ad694275b0 Merge remote-tracking branch 'origin/next' into fix/harden-getlogs-livewire-properties 2026-03-28 14:10:15 +01:00
Andras Bacsai
67a4fcc2ab fix: add mass assignment protection to models
Replace $guarded = [] with explicit $fillable whitelists across all
models. Update controllers to use request->only($allowedFields) when
assigning request data. Switch Livewire components to forceFill() for
explicit mass assignment. Add integration tests for mass assignment
protection.
2026-03-28 12:32:57 +01:00
Andras Bacsai
e36622fdfb refactor: scope server and project queries to current team
Ensure Server and Project lookups in Livewire components and API
controllers use team-scoped queries (ownedByCurrentTeam / whereTeamId)
instead of unscoped find/where calls. This enforces consistent
multi-tenant isolation across all user-facing code paths.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 12:29:08 +01:00
Andras Bacsai
3d1b9f53a0 fix: add validation and escaping for Docker network names
Add strict validation for Docker network names using a regex pattern
that matches Docker's naming rules (alphanumeric start, followed by
alphanumeric, dots, hyphens, underscores).

Changes:
- Add DOCKER_NETWORK_PATTERN to ValidationPatterns with helper methods
- Validate network field in Destination creation and update Livewire components
- Add setNetworkAttribute mutator on StandaloneDocker and SwarmDocker models
- Apply escapeshellarg() to all network field usages in shell commands across
  ApplicationDeploymentJob, DatabaseBackupJob, StartService, Init command,
  proxy helpers, and Destination/Show
- Add comprehensive tests for pattern validation and model mutator

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 12:28:59 +01:00
Andras Bacsai
48ba4ece3c fix: harden GetLogs Livewire component with locked properties and input validation
Add #[Locked] attributes to security-sensitive properties (resource, servicesubtype,
server, container) to prevent client-side modification via Livewire wire protocol.
Add container name validation using ValidationPatterns::isValidContainerName() and
server ownership authorization via Server::ownedByCurrentTeam() in both getLogs()
and downloadAllLogs() methods.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 12:28:54 +01:00
Andras Bacsai
c9922c30c2 fix: add input validation for install/build/start command fields
Add shellSafeCommandRules() validation to install_command, build_command,
and start_command fields in both the Livewire UI and REST API layers.
These fields previously accepted arbitrary strings without validation,
unlike other shell-adjacent fields which already used this pattern.

Also adds comprehensive tests for rejection of dangerous input and
acceptance of legitimate build commands.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 12:28:29 +01:00
Andras Bacsai
f493b96be3 refactor: use random_int() for email change verification codes
Replace mt_rand/rand with random_int for stronger randomness guarantees
in verification code generation and Blade component keying.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 12:25:54 +01:00
Andras Bacsai
aea201fcba refactor: move admin route into middleware group and harden authorization
Move the admin panel route into the existing auth middleware group and
replace client-side redirects with server-side abort calls in the
Livewire component. Extract shared authorization logic into reusable
private methods.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 12:24:40 +01:00
Andras Bacsai
564cd8368b fix: add URL validation for notification webhook fields
Add SafeWebhookUrl validation rule to notification webhook URL fields
(Slack, Discord, custom webhook) to enforce safe URL patterns including
scheme validation and hostname checks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 12:22:59 +01:00
Andras Bacsai
98569e4edb
fix: use server-side config for password reset URL generation (#9193) 2026-03-28 12:20:42 +01:00
Andras Bacsai
25dcde6a47
fix: sanitize error output in server validation logs (#9197) 2026-03-28 12:13:50 +01:00
Andras Bacsai
e396c70903 refactor: simplify TrustHosts middleware and use APP_URL as base_url fallback
- Delegate host validation to parent class instead of custom implementation
- Update base_url() helper to use config('app.url') instead of url('/')
- Add test for APP_URL fallback when no FQDN or public IPs configured
- Remove dedicated TrustHostsMiddlewareTest (logic now tested via integration tests)
2026-03-28 12:12:48 +01:00
Andras Bacsai
638f1d37f1 feat(subscription): add billing interval to price preview
Extract and return the billing interval (month/year) from subscription pricing
data in fetchPricePreview. Update the view to dynamically display the correct
billing period based on the preview response instead of using static PHP logic.
2026-03-27 19:05:13 +01:00
Andras Bacsai
ba6f0cdb38 Merge remote-tracking branch 'origin/next' into fix/trust-hosts-url-generation 2026-03-27 14:14:36 +01:00
Andras Bacsai
af3826eac0 feat(reset-password): add IPv6 support and header poisoning protection
- Add support for bracketed IPv6 addresses when FQDN is not configured
- Harden password reset URL generation against X-Forwarded-Host header poisoning
- Add test coverage for IPv6-only configurations with malicious headers
- Update imports and clean up exception syntax in shared helpers
2026-03-27 14:14:01 +01:00
Andras Bacsai
f2e4879742 Merge remote-tracking branch 'origin/next' into feat/refresh-repos 2026-03-26 19:00:08 +01:00
Andras Bacsai
e1d4b4682e fix: harden TrustHosts middleware and use base_url() for password reset links
- Fix circular cache dependency in TrustHosts where handle() checked cache
  before hosts() could populate it, causing host validation to never activate
- Validate both Host and X-Forwarded-Host headers against trusted hosts list
  (X-Forwarded-Host is checked before TrustProxies applies it to the request)
- Use base_url() instead of url() for password reset link generation so the
  URL is derived from server-side config (FQDN / public IP) instead of the
  request context
- Strip port from X-Forwarded-Host before matching (e.g. host:443 → host)
- Add tests for host validation, cache population, and reset URL generation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 18:39:54 +01:00
Andras Bacsai
103d5b6c06 fix: sanitize error output in server validation logs
Escape dynamic error messages with htmlspecialchars() before
concatenating into HTML strings stored in validation_logs. Add a
Purify-based mutator on Server model as defense-in-depth, with a
dedicated HTMLPurifier config that allows only safe structural tags.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 18:36:36 +01:00
Andras Bacsai
25d424c743 refactor: split invitation endpoint into GET (show) and POST (accept)
Refactor the invitation acceptance flow to use a landing page pattern:
- GET shows invitation details (team name, role, confirmation button)
- POST processes the acceptance with proper form submission
- Remove unused revoke GET route (handled by Livewire component)
- Add Blade view for the invitation landing page
- Add feature tests for the new invitation flow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 14:30:27 +01:00
Andras Bacsai
0fce7fa948 fix: add URL validation for GitHub source api_url and html_url fields
Add SafeExternalUrl validation rule that ensures URLs point to
publicly-routable hosts. Apply to all GitHub source entry points
(Livewire Create, Livewire Change, API create and update).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 13:45:33 +01:00
Andras Bacsai
3e0d48faea refactor: simplify remote process chain and harden ActivityMonitor
- Inline PrepareCoolifyTask and CoolifyTaskArgs into remote_process(),
  removing two single-consumer abstraction layers
- Add #[Locked] attribute to ActivityMonitor $activityId property
- Add team ownership verification in ActivityMonitor.hydrateActivity()
  with server_uuid fallback and fail-closed default
- Store team_id in activity properties for proper scoping
- Update CLAUDE.md to remove stale reference
- Add comprehensive tests for activity monitor authorization

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 13:26:16 +01:00
Andras Bacsai
d2064dd499 fix(storage): use escapeshellarg for volume names in shell commands
Add proper shell escaping for persistent volume names when used in
docker volume rm commands. Also add volume name validation pattern
to ValidationPatterns for consistent input checking.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 11:06:30 +01:00
Andras Bacsai
dd2c9c291a feat(jobs): implement exponential backoff for unreachable servers
Reduce load on unreachable servers by implementing exponential backoff
during connectivity failures. Check frequency decreases based on
consecutive failure count:
  0-2: every cycle
  3-5: ~15 min intervals
  6-11: ~30 min intervals
  12+: ~60 min intervals

Uses server ID hash to distribute checks across cycles and prevent
thundering herd.

ServerCheckJob and ServerConnectionCheckJob increment unreachable_count
on failures. ServerManagerJob applies backoff logic before dispatching
checks. Includes comprehensive test coverage.
2026-03-26 10:51:36 +01:00
Andras Bacsai
d77e4c864f
fix(backup): use escapeshellarg for credentials in backup commands (#9175) 2026-03-26 07:50:09 +01:00
Andras Bacsai
fecb80b596
fix(storage): consistent path validation and escaping for file volumes (#9176) 2026-03-26 07:44:46 +01:00
Andras Bacsai
3fdce06b65 fix(storage): consistent path validation and escaping for file volumes
Ensure all file volume paths are validated and properly escaped before
use. Previously, only directory mount paths were validated at the input
layer — file mount paths now receive the same treatment across Livewire
components, API controllers, and the model layer.

- Validate and escape fs_path at the top of saveStorageOnServer() before
  any commands are built
- Add path validation to submitFileStorage() in Storage Livewire component
- Add path validation to file mount creation in Applications, Services,
  and Databases API controllers
- Add regression tests for path validation coverage

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 23:44:37 +01:00
Andras Bacsai
952f324797 fix(backup): use escapeshellarg for credentials in database backup commands
Apply proper shell escaping to all user-controlled values interpolated into
backup shell commands (PostgreSQL username/password, MySQL/MariaDB root
password, MongoDB URI). Also URL-encode MongoDB credentials before embedding
in connection URI. Adds unit tests for escaping behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 23:43:57 +01:00
Andras Bacsai
6f163ddf02 fix(deployment): normalize whitespace in pre/post deployment commands
Ensure pre_deployment_command and post_deployment_command have consistent
whitespace handling, matching the existing pattern used for health_check_command.
Adds regression tests for the normalization behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 20:57:17 +01:00
Andras Bacsai
ae31111813 fix(livewire): add input validation to unmanaged container operations
Add container name validation and shell argument escaping to
startUnmanaged, stopUnmanaged, restartUnmanaged, and restartContainer
methods, consistent with existing patterns used elsewhere in the
codebase.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 20:42:00 +01:00
Andras Bacsai
e2ba44d0c3 fix(validation): allow ampersands and quotes in shell-safe command pattern
Previously, the SHELL_SAFE_COMMAND_PATTERN was overly restrictive and blocked
legitimate characters needed for common Docker operations:

- Allow & for command chaining with && in multi-step build commands
- Allow " for build arguments with spaces (e.g., --build-arg KEY="value")

Update validation messages to reflect the new allowed operators and refactor
code to use imports instead of full class paths for better readability.
2026-03-25 20:27:21 +01:00
Andras Bacsai
d486bf09ab fix(livewire): add Locked attributes and consolidate container name validation
- Add #[Locked] to server-set properties on Import component (resourceId,
  resourceType, serverId, resourceUuid, resourceDbType, container) to
  prevent client-side modification via Livewire wire protocol
- Add container name validation in runImport() and restoreFromS3()
  using shared ValidationPatterns::isValidContainerName()
- Scope server lookup to current team via ownedByCurrentTeam()
- Consolidate duplicate container name regex from Import,
  ExecuteContainerCommand, and Terminal into shared
  ValidationPatterns::isValidContainerName() static helper
- Add tests for container name validation, locked attributes, and
  team-scoped server lookup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 20:21:39 +01:00
Andras Bacsai
0fed553207 fix(settings): require instance admin authorization for updates page 2026-03-25 19:33:51 +01:00
Andras Bacsai
bc91b41f92
fix(terminal): apply authorization middleware to terminal bootstrap routes (#9169) 2026-03-25 18:44:08 +01:00
Andras Bacsai
847166a3f8 fix(terminal): apply authorization middleware to terminal bootstrap routes
Apply the existing `can.access.terminal` middleware to `POST /terminal/auth`
and `POST /terminal/auth/ips` routes, consistent with the `GET /terminal` route.

Adds regression tests covering unauthenticated, member, admin, and owner roles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 16:56:37 +01:00
Andras Bacsai
99043600ee fix(backup): validate MongoDB collection names in backup input
Add validateDatabasesBackupInput() helper that properly parses all
database backup formats including MongoDB's "db:col1,col2|db2:col3"
and validates each component individually.

- Validate and escape collection names in DatabaseBackupJob
- Replace comma-only split in BackupEdit with format-aware validation
- Add input validation in API create_backup and update_backup endpoints
- Add unit tests for collection name and multi-format validation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 16:52:06 +01:00
Andras Bacsai
207002dbb7 Merge remote-tracking branch 'origin/next' into feat/railpack 2026-03-25 16:45:30 +01:00
Andras Bacsai
a94517f452 fix(api): validate server ownership in domains endpoint and scope activity lookups
- Add team-scoped server validation to domains_by_server API endpoint
- Filter applications and services to only those on the requested server
- Scope ActivityMonitor activity lookups to the current team
- Fix query param disambiguation (query vs route param) in domains endpoint
- Fix undefined $ip variable in services domain collection

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 16:20:53 +01:00
Andras Bacsai
811ee5d327 refactor(jobs): extract container resolution logic for deployment commands
Extract common container selection logic into resolveCommandContainer() method
that handles both single and multi-container app scenarios. This consolidates
duplicated code from run_pre_deployment_command() and run_post_deployment_command()
while improving error messaging and test coverage.
2026-03-25 14:09:07 +01:00
Andras Bacsai
3034e89edb feat(preview-env): add production variable fallback for docker-compose
When preview environment variables are configured, fall back to production
variables for keys not overridden by preview values. This ensures variables
like DB_PASSWORD that exist only in production are available in the preview
.env file, enabling proper ${VAR} interpolation in docker-compose YAML.

Fallback only applies when preview variables are configured, preventing
unintended leakage of production values when previews aren't in use.

Also improves UI by hiding the Domains section when only database services
are present, and simplifies the logs view by removing status checks.
2026-03-25 13:26:50 +01:00
Andras Bacsai
14a7f8646c fix(backup): prevent notification failures from affecting backup status
- Wrap notification calls in try-catch blocks to log failures instead
- Prevent failed() method from overwriting successful backup status
- Skip failure notifications if backup already completed successfully
- Ensures post-backup errors (e.g. notification failures) never
  retroactively mark successful backups as failed

Fixes #9088
2026-03-25 12:43:47 +01:00
Andras Bacsai
5c460dd2a1
fix(proxy): validate stored config matches proxy type (#9146) 2026-03-24 21:53:48 +01:00
Andras Bacsai
6a14a12a58 fix(parsers): preserve ${VAR} references in compose instead of resolving to DB values
Do not replace self-referencing environment variables (e.g., DATABASE_URL: ${DATABASE_URL})
with saved DB values in the compose environment section. Keeping the reference intact allows
Docker Compose to resolve from .env at deploy time, preventing stale values from overriding
user updates that haven't been re-parsed.

Fixes #9136
2026-03-24 21:52:36 +01:00
Andras Bacsai
b8e52c6a45 feat(proxy): validate stored config matches current proxy type
Add validation in GetProxyConfiguration to detect when stored proxy config
belongs to a different proxy type (e.g., Traefik config on a Caddy server)
and trigger regeneration with a warning log. Clear cached proxy configuration
and settings when proxy type is changed to prevent stale configs from being
reused. Includes tests verifying config rejection on type mismatch and
graceful fallback on invalid YAML.
2026-03-24 21:32:34 +01:00
Andras Bacsai
d3beeb2d00 fix(subscription): prevent duplicate subscriptions with updateOrCreate
- Replace manual subscription create/update logic with updateOrCreate() and firstOrCreate() to eliminate race conditions
- Add validation in PricingPlans to prevent subscribing if team already has active subscription
- Improve error handling for missing team_id in customer.subscription.updated event
- Add tests verifying subscriptions are updated rather than duplicated
2026-03-24 10:52:41 +01:00
Andras Bacsai
233f53494e
fix(team): resolve server limit checks for API token authentication (#9123) 2026-03-24 08:12:56 +01:00
Andras Bacsai
988dd57cf4 feat(validation): make hostname validation case-insensitive and expand allowed characters
- Normalize hostnames to lowercase for RFC 1123 compliance while accepting uppercase input
- Expand NAME_PATTERN to allow parentheses, hash, comma, colon, and plus characters
- Add fallback to random name generation when application name doesn't meet minimum requirements
- Add comprehensive test coverage for validation patterns and edge cases
2026-03-24 08:03:08 +01:00
Andras Bacsai
2ed360f0e0 Merge remote-tracking branch 'origin/next' into feat/railpack 2026-03-23 21:58:33 +01:00
Andras Bacsai
e37cb98c7c refactor(team): make server limit methods accept optional team parameter
Allow serverLimit() and serverLimitReached() to accept an optional team
parameter instead of relying solely on the current session. This improves
testability and makes the methods more flexible by allowing them to work
without session state.

Add comprehensive tests covering various scenarios including no session,
team at limit, and team under limit.
2026-03-23 21:56:50 +01:00
Andras Bacsai
dac940807a fix(deployment): properly escape shell arguments in nixpacks commands
Add escapeShellValue() helper function to safely escape shell values by wrapping
them in single quotes and escaping embedded quotes. Use this function throughout
the nixpacks command building to prevent shell injection vulnerabilities when
passing user-provided build commands, start commands, and environment variables.

This fixes unsafe string concatenation that could allow command injection when
user input contains special shell characters like &&, |, ;, etc.
2026-03-23 21:55:46 +01:00
Andras Bacsai
b931418c1e fix(github-webhook): handle unsupported event types gracefully
Add validation in manual and normal webhook handlers to reject GitHub
event types other than 'push' and 'pull_request'. Unsupported events
now return a graceful response instead of potentially causing
downstream errors. Includes tests for ping events, unsupported event
types, and unknown events.
2026-03-23 21:33:40 +01:00
Aditya Tripathi
cddbaf581f refactor(railpack): extract static image build, fix port logic, bump to v0.22.0
Extract build_railpack_static_image() into its own method, prevent port
override when is_static is set, bump Railpack to 0.22.0, and improve
test setup with beforeEach and correct polymorphic env var fields.
2026-03-23 19:02:10 +00:00
Aditya Tripathi
793077d74f feat(buildpack): add Railpack as a build pack option 2026-03-23 17:12:02 +00:00
Andras Bacsai
ae33447994 feat(storage): add storage endpoints and UUID support for databases and services
- Add storage endpoints (list, create, update, delete) to DatabasesController
- Add storage endpoints (list, create, update, delete) to ServicesController
- Add UUID field and migration for local_persistent_volumes table
- Update LocalPersistentVolume model to extend BaseModel
- Support UUID-based storage identification in ApplicationsController
- Update OpenAPI documentation with new storage endpoints and schemas
- Fix application name generation to extract repo name from full git path
- Add comprehensive tests for storage API operations
2026-03-23 15:15:02 +01:00
Andras Bacsai
f8f27fff13 refactor(scheduler): extract cron scheduling logic to shared helper
Extract the shouldRunNow() method from ScheduledJobManager and ServerManagerJob into
a reusable shouldRunCronNow() helper function. This centralizes cron scheduling logic
and enables consistent deduplication behavior across all scheduled job types.

- Create shouldRunCronNow() helper in bootstrap/helpers/shared.php with timezone
  and dedup support
- Refactor ScheduledJobManager and ServerManagerJob to use the shared helper
- Add ScheduledJobDiagnostics command for inspecting cache state and scheduling
  decisions across all scheduled jobs
- Simplify shouldRunNow tests to directly test the helper function
- Add DockerCleanupJob test for error handling and execution tracking
- Increase scheduled log retention from 1 to 7 days
2026-03-23 10:37:49 +01:00
Andras Bacsai
6aa618e57f feat(jobs): add cache-based deduplication for delayed cron execution
Implements getPreviousRunDate() + cache-based tracking in shouldRunNow()
to prevent duplicate dispatch of scheduled jobs when queue delays push
execution past the cron minute. This resilience ensures jobs catch missed
windows without double-dispatching within the same cron window.

Updated scheduled job dispatches to include dedupKey parameter:
- Docker cleanup operations
- Server connection checks
- Sentinel restart checks
- Server storage checks
- Server patch checks

DockerCleanupJob now dispatches on the 'high' queue for faster processing.

Includes comprehensive test coverage for dedup behavior across different
cron schedules and delay scenarios.
2026-03-20 15:44:10 +01:00
Andras Bacsai
2bc8fe3dd7
fix(backup): throw explicit error when S3 storage missing or deleted (#9038) 2026-03-19 23:39:36 +01:00
Andras Bacsai
c00d5de03e feat(api): add database environment variable management endpoints
Add CRUD API endpoints for managing environment variables on databases:
- GET /databases/{uuid}/envs - list environment variables
- POST /databases/{uuid}/envs - create environment variable
- PATCH /databases/{uuid}/envs - update environment variable
- PATCH /databases/{uuid}/envs/bulk - bulk create environment variables
- DELETE /databases/{uuid}/envs/{env_uuid} - delete environment variable

Includes comprehensive test suite and OpenAPI documentation.
2026-03-19 23:29:50 +01:00
Andras Bacsai
fb76b68c08 feat(api): support comments in bulk environment variable endpoints
Add support for optional comment field on environment variables created or
updated through the bulk API endpoints. Comments are validated to a maximum
of 256 characters and are nullable. Updates preserve existing comments when
not provided in the request.
2026-03-19 22:17:55 +01:00
Andras Bacsai
8a164735cb fix(api): extract resource UUIDs from route parameters
Extract resource UUIDs from route parameters instead of request body
in ApplicationsController and ServicesController environment variable
endpoints. This prevents UUID parameters from being spoofed in the
request body.

- Replace $request->uuid with $request->route('uuid')
- Replace $request->env_uuid with $request->route('env_uuid')
- Add tests verifying route parameters are used and body UUIDs ignored
2026-03-19 21:56:58 +01:00
Andras Bacsai
ca3ae289eb feat(storage): add resources tab and improve S3 deletion handling
Add new Resources tab to storage show page displaying backup schedules using
that storage. Refactor storage show layout with navigation tabs for General
and Resources sections. Move delete action from form to show component.

Implement cascade deletion in S3Storage model to automatically disable S3
backups when storage is deleted. Improve error handling in DatabaseBackupJob
to throw exception when S3 storage is missing instead of silently returning.

- New Storage/Resources Livewire component
- Add resources.blade.php view
- Add storage.resources route
- Move delete() method from Form to Show component
- Add deleting event listener to S3Storage model
- Track backup count and current route in Show component
- Add #[On('submitStorage')] attribute to form submission
2026-03-19 11:42:29 +01:00
Andras Bacsai
d0b4dc1c63
fix(stripe): add error handling and resilience to subscription operations (#9030) 2026-03-18 15:38:59 +01:00
Andras Bacsai
566744b2e0 fix(stripe): add error handling and resilience to subscription operations
- Record refunds immediately before cancellation to prevent retry issues if cancel fails
- Wrap Stripe API calls in try-catch for refunds and quantity reverts with internal notifications
- Add null check in Team.subscriptionEnded() to prevent NPE when subscription doesn't exist
- Fix control flow bug in StripeProcessJob (add missing break statement)
- Cap dynamic server limit with MAX_SERVER_LIMIT in subscription updates
- Add comprehensive tests for refund failures, event handling, and null safety
2026-03-18 15:21:59 +01:00
Andras Bacsai
426a708374 feat(subscription): display next billing date and billing interval
Add current_period_end to refund eligibility checks and display next billing
date and billing interval in the subscription overview. Refactor the plan
overview layout to show subscription status more prominently.
2026-03-18 15:11:19 +01:00
Andras Bacsai
23f9156c73 Squashed commit from 'qqrq-r9h4-x6wp-authenticated-rce' 2026-03-18 13:53:01 +01:00
Andras Bacsai
d4bf011a8e Merge remote-tracking branch 'origin/next' into next 2026-03-16 21:38:07 +01:00
Andras Bacsai
6325e41aec fix(ssh): handle chmod failures gracefully and simplify key management
- Log warnings instead of silently failing when chmod 0600 fails
- Remove redundant refresh() call before SSH key validation
- Remove storeInFileSystem() call from updatePrivateKey() transaction
- Remove @unlink() of lock file after filesystem store
- Refactor unit tests to use real temp disk and anonymous class stub
  instead of reflection-only checks
2026-03-16 21:27:10 +01:00
Andras Bacsai
2ba62ffe02 Merge remote-tracking branch 'origin/next' into next 2026-03-16 21:22:32 +01:00
Andras Bacsai
9976645c25 Merge remote-tracking branch 'origin/next' into fix/ssh-sporadic-permission-denied 2026-03-16 21:15:30 +01:00
Andras Bacsai
15d6de9f41 fix(storages): hide PR suffix for services and fix instantSave logic
- Restrict "Add suffix for PR deployments" checkbox to non-service
  resources in both shared and service file-storage views
- Replace condition `is_preview_deployments_enabled` with `!$isService`
  for PR suffix visibility in storages/show.blade.php
- Fix FileStorage::instantSave() to use authorize + syncData instead
  of delegating to submit(), preventing unintended side effects
- Add $this->validate() to Storages/Show::instantSave() before saving
- Add response content schemas to storages API OpenAPI annotations
- Add additionalProperties: false to storage update request schema
- Rewrite PreviewDeploymentBindMountTest with behavioral tests of
  addPreviewDeploymentSuffix instead of file-content inspection
2026-03-16 21:10:00 +01:00
Andras Bacsai
fe1aa94144 Merge remote-tracking branch 'origin/next' into fix/ssh-sporadic-permission-denied 2026-03-16 20:26:56 +01:00
Andras Bacsai
0ffcee7a4d Squashed commit from '4fhp-investigate-os-command-injection' 2026-03-16 16:40:16 +01:00
Andras Bacsai
add16853a8 feat(preview): add configurable PR suffix toggle for volumes
Add `is_preview_suffix_enabled` flag to `local_file_volumes` and
`local_persistent_volumes` tables, allowing per-volume control over
whether a `-pr-N` suffix is appended during preview deployments.

Defaults to `true` to preserve existing behavior. Users can disable
it for volumes containing shared config or repository scripts that
should not be isolated per PR.
2026-03-16 14:54:22 +01:00
Andras Bacsai
5b424f1f0e fix(preview): exclude bind mounts from preview deployment suffix
Bind mount volumes reference files at the repository's original path and
should not receive the -pr-N suffix. Only named Docker volumes require
the suffix for isolation between preview deployments.

Adds PreviewDeploymentBindMountTest to verify the correct behavior.

Fixes #7802
2026-03-16 13:33:58 +01:00
pannous
2f96a759df test: add behavioral ssh key stale-file regression 2026-03-16 10:40:22 +01:00
pannous
4bf94fac2d fix: prevent sporadic SSH permission denied by validating key content
The root cause of sporadic "Permission denied (publickey)" errors was
that validateSshKey() only checked if the key file existed on disk,
never verifying its content matched the database. When keys were rotated
or updated, the stale file persisted and SSH used the wrong key.

Changes:
- validateSshKey() now refreshes key from DB and compares file content
- Server saved event detects private_key_id changes to invalidate mux
- PrivateKey storeInFileSystem() uses file locking to prevent races
- PrivateKey saved event auto-resyncs file on key content changes
- Enforces 0600 permissions on key files

Fixes coollabsio/coolify#7724
2026-03-15 03:06:21 +01:00
Niklas Wichter
2f8df2f9bd fix(test): align test setup with project conventions 2026-03-13 17:25:00 +01:00
Andras Bacsai
74d591e6e9
feat(server): auto-fetch server metadata after validation (#8964) 2026-03-13 17:08:15 +01:00
Andras Bacsai
1936bb08bf feat(server): auto-fetch server metadata after validation
Server metadata is now automatically gathered when server validation completes successfully, both in the async job and Livewire component. This ensures server details (OS, CPU count, etc.) are populated immediately after validation passes, improving the user experience without requiring manual metadata fetching.

Tests added to verify gatherServerMetadata is called on successful validation and skipped when validation fails.
2026-03-13 17:07:50 +01:00
Niklas Wichter
94700347f8 test: add move resource API tests 2026-03-13 17:05:00 +01:00
Andras Bacsai
c39a287b47 feat(compose-preview): populate fqdn from docker_compose_domains
The generate_preview_fqdn_compose method now extracts and populates the fqdn field from docker_compose_domains, making it available for webhook notifications. This handles multiple domains across services and gracefully sets fqdn to null when no domains are configured.
2026-03-13 17:02:05 +01:00
Andras Bacsai
d5b3a0380c
fix(docker-compose): respect preserveRepository when injecting --project-directory (#8956) 2026-03-13 13:55:50 +01:00
Andras Bacsai
a97612b29e fix(docker-compose): respect preserveRepository when injecting --project-directory
When adding --project-directory to custom docker compose start commands,
use the application's host workdir if preserveRepository is true, otherwise
use the container workdir. Add tests for both scenarios and explicit paths.
2026-03-13 13:53:03 +01:00
Andras Bacsai
b9cae51c5d feat(service): add container label escape control to services API
Add `is_container_label_escape_enabled` boolean field to services API,
allowing users to control whether special characters in container labels
are escaped. Defaults to true (escaping enabled).

When disabled, users can use environment variables within labels.
Includes validation rules and comprehensive test coverage.
2026-03-13 13:32:58 +01:00
Andras Bacsai
aac34f1d14 fix(git-import): explicitly specify ssh key and remove duplicate validation rules
- Add -i flag to explicitly specify ssh key path in git ls-remote operations
- Remove static $rules properties in favor of dynamic rules() method
- Fix test syntax error
2026-03-12 14:19:53 +01:00
Andras Bacsai
0991f8e2ca fix(application): clarify deployment type precedence logic
- Prioritize real private keys (id > 0) first
- Check source second before falling back to zero key
- Remove isDev() check that was restricting zero key behavior in dev
- Remove exception throw, use 'other' as safe fallback
- Expand test coverage to validate all precedence scenarios
2026-03-12 13:48:30 +01:00
Andras Bacsai
4f1fe824e5
fix(git-import): ensure ssh key is used for fetch, submodule, and lfs operations (#8933) 2026-03-12 13:35:26 +01:00
Andras Bacsai
92c8ad449f feat(git-import): support custom ssh command for fetch, submodule, and lfs
Allow passing a custom GIT_SSH_COMMAND to setGitImportSettings() so that git fetch,
submodule update, and lfs pull use the same SSH authentication as the initial clone.
This is required for git sources like GitLab that use custom ports and identity files.

Also remove unnecessary SSH retry event tracking and add test coverage.
2026-03-12 13:32:43 +01:00
Andras Bacsai
8b8a09ad39
fix(api): cast teamId to int in deployment authorization check (#8931) 2026-03-12 13:26:08 +01:00
Andras Bacsai
3819676555 fix(api): cast teamId to int in deployment authorization check
Ensure proper type comparison when verifying deployment team ownership.
Adds comprehensive feature tests for the GET /api/v1/deployments/{uuid} endpoint.
2026-03-12 13:25:10 +01:00
Andras Bacsai
8cb5e70167
fix(parsers): resolve shared variables in compose environment (#8930) 2026-03-12 13:24:48 +01:00
Andras Bacsai
7cfc6746c7 fix(parsers): resolve shared variables in compose environment
Extract shared variable resolution logic into a reusable helper function
`resolveSharedEnvironmentVariables()` and apply it in applicationParser and
serviceParser to ensure patterns like {{environment.VAR}}, {{project.VAR}},
and {{team.VAR}} are properly resolved in the compose environment section.

Without this, unresolved {{...}} strings would take precedence over resolved
values from the .env file (env_file:) in docker-compose configurations.
2026-03-12 13:23:13 +01:00
Andras Bacsai
01031fc5f3 refactor: consolidate file path validation patterns and support scoped packages
- Extract file path validation regex into ValidationPatterns::FILE_PATH_PATTERN constant
- Add filePathRules() and filePathMessages() helper methods for reusable validation
- Extend allowed characters from [a-zA-Z0-9._\-/] to [a-zA-Z0-9._\-/~@+] to support:
  - Scoped npm packages (@org/package)
  - Language-specific directories (c++, rust+)
  - Version markers (v1~, build~)
- Replace duplicate inline regex patterns across multiple files
- Add tests for paths with @ symbol and tilde/plus characters
2026-03-12 13:09:13 +01:00
Andras Bacsai
709e5e882e Merge remote-tracking branch 'origin/next' into next 2026-03-11 18:16:15 +01:00
Andras Bacsai
54c5ad38da test(magic-variables): add feature tests for SERVICE_URL/FQDN variable handling
Add comprehensive test suite verifying that magic (referenced) SERVICE_URL_ and
SERVICE_FQDN_ variables don't overwrite values set by direct template declarations
or updateCompose(). Tests cover the fix for GitHub issue #8912 where generic
SERVICE_URL and SERVICE_FQDN variables remained stale after changing a service
domain in the UI. These tests ensure the transition from updateOrCreate() to
firstOrCreate() in the magic variables section works correctly.
2026-03-11 17:15:17 +01:00
Andras Bacsai
e52a49b5e9 feat(server): add server metadata collection and display
Add ability to gather and display server system information including OS, architecture, kernel version, CPU count, memory, and uptime. Includes:
- New gatherServerMetadata() method to collect system details via remote commands
- New refreshServerMetadata() Livewire action with authorization and error handling
- Server Details UI section showing collected metadata with refresh capability
- Database migration to add server_metadata JSON column
- Comprehensive test suite for metadata collection and persistence
2026-03-11 16:21:05 +01:00
Andras Bacsai
b2135bb4fa feat(gitlab): add GitLab source integration with SSH and HTTP basic auth
Add full GitLab application source support for git operations:
- Implement SSH-based authentication using private keys with configurable ports
- Support HTTP basic auth for HTTPS GitLab URLs (with or without deploy keys)
- Handle private key setup and SSH command configuration in both Docker and local modes
- Support merge request checkouts for GitLab with SSH authentication

Improvements to credential handling:
- URL-encode GitHub access tokens to handle special characters properly
- Update log sanitization to redact passwords from HTTPS/HTTP URLs
- Extend convertGitUrl() type hints to support GitlabApp sources

Add test coverage and seed data:
- New GitlabSourceCommandsTest with tests for private key and public repo scenarios
- Test for HTTPS basic auth password sanitization in logs
- Seed data for GitLab deploy key and public example applications
2026-03-11 15:30:46 +01:00
Andras Bacsai
108bae02d0
fix(livewire): add error handling and selectedActions to delete methods (#8909) 2026-03-11 15:05:53 +01:00
Andras Bacsai
8366e150b1 feat(livewire): add selectedActions parameter and error handling to delete methods
- Add `$selectedActions = []` parameter to delete/remove methods in multiple
  Livewire components to support optional deletion actions
- Return error message string when password verification fails instead of
  silent return
- Return `true` on successful deletion to indicate completion
- Handle selectedActions to set component properties for cascading deletions
  (delete_volumes, delete_networks, delete_configurations, docker_cleanup)
- Add test coverage for Danger component delete functionality with password
  validation and selected actions handling
2026-03-11 15:04:45 +01:00
Andras Bacsai
6488751fd2 feat(proxy): add database-backed config storage with disk backups
- Store proxy configuration in database as primary source for faster access
- Implement automatic timestamped backups when configuration changes
- Add backfill migration logic to recover configs from disk for legacy servers
- Simplify UI by removing loading states (config now readily available)
- Add comprehensive logging for debugging configuration generation and recovery
- Include unit tests for config recovery scenarios
2026-03-11 14:11:31 +01:00
Andras Bacsai
a7f491170a fix(deployment): filter null and empty environment variables from nixpacks plan
When application->fqdn is null, COOLIFY_FQDN and COOLIFY_URL are set to null.
These null values cause nixpacks to fail parsing the config with
"invalid type: null, expected a string".

Filter out null and empty string values when generating environment variables
for the nixpacks plan JSON. Fixes #6830.
2026-03-11 13:41:34 +01:00
Andras Bacsai
dcd976ae06 fix(git): ensure ssh credentials are propagated to submodule operations
- Add gitSshCommand parameter to setGitImportSettings and buildGitCheckoutCommand
- Extract hardcoded ssh commands to variables for consistency
- Apply custom ssh credentials to all git operations including submodule sync/update
- Configure git url rewriting for github token-based authentication with submodules
- Add comprehensive test suite for submodule credential propagation
2026-03-11 11:30:58 +01:00
Andras Bacsai
a596ff313e chore: prepare for PR 2026-03-11 07:04:33 +01:00
Andras Bacsai
5cac559602 chore: prepare for PR 2026-03-11 06:36:12 +01:00
Andras Bacsai
d174724bf6 Merge branch 'ghsa-mw5w-2vvh-mgf4-investigation' 2026-03-10 22:22:51 +01:00
Andras Bacsai
fcd574e1eb fix(log-drain): prevent command injection by base64-encoding environment variables
Replace direct shell interpolation of environment values with base64 encoding
to prevent command injection attacks. Environment configuration is now built as
a single string, base64-encoded, then decoded to file atomically.

Also add regex validation to restrict environment field values to safe
characters (alphanumeric, underscore, hyphen, dot) at the application layer.

Fixes GHSA-3xm2-hqg8-4m2p
2026-03-10 22:22:51 +01:00
Andras Bacsai
a1c30cb0e7 fix(git-ref-validation): prevent command injection via git references
Add validateGitRef() helper function that uses an allowlist approach to prevent
OS command injection through git commit SHAs, branch names, and tags. Only allows
alphanumeric characters, dots, hyphens, underscores, and slashes.

Changes include:
- Add validateGitRef() helper in bootstrap/helpers/shared.php
- Apply validation in Rollback component when accepting rollback commit
- Add regex validation to git commit SHA fields in Livewire components
- Apply regex validation to API rules for git_commit_sha
- Use escapeshellarg() in git log and git checkout commands
- Add comprehensive unit tests covering injection payloads

Addresses GHSA-mw5w-2vvh-mgf4
2026-03-10 22:22:48 +01:00
Andras Bacsai
096d4369e5 fix(sentinel): add token validation to prevent command injection
Add validation to ensure sentinel tokens contain only safe characters
(alphanumeric, dots, hyphens, underscores, plus, forward slash, equals),
preventing OS command injection vulnerabilities when tokens are
interpolated into shell commands.

- Add ServerSetting::isValidSentinelToken() validation method
- Validate tokens in StartSentinel action and metrics queries
- Improve shell argument escaping with escapeshellarg()
- Add comprehensive test coverage for token validation
2026-03-10 22:19:19 +01:00
Andras Bacsai
6fbb5e626a Squashed commit from '565g-9j4m-wqmr-cross-team-idor-logs-fix' 2026-03-10 22:11:52 +01:00
Andras Bacsai
c15bcd5634 fix(api): require write permission for validation endpoints
Validation operations should require write permissions as they trigger
state-changing actions. Updated middleware for:
- POST /api/v1/cloud-tokens/{uuid}/validate
- GET /api/v1/servers/{uuid}/validate

Added tests to verify read-only tokens cannot access these endpoints.
2026-03-10 22:11:52 +01:00
Andras Bacsai
0a1782175a Merge remote-tracking branch 'origin/next' into 8826-investigate-postgresql-restart 2026-03-10 21:46:03 +01:00
Andras Bacsai
d6ac8de6b7 Merge remote-tracking branch 'origin/next' into 8765-investigate-docker-cleanup-keep 2026-03-10 21:41:25 +01:00
Andras Bacsai
5c5f67f48b chore: prepare for PR 2026-03-10 20:37:22 +01:00
Andras Bacsai
e41dbde46b chore: prepare for PR 2026-03-10 18:34:37 +01:00
Andras Bacsai
9702543e20 chore: prepare for PR 2026-03-10 18:32:19 +01:00
Andras Bacsai
a362282976 chore: prepare for PR 2026-03-10 17:37:13 +01:00
Andras Bacsai
9b94ae1c1a Merge remote-tracking branch 'origin/next' into audit-policies 2026-03-10 10:52:39 +01:00
Andras Bacsai
27e2680d70 Merge remote-tracking branch 'origin/next' into fix/configurable-proxy-timeout 2026-03-10 10:01:46 +01:00
Andras Bacsai
184fbb98f3 fix(proxy): add validation and normalization for database proxy timeout
- Extract proxy timeout configuration logic into dedicated method
- Add min:1 validation rule for publicPortTimeout
- Normalize invalid timeout values (null, 0, negative) to default 3600s
- Add tests for timeout configuration normalization and validation
2026-03-10 09:59:19 +01:00
Andras Bacsai
e3daba0b1d chore: prepare for PR 2026-03-10 09:43:29 +01:00
Andras Bacsai
01aa534556 fix(application-source): support localhost key with id=0
Previously, the view checked $privateKeyId with ! operator, which
incorrectly treats 0 (localhost key) as falsy. Changed to explicit
is_null() checks to distinguish between null (no key) and 0 (localhost).
Added test coverage for both cases.
2026-03-09 17:20:33 +01:00
Andras Bacsai
4fa048f931 Merge remote-tracking branch 'origin/next' into audit-policies 2026-03-03 19:41:05 +01:00
Andras Bacsai
0ca5596b1f fix(server-limit): re-enable force-disabled servers at limit
Handle non-positive disable counts with `<= 0` so teams at or under the
server limit correctly re-enable force-disabled servers. Add a feature test
suite for ServerLimitCheckJob covering under-limit, at-limit, over-limit,
and no-op behavior.
2026-03-03 17:03:59 +01:00
Andras Bacsai
4f39cf6dc8 chore: prepare for PR 2026-03-03 16:43:29 +01:00
Andras Bacsai
d3b8d70f08 fix(subscription): harden quantity updates and proxy trust behavior
Centralize min/max server limits in Stripe quantity updates and wire them into
Livewire subscription actions with price preview/update handling.

Also improve host/proxy middleware behavior by trusting loopback hosts when FQDN
is set and auto-enabling secure session cookies for HTTPS requests behind
proxies when session.secure is unset.

Includes feature tests for loopback trust and secure cookie auto-detection.
2026-03-03 12:28:16 +01:00
Andras Bacsai
76ae720c36 feat(subscription): add Stripe server limit quantity adjustment flow
Introduce a new `UpdateSubscriptionQuantity` Stripe action to:
- preview prorated due-now and next-cycle recurring costs
- update subscription item quantity with proration invoicing
- revert quantity and void invoice when payment is not completed

Wire the flow into the Livewire subscription actions UI with a new adjust-limit modal,
price preview loading, and confirmation-based updates. Also refactor the subscription
management section layout and fix modal confirmation behavior for temporary 2FA bypass.

Add `Subscription::billingInterval()` helper and comprehensive Pest coverage for
quantity updates, preview calculations, failure/revert paths, and billing interval logic.
2026-03-03 12:24:13 +01:00