{"record":{"id":"0e16b3340715d0f5","repo":"jdx/mise","slug":"brew-cask-invalid-kind-run-command-path","errorCode":null,"errorMessage":"brew-cask:{}: invalid {kind} run command path {}","messagePattern":"brew-cask:(.+?): invalid (.+?) run command path (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask.rs","lineNumber":5877,"sourceCode":"            \"brew-cask:{}: unsupported {kind} run command base {}\",\n            cask.token,\n            base\n        ),\n        None => FlightPathBase::Literal,\n    };\n    let path_value = Path::new(path);\n    let invalid_absolute_path = base == FlightPathBase::Literal\n        && !path_value.is_absolute()\n        && path_value.components().count() > 1;\n    let invalid_based_path = matches!(\n        base,\n        FlightPathBase::StagedPath | FlightPathBase::AppDir | FlightPathBase::HomebrewPrefix\n    ) && (path_value.is_absolute()\n        || path_value\n            .components()\n            .any(|component| matches!(component, Component::ParentDir)));\n    if invalid_absolute_path || invalid_based_path {\n        bail!(\n            \"brew-cask:{}: invalid {kind} run command path {}\",\n            cask.token,\n            path\n        );\n    }\n    Ok(FlightPath {\n        base,\n        path: path.to_string(),\n    })\n}\n\nfn parse_flight_guard(cask: &Cask, kind: &str, value: &Value) -> Result<FlightGuard> {\n    let object = value.as_object().ok_or_else(|| {\n        eyre!(\n            \"brew-cask:{}: unsupported {kind} run guard metadata format\",\n            cask.token\n        )\n    })?;","sourceCodeStart":5859,"sourceCodeEnd":5895,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/src/system/packages/brew/cask.rs#L5859-L5895","documentation":"Path-shape validation for run command paths. Two cases bail: (1) base absent (Literal) and the path is relative with more than one component (e.g. \"bin/helper.sh\") — literal paths must be absolute or a single filename; (2) base is staged_path/appdir/homebrew_prefix and the path is absolute or contains \"..\" — based paths must stay inside the base directory. This blocks relative-path ambiguity and parent-directory traversal.","triggerScenarios":"Literal: {\"path\": \"bin/helper.sh\"} with no base. Based: {\"path\": \"/etc/x\", \"base\": \"appdir\"} or {\"path\": \"../../etc/passwd\", \"base\": \"staged_path\"}. Both set invalid_absolute_path/invalid_based_path and bail with the path echoed.","commonSituations":"Assuming relative multi-segment paths resolve against the staging dir without declaring a base; porting shell scripts that use \"..\" navigation; absolute paths left over when converting to based paths.","solutions":["For multi-component relative paths, add the right base: \"base\": \"staged_path\" (or appdir/homebrew_prefix)","Keep based paths relative and free of \"..\" — the base already anchors them","Use literal absolute paths only without a base, and single bare filenames only for PATH-style lookups"],"exampleFix":"// before\n{\"path\": \"bin/helper.sh\"}\n// after\n{\"path\": \"bin/helper.sh\", \"base\": \"staged_path\"}","handlingStrategy":"validation","validationCode":"use std::path::{Path, Component};\n\nfn run_path_ok(cmd: &serde_json::Value) -> bool {\n    let Some(path) = cmd.get(\"path\").and_then(|p| p.as_str()) else { return false; };\n    let pv = Path::new(path);\n    let base = cmd.get(\"base\").and_then(|b| b.as_str());\n    match base {\n        None => pv.is_absolute() || pv.components().count() <= 1,\n        Some(\"staged_path\" | \"appdir\" | \"homebrew_prefix\") => {\n            !pv.is_absolute() && !pv.components().any(|c| matches!(c, Component::ParentDir))\n        }\n        _ => true, // unsupported base handled by its own error\n    }\n}","typeGuard":null,"tryCatchPattern":"match parse_run_command(&cask, kind, Some(&cmd)) {\n    Ok(path) => { /* proceed */ }\n    Err(e) if e.to_string().contains(\"invalid\") && e.to_string().contains(\"run command path\") => {\n        eprintln!(\"literal paths must be absolute or a single name; based paths must be relative without '..'\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always pair multi-component relative paths with an explicit base","Never use '..' segments in based paths — they are treated as traversal attempts","Absolute paths only in literal (no-base) form"],"tags":["brew-cask","mise","path-validation","path-traversal","flight-steps"],"backgroundTag":"config-path-validation","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}