jdx/mise · error

brew-cask: : git only_path must stay within the checkout

Error message

brew-cask:{}: git only_path must stay within the checkout

What it means

When a cask is fetched from a git repository with an `only_path` (fetching a subdirectory of the checkout), the path must be relative and must not escape the clone. `git_only_path_source` rejects absolute paths and any component that is ParentDir ("..") or a Prefix (e.g. "C:\\" on Windows) before any filesystem access, preventing path traversal outside the cloned repository.

Solutions

  1. Rewrite only_path as a plain relative path within the repo (e.g. "subdir/tool" instead of "/subdir/tool")
  2. Remove any ".." segments and reference the intended path from the clone root
  3. Fix the cask's git stanza in the tap if upstream data is malformed

Example fix

// before (cask git stanza)
url "https://github.com/x/y.git", only_path: "/tools/foo"
// after
url "https://github.com/x/y.git", only_path: "tools/foo"
Defensive patterns

Strategy: validation

Validate before calling

// Validate only_path before fetching a git cask
fn safe_only_path(p: &str) -> bool {
    !p.is_absolute()
        && std::path::Path::new(p).components().all(|c| {
            matches!(c, std::path::Component::Normal(_) | std::path::Component::CurDir)
        })
}

Prevention

When it happens

Trigger: fetch_git_clone_and_stage calls git_only_path_source with an only_path that is absolute or contains ".." / a Windows prefix component, e.g. "/etc/passwd" or "../../foo".

Common situations: A cask's git url stanza specifies a subdirectory with a leading slash or ".."; config templating builds the only_path from user input that includes absolute paths.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/c28293e0d1369c99. Report an issue: GitHub.

Appendix: source

Thrown at src/system/packages/brew/cask/fetch.rs:209

            let dest = extract_dir.join(entry.file_name());
            file::rename(entry.path(), &dest)?;
        }
    }
    file::remove_all(&clone_dir)?;
    Ok(extract_dir)
}

pub(super) fn git_only_path_source(
    cask: &Cask,
    clone_dir: &Path,
    only_path: &Path,
) -> Result<PathBuf> {
    if only_path.is_absolute()
        || only_path
            .components()
            .any(|component| matches!(component, Component::ParentDir | Component::Prefix(_)))
    {
        bail!(
            "brew-cask:{}: git only_path must stay within the checkout",
            cask.token
        );
    }
    let clone_root = clone_dir.canonicalize()?;
    let source = clone_dir.join(only_path).canonicalize().wrap_err_with(|| {
        format!(
            "brew-cask:{}: git only_path does not exist: {}",
            cask.token,
            only_path.display()
        )
    })?;
    if !source.starts_with(&clone_root) || !source.is_dir() {
        bail!(
            "brew-cask:{}: git only_path must name a directory within the checkout",
            cask.token
        );
    }

View on GitHub (pinned to 533346cc37)