Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ The daemon also supports an optional shared-secret password (set via `auth.passw

Connected clients are trusted operators of the daemon user. File previews follow that authority: a preview request may read any regular file the daemon process can read, while keeping path normalization and symlink checks in the daemon file service. Workspace-relative paths remain a UI convenience, not a security boundary.

An explicit `symlink <path>` entry in a repository's .worktreeinclude intentionally gives a
Paseo-created worktree live access to that source-checkout file or directory. It is useful for
local dependencies and caches, but it weakens the usual worktree isolation: agents and lifecycle
scripts can modify the source through the link. Paseo validates entries and refuses traversal or
destination-link escapes, but the linked source is a deliberate shared-data boundary.

If you expose the daemon beyond loopback, such as by binding to `0.0.0.0`, forwarding it through a tunnel or reverse proxy, or publishing it from a Docker container, you are responsible for restricting and securing that access. Setting a password is strongly recommended in that case.

In Docker, the official image runs the daemon and agents as the non-root
Expand Down
1 change: 1 addition & 0 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Root checkout dev is intentionally split across terminals:
- **Repo dev scripts** default to `$ROOT/.dev/paseo-home`, where `$ROOT` is the current checkout or worktree root. This keeps all dev state scoped to the checkout instead of the packaged desktop app.
- **`npm run cli -- ...`** runs through the same dev-home wrapper as the dev scripts, so the in-repo CLI automatically targets the current checkout's `.dev/paseo-home` and configured dev daemon endpoint.
- **Paseo-created worktrees** seed `$PASEO_WORKTREE_PATH/.dev/paseo-home` from `$PASEO_SOURCE_CHECKOUT_PATH/.dev/paseo-home` by copying durable JSON metadata. Runtime files like pid files, sockets, and logs are not copied.
- **Paseo-created worktrees** read `.worktreeinclude` from the live source checkout before creation. Bare paths and `copy <path>` copy a snapshot into the new worktree; `symlink <path>` creates a live source link. Missing paths, malformed entries, unsafe paths, incompatible include overlaps, destination conflicts, unavailable platform links, and ordinary read/write failures are skipped individually and reported in the daemon log, so the rest of the plan still runs. A source symlink is allowed only when its resolved target remains inside the active source checkout. If that checkout is itself Paseo-managed, its own paths remain eligible while other managed worktree paths stay protected; `copy` snapshots that resolved target, while `symlink` links directly to it. Hard links are ordinary files. Each include is staged before it is committed; Paseo aborts creation only if it cannot safely clean up partial materialization state (or Git/worktree setup itself fails). Materialization finishes before `worktree.setup` runs.
- **This repo's worktree setup** also best-effort seeds `packages/app/ios` and the newest `.dev/ios-build` entry from the source checkout so iOS simulator services can reuse native project and Xcode cache state when it is safe enough to do so.

Override knobs:
Expand Down
11 changes: 11 additions & 0 deletions packages/server/src/server/worktree-session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,17 @@ export async function createPaseoWorktreeWorkflow(
const workspace = createdWorktree.workspace;
const setupContinuation = options?.setupContinuation ?? { kind: "workspace" };

if (createdWorktree.created && createdWorktree.worktree.worktreeIncludeSummary?.skipped.length) {
dependencies.sessionLogger.warn(
{
materialized: createdWorktree.worktree.worktreeIncludeSummary.materialized,
skipped: createdWorktree.worktree.worktreeIncludeSummary.skipped,
worktreePath: createdWorktree.worktree.worktreePath,
},
"Worktree include completed with skipped entries",
);
}

setTimeout(() => {
if (input.firstAgentContext) {
dependencies.autoNameWorkspaceBranchForFirstAgent({
Expand Down
Loading