Closes#5134. The container list queries in the Logs tab only fetched
once on mount, so if the underlying container was replaced (restart,
reschedule, redeploy) while the page stayed open, the native log
WebSocket kept streaming from the stale id and either froze or failed
with 'No such container'.
Poll the container list every 5s and reconcile the selected id against
it, matching the pattern already used for automatic selection.
Fixes#5152. updateFileMount wrote directly to the target path without
ensuring its parent directory existed, and silently swallowed errors
instead of surfacing them. If the path already existed as a directory
(e.g. Docker pre-creating a bind mount target), the write silently
failed and left an empty directory instead of the file.
Attaching Basic Auth or a Redirect to an application with no domains
wrote an empty routers/services block to the app's dynamic config
file. Traefik's file provider rejects that as invalid and aborts its
watcher, blocking config updates for every other application.
Fixes#5189
Compose deployments using a git provider (GitHub/GitLab/Gitea/Bitbucket/
custom Git) clone the repo verbatim, so composePath can point into a
subdirectory (e.g. deploy/docker-compose.yml). Docker Compose resolves
relative bind mounts (../files) against the compose file's own directory,
not against the code/ dir where file mounts are actually written, so the
mount silently binds an empty directory instead of the configured content.
Pin --project-directory to code/ when building the docker compose command
so relative mounts always resolve the same way raw deployments already do.
Fixes#5181
Network chart showed values labeled as KB/s, but the underlying data
is MB totals accumulated since boot. Convert to GB and relabel as
Network Total (since Boot).
Fixes#5115
Network sync compared only by name, so a network deleted and
recreated with the same name but different attributes (driver,
attachable, etc.) was reported as already in sync.
Store Docker's network Id (dockerId column) and compare it against
the live Id during sync. A name match with a dockerId mismatch is
now surfaced as a new "changed" state, with an Update action to
refresh the DB row from the live network.
Fixes#5179
Escaping in prepareEnvironmentVariablesForFile escaped every $,
including inside a deliberate ${VAR} reference, breaking Compose's
documented .env variable interpolation. Only escape $ that isn't
part of a ${IDENTIFIER} sequence.
Fixes#5151
Reaching a server implied being able to open an SSH root shell on it: the
/terminal websocket only checked that the server was in the caller's accessible
set, so granting a server to a developer necessarily granted root on it.
Add a server.terminal action, assignable on custom roles, and require it on the
remote-server terminal websocket on top of server access. Owner/admin keep it
through the enterprise bypass; the local host terminal stays owner/admin only.
A migration grants server.terminal to existing custom roles that already have
server.read, which is the permission that surfaces the terminal today, so
current setups keep working. Roles without a server entry are left alone.
Note: server.create still implies root execution (server.update persists
server.command and server.setup runs it over SSH), reflected in the Create
description in the role editor.
The swarm migration in 3848fa9c0 dropped the container.remove({force:true})
that the standalone deploy path used to run. Swarm tasks are named
dokploy-monitoring.<slot>.<id>, so there is no name collision and the
pre-v0.30.0 container survives every redeploy. It also stays pinned to an
orphaned image ID once pullRemoteImage moves the latest tag, so neither a
pull nor a Save clears it and it restarts forever.
Cloud setup spread metricsConfig straight from the row, shipping
cronJob: "" to the agent. robfig/cron rejects an empty spec, so the Go
binary exits before Fiber binds 4500 and Docker restarts it every ~60s.
- remove the legacy container in deployMonitoringService, which covers both
setupMonitoring and setupWebMonitoring. Cleanup is best effort: a failure
is logged and the deploy continues, matching the pre-migration behaviour
- default cronJob when configuring monitoring for cloud
- on build servers, clean up the legacy container but deploy no service.
They never join the swarm, yet cloud setup did create the standalone
container there before v0.30.0, and the monitoring form has always been
hidden for them, so those agents are all stuck with an empty cronJob
- cover the above with real-docker tests
docker stack deploy reads env_file literally without stripping
quotes (unlike docker compose), so the quoting/escaping added to
fix#4694 was shipping literal quote characters into stack
containers.
Fixes#5096, #5110.
The tag dialog's form is nested inside the project dialog's form in the
React tree, and React propagates events along the React tree rather than
the DOM tree, so submitting the tag form also submitted the project form.
The project was created immediately with no tags and the dialog closed
before more than one tag could be picked.
Stop propagation in the tag form's onSubmit, and select the new tag in
the selector so it is included when the project is saved.
Fixes#5117
Fixes#5108. The changePassword mutations for postgres/mysql/mariadb/mongo/redis
detected the running container via a shell one-liner (docker ps -q --filter
status=running | head -n1) executed through execAsync/execAsyncRemote. When that
shell command failed for any reason the CONTAINER_ID ended up empty and the
mutation incorrectly reported the container as not running even though it was.
Replaced it with getServiceContainer(), the existing dockerode-based lookup
already used by mount.ts and schedules/utils.ts for the same purpose.
Also fixes the postgres ALTER USER command, which never selected a database
and defaulted to a database named after the user, causing a false
'database "<user>" does not exist' failure whenever the db name differs
from the username.
Fixes#5092 — typing in the database/docker terminal overwrote text
instead of continuing on new lines. The xterm.js client never told the
backend PTY its actual size (node-pty/ssh2 always defaulted to 80x24
and were never resized), so whenever the rendered terminal width
differed from that, the remote shell's cursor math diverged from what
the client displayed.
- docker-container-terminal.ts / terminal.ts: pass the client's initial
cols/rows into node-pty spawn and ssh2 exec/shell, and resize the PTY
on a {type:"resize"} control message sent over the same ws channel.
- docker-terminal.tsx / settings/web-server/terminal.tsx: send cols/rows
on connect and on every term.onResize, and watch the container with a
ResizeObserver to refit on dialog/window resize.
Also fixes two related terminal/logs bugs surfaced while testing this:
- docker-terminal.tsx no longer opens a connection with the
"select-a-container" placeholder ID before a real container is
selected, and defers terminal creation a frame so React StrictMode's
dev-only phantom mount doesn't hit a known xterm.js dispose race
(xtermjs/xterm.js#5011, "Cannot read properties of undefined
(reading 'dimensions')").
- docker-logs-id.tsx (shared by application/compose/compose-stack logs)
had the same placeholder-ID issue, surfacing Docker's raw
"No such container: select-a-container" daemon error instead of a
proper empty state.
The application table has 101 columns. The restricted-member branch of
project.one (apps/dokploy/server/api/routers/project.ts) queried the
applications relation with no columns narrowing, so Drizzle's relational
query builder generated a json_build_array call with one argument per
column, exceeding Postgres's FUNC_MAX_ARGS (100). Any non-owner/admin
member with limited access to a project containing at least one
application hit an opaque INTERNAL_SERVER_ERROR and got redirected away
from the project/environment page instead of seeing their project.
The same branch was also missing the "server" relation that the
owner/admin path (findProjectById) already includes, so restricted
members saw different (incomplete) data than owners/admins for the same
project.
Fixes this by extracting the existing serviceColumns column-selection
constant to a module-level export in packages/server/src/services/project.ts
and applying it (plus the server relation) to all 8 service relations in
the restricted-member query path, matching the owner/admin path.
Replaces the static quote in the onboarding layout's left panel with
an auto-rotating carousel of product highlights (Deploy / Manage /
Scale, 3 slides x 4 items), shown on the cloud signup page only.
- OnboardingLayout gets an optional leftPanel override, default
quote untouched everywhere else (login, invitation, password reset).
- Auto-advances every 6s, pauses on hover/focus, respects
prefers-reduced-motion, manual dot + arrow navigation.
- Copy pulled from the website's existing first-features.tsx section
to stay consistent with approved marketing copy.
Fires the sign_up dataLayer event already read by GTM for the three
signup paths on the cloud version: email/password (register.tsx),
GitHub/Google OAuth (via better-auth's newUserCallbackURL, distinct
from callbackURL so returning-user logins aren't counted), and
invitation acceptance. All gated behind isCloud, same as the rest of
the analytics wiring.
Mounts the existing cloud-gated Analytics component (GTM + HubSpot
script loader) in _app.tsx. It was already implemented behind
api.settings.isCloud but never wired into the app, so it never loaded
on cloud or self-hosted instances.
Resolve conflicts in docker.ts and domain.ts: canary already contains
a superset of main's hotfix cherry-picks (isDockerDesktop, isolated
network label pinning), just refactored/reformatted, so both sides
kept canary's version.
Also fix hotfix-cherry-pick.yml to sync each cherry-pick back into
canary immediately, so canary and main share history for that change
and the next canary->main release PR doesn't re-conflict on it.
Some self-hosted GitLab instances (e.g. older versions without
expires_in configured in doorkeeper) omit expires_in from the
OAuth token response. Computing Date.now()/1000 + undefined
produced NaN, which Postgres rejected on the expires_at integer
column, crashing both the initial OAuth callback and the token
refresh flow with a 500.
Falls back to null when expires_in is absent, matching the
existing Gitea callback behavior.
Closes#4362
Node.js as PID 1 does not reap children it did not spawn, so the
HEALTHCHECK curl fired every 10s accumulates as <defunct>. Install
tini and set it as ENTRYPOINT so any orphaned child is reaped while
signals still reach Node.
The preview deployment limit was checked before looking up whether the
pull request already had a preview, so once an application reached the
limit every `synchronize` event was dropped and existing previews went
stale while GitHub still saw a 200. The check now runs inside the branch
that creates a preview, uses the schema default of 3 when no limit is
configured (instead of 0, which blocked every app without an explicit
value) and compares with `>=` so the configured limit is inclusive.
Closes#4074
- Log tail for failed-deployment classification now checks the app's
current buildServer before falling back to its server, matching the
buildServerId-then-serverId precedence used everywhere else in the
codebase (application.ts, drop.ts, directory.ts, patch-repo.ts).
- Removes a stale !isCloud gate on the Networks tab that this branch
had reintroduced from before Mauricio removed it in daba2d7fb
(Networks is intentionally shown in cloud now) — unrelated to this
PR's scope, docker.tsx's Networks tab/content now matches canary.
Reverts the mount-only auto-refetch — it still ran host shell, Docker,
DB, and SSH log-tail work before the user asked for it, just once
instead of on every filter change. Back to fully manual: nothing runs
until Check/Re-check is clicked, matching the panel's own copy
("Nothing runs automatically — click to check").
Tightens a handful of two-line comments left over from earlier
iterations (Health tab / failed-deployment classification) down to
one line each, no behavior change.
Server diagnostics tab (Docker dashboard) with:
- Per-network IP usage: subnet capacity vs. containers in use, including
reserved networks like dokploy-network which are excluded from the
managed Networks tab. Surfaces read errors instead of silently showing
zeroes when the Docker API call fails.
- Broadened daemon-error detection and failure classification for Swarm
network failures: IP pool exhaustion on an existing network
("could not find an available IP", "task allocation failure") and
network attach timeouts ("attaching to network failed", "context
deadline exceeded") — both previously fell through as Unclassified.
Verified end-to-end against a real systemd-managed dockerd.
- Failed-deployment rows now carry the raw log tail used for
classification, shown on hover and linked to their service/project,
so a guess (or lack of one) can be verified against the actual error
and followed straight to the app.
- Daemon-error panel is a read-only code editor, always visible (not
hidden when empty), prefixed with the actual "Logs from X to Y"
window passed to journalctl so the --since window can be verified.
- "Download report" exports everything on screen (metrics + raw logs)
as Markdown, so a customer can send one file instead of a screen-share.
- Health check now IS_CLOUD-gated the same way network sync already is:
a cloud org can no longer omit serverId and have the check silently
run against the shared platform host instead of their own server.
Includes an inotify diagnostics card (current vs. max_user_instances/
watches/queued_events) and a failed-deployments log with automatic
cause classification based on daemon/log error patterns.
SCIM provisioning created users with emailVerified: false, so better-auth
refused to link the matching SSO account (account_not_linked), and the
resulting redirect landed on better-auth's bare /error page with no
actionable feedback.
- Mark SCIM-provisioned users as email-verified at creation time, same
trust rationale already applied to admin-invited credential users.
- Sync a SCIM user's membership role to the organization's configured
default role instead of the hardcoded "member" the SCIM plugin creates.
- Set errorCallbackURL/onAPIError.errorURL to the sign-in page so failed
SSO/OAuth callbacks land back on Dokploy's UI instead of better-auth's
generic error page.
- Read the error query param on the sign-in page and show it through the
existing AlertBlock instead of failing silently.
Fixes#4973
Radix locks scroll on <body>, but the dashboard's actual scroll
container is the sidebar's <main data-slot="sidebar-inset">, so the
background stayed scrollable behind dialogs/sheets. Extend the lock
to that container using the same data-scroll-locked attribute Radix
already sets.
Fixes#5064
The docker container terminal did not load xterm's ClipboardAddon, so
pasting into it (e.g. a MariaDB shell) broke the cursor and left the
pasted text uneditable. The web server terminal already loads this addon;
this brings the container terminal in line with it.
Also dispose the terminal on cleanup so its addons don't leak on remount.
Fixes#5065
- Images tab: list, inspect and delete docker images, with a
force-delete fallback when an image is in use.
- Disk Usage tab: docker system df summary as stat cards plus a
Build Cache table (docker system df -v) with a prune action.
@aws-sdk/client-secrets-manager (pre-existing, unrelated to any recent
PR) transitively pulled @smithy/fetch-http-handler + @smithy/core
versions published the same day, with no older compatible version to
fall back to. AWS SDK v3 is dozens of interdependent packages often
published together same-day, so a global minimumReleaseAge with no
per-scope threshold (pnpm only supports all-or-nothing exclude) was
going to keep breaking builds on any lockfile touch. Commented out
rather than deleted -- left for whoever wants to revisit it, see
discussion on #4679.
Also lets @aws-sdk/client-route-53 and @aws-sdk/client-secrets-manager
resolve to their actual latest versions now that nothing blocks it.
Adds a new Events tab to /dashboard/docker showing Docker daemon
events (equivalent to `docker events`), polled via docker.getEvents
with a time-range selector and refresh button.
Also fixes a stale isCloud redirect that forced the Networks tab
back to Containers even though it is now shown in cloud.
The endpoint field let anyone with dnsProvider create permission point
the AWS SDK at an arbitrary URL (loopback, link-local, internal
network, cloud metadata), turning testConnection and every other
Route53 operation into an SSRF oracle. There's no way to keep
LocalStack-style testing working while blocking that, since the
target address is identical either way, so the field is removed
entirely rather than validated. Route53 always talks to real AWS now.
Also pin @aws-sdk/client-route-53 to ^3.1097.0 (matching the existing
client-secrets-manager pin) instead of whatever caret-latest resolved
to at install time. The version that landed in the merged PR was
published less than a day before this, which violates the
minimumReleaseAge policy that merged into canary around the same time
and broke the Docker build.
* ci: update pull request actions for node 24
Что:
- Обновлены actions checkout, setup-node и pnpm/action-setup в Pull Request workflow до v5.
Зачем:
- Убрать Node.js 20 deprecation annotations из pr-check jobs и использовать actions с Node.js 24 runtime.
Риски:
- Не выявлены; изменение ограничено версиями GitHub Actions без изменения команд workflow.
Проверки:
- Команды и результаты: gh api action.yml для actions/checkout@v5, actions/setup-node@v5 и pnpm/action-setup@v5 подтвердил runs.using node24; git diff --check прошел; ruby YAML parse .github/workflows/pull-request.yml вернул yaml ok; go run github.com/rhysd/actionlint/cmd/actionlint@latest .github/workflows/pull-request.yml прошел без diagnostics; независимый Agent Flow reviewer вернул pass.
- Ограничения: Локальные build/test/typecheck не запускались, потому что изменение касается только GitHub Actions workflow versions.
What:
- Updated checkout, setup-node, and pnpm/action-setup actions in the Pull Request workflow to v5.
Why:
- Remove Node.js 20 deprecation annotations from pr-check jobs and use actions with the Node.js 24 runtime.
Risks:
- None identified; the change is limited to GitHub Actions versions without changing workflow commands.
Checks:
- Commands and results: gh api action.yml for actions/checkout@v5, actions/setup-node@v5, and pnpm/action-setup@v5 confirmed runs.using node24; git diff --check passed; ruby YAML parse .github/workflows/pull-request.yml returned yaml ok; go run github.com/rhysd/actionlint/cmd/actionlint@latest .github/workflows/pull-request.yml passed with no diagnostics; independent Agent Flow reviewer returned pass.
- Limitations: Local build/test/typecheck were not run because the change only touches GitHub Actions workflow versions.
* ci: update format actions for node 24
Что:
- Обновлены actions/checkout и pinned autofix-ci/action в format workflow до Node.js 24-compatible версий.
Зачем:
- Убрать оставшуюся Node.js 20 deprecation annotation из autofix.ci после исправления pr-check workflow.
Риски:
- Не выявлены; изменение ограничено версиями GitHub Actions без изменения formatter-команды.
Проверки:
- Команды и результаты: gh api action.yml для autofix-ci/action@v1.3.4 подтвердил runs.using node24; git ls-remote подтвердил SHA c5b2d67aa2274e7b5a18224e8171550871fc7e4a для tag v1.3.4; git diff --check прошел; ruby YAML parse для pull-request.yml и format.yml вернул yaml ok; go run github.com/rhysd/actionlint/cmd/actionlint@latest .github/workflows/pull-request.yml .github/workflows/format.yml прошел без diagnostics; независимый Agent Flow reviewer подтвердил корректность полного local diff и отметил, что fix нужно опубликовать.
- Ограничения: Локальные build/test/typecheck не запускались, потому что изменение касается только GitHub Actions workflow versions.
What:
- Updated actions/checkout and the pinned autofix-ci/action in the format workflow to Node.js 24-compatible versions.
Why:
- Remove the remaining Node.js 20 deprecation annotation from autofix.ci after fixing the pr-check workflow.
Risks:
- None identified; the change is limited to GitHub Actions versions without changing the formatter command.
Checks:
- Commands and results: gh api action.yml for autofix-ci/action@v1.3.4 confirmed runs.using node24; git ls-remote confirmed SHA c5b2d67aa2274e7b5a18224e8171550871fc7e4a for tag v1.3.4; git diff --check passed; ruby YAML parse for pull-request.yml and format.yml returned yaml ok; go run github.com/rhysd/actionlint/cmd/actionlint@latest .github/workflows/pull-request.yml .github/workflows/format.yml passed with no diagnostics; independent Agent Flow reviewer confirmed the full local diff is correct and noted that the fix needed to be published.
- Limitations: Local build/test/typecheck were not run because the change only touches GitHub Actions workflow versions.
Route53 rejects the literal "@" (RRSet with DNS name @. is not
permitted); Cloudflare happens to accept it, but relying on
provider-specific handling of that shorthand isn't safe. Resolve it
client-side to the zone's actual domain name before building the
create/update payload.
Lets you connect a DNS provider and manage its records (create,
update, delete) from Settings -> DNS Providers, instead of doing it
by hand in Cloudflare/AWS.
- dns_provider table, org-scoped, jsonb config as a discriminated
union per provider type
- Cloudflare adapter (REST, bearer token)
- Route53 adapter (AWS SDK, SigV4); records are identified by
type:name since Route53 has no native record id, so update
handles renames as delete-old + upsert-new
- listZones/listRecords/createRecord/updateRecord/deleteRecord/
testConnection wired through a shared DnsClient interface
- Settings UI: provider management, zone browser, record CRUD,
IP-fill dropdown for A records (panel IP + remote servers)
- Access control: dnsProvider resource wired into custom roles
- Unit tests for both adapters and the config mask/merge logic
Monitoring was the only component still using docker.createContainer
directly instead of docker.createService like every other Dokploy
component (postgres, traefik, forward-auth, etc). This meant it never
benefited from Swarm's own reconciliation, relying only on Docker's
restart policy with no self-healing if the daemon didn't come back
cleanly after a reboot.
Also removed the try/catch that silently swallowed setup errors,
which made the UI report success even when the container/service
failed to start.
Fixes#4986. initCancelDeployments blindly marked every 'running'
deployment as 'cancelled' on boot, including schedule runs whose
actual work (docker exec into another container, or SSH to a remote
host) is decoupled from the Dokploy process and keeps running after
a restart. Now only deployments with no schedule, or schedules of
type dokploy-server (a real child process), get cancelled.
Also resolve any stale 'running' deployment for a schedule when a
new run starts, so restarted panels don't leave ghost 'running' rows
forever.
dockerSafeExec's busy-wait matched any process with "docker <letter>"
anywhere in its argv (e.g. Grafana's --packaging=docker cfg:...),
causing the wait loop to spin forever. Anchor the match to the actual
docker binary (argv[0]) instead, and add a MAX_WAIT ceiling so a
genuinely stuck docker process can't hang cleanup indefinitely either.
Also log failures in cleanupAll's catch instead of swallowing them,
since the scheduled cleanup path only goes through this function.
Fixes#5044
Adds Scaleway Secret Manager as a first-class vault provider alongside
HashiCorp Vault/OpenBao, Infisical, AWS, Doppler and Azure Key Vault.
- New `scaleway` provider type, zod-validated config (region, project ID,
API secret key, overridable API URL) and migration adding the enum value
- Plain `fetch` client (no new dependency) against the Secret Manager
v1beta1 REST API: access-by-path for reads, paginated listing for the
env editor autocomplete, and a connection test
- Refs are `[folder/]name[:field]` — the field selector extracts a key
from JSON/key-value secrets, like the AWS provider
- Secret key masked in API responses like every other provider credential
- Settings -> Secrets form with region picker, brand icon and reference
format help
- Add Nodes sub-tab under Docker > Swarm (visible with organization.update permission)
- Remove Cluster item from settings sidebar and delete /dashboard/settings/cluster page
- Point internal cluster links to /dashboard/docker?tab=swarm&subtab=nodes
- Make ShowNodes card full-width to match the other docker tabs
fix(restore): drop USE/CREATE DATABASE statements so mysql/mariadb restores target the selected database
(cherry picked from commit ce0fe63b4a)
[skip ci]
- Included the @aws-sdk/client-secrets-manager package version 3.1097.0 to facilitate AWS Secrets Manager integration for managing environment secrets.
- Updated the environment autocomplete component to include projectId and environmentId in vault secret fetching logic.
- Added authorization checks in the vault provider router to ensure users have access to the specified project and environment.
- Modified the vault provider schema to include projectId and optional environmentId for better validation.
- Improved error handling for unauthorized access and invalid vault provider assignments.
- Introduced support for project and environment assignments for vault providers, allowing for more granular access control.
- Updated the vault provider schema to include assignments and modified related components to handle these changes.
- Enhanced UI to display assignment status and allow users to manage project and environment associations effectively.
- Added validation to ensure assignments reference valid projects and environments within the organization.
- Updated tests to cover new functionality related to vault provider assignments and environment variable resolution.
- Added support for managing various vault providers (HashiCorp, AWS, Azure, Doppler, Infisical) in the dashboard.
- Implemented environment variable resolution using vault references, allowing seamless integration of secrets into application environments.
- Enhanced UI components to display and manage vault providers effectively.
- Introduced tests for vault reference resolution and environment variable preparation.
- Updated related components to utilize new vault management features.
Biome 2.5.7's CSS parser rejects @apply/@theme (Tailwind v4 syntax)
by default, which broke the format CI job after the version bump.
Enable css.parser.tailwindDirectives and apply the resulting
formatter output (quote-style/line-wrap normalization from the
newer formatter).
Biome's scanner walks node_modules and generated build output
(e.g. Next.js/Turbopack .next/dev chunks) regardless of files.includes,
which only governs lint/format targets, not the module-graph scanner.
On this monorepo (112k+ files under node_modules, actively regenerated
.next/dev artifacts) that let the biome daemon's memory grow unbounded
over a long-lived editor session.
Set files.experimentalScannerIgnores to exclude node_modules, .next,
.docker, and dist from the scanner, and bump @biomejs/biome from 2.1.1
to 2.5.7 to pick up several intervening scanner/module-graph fixes
(deadlock fix in 2.5.3, scanner-triggered memory fix in 2.5.2).
- Refactored SwarmMonitorCard to use optional chaining for node data handling.
- Consolidated loading and error states into a single conditional rendering block.
- Updated dashboard layout to include tabs for containers and swarm, enhancing navigation.
- Removed deprecated network-related code from the dashboard.
Deploy-time Railpack install ran without sudo, so deploys to a remote
server with a non-root user (passwordless sudo) failed because the
install script could not write to /usr/local/bin ("A terminal is
required to authenticate").
Detect whether sudo is needed (root vs. passwordless-sudo user) and run
the install through it, matching the server-setup script.
Fixes#5007
The backend already honors isStaticSpa for the Nixpacks builder when a
publishDirectory is set (getStaticCommand generates an SPA-aware nginx
config with try_files fallback to index.html), but the build type form
only wired the field for the Static builder. As a result the toggle
never rendered for Nixpacks and any save in that mode silently cleared
the flag via the discriminated union schema and resetData mapping.
Add isStaticSpa to the nixpacks schema variant and resetData case,
render the same SPA checkbox once a publish directory is set, and
include the field in the save mutation payload for nixpacks.
Fixes#4993
The cli/sdk steps copied the repo-root openapi.json, which was last committed in March, and the mcp step fetched docs.dokploy.com, which canary pushes can overwrite. Generate the spec from the release commit instead so each package release matches its dokploy tag.
npm install -g pnpm resolved to pnpm 11, which turns the esbuild ignored-build-scripts warning into a fatal error, so sync-version has failed on every release since v0.29.5 and mcp/cli/sdk were never bumped or published. Pin pnpm to 10.22.0 (same as packageManager) and write the version without the v prefix so npm packages get valid semver.
`findApplicationById` redacts `githubPrivateKey` from the `github`
relation, but `createPreviewDeployment` passed that redacted object
straight to `authGithub`. Since `haveGithubRequirements` requires the
private key, it always returned false and `authGithub` threw
`TRPCError NOT_FOUND: "Github Account not configured correctly"`.
That throw is uncaught in `pages/api/deploy/github.ts`, so every
`pull_request` webhook returned a bare 500 and no preview deployment
was ever created.
Resolve the provider through `findGithubById(application.githubId)`
instead, matching how every other call site obtains credentials. This
keeps the redaction introduced for `findApplicationById` intact.
Fixes#4898
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Updated ShowIconSettings component to handle both application and compose service types.
- Added new icon column to the compose table in the database.
- Implemented fetching and updating of icons for services in the environment and application pages.
- Introduced fetchTemplateLogo function to retrieve logos for templates, improving icon handling for compose services.
Dokploy stopped using Redis in v0.29.9 when the deployment queue moved
to an in-memory implementation, and install.sh no longer creates the
dokploy-redis service. Remove the remaining references so fresh installs
don't report Redis as unhealthy:
- checkRedisHealth from infrastructure health check
- cleanRedis/reloadRedis endpoints and their UI actions
- initializeRedis dev setup and redis-connection config
- unused bullmq dependency
Rolling back any application fails with
PostgresError: cannot pass more than 100 arguments to a function (54023)
since 0175_fantastic_peter_quill took the application table to 101 columns.
findRollbackById hydrated deployment -> application -> environment -> project,
so drizzle compiled all 101 application columns plus the nested blob into one
json_build_array() call, above the FUNC_MAX_ARGS = 100 limit. At 99 columns it
sat exactly on the limit.
None of that nested data is read: the routers only use deployment.applicationId,
and rollback()/removeRollbackById() read the rollback row itself. Drop the nested
relations, the same shape as #4257 for findPreviewDeploymentById.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
rollbackApplication() called prepareEnvironmentVariables() without the
environment env, so every ${{environment.*}} reference threw "Invalid
environment variable: environment.X" and the rollback failed with an
opaque 400 before the swarm service was updated.
fb749cd86 added the third argument to every other call site but left
services/rollbacks.ts, which had been calling the helper since 24bff9689.
The value is already captured in the snapshot by createRollback(); both
fullContext declarations simply typed environment as { project: Project },
so the missing argument was invisible to the compiler.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Added new endpoints for application creation, retrieval, and reloading with detailed request and response schemas.
- Updated existing network validation schemas to enforce minimum length requirements for network IDs.
- Improved OpenAPI documentation to ensure better clarity and validation for application-related operations.
- Added auditing functionality for network creation, recreation, and deletion actions in the network API.
- Updated the audit log schema to include "network" as a resource type.
- Enhanced the network router to log actions with relevant metadata, improving traceability and accountability for network management operations.
validateDomain returns isValid: true for CDN-fronted domains but reuses
the `error` field to carry the provider's informational warning. Both
domain tooltips branched on `error` alone, so the message rendered under
a red "Error:" heading even though the badge correctly showed a green
"Behind Cloudflare" state.
Check the valid+message case first, matching how the badge already
distinguishes the two. Applied to both the table view (columns.tsx) and
the card view (show-domains.tsx), which shares the same tooltip.
Fixes#4910
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Added functionality for assigning Docker networks to services, allowing users to manage network associations directly from the UI.
- Introduced new components for assigning networks to both individual services and compose files, improving user experience and flexibility.
- Updated existing components to integrate network assignment features, ensuring seamless interaction within the dashboard.
- Enhanced the database schema to support new network-related fields, including `networkIds` and `detachDokployNetwork`, for better service configuration.
- Improved the layout and responsiveness of various UI elements to accommodate new features and enhance usability.
- Added a new API endpoint for recreating Docker networks that have been removed, allowing users to restore networks directly from the Dokploy interface.
- Updated the ShowNetworks and SyncNetworks components to include options for recreating networks, improving user management capabilities.
- Enhanced the network synchronization process to better handle stale records, providing users with clear actions for network maintenance.
- Refactored network creation logic to streamline the process and ensure consistency across network management operations.
- Added server filtering capability to the dashboard, allowing users to manage networks specific to selected servers.
- Introduced SyncNetworks component for synchronizing Docker networks with Dokploy, enabling import of new networks and cleanup of stale records.
- Updated HandleNetwork and ShowNetworks components to support server-specific operations, improving user experience and functionality.
- Enhanced API to support network synchronization and importing, ensuring accurate data handling for network management.
- Introduced a new ShowNetworkConfig component for displaying detailed Docker network configuration.
- Integrated ShowNetworkConfig into the ShowNetworks component, allowing users to view network details directly.
- Updated the layout of network actions for improved user experience and accessibility.
- Enhanced the API to support network inspection functionality, providing necessary data for the new component.
- Simplified the network form schema by removing unnecessary fields and enforcing validation rules for IP settings.
- Updated the HandleNetwork component to eliminate the edit functionality, focusing on network creation only.
- Improved the ShowNetworks component by adding a delete action for network management, enhancing user experience.
- Introduced a new SQL migration for the network schema, establishing necessary constraints and types.
- Cleaned up the API by removing the update network functionality, reflecting the immutable nature of Docker networks.
- Replaced zodResolver with standardSchemaResolver for improved schema validation.
- Added new toggle options for network settings, enhancing user interface clarity.
- Refactored network creation and update logic to streamline payload handling.
- Updated network form schema to remove default values, ensuring explicit user input.
- Introduced SERVER_LOCAL sentinel for local Dokploy server identification.
- Updated the ShowNetworks component to improve the layout and user experience.
- Introduced a new Pencil icon for editing networks and added a Badge component for displaying network drivers.
- Refactored loading and empty state handling for better visual feedback.
- Modified the API query to include server details for each network, enhancing the data returned for better context.
- Introduced a new SQL file defining the "network" type and its associated table structure.
- Added "networkIds" column to multiple application tables for network association.
- Established foreign key constraints for the "network" table linking to "organization" and "server" tables.
- Updated migration journal and added a new snapshot for versioning.
- Deleted the SQL file and snapshot related to the "network" management schema, cleaning up the database structure.
- Updated the migration journal to reflect these deletions.
- Added .playwright-* to .gitignore to exclude Playwright test files from version control.
Organization admins can define their own AI providers (name + API URL)
from the AI settings section. When at least one custom provider is
defined, it replaces the built-in provider list in the Add AI form,
the API URL is auto-filled and locked, and the backend rejects any
configuration whose URL is not in the allowed list.
Updated the SSO configuration to trust verified emails and modified user creation to set emailVerified to true by default. This enhances security and ensures that user email verification is properly handled.
The verify-totp handler checked for the error code
INVALID_TWO_FACTOR_AUTHENTICATION, which no longer exists in
better-auth 1.6.23 (the two-factor plugin now returns INVALID_CODE).
As a result, entering a wrong TOTP code fell through to the generic
catch and showed "Error verifying 2FA code / Unknown error" instead of
a clear "Invalid verification code" message.
Match the current better-auth error code so the specific, actionable
message is shown.
The organization switcher's DropdownMenuContent inherited its width from
the collapsed trigger (~40px) via the base primitive's
w-(--radix-dropdown-menu-trigger-width), clamping the menu to the
min-w-32 (128px) floor. This cut off the org name and action buttons in
icon mode.
Set an explicit w-64 so the menu fits its content regardless of the
trigger width, matching the pattern already used by the notification
dropdown in the same file.
Fixes#4840
The remote (execAsyncRemote) path built `echo ${password} | docker ${args.join(" ")}`
with the password, registryUrl and username interpolated unescaped, so a password
like `pw; whoami` ran arbitrary commands as root on the target server. Reuse
safeDockerLoginCommand (already used by create/update), which shell-escapes each
field and feeds the password via --password-stdin. The local argv+stdin path was
already safe.
server.remove deleted a server (and its deployment rows) by caller-supplied
serverId without checking it belongs to the active organization, unlike server.one
and server.update. An owner/admin of org A could delete org B's server registration.
Resolve and compare the server's organizationId before the active-services guard,
so cross-org callers are rejected without leaking existence.
writeTraefikConfigRemote piped the stringified YAML through echo '...' where a
single quote in any label/host/serviceName broke out (GHSA-478p). Encode it as
base64 like the other writers, and quote() every configPath used in remote
rm/cat/redirect commands (including the input.path-derived ones).
quote() the user-derived paths that reach the shell in file mounts
(mount.ts, docker getCreateFileCommand), patch repo read (repoPath/filePath),
certificate create/remove (certificatePath), and the remote scheduled command
(containerId/shellType/command/logPath), so $(), backticks and traversal in
these fields can no longer inject commands.
Add VOLUME_NAME_REGEX (Docker volume-name format) and enforce it on volumeName in
create/update/runManually — a legit volume name never contains shell metacharacters,
so this blocks injection across every docker run/rm/rclone sink at once. Escape the
user-supplied backupFileName and the mount volumeName in database rebuild with quote().
Wrap S3 credential flags (getS3Credentials + destination.testConnection), the
listBackupFiles search path, and every restore backupPath/backupFile with
shell-quote's quote() so $(), backticks, quotes and spaces in destination
fields or backupFile can no longer break out of the rclone shell commands.
quote() legitimately wraps the payload text inside single quotes, so the raw
substring is present but inert. leaksShellSyntax (via shell-quote parse) is the
correct assertion; the literal not.toContain check was wrong.
writeDomainsToCompose returns a shell fragment that is executed as part of the
compose build script. On error it interpolated error.message (which embeds the
user-controlled serviceName/host) directly into an echo, so a serviceName like
$(cmd) executed as root. Escape the message with quote().
Use shell-quote's quote([...]) directly at each git-provider clone call site
instead of the one-line shellWord wrapper, and remove the now-unused helper.
Behavior is identical (quote([String(v ?? '')])).
The /api/providers/github/setup callback performed privileged writes (persisting
App client_secret/webhook_secret/private_key, re-pointing installations) with no
session check, deriving the write target (organizationId/userId on gh_init,
githubId on gh_setup) from the attacker-controlled state parameter. An
unauthenticated request, or a member with no gitProviders permission, could plant
or re-point a provider in any organization.
Require a valid session, gate on the gitProviders permission (same guard the tRPC
github router uses), derive the create target from the session, and verify the
gh_setup provider belongs to the caller's organization.
createInsertSchema inferred scheduleType as a broadened union (drizzle-zod 0.5.1),
so passing input.scheduleType into assertHostScheduleAccess failed typecheck on a
cold build. Refine the insert schema's scheduleType to a plain z.enum and type the
helper param as the schedule enum.
Host-level schedules (server / dokploy-server) run their script as root on the
host. The owner/admin gate only ran in the no-service branch, so a member could
attach an accessible applicationId to a dokploy-server schedule and skip it,
gaining root via schedule.runManually.
Extract assertHostScheduleAccess into the schedule service and call it before
the service-access branch in create/update/delete/runManually so the host-level
authorization always applies.
- application general 'Open Terminal' now passes serviceId (applicationId).
- The docker/terminal DockerTerminalModal now forwards serviceId to its Terminal.
- compose container rows thread serviceId to their terminal + logs modals.
This lets a member with service access (but without the docker permission) open
the terminal / read logs of their own service's containers from every service
view, matching the backend service-first authorization.
When a container is opened from a service page (serviceId present), gate on
service access alone — matching application.readLogs — instead of requiring the
docker permission first. This unblocks a member who has the service but not the
canAccessToDocker permission (or the server it runs on) from reading its logs /
opening its terminal. Generic Docker-overview ops (no serviceId) still require
docker permission + server access.
- Reorder canAccessDockerOverWss: docker permission -> service access (if
serviceId) -> server access, so the service grant is the primary signal.
- Pass serviceId from the service log views (application + postgres/mysql/mariadb/
mongo/redis/libsql + compose) so container logs opened from a service page are
gated by checkServiceAccess, matching the terminal path.
Completes GHSA-qf9j service-level dimension: when a container terminal/logs/stats
is opened from a service page, the frontend now passes serviceId, and the wss
authorizer calls checkServiceAccess so a member restricted to specific services
cannot reach another service's containers. Generic Docker-overview opens have no
serviceId and keep the docker-permission + server-access gate.
Verified against the local WebSocket: a member (docker:read=false) is rejected
with close code 4003; owner is allowed.
Closes GHSA-qf9j-c9p4-r4xp
The /terminal, /docker-container-terminal, /docker-container-logs and
/docker-stats WebSocket handlers only checked session + organization, so any
authenticated member could open a root shell / read logs of any container, and
the local (serverId=local) branch reached a root SSH shell on the control-plane
host.
Adds an authorization layer (server/wss/authorize.ts):
- container ops (terminal/logs/stats): require the docker permission (owner/admin
or a member granted canAccessToDocker); for a remote server, require the server
be accessible to the caller.
- host/server terminal: the local host root terminal is restricted to owner/admin;
a remote server terminal is gated on server access.
Closes GHSA-c68r-7wg9-p7v2, GHSA-899j-cjwp-v4gw, GHSA-7r6p-v9gw-pwc8, GHSA-qf9j-c9p4-r4xp
- cluster.removeWorker: input.nodeId (z.string(), no regex) was interpolated raw
into 'docker node update/rm ${nodeId}' — now shell-quoted.
- swarm image upload (getRegistryCommands): registryTag / imageName were
interpolated raw into 'docker tag'/'docker push' and an echo. registryTag is
built from username and imagePrefix, which have no schema regex, so it was
injectable — now shell-quoted. (The docker login already used
safeDockerLoginCommand, so credentials were already safe.)
- gpu-setup: nodeId (derived from 'docker info', not user input) escaped as
defense-in-depth.
Closes GHSA-4mfc-grxw-6858, GHSA-hfwh-69ch-gv47, GHSA-prwq-2mcm-mvhr
- composePath / appName are now passed through shell-quote in createCommand,
getCreateEnvFileCommand and services/compose.ts deploy commands, instead of
being interpolated raw into 'docker compose'/'docker stack' shell commands.
- compose.command: sanitizeCommand was cosmetic (trim + strip quotes). It now
rejects shell control characters (; & | ` $ () {} <> newline), which a normal
docker compose CLI line never contains, blocking breakout into host commands.
Closes GHSA-8r5w-vqjr-8c44, GHSA-5xv2-7f8w-9j5c, GHSA-qh6h-669j-77rw
The backup and restore command builders interpolated database name / user /
password directly into a 'docker exec ... {bash,sh} -c "..."' string executed
via execAsync / execAsyncRemote. Because the values sit inside the outer shell's
double quotes, a simple quote() is insufficient: the outer shell expands $(),
backticks and $VAR before the inner quoting applies (double-nested shell).
Values are now passed to the container as environment variables (docker exec -e
VAR=<shell-quoted>) and referenced as "$VAR" inside a single-quoted inner
script, so they never enter the inner command text and cannot break out of
either shell layer. The rest of each command (pg_dump/mysqldump/etc., flags,
| gzip) is unchanged.
Closes GHSA-qc73-mp78-4833, GHSA-qf8x-98cv-92qh, GHSA-ww4j-wjrr-rq8v, GHSA-7m3w-rm5f-h4fr, GHSA-f7mp-9jfp-mjrr
The deploy functions for postgres/mysql/mariadb/mongo/redis/libsql interpolated
the user-settable dockerImage field unquoted into 'docker pull ${dockerImage}'
executed via execAsyncRemote (SSH) on the remote server path. Now passed through
shell-quote. The local path already used pullImage() (execFile-based) and is
unaffected.
Closes GHSA-6jrh-8qmg-jj3p
- dockerImage (buildRemoteDocker) -> docker pull / echo
- dockerContextPath (docker-file builder) -> cd
- publishDirectory (nixpacks builder) -> docker cp source/dest paths
These fields were interpolated unescaped into shell commands run via execAsync /
execAsyncRemote during deployment. All are now passed through shell-quote.
Registry credentials already went through safeDockerLoginCommand (unchanged).
Closes GHSA-g9cg-4mmj-mh7p, GHSA-jxxj-gmpx-h5rj, GHSA-qjrc-g63x-qhp9, GHSA-98j8-6vjr-c3xw
Simpler and consistent with the existing registry column exclusion in the same
query: drop the secret columns from the nested github/gitlab/gitea/bitbucket
relations via columns:{ ...: false } instead of a post-fetch redaction helper.
Server-side clone paths re-fetch providers by id (find{Github,Gitlab,...}ById),
so deployments are unaffected. Column names are validated at compile time by
drizzle's typed columns config.
Closes GHSA-hg9j-j5mc-phf5, GHSA-wx75-vxph-2m2f
findApplicationById eagerly loads the github/gitlab/gitea/bitbucket relations
(needed server-side to clone) including OAuth tokens, the GitHub App private key
and webhook secret. application.one returned them to the client, exposing them to
any member with service:read even when hasGitProviderAccess was false.
Adds redactApplicationGitSecrets() in the application service (blanks the secret
columns, immutably) and applies it to application.one. No client feature reads
these secrets (verified in the frontend); server-side clone paths use
findApplicationById directly, so behaviour is unchanged.
Closes GHSA-hg9j-j5mc-phf5, GHSA-wx75-vxph-2m2f
swarm.getNodes/getNodeInfo/getNodeApps/getAppInfos accepted a caller-supplied
serverId and ran remote Docker Swarm reads against it with no organization
check, exposing another tenant's swarm topology cross-org (getContainerStats
already had the check; the others did not). getNodeInfo additionally
interpolated nodeId unescaped into 'docker node inspect ${nodeId}'.
Adds an org-ownership assertion to the four unscoped handlers and passes nodeId
through shell-quote in getNodeInfo.
Closes GHSA-jj6h-388v-9rwm
findServerById eagerly loads the sshKey relation (needed for server-side SSH
operations) including the plaintext privateKey. server.one and server.remove
returned that record to the client, exposing the private key to any member
with server:read regardless of canAccessToSSHKeys.
Adds redactServerSshKey() in the server service and applies it to the server.one
and server.remove responses. No client feature consumes the private key (the SSH
key management UI uses the dedicated sshKey router), and server-side callers keep
using findServerById directly, so behaviour is unchanged.
Closes GHSA-w9cp-jqfw-4xj9
The getBranches inputs type the provider id as optional, so only fetch and
authorize when an id is actually present; the underlying getBranches already
returns [] when no id is supplied.
The .one / getRepositories / getBranches / testConnection handlers for
github, gitlab, gitea and bitbucket resolved a provider by bare id under
protectedProcedure and returned the full row (OAuth tokens, app private
keys, webhook secrets) with no organization or entitlement check, letting
any authenticated user read another org's git-provider credentials (IDOR).
Adds assertGitProviderAccess() in the git-provider service (rejects cross-org
with NOT_FOUND and non-entitled same-org with FORBIDDEN, reusing the existing
getAccessibleGitProviderIds entitlement logic) and calls it in every read
handler before returning secret-bearing data.
Closes GHSA-66r5-5m5f-57vg
User-controlled git fields (customGitUrl, branch names, repo owner/name,
gitlab namespace, SSH hostname) were interpolated unescaped into git clone /
ssh-keyscan shell commands run via execAsync / execAsyncRemote, allowing
authenticated OS command injection. All such values are now passed through
shell-quote before interpolation (defense at the sink, covering every code
path including the compose branch bypass).
Closes GHSA-qxcw-cx35-2hrw, GHSA-hrfh-82jj-3q46, GHSA-6693-xv3f-69px,
GHSA-qwwm-hc7m-7xp9, GHSA-grrj-6xrh-j6vp, GHSA-x2p2-qq8g-2mqq,
GHSA-cg8g-x23v-5fw8
Renames the compose "Reload" action to "Rebuild" to accurately reflect its actual behavior. Clicking "Reload" triggers rebuildCompose() which executes a full Docker build (docker compose up -d --build). Also updates dialog text, toast notifications, and tooltips accordingly.
Fixes#4666
Add a new settings page under Settings > Sessions that shows all active
and expired login sessions with user info, IP address, device, and an
option to revoke (force logout) any session.
Backend:
- listSessions: adminProcedure that returns sessions joined with user
data, ordered by creation date
- revokeSession: adminProcedure that deletes a session by ID (blocks
self-revocation)
Frontend:
- New /dashboard/settings/sessions page with ShowSessions component
- Sessions table with user, IP, device, timestamps, and revoke action
- Sidebar link under Users (gated by member.read permission)
Tests:
- Input validation tests for revokeSession schema
Updated the PopoverContent components across various provider files to ensure consistent width and padding. Enhanced the display of repository and branch names by adding truncation to prevent overflow in the UI. This change applies to Bitbucket, Gitea, GitHub, and GitLab provider components, as well as their respective compose components.
The indentNodeProp from @codemirror/lang-yaml computes column-based
indents that produce inconsistent and odd-numbered indentation when
pressing Enter (e.g. 9 spaces after a nested 'web:' line, 6 after a
4-space 'image:' line). Override it with a line-based indentService:
keep the current line's indent, align list-entry keys after the dash
marker, and indent one unit deeper after lines opening a block
(':', '|', '>').
Fixes#4650
The repository CommandItem used the repo name as its cmdk value and
the check icon compared only names, so two repos with the same name in
different owners/orgs showed the selected checkmark and hover on both
entries. Key the item by owner/name and include the owner in the
selected comparison. GitLab already keyed by URL and is unaffected.
Fixes#4793
The Server Domain form rejected an empty value ('Invalid domain name'),
making domain assignment a one-way operation. The backend already
removes the Traefik router and clears the host when it receives an
empty host, so only the client-side validation blocked removal.
Allow an empty domain to clear it, and skip the https/letsencrypt
requirements when the domain is being removed.
Fixes#4821
Lines like 'failed: false, error: none' (e.g. ofelia job summaries for
successful runs) were rendered red because the error patterns matched
the key regardless of its value. Strip key/value pairs whose value
explicitly reports a non-error before running the error keyword
patterns.
Fixes#4538
The randomize/isolated-deployment volume transform split mount strings
on ':' and kept only the first two segments, so an access mode like
:ro, :z or :Z was silently dropped and read-only mounts became
read-write. Keep the full path+mode remainder when rebuilding the
mount string.
Fixes#4818
The new non-null `enabled` column makes it a required field on the Domain
type, so the existing traefik/compose test fixtures need it too. Adds
`enabled: true` to each base fixture (spread-based fixtures inherit it).
Fixes the apps/dokploy typecheck failure on CI.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add unit tests for addDomainToCompose verifying that a disabled domain
produces no traefik labels, an enabled domain does, and only the enabled
one emits labels when both are attached to the same service. Mocks node:fs
so loadDockerCompose runs against an in-memory compose spec.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an `enabled` flag (default true) so a domain can be switched off
without deleting it, preserving its configuration.
- schema: new `enabled` column + migration; added to apiUpdateDomain
- traefik (applications): guard manageDomain so a disabled domain never
exposes a router from any caller (create/update/forward-auth/toggle);
applies instantly through the file provider
- compose: skip disabled domains when generating docker labels, so the
change applies on the next deployment
- tRPC: new domain.toggleEnable procedure (permission-checked + audited),
returns requiresRedeploy for compose domains
- UI: switch on the domain card (host row, variant E) and a Status column
in the table view; disabled cards are dimmed; reuses the compose
redeploy hint for the toast
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Compose domains are rendered as docker labels and only take effect on the
next deployment. Extract the "redeploy required" notice into a reusable
component/strings and surface it consistently: as a banner in the domains
list, in the add/edit dialog (replacing the inline copy), and in the toast
shown after create/update/delete. Unify grid deletion onto the shared
handler so the hint applies in both grid and table views.
Groundwork for the upcoming domain enable/disable toggle.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
API key names longer than 32 characters were rejected by better-auth
with a 400 that surfaced as an opaque INTERNAL_SERVER_ERROR (the generic
"Failed to generate API key" toast). Add a shared name schema (min 1,
max 32, matching better-auth's default maximumNameLength) used by both
the tRPC input and the client form, and surface the limit on the Name
field so users see it before submitting.
Fixes#4798
Use the saved raw compose source during conversion instead of reading a potentially stale remote materialization. Preserve tmpfs declarations and long-syntax volume mounts through preview and stack deployment.
Fixes#4794
Co-Authored-By: Codex <noreply@openai.com>
Server CPU/Memory threshold notifications for remote servers always
showed "Server Name: Remote" instead of the actual server name, making
it impossible to tell which server triggered the alert when more than
one remote server is registered.
The remote branch of receiveNotification already fetches the matching
server row (looked up by its metrics token) but discarded it, hardcoding
ServerName to the literal "Remote". Use the fetched row's name instead,
falling back to "Remote" if it is somehow absent.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Added a "Ports" column to display container port information with sorting functionality.
- Implemented a dropdown menu item to copy the Container ID to the clipboard with a success toast notification.
- Introduced a state filter dropdown to filter containers by their current state, with options for all defined states.
- Added a refresh button to allow manual refreshing of the container list.
- Added @better-auth/scim version 1.6.23 to package.json.
- Updated versions of several @codemirror packages in pnpm-lock.yaml:
- @codemirror/autocomplete from 6.20.0 to 6.20.3
- @codemirror/language from 6.12.1 to 6.12.4
- @codemirror/search from 6.6.0 to 6.7.1
- @codemirror/view from 6.39.15 to 6.43.6
The @dokploy/server modules get bundled multiple times per process
(esbuild inline copy, compiled node_modules copy, and several Next.js
chunks via transpilePackages), so every module-level side effect ran
once per copy: up to 6 postgres pools, 6 dockerode clients and 6
better-auth instances in the server process, plus the repeated
'Using Docker socket' logs at boot.
- db/index.ts: use the globalThis cache in production too (one pool per process)
- constants/index.ts: cache the dockerode client on globalThis
- lib/auth.ts: wrap betterAuth() in a factory and cache the instance
- Dockerfile: exec node directly instead of leaving pnpm resident (~100MB RSS)
Currently, Dokploy only extracts modified files from webhook payloads.
This causes watchPaths to fail matching commits that only add or remove files (such as adding new routes or deleting files), preventing auto-deployments.
This commit updates the commit parsing logic to aggregate added, modified, and removed files.
- Eliminated the EnterpriseFeatureGate card for Application Authentication from the SSO settings page to streamline the UI.
- This change simplifies the layout and focuses on relevant features for users, particularly in non-cloud environments.
- Wrapped the project name in a paragraph element to improve text styling and ensure proper truncation for better readability.
- Enhanced the layout of the EnvironmentPage component for a more polished user interface.
- Added a new service to fetch public whitelabeling configuration for unauthenticated contexts.
- Updated the whitelabeling router to utilize the new service for public requests.
- Enhanced license validation checks to ensure proper access control based on organization licenses.
- Integrated a new Badge component to display an "Enterprise" label when a valid license is detected.
- Enhanced the sidebar layout to accommodate the new badge alongside the organization name, improving user visibility of license status.
- Removed unnecessary width class from buttons in ShowNodeApplications and ShowNodeConfig components for a cleaner design.
- Updated spacing in the NodeCard component to use gap instead of space-x for improved layout consistency.
These changes enhance the visual consistency and usability of the dashboard UI components.
- Changed the message displayed when no tags are found to "No tags created yet." for better clarity.
- Added a consistent layout for the tag handling component in both TagFilter and TagSelector, ensuring a unified user experience.
- Added a check to prevent empty values from being processed in the onValueChange handler for Bitbucket, Gitea, GitHub, and GitLab providers.
- Removed unnecessary defaultValue prop from Select components to streamline the code.
- Updated button styles to remove background color for better consistency across the UI.
- Enhanced volume backup selection to display a message when no volumes are found.
This update enhances user experience by ensuring that empty selections are handled gracefully and improves the overall visual consistency of the UI components.
The Ollama detection matched any URL containing "ollama", which hides
the API Key field for Ollama Cloud (ollama.com) and drops the key from
the createOllama() client, so cloud requests go out unauthenticated.
Narrow the rule to localhost-only Ollama and forward the API key as a
Bearer header when provided.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(backup): redact S3 credentials from logs and error output (#4621)
S3 backup credentials (access key + secret) were logged in plaintext
to Dokploy service stdout via logger.info in getBackupCommand() and
console.error in keepLatestNBackups(). Any operator with access to
service logs could recover S3 credentials.
Added redactRcloneCredentials() pure function that masks
--s3-access-key-id and --s3-secret-access-key values with [REDACTED].
Applied to both the structured logger call and the error handler.
Closes#4621
* fix(backups): redact sensitive information in error logs during web server backup process
Updated error handling in the web server backup function to redact Rclone credentials from error messages before logging and notification. This change enhances security by preventing sensitive data exposure in logs.
---------
Co-authored-by: Mauricio Siu <siumauricio@icloud.com>
* feat(databases): add copy button to User and Database Name fields
Adds an enableCopyButton prop to the Input component and uses it on
the User, Database Name, and Internal Host fields across Postgres,
MySQL, MariaDB, MongoDB, Redis, and Libsql credential views.
Closes#4495
* [autofix.ci] apply automated fixes
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Members with access to a schedule's application/compose got a 401 on
deployment.allByType because it passed the scheduleId straight into
checkServicePermissionAndAccess, which expects a service id.
OpenAI strict mode for response_format requires every property to be
listed in 'required'. Optional fields must instead be modeled as
nullable so the key stays required while still allowing no value.
Fixes#4267
apiKeys and nested user were returned without column projection, shipping
secrets (key, permissions, metadata) and unused fields to every page that
prefetches user.get, causing the /dashboard/home SSR payload to exceed
Next.js's 128kB warning threshold.
* fix(domain): validate hostname format to reject invalid characters
Underscores and other invalid characters were accepted in domain
inputs with no validation, causing Let's Encrypt to silently fail
certificate issuance while Dokploy fell back to a self-signed cert.
Fixes#4716
* fix(create-server): update SSH key label for clarity in server creation form
Replaced existing color definitions in the whitelabeling settings with the oklch color format for improved color management and consistency. This change enhances the customization capabilities of the theme while maintaining compatibility with Tailwind CSS v4.
No functional changes were made to the application behavior.
* fix: use github owner login for webhook deploy matching
* fix: prefer github owner name for webhook matching
Что:
- Инвертирован порядок fallback для GitHub webhook owner: сначала repository.owner.name, затем repository.owner.login.
- Обновлен focused regression test для приоритета owner.name и fallback на owner.login.
Зачем:
- Выполнить maintainer review request в PR #4674 и сохранить совместимость deploy matching для payload без owner.name.
Риски:
- Не выявлены для push/tag matching; preview pull_request путь использует тот же helper, но отдельным PR-event тестом не покрыт.
Проверки:
- Команды и результаты: git diff --check -- apps/dokploy/pages/api/deploy/github.ts apps/dokploy/__test__/deploy/github-webhook-handler.test.ts - passed; CI=true corepack pnpm --dir apps/dokploy exec vitest --config __test__/vitest.config.ts run __test__/deploy/github-webhook-handler.test.ts --reporter=verbose - passed, 1 file / 4 tests; CI=true corepack pnpm exec biome check apps/dokploy/pages/api/deploy/github.ts apps/dokploy/__test__/deploy/github-webhook-handler.test.ts - exit 0, reported existing Number.parseInt radix info at github.ts:464; mandatory QA subagent Boyle - pass.
- Ограничения: repo-wide format-and-lint, typecheck, build, and test не запускались для этого точечного review fix.
What:
- Inverted the GitHub webhook owner fallback order to prefer repository.owner.name before repository.owner.login.
- Updated the focused regression test for owner.name precedence and owner.login fallback.
Why:
- Address the maintainer review request in PR #4674 while preserving deploy matching for payloads without owner.name.
Risks:
- None identified for push/tag matching; the preview pull_request path uses the same helper but is not covered by a dedicated PR-event test.
Checks:
- Commands and results: git diff --check -- apps/dokploy/pages/api/deploy/github.ts apps/dokploy/__test__/deploy/github-webhook-handler.test.ts - passed; CI=true corepack pnpm --dir apps/dokploy exec vitest --config __test__/vitest.config.ts run __test__/deploy/github-webhook-handler.test.ts --reporter=verbose - passed, 1 file / 4 tests; CI=true corepack pnpm exec biome check apps/dokploy/pages/api/deploy/github.ts apps/dokploy/__test__/deploy/github-webhook-handler.test.ts - exit 0, reported existing Number.parseInt radix info at github.ts:464; mandatory QA subagent Boyle - pass.
- Limitations: repo-wide format-and-lint, typecheck, build, and test were not run for this targeted review fix.
The nightly access-log-cleanup job hardcoded "dokploy-traefik" as the
container name when sending SIGUSR1. In Docker Swarm mode Traefik runs as
a service task named "dokploy-traefik.1.<task-id>", so `docker exec
dokploy-traefik` fails every night with "No such container". The log file
is rotated (inode changes) but Traefik never reopens it, leaving the
on-disk access.log frozen while real logs go to a deleted file handle.
Resolve the running container id dynamically with `docker ps --filter`,
matching the pattern already used elsewhere in the codebase, so it works
for both standalone and swarm deployments. Skip gracefully if no running
container is found.
Closes#4620
The RequestPath in the request log table was truncated to 82 characters
with an ellipsis when it exceeded 100 characters, hiding part of the
route. Show the full path and let it wrap with flex-wrap and break-all.
Fixes#4642
Branch names containing '#' (e.g. feat#123) were rejected by
VALID_BRANCH_REGEX when saving a git provider configuration, even
though '#' is a legal git ref character.
Add '#' to the allowed character set. The change propagates to the
backend zod schemas and all provider UI forms, since they share this
constant.
'#' is not a shell injection vector: the regex still rejects every
character needed to terminate a command (; | & $ ( ) ` newline space
quotes), and '#' only starts a shell comment at the beginning of a
word, never mid-argument as in 'git clone --branch feat#123'.
Fixes#4585
cloneGitRepository runs `ssh-keyscan <host> >> known_hosts` as one step
of a `set -e` script. Hosts whose SSH endpoint waits for the client's
identification string first — Hugging Face's hf.co among them — never
complete the keyscan handshake, so it exits 1 and `set -e` aborts the
deploy before `git clone` ever runs.
Make ssh-keyscan non-fatal and let the real ssh client record the host
key on first connect (StrictHostKeyChecking=accept-new), which reaches
hosts ssh-keyscan can't scan. Same TOFU trust model, so no regression;
GitHub/GitLab/Gitea still pre-seed and verify known_hosts as before.
Remove .toLowerCase() transform from registryUsernameSchema.
AWS ECR requires the username to be exactly 'AWS' (uppercase) for
authentication. Docker Hub usernames are case-insensitive for login,
so preserving case is safe for all providers.
Closes#4632
* prevent social icons from overlapping in onboarding layout
* fixed the alignment social icon forms
* revert
* fix: adjust spacing in social sign-in section of registration page
Updated the layout of the social sign-in options by adding a gap between the elements to improve visual clarity and user experience.
---------
Co-authored-by: Mauricio Siu <siumauricio@icloud.com>
The canAccessToGitProviders legacy override only granted read access, so
members with the Git Providers toggle enabled could not add providers — the
create/delete endpoints require gitProviders.create / gitProviders.delete.
This mirrors how the SSH Keys toggle already grants read/create/delete.
The git-provider remove endpoint now restricts non owner/admin roles to
deleting only their own providers (matching the ownership model used for
visibility and sharing), while owner/admin can still delete any provider in
the organization.
Closes#4695
- Introduced a new mapping schema to handle user claims for OIDC providers, allowing for customizable mapping of claims to user fields.
- Implemented default mapping logic for Azure and generic providers, ensuring appropriate claim handling based on the issuer.
- Enhanced the registration dialog UI to include fields for claim mapping, improving user experience and configurability.
- Updated parsing logic to accommodate claim mapping in OIDC configuration.
This update enhances the flexibility of OIDC integration by allowing users to define how claims from identity providers map to application user fields.
* feat: update dependencies and enhance UI components in Dokploy
- Updated various package versions in pnpm-lock.yaml to improve compatibility and performance, including React and Tailwind CSS.
- Modified components.json to change the styling to "radix-nova" and added new properties for icon library and menu color.
- Refactored multiple components to use updated class names for better styling consistency and responsiveness.
- Removed unused Radix UI components from package.json to streamline dependencies.
- Adjusted layout and styling in several dashboard components for improved user experience and visual appeal.
- Enhanced tooltip and form item components for better accessibility and usability.
* refactor: enhance UI components in HandleCertificate and SidebarLogo
- Updated the HandleCertificate component to improve dialog content height and textarea styling for better usability.
- Adjusted the SidebarLogo component layout to enhance alignment and spacing, ensuring a more consistent appearance across the sidebar.
- Implemented responsive design adjustments to textarea elements, preventing overflow and improving user experience.
* refactor: improve UI consistency and styling across dashboard components
- Updated Card components in ShowDeployments, ShowSchedules, and ShowVolumeBackups to remove unnecessary border styles for a cleaner look.
- Enhanced TabsList components in ShowProviderForm and ShowProviderFormCompose by adding a variant for improved visual distinction.
- Adjusted spacing in AdvancedEnvironmentSelector for better layout and readability.
- Removed redundant border classes in Service component for a more streamlined design.
* [autofix.ci] apply automated fixes
* chore: update package dependencies and refactor email rendering
- Upgraded React and React DOM to version 19.2.7 across multiple packages for improved performance and compatibility.
- Updated TSX to version 4.22.4 in various package.json files.
- Refactored email rendering from `renderAsync` to `render` in notification utilities and email templates for consistency.
- Adjusted Tailwind configuration usage in email templates to utilize a centralized configuration file.
These changes enhance the overall stability and maintainability of the codebase.
* refactor: update badge variants across dashboard components
- Changed badge variant from "outline-solid" to "outline" in multiple components including columns, show-domains, and various deployment tables for consistency in styling.
- Updated button variants in billing and project templates to align with the new badge styling.
- Enhanced input components to support password generation and error messaging, improving user experience.
These changes streamline the UI and ensure a cohesive design across the application.
* refactor: clean up calendar component imports and structure
- Removed redundant imports of icons from lucide-react and streamlined the import statements for better readability.
- Adjusted the placement of type imports to enhance code organization.
These changes improve the maintainability and clarity of the calendar component.
* [autofix.ci] apply automated fixes
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
apiCreateCompose and apiCreateApplication did not include sourceType in their .pick() schemas, causing every compose/application created via the API to default to 'github' in the DB. Users had to manually update the sourceType after creation.
sourceType is already defined as .optional() in both createSchemas, so this is backward-compatible — callers that don't send it will still get the DB default ('github').
Auth forms (login, register, 2FA, backup-code, reset-password) had no
method attribute, defaulting to GET. react-hook-form's handleSubmit
preventDefault()s only after hydration; submitting in the pre-hydration
or no-JS window triggers a native GET to the current URL, leaking
email/password into the URL, history, access logs and Referer header.
Setting method="post" makes the native fallback a POST so credentials
go in the request body instead. Normal JS submit path is unchanged.
Verified in a browser: GET (?email&password) -> POST (clean URL).
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: enhance TLS certificate selection UI in AddDomain component
- Added descriptive FormDescriptions for different TLS certificate options (None, Let's Encrypt, Custom) to improve user understanding of certificate provisioning.
- Updated placeholder text for the custom certificate resolver input field to provide clearer guidance on expected input format.
This update enhances the user experience by providing contextual information directly within the form.
* [autofix.ci] apply automated fixes
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
The readLogs endpoint only checked deployment.serverId and
deployment.schedule?.serverId to determine where to read log files.
For application and compose deployments on remote servers, serverId
is not stored on the deployment record — the server is resolved from
the parent entity (application.serverId, compose.serverId).
This caused readLogs to fall through to local execAsync, which would
silently fail (2>/dev/null) because the log file lives on the remote
server, returning empty content.
Fix by loading the compose relation in findDeploymentById and adding
fallback resolution through application?.serverId and compose?.serverId.
Fixes#4687
Co-authored-by: Roo <roo@agent.com>
- Replace second form field (extra_pairs) with target_version
- target_version sets version B ("to"); empty = highest available tag
- Pair every tag in [floor_version, target_version) with target_version
The create step was calling postgres.start / mongo.start immediately after
create. In Dokploy, .start only scales an already-deployed Swarm service;
on a freshly created resource the service doesn't exist yet, so the server
ran 'docker service scale ci-pg-db-xxx=1' against a missing service and
returned a 500 (curl -sf → exit 22 → step failure).
.deploy is the mutation that actually builds and creates the Swarm service.
Applications already used .deploy correctly; this aligns the databases.
v0.20.x used a completely different postgres/mongo/app API schema —
projectId fallback returned boolean false, not the expected resource object.
Since the goal is testing v0.29.4+, drop the old-API compatibility shim
and fail fast with a clear message if environmentId is missing.
Also: default floor_version changed from v0.20.0 to v0.29.4 to reduce
the number of matrix jobs and focus on the stable modern API surface.
In Dokploy <= ~v0.24, project.create returns a flat object with just
projectId at the top level; no environment concept exists yet, so
resources (postgres, mongo, apps) are created with projectId.
In Dokploy >= ~v0.25, project.create returns nested {project, environment}
objects and resources require environmentId.
Previous workflow always used .project.projectId and .environment.environmentId,
both of which evaluated to null on old versions, causing curl to exit with
code 22 (HTTP error) on every subsequent resource-create call.
Fix: extract PROJECT_ID with a // fallback, check ENV_ID nullness, and
build a SCOPE fragment (either 'environmentId' or 'projectId') used in
all resource-creation tRPC calls.
Previous run failed with 'This script must be run as root'. install.sh also
respects DOKPLOY_VERSION and ADVERTISE_ADDR env vars, so we can install
version A directly instead of installing latest and downgrading (which
would risk B's migrations running on A's expected schema).
Supply-chain hardening. pnpm 10.16+ native minimumReleaseAge refuses to
resolve any dependency version published less than 3 days ago (4320 min),
so newly-published malicious versions get caught/yanked before we install.
Workspace-wide, so it covers root, apps/* and packages/server. Only gates
new resolutions; versions already pinned in the lockfile are unaffected.
Closes#4678
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The provisioning script pins DOCKER_VERSION=28.5.0 and passes it to
get.docker.com via --version. Ubuntu 26.04 (resolute) ships a docker-ce
repo with no 28.5.0, so the pin is not found in apt-cache madison and
Docker is never installed, aborting setup with 'Failed to initialize
Docker Swarm'.
Repin to a version present on every architecture Docker ships resolute
for. amd64/arm64/armhf start at 29.3.1, but the s390x pool only carries
29.4.0-29.4.2, so 29.3.1 still fails there; 29.4.2 is the newest version
common to all shipped arches (ppc64le is not shipped for resolute). The
override applies to Ubuntu 26.04 only; all other releases keep 28.5.0,
and it runs before the install banner so the reported version stays
accurate and both the full-server and build-server paths are covered.
Fixes#4327, #4349. Closes#4501.
* feat: add builds concurrency management for servers
- Introduced a new `BuildsConcurrency` component to manage the number of concurrent builds for both local and remote servers, gated by license validity.
- Implemented backend logic to resolve effective builds concurrency based on server settings and organization licenses.
- Added unit tests for concurrency resolution logic to ensure correct behavior under various licensing scenarios.
- Updated database schema to include `buildsConcurrency` field for servers and web server settings.
- Refactored deployment queue to support in-memory job processing with configurable concurrency limits.
This feature enhances deployment flexibility and control for enterprise users.
* refactor: enhance deployment cancellation logic and improve Railpack build isolation
- Reintroduced the `initCancelDeployments` function in the server initialization sequence to ensure deployments can be canceled effectively.
- Updated the Railpack build command to use a unique builder name for each build, preventing conflicts during concurrent deployments.
- Enhanced the cancellation logic to reset application and compose statuses to "idle" after canceling running deployments, improving system reliability.
* test: add buildsConcurrency setting to server configuration tests
- Introduced a new `buildsConcurrency` property in the server configuration tests to ensure proper handling of concurrent builds in deployment scenarios.
* feat: implement builds concurrency management and validation
- Added `assertBuildsConcurrencyAllowed` function to validate concurrency settings based on license status.
- Updated `resolveBuildsConcurrency` to reflect new concurrency limits for free and enterprise tiers.
- Enhanced `BuildsConcurrency` component to manage concurrent builds for servers, with UI adjustments for better user experience.
- Introduced a new settings page for managing concurrent builds across servers, ensuring proper handling of deployments.
- Updated database schema to support increased maximum concurrency values for servers and web server settings.
The application environment editor shares the application.one query with
its parent page, which polls every 5s. Each refetch pushed fresh data
into a useEffect that called form.reset(), wiping any in-progress edits
(e.g. while scrolling down to the Save button). Gate the reset on the
form not being dirty so background refetches no longer clobber unsaved
edits, and reset the dirty baseline after a successful save so the form
re-syncs with the server normally.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor: unify server admin tools into dashboard pages with server selector
Replace the per-server Advanced dropdown (Traefik file system, Docker
containers, swarm overview, swarm nodes, schedules) with a server
selector on the existing dashboard routes, defaulting to the Dokploy
server. Pages are now available in cloud too, since the dropdown was
the only entry point there; the cloud-only monitoring modal moves to
an icon button on the server card.
* feat: add frontend-design skill and enhance dashboard UI components
- Introduced a new skill for creating high-quality frontend designs, emphasizing intentional aesthetics and detailed guidelines for implementation.
- Updated the Traefik system component to improve the user experience when no files or directories are found, incorporating new icons and a more informative layout.
- Enhanced the server filter component with improved loading states, user prompts, and a more visually appealing design, including badges and better server information display.
* [autofix.ci] apply automated fixes
* style: adjust Card component layout in schedules page for improved responsiveness
- Modified the Card component in the schedules page to ensure it utilizes full width while maintaining the minimum height, enhancing the overall layout and user experience.
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
The Open action in the centralized deployments list navigated to the service's General tab instead of its Deployments tab. Append `?tab=deployments` to the generated link so it deep-links straight to the Deployments tab, matching the redirect the app already performs after a deploy.
* fix(migrate-auth-secret): exit cleanly when there are no 2FA records
The empty-records branch of `main()` returned without calling
`process.exit(0)`, leaving the Drizzle Postgres connection pool
holding the event loop open. The `migrate-auth-secret` process
then hangs indefinitely after printing "No 2FA records found,
nothing to migrate." causing the upstream `0.29.3.sh` security
migration script (which calls this via `docker exec`) to never
reach its final `docker service update` step that mounts the new
Docker Secret. Operators end up with the new secret created but
the dokploy service still configured with the hardcoded
`BETTER_AUTH_SECRET`, while believing the migration completed.
Match the success branch a few lines below which already does
`process.exit(0)`, and the pattern used in sibling scripts
`reset-password.ts` and `reset-2fa.ts`.
Closes#4392
* feat(compose): add import from base64 in create service dropdown
Adds an "Import" option to the Create Service dropdown that lets users
paste a base64-encoded compose export, preview the template (compose YAML,
domains, envs, mounts) before confirming, and create the service only on
confirm. Adds a `previewTemplate` tRPC procedure that processes the base64
without touching the DB, with server access validation via session.
* [autofix.ci] apply automated fixes
* Enhance version synchronization workflow to include SDK repository
- Updated the GitHub Actions workflow to sync versioning across MCP, CLI, and SDK repositories.
- Added steps to bump the version in the SDK repository and regenerate tools from the latest OpenAPI spec.
- Improved commit message formatting to include source and release information for all repositories.
- Ensured successful synchronization messages for each repository after the version update.
* feat(deployment): add readLogs procedure to fetch deployment logs
- Introduced a new `readLogs` procedure that allows users to retrieve logs for a specific deployment by providing the deployment ID and an optional tail parameter.
- Implemented permission checks to ensure users have access to the requested logs.
- Enhanced log retrieval for both cloud and non-cloud environments, utilizing appropriate commands based on the server context.
Resolve https://github.com/Dokploy/mcp/issues/14
* feat(deployment): add server access validation for deployment actions
- Implemented server access validation in deployment procedures to ensure users can only access deployments associated with their active organization.
- Added checks to throw an UNAUTHORIZED error if a user attempts to access a deployment linked to a server outside their organization.
This enhancement improves security and access control within the deployment management system.
* feat(organization): prevent inviting users with owner role
- Added validation to prevent users from being invited with the owner role in the organization and user routers.
- Implemented TRPCError responses to ensure proper error handling when attempting to assign the owner role.
This change enhances role management and security within the organization structure.
https://github.com/Dokploy/dokploy/security/advisories/GHSA-fm9p-wmpw-gxjh
* feat(user): implement session cleanup on user update
- Added functionality to delete old sessions when a user updates their password, ensuring that only the current session remains active.
- This change enhances security by preventing unauthorized access from previous sessions after a password change.
Close here https://github.com/Dokploy/dokploy/security/advisories/GHSA-rr9m-w87g-46f3
* feat(settings): add copy button to server IP in web server settings (#4397)
* fix: copy Dokploy server IP when clicking server badge (#4390)
* fix: copy Dokploy server IP when clicking server badge
When a service runs on the local Dokploy server (no remote server),
clicking the server badge did nothing because `data.server` is null.
Now falls back to the server IP from settings so the badge always
copies an IP address.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(copy-ip): implement IP address copying functionality across database service components
- Added the ability to copy the server IP address to the clipboard when clicking the server badge in various database service components (Libsql, MariaDB, MongoDB, MySQL, PostgreSQL, Redis).
- Integrated the `copy-to-clipboard` library and `sonner` for user feedback upon successful copy action.
- Ensured fallback to the server IP from settings when the service data is not available, enhancing user experience and functionality.
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Mauricio Siu <siumauricio@icloud.com>
* fix: responsive layout (#4391)
Signed-off-by: Nahidujjaman Hridoy <hridoyboss12@gmail.com>
* fix: automatically converting username to lowercase both in creation of register, and build for extra. (#4382)
* fix: allow square brackets in zip path validation for Next.js dynamic routes (#4468)
* fix: allow square brackets in zip drop path validation for Next.js dynamic routes
ZIP uploads containing Next.js dynamic route files (e.g. app/api/[id]/route.ts,
pages/[slug].tsx) were rejected by readValidDirectory because the path regex
did not include square bracket characters.
* [autofix.ci] apply automated fixes
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
* fix: prevent webhook deploy crash when commit data lacks modified files (#4470)
shouldDeploy passed undefined/null entries from commit.modified straight
into micromatch, which throws "Expected input to be a string" and fails
every webhook deployment when watch paths are configured. Filter out
non-string values before matching.
* fix: add type="button" to TooltipTrigger in form components to prevent accidental submission (#4422)
Co-authored-by: Maks Pikov <mixelburg@users.noreply.github.com>
* fix: enable comment toggle shortcut in env variable editor (#4402) (#4473)
* fix: add tls=true label for domains when certificateType is none (#4018) (#4474)
* fix: add tls=true label for compose domains when certificateType is none (#4018)
* test: cover tls=true label for certificateType none, require https
* fix: scope tls fix to compose labels, leave traefik file config unchanged (#4018)
* chore: update version to v0.29.5 in package.json
* chore(deps): upgrade next to 16.2.6 (#4477)
Upgraded next dependency in apps/dokploy to 16.2.6 exactly. Verified typescript typecheck passes successfully.
* feat: add self-hosted enterprise restrictions (remote-servers-only, enforce-sso) (#4511)
* feat: add self-hosted enterprise restrictions (remote-servers-only, enforce-sso)
- Add `remoteServersOnly` field to webServerSettings: prevents creating services
on the local Dokploy VM, forcing all deployments to remote servers. Validated
in all 8 service routers (application, compose, postgres, mysql, mongo, redis,
mariadb, libsql).
- Add `enforceSSO` field to webServerSettings: hides the email/password login
form and shows only the SSO button on the login page.
- Both settings are enterprise-only (enterpriseProcedure) and self-hosted-only
(blocked at the API level when IS_CLOUD=true).
- UI toggles added to the SSO settings page under a new "Self-hosted
Restrictions" card (hidden in cloud). Login page reads enforceSSO from
getServerSideProps to avoid client-side flash.
- Migrations: 0167_fresh_goliath.sql, 0168_long_justice.sql
* fix: add missing final newlines to migration files
* refactor: improve code formatting for better readability in multiple components
- Adjusted formatting in `add-application.tsx`, `add-compose.tsx`, and `add-database.tsx` to enhance readability by adding line breaks and consistent indentation.
- Updated `toggle-enforce-sso.tsx` to simplify the Switch component's props.
- Reformatted imports in `index.tsx` and `sso.tsx` for consistency.
- Cleaned up conditional statements in various router files for improved clarity.
* fix: add enforceSSO to test mock
* fix: grant create and delete SSH key permissions when canAccessToSSHKeys is enabled for members (#4512)
* fix: use create permission for basic auth delete instead of delete (#4513)
* fix: wrap long server names and keep actions menu visible (#4434)
On settings/servers, a long server name in the card title (h3) did not
wrap and overflowed its container, overlapping nearby content and
squeezing the three-dots actions menu until it disappeared.
Allow the title block to shrink and wrap (min-w-0 + break-words), keep
the server icon and the actions trigger from being crushed (shrink-0),
and add gap between the title and the actions button.
* chore: update version to v0.29.6 in package.json
* fix: preserve HOME in compose deploy so --with-registry-auth can read docker config (#4485)
The compose/stack deploy command runs under `env -i PATH="$PATH"`, which
clears the environment except for PATH. That strips HOME, so when the
generated command is `docker stack deploy --prune --with-registry-auth`
the docker CLI cannot resolve `~/.docker/config.json` (e.g.
`/root/.docker/config.json`) and ships no registry credentials to the
swarm. Private-registry images then fail to pull on the nodes:
image registry.example.com/... could not be accessed on a registry to
record its digest. Each node will access ... independently
while the deploy still logs "Docker Compose Deployed: ✅".
Keep PATH isolation but preserve HOME so docker can read its config for
both `stack deploy --with-registry-auth` and `compose up -d --build`.
Add a regression test asserting the generated command preserves
`HOME="$HOME"` for both stack and docker-compose deploys.
Fixes#4401
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: scope dokploy-server schedules to organization instead of user (#4526)
* fix: scope dokploy-server schedules to organization instead of user
Replaces userId with organizationId on the schedule table so that
global (dokploy-server) schedules are shared across all owners and
admins of the same organization, while remaining isolated between
different organizations.
Includes a data migration that backfills organizationId from the
owner membership record for any existing dokploy-server schedules.
Closes#4300
* [autofix.ci] apply automated fixes
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
* feat: implement forward authentication settings and UI components
- Added a new `forward_auth_settings` table to manage authentication domains and their configurations.
- Introduced UI components for handling forward authentication, including enabling/disabling SSO for domains and selecting SSO providers.
- Updated existing tests to include validation for the new `forwardAuthProviderId` field in domain configurations.
- Enhanced the dashboard to integrate forward authentication management, allowing users to configure SSO settings directly from the application interface.
This update improves the flexibility and security of application authentication by allowing integration with various identity providers.
* refactor: simplify forward authentication handling in UI and API
- Removed the selection of SSO providers from the UI, streamlining the process to enable/disable SSO for domains.
- Updated the API to eliminate the need for a provider ID when enabling forward authentication, relying on the configured settings instead.
- Enhanced user feedback by updating toast messages to reflect the current state of SSO authentication.
- Improved the UI layout for better clarity on SSO status and actions.
This refactor enhances the user experience by simplifying the SSO configuration process and ensuring clearer communication of actions taken.
* refactor: unify branch validation imports across provider components
- Added the `VALID_BRANCH_REGEX` import to all Git provider components to ensure consistent branch validation.
- Removed duplicate imports of `VALID_BRANCH_REGEX` to streamline the code and improve readability.
This change enhances maintainability by centralizing branch validation logic across the application.
* refactor: remove obsolete SQL migration files and snapshots
- Deleted several SQL migration files related to the `webServerSettings` and `schedule` tables, which included adding and dropping columns and constraints.
- Removed snapshots corresponding to the deleted migrations to maintain consistency in the database schema history.
This cleanup enhances the maintainability of the migration history by removing outdated and unused files.
* refactor: update forward authentication handling in domain schema and tests
- Replaced `forwardAuthProviderId` with `forwardAuthEnabled` in the domain schema to simplify the configuration of forward authentication.
- Updated related tests to reflect this change, ensuring consistency across the application.
- Introduced a new SQL migration to create the `forward_auth_settings` table for managing authentication domains and their configurations.
This refactor enhances the clarity and maintainability of the forward authentication logic within the application.
* chore: remove PR quality workflow configuration
Deleted the `.github/workflows/pr-quality.yml` file, which contained the configuration for the PR Quality workflow. This removal streamlines the repository by eliminating unused workflow files.
* Delete .github/workflows/pr-quality.yml
* refactor: enhance forward authentication UI and API integration
- Updated the alert block in the HandleForwardAuth component to provide clearer requirements for deploying the authentication proxy.
- Added a DnsHelperModal to assist with DNS configuration in the ForwardAuthServers component.
- Refined API input schemas for forward authentication operations to improve type safety and clarity.
- Removed the obsolete forward-auth SSO design document to streamline documentation.
These changes improve the user experience and maintainability of the forward authentication feature across the application.
* feat: add SQL migration for lucky echo and update foreign key constraints
- Introduced a new SQL migration file `0171_lucky_echo.sql` to modify the foreign key constraint on the `sso_provider` table, changing the `ON DELETE` behavior from `cascade` to `set null`.
- Updated the journal to include the new migration version and its associated tag.
- Added a snapshot file for version 7 of the database schema, reflecting the current state of the `sso_provider` and other related tables.
These changes enhance the integrity of the database by ensuring that user references are set to null instead of being deleted when the referenced user is removed.
* refactor: improve path validation in Traefik configuration schema
- Enhanced the `apiReadTraefikConfig` schema by reintroducing path validation logic to prevent directory traversal attacks and unauthorized access.
- The validation now includes checks for null bytes and ensures paths start with a defined main Traefik path, improving security and robustness.
These changes strengthen the integrity of the configuration handling by ensuring only valid paths are accepted.
* fix: swarm health check fields not resetting to default values (#4558)
Fixes#4553
- Replace z.coerce.number() with a custom transform that converts empty strings to undefined instead of 0
- Add value={field.value ?? ""} to numeric inputs so they visually clear when reset to undefined
* fix: add docker cleanup toggle to remote server creation (#4559)
* fix: add docker cleanup toggle to remote server creation and update forms
* [autofix.ci] apply automated fixes
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
* fix: use stop-first update order for all database services (#4560)
Docker Swarm's default start-first update order causes new database
containers to fail with 'DBPathInUse' because two containers compete
for the same data volume simultaneously. Docker then rolls back the
update, silently reverting any env var or config changes.
Using stop-first ensures the old container is stopped before the new
one starts, preventing volume lock conflicts across all database types.
Fixes#4550
* fix: respect gitProviders permissions in git provider UI (#4561)
* chore: bump dokploy version to v0.29.8
* fix: strip credentials from service-level API responses (#4564)
* fix: strip credentials from service-level API responses
Registry passwords and S3 destination credentials were being returned
in service `.one` tRPC endpoints to any user with service-level read
access. Reported by Nihon Kohden Corporation security team.
- Strip registry `password` from `findApplicationById` via Drizzle `columns: { password: false }`
- Strip destination `accessKey`/`secretAccessKey` from all DB service finders (postgres, mysql, mariadb, mongo, libsql, compose, backup, volume-backups)
- Add `findRegistryByIdWithCredentials` for internal use only
- Builders and upload utils now load registry credentials by ID at execution time
- `createRollback` enriches `fullContext` with registry credentials before persisting to DB so rollback execution has what it needs
- Remove `findApplicationByIdWithCredentials` and `ApplicationNestedWithCredentials` — no longer needed
- Backup execution utils load full destination via `findDestinationById` at runtime instead of reading from the joined relation
* [autofix.ci] apply automated fixes
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
* refactor: improve restore logging for database backups (#4566)
* refactor: improve restore logging for database backups
- Updated restore functions across various database types (Postgres, MySQL, MongoDB, MariaDB, LibSQL, and Compose) to provide clearer logging messages.
- Replaced generic command execution logs with specific messages indicating the database being restored and the source backup file.
- This change enhances the clarity of restore operations and aids in troubleshooting by providing more context in the logs.
* [autofix.ci] apply automated fixes
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
* fix: use swarm advertise address in docker swarm join command (#4567)
* fix: enforce docker:read on container start/stop/kill/restart mutations (#4568)
* refactor: replace BETTER_AUTH_SECRET with betterAuthSecret in forward-auth setup
* fix: update deriveCookieSecret to meet oauth2-proxy requirements
* fix: correct deriveCookieSecret test to validate 16-byte hex secret as per oauth2-proxy requirements
* fix: strip credentials from gitProvider.getAll API response (#4569)
* fix: strip credentials from gitProvider.getAll API response
* [autofix.ci] apply automated fixes
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
* fix: correct git provider access check for existing deploys (#4570)
* fix: use canEditDeployGitSource for git provider access on existing deploys
Replaces the simple userId ownership check with a new canEditDeployGitSource
function that correctly handles all role/sharing scenarios. Owner always has
access; admin and member only if they own the provider or it is shared with
the org — being assigned via accessedGitProviders (enterprise) only grants
permission to connect new deploys, not to edit the git source of existing ones.
Adds 26 unit tests covering owner, admin, member (with/without enterprise
license), shared providers, and the key regression case from issue #4469.
* [autofix.ci] apply automated fixes
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
* fix: prevent registry password from appearing in error messages and shell commands (#4579)
---------
Signed-off-by: Nahidujjaman Hridoy <hridoyboss12@gmail.com>
Co-authored-by: ngenohkevin <ngenohkevin19@gmail.com>
Co-authored-by: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com>
Co-authored-by: Mauricio Siu <siumauricio@icloud.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Volodymyr Kravchuk <volodymyr.kravch@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Nahidujjaman Hridoy <75487507+nhridoy@users.noreply.github.com>
Co-authored-by: Francis <9560564+Baker@users.noreply.github.com>
Co-authored-by: mixelburg <52622705+mixelburg@users.noreply.github.com>
Co-authored-by: Maks Pikov <mixelburg@users.noreply.github.com>
Co-authored-by: Jasael <67719321+jasael@users.noreply.github.com>
Co-authored-by: Philippe Parage <69145356+pparage@users.noreply.github.com>
Co-authored-by: youcef zr <93142224+youcefzemmar@users.noreply.github.com>
* fix: use canEditDeployGitSource for git provider access on existing deploys
Replaces the simple userId ownership check with a new canEditDeployGitSource
function that correctly handles all role/sharing scenarios. Owner always has
access; admin and member only if they own the provider or it is shared with
the org — being assigned via accessedGitProviders (enterprise) only grants
permission to connect new deploys, not to edit the git source of existing ones.
Adds 26 unit tests covering owner, admin, member (with/without enterprise
license), shared providers, and the key regression case from issue #4469.
* [autofix.ci] apply automated fixes
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
The Daily Docker Cleanup tooltip lists `volumes` among pruned
resources, but `cleanupAll` in `packages/server/src/utils/docker/utils.ts`
excludes the volume prune via `excludedCleanupAllCommands` (added in #3267).
Removes `volumes` from the tooltip to match actual behavior.
The previous implementation returned null when config was not yet loaded,
preventing the theme-aware favicon from rendering during initial page load.
Now uses optional chaining (config?.metaTitle, config?.customCss) throughout
so the <link rel="icon"> always renders with the correct theme-aware favicon
regardless of config loading state.
Fixes P1 issue from code review.
Add icon-light.svg and icon-dark.svg with fixed fills (black/white)
instead of relying on CSS prefers-color-scheme media query.
Update WhitelabelingProvider to use useTheme() and switch favicon
based on resolvedTheme (dark/light/unknown).
When custom faviconUrl is set, it takes precedence.
Closes#4100.
- Introduced a new ENUM type "networkDriver" and created the "network" table with various attributes for network management.
- Added "networkIds" column to multiple existing tables (application, compose, mariadb, mongo, mysql, postgres, redis) to support network associations.
- Established foreign key constraints for "organizationId" and "serverId" in the "network" table to ensure referential integrity.
- Updated migration journal and added a new snapshot for version 0166 to reflect these changes.
- Deleted the SQL file for the "network" table and its associated constraints, as well as the snapshot for version 0146, to clean up the database schema.
- Updated the migration journal to reflect these deletions, ensuring consistency in the database structure.
Calling getTerminalKey() and getDefaultDateRange() directly in useState
re-runs them on every render. Wrap in an arrow function so they execute
only once during component initialization.
- Updated the createNetwork function to ensure serverId is required when in cloud mode, improving error handling for network creation.
- Added braces for clarity in the conditional statement, enhancing code readability.
- Added a new "network" table with various attributes including networkId, name, driver, and constraints for organizationId and serverId.
- Introduced a custom ENUM type "networkDriver" for network drivers.
- Updated existing tables (application, compose, mariadb, mongo, mysql, postgres, redis) to include a new "networkIds" column of type text[].
- Created a snapshot for version 7 to reflect these schema changes in the database.
- Deleted the SQL files for the "network" table and its associated constraints, as well as the snapshots for versions 0146 and 0147, to clean up the database schema and remove unused components.
- Updated the migration journal to reflect these deletions, ensuring the database remains consistent and manageable.
- Introduced a new column "networkIds" of type text[] with a default value of an empty array to the application, compose, mariadb, mongo, mysql, postgres, and redis tables.
- Updated the application and compose schemas to include the new networkIds field in their respective TypeScript definitions.
- Added corresponding entries in the migration journal and created a snapshot for version 7 to reflect these changes.
- Eliminated the unused DOKPLOY_SERVER_VALUE constant from the network handling component.
- Updated the default serverId to undefined in the network form values and adjusted related logic to ensure compatibility with cloud environments.
- Enhanced server validation in the createNetwork function to require a serverId when in cloud mode, improving error handling for network creation.
- Added components for handling and displaying Docker networks, including creation, editing, and listing of networks.
- Introduced a new API router for network operations, integrating with the database schema for network management.
- Updated the sidebar layout to include a link to the networks dashboard, ensuring user access to network features.
- Created necessary database migrations for the network table and its associated types.
- Enhanced the dashboard layout to support the new network management interface.
2026-02-21 14:53:27 -06:00
722 changed files with 220234 additions and 36145 deletions
description: Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
license: Complete terms in LICENSE.txt
---
This skill guides creation of distinctive, production-grade frontend interfaces that avoid generic "AI slop" aesthetics. Implement real working code with exceptional attention to aesthetic details and creative choices.
The user provides frontend requirements: a component, page, application, or interface to build. They may include context about the purpose, audience, or technical constraints.
## Design Thinking
Before coding, understand the context and commit to a BOLD aesthetic direction:
- **Purpose**: What problem does this interface solve? Who uses it?
- **Tone**: Pick an extreme: brutally minimal, maximalist chaos, retro-futuristic, organic/natural, luxury/refined, playful/toy-like, editorial/magazine, brutalist/raw, art deco/geometric, soft/pastel, industrial/utilitarian, etc. There are so many flavors to choose from. Use these for inspiration but design one that is true to the aesthetic direction.
- **Differentiation**: What makes this UNFORGETTABLE? What's the one thing someone will remember?
**CRITICAL**: Choose a clear conceptual direction and execute it with precision. Bold maximalism and refined minimalism both work - the key is intentionality, not intensity.
Then implement working code (HTML/CSS/JS, React, Vue, etc.) that is:
- Production-grade and functional
- Visually striking and memorable
- Cohesive with a clear aesthetic point-of-view
- Meticulously refined in every detail
## Frontend Aesthetics Guidelines
Focus on:
- **Typography**: Choose fonts that are beautiful, unique, and interesting. Avoid generic fonts like Arial and Inter; opt instead for distinctive choices that elevate the frontend's aesthetics; unexpected, characterful font choices. Pair a distinctive display font with a refined body font.
- **Color & Theme**: Commit to a cohesive aesthetic. Use CSS variables for consistency. Dominant colors with sharp accents outperform timid, evenly-distributed palettes.
- **Motion**: Use animations for effects and micro-interactions. Prioritize CSS-only solutions for HTML. Use Motion library for React when available. Focus on high-impact moments: one well-orchestrated page load with staggered reveals (animation-delay) creates more delight than scattered micro-interactions. Use scroll-triggering and hover states that surprise.
- **Spatial Composition**: Unexpected layouts. Asymmetry. Overlap. Diagonal flow. Grid-breaking elements. Generous negative space OR controlled density.
- **Backgrounds & Visual Details**: Create atmosphere and depth rather than defaulting to solid colors. Add contextual effects and textures that match the overall aesthetic. Apply creative forms like gradient meshes, noise textures, geometric patterns, layered transparencies, dramatic shadows, decorative borders, custom cursors, and grain overlays.
NEVER use generic AI-generated aesthetics like overused font families (Inter, Roboto, Arial, system fonts), cliched color schemes (particularly purple gradients on white backgrounds), predictable layouts and component patterns, and cookie-cutter design that lacks context-specific character.
Interpret creatively and make unexpected choices that feel genuinely designed for the context. No design should be the same. Vary between light and dark themes, different fonts, different aesthetics. NEVER converge on common choices (Space Grotesk, for example) across generations.
**IMPORTANT**: Match implementation complexity to the aesthetic vision. Maximalist designs need elaborate code with extensive animations and effects. Minimalist or refined designs need restraint, precision, and careful attention to spacing, typography, and subtle details. Elegance comes from executing the vision well.
Remember: Claude is capable of extraordinary creative work. Don't hold back, show what can truly be created when thinking outside the box and committing fully to a distinctive vision.
if ! git merge origin/main -m "chore: sync hotfix from main into canary [skip ci]"; then
git merge --abort
echo "::error::Could not auto-sync the hotfix into canary (real conflict, not just history divergence). Merge main into canary manually to avoid a conflict on the next release PR."
test("declared level wins over keywords in the message (#4589, #1996)",()=>{
// "version"/"GET" in this pino line would otherwise match the debug keywords
constpinoError=
'{"level":"error","version":"72b4450","method":"GET","path":"/api/campaigns","err":{"type":"ForbiddenError","stack":"ForbiddenError: at requireRole (/app/src/plugins/campaign.plugin.ts:166:15)"},"msg":"Forbidden"}';
expect(getLogType(pinoError).type).toBe("error");
// info line containing error-like keywords (#4589)
expect(
getLogType(
'{"level":"info","msg":"Failed to open mempool file. Continuing anyway."}',
).type,
).toBe("info");
// successful job summary with "failed: false, error: none" (#4538)
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.