{"record":{"id":"c737a5c4998bd4a6","repo":"jdx/mise","slug":"brew-cask-structured-set-permissions-must-use-staged-path-or","errorCode":null,"errorMessage":"brew-cask: structured set_permissions must use staged_path or appdir","messagePattern":"brew-cask: structured set_permissions must use staged_path or appdir","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask/flight.rs","lineNumber":1083,"sourceCode":"    staged_path: &Path,\n    appdir: &Path,\n) -> Result<Vec<PathBuf>> {\n    match path.base {\n        FlightPathBase::StagedPath if is_flight_glob(&path.path) => {\n            // Like remove steps, set_permissions has no glob flag; Homebrew\n            // globs the path syntax itself.\n            let pattern = expand_flight_template(cask, &path.path, staged_path, appdir);\n            expand_staged_glob(staged_path, &pattern)\n        }\n        FlightPathBase::StagedPath | FlightPathBase::AppDir => {\n            Ok(vec![resolve_flight_path_with_context(\n                cask,\n                path,\n                staged_path,\n                appdir,\n            )?])\n        }\n        _ => bail!(\"brew-cask: structured set_permissions must use staged_path or appdir\"),\n    }\n}\n\npub(super) fn expand_staged_glob(staged_path: &Path, pattern: &str) -> Result<Vec<PathBuf>> {\n    let mut matches = Vec::new();\n    let escaped_root = glob::Pattern::escape(staged_path.to_string_lossy().as_ref());\n    for pattern in expand_braces(pattern) {\n        validate_flight_relative_path(&pattern)?;\n        let rooted_pattern = Path::new(&escaped_root)\n            .join(Path::new(&pattern))\n            .to_string_lossy()\n            .to_string();\n        for path in glob::glob_with(\n            &rooted_pattern,\n            glob::MatchOptions {\n                require_literal_separator: true,\n                ..Default::default()\n            },","sourceCodeStart":1065,"sourceCodeEnd":1101,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/packages/brew/cask/flight.rs#L1065-L1101","documentation":"A structured set_permissions flight step must resolve its path against either the staged cask directory or the appdir; any other FlightPathBase is rejected by permissions_flight_paths. Restricting chmod-style operations to these bases prevents a cask from altering permissions on arbitrary filesystem locations.","triggerScenarios":"execute_flight_step processes a set_permissions step; permissions_flight_paths matches the path's base against staged_path/appdir variants and hits the _ wildcard arm, bailing — e.g. base set to an absolute/custom path value.","commonSituations":"A hand-written cask flight config sets a permissions path with a base other than staged_path or appdir; a config was edited or migrated incorrectly; copying a stanza from another tool that allows absolute paths.","solutions":["Change the set_permissions path base to \"staged_path\" or \"appdir\" in the flight definition.","If the target truly lives outside those trees, the operation is not supported — perform the permission change out-of-band (post-install script) instead.","Validate the cask's flight config against the supported FlightPathBase values before installing."],"exampleFix":"// before\n{ \"set_permissions\": { \"path\": { \"base\": \"absolute\", \"path\": \"/usr/local/bin/tool\" }, \"mode\": \"0755\" } }\n// after\n{ \"set_permissions\": { \"path\": { \"base\": \"staged_path\", \"path\": \"Tool.app/Contents/MacOS/tool\" }, \"mode\": \"0755\" } }","handlingStrategy":"validation","validationCode":"function validatePermissionsBase(step) {\n  const allowed = ['staged_path', 'appdir'];\n  if (!allowed.includes(step.set_permissions.path.base)) {\n    throw new Error(`set_permissions base must be one of ${allowed}, got '${step.set_permissions.path.base}'`);\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Restrict set_permissions paths to staged_path or appdir bases.","Perform out-of-tree permission changes with a separate post-install step, not flight stanzas.","Lint cask flight configs before publishing or installing them."],"tags":["brew-cask","permissions","invalid-config-value"],"backgroundTag":"invalid-config-value","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}