Skip to content

Backup silently drops entire top-level directories: ... a/b exclude expansion over-excludes on mksquashfs 4.5 (ubuntu:22.04 base) #859

Description

@ken8203

Summary

createBackup() with a multi-component exclude pattern (e.g. excludes: ['.cache/foo/*/node_modules']) silently drops the entire first path component (.cache/) from the archive — not just the matched subpath. The backup reports success and the archive looks valid, so the data loss only surfaces on a later restoreBackup(), by which point the original container filesystem may be gone.

We hit this in production-like usage: our workspace's .entrydesk/ directory (application state) vanished from every backup because we passed excludes: ['node_modules', '.entrydesk/sites/*/node_modules']. Every sleep→wake cycle then restored a workspace missing that tree.

Root cause

Two ingredients, both in this repo:

  1. packages/sandbox-container/src/services/backup-service.ts expands every user exclude P into [P, ... ${P}] before writing the -ef file for mksquashfs -wildcards:

    const userExcludePatterns = normalizedExcludes.flatMap((pattern) => [
      pattern,
      `... ${pattern}`
    ]);

    The gitignore-derived patterns take the same expansion (relativePaths.flatMap((path) => [path, ... ${path}])), and gitignore paths are very often multi-component (dist/foo, packages/x/build), so gitignore: true is affected even more broadly.

  2. The container image (Dockerfile, FROM ubuntu:22.04) ships squashfs-tools 4.5, which has a matching bug: a non-anchored ... a/b pattern excludes the whole first component a at the archive root, instead of only a/b. squashfs-tools 4.6.1 (ubuntu 24.04) and 4.7 behave correctly.

Reproduction (inside the sandbox container image, mksquashfs 4.5)

mkdir -p /ws/alpha/beta /ws/keep
touch /ws/alpha/file.txt /ws/keep/file.txt

printf '%s\n' '... alpha/beta/gamma' > /tmp/ex.txt   # note: gamma does not even exist
mksquashfs /ws /tmp/out.sqsh -no-progress -wildcards -ef /tmp/ex.txt
unsquashfs -l /tmp/out.sqsh
# squashfs-root
# squashfs-root/keep
# squashfs-root/keep/file.txt
#   -> alpha/ is gone entirely

Same commands on ubuntu:24.04 (squashfs-tools 4.6.1) keep alpha/ and only exclude the named subpath. Verified on @cloudflare/sandbox 0.12.3; the expansion is unchanged on main as of today.

Impact

  • Any BackupOptions.excludes entry containing / silently truncates the archive at its first path component.
  • gitignore: true can drop arbitrary top-level directories whenever an ignored path is nested.
  • The failure is invisible at backup time (createBackup succeeds, plausible archive size) and destructive at restore time.

Suggested fixes

Either (ideally both):

  1. Don't emit the ... P variant for patterns containing /. Anchored multi-component patterns already match from the source root; the recursive variant is only meaningful for single-component names. This fixes the data loss even on mksquashfs 4.5.
  2. Bump the base image / squashfs-tools to ≥ 4.6 so non-anchored multi-component patterns behave per the documented semantics.

A backup-time integrity check (e.g. verifying a known sentinel file made it into the archive) would also turn this class of bug from silent data loss into a loud failure, but that's a separate hardening suggestion.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions