Commit graph

727 commits

Author SHA1 Message Date
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
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
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
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
29d41ba041 Merge remote-tracking branch 'origin/next' into 9916-investigate-undefined-relationship 2026-05-06 14:32:16 +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
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
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
d057ce5172 Merge remote-tracking branch 'origin/next' into mcp-server-instance-toggle 2026-04-30 11:30:45 +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
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
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
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
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
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
Andras Bacsai
f09115afdc Merge remote-tracking branch 'origin/next' into feat/refresh-repos 2026-03-30 17:30:14 +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
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
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
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