{"record":{"id":"9f7866e1ecd08676","repo":"astrid-runtime/astrid","slug":"distro-toml-has-no-parent-directory","errorCode":null,"errorMessage":"Distro.toml has no parent directory","messagePattern":"Distro\\.toml has no parent directory","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/distro/local_source.rs","lineNumber":57,"sourceCode":"/// The returned path is canonicalized so the subsequent copy and hash cover\n/// the same filesystem object that passed containment checks.\npub(crate) fn resolve_local_capsule_archive(\n    source: &str,\n    manifest_path: Option<&Path>,\n) -> anyhow::Result<Option<PathBuf>> {\n    if !is_local_capsule_source(source) {\n        return Ok(None);\n    }\n    let Some(manifest_path) = manifest_path else {\n        bail!(\n            \"local capsule source {source:?} requires a local authenticated Distro.toml; \\\n             remote manifests cannot resolve relative members\"\n        );\n    };\n\n    let root = manifest_path\n        .parent()\n        .ok_or_else(|| anyhow::anyhow!(\"Distro.toml has no parent directory\"))?;\n    let source_path = Path::new(source);\n    let candidate = if source_path.is_absolute() {\n        source_path.to_path_buf()\n    } else {\n        root.join(source_path)\n    };\n    if source_path\n        .components()\n        .any(|component| matches!(component, Component::ParentDir))\n    {\n        bail!(\"local capsule source {source:?} escapes the authenticated Distro.toml directory\");\n    }\n\n    let canonical_root = root\n        .canonicalize()\n        .with_context(|| format!(\"failed to resolve Distro.toml directory {}\", root.display()))?;\n    let canonical_path = candidate\n        .canonicalize()","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/distro/local_source.rs#L39-L75","documentation":"Thrown by `resolve_local_capsule_archive` when the local Distro.toml manifest path has no parent directory component, so relative member paths inside the manifest cannot be resolved against a root. In practice this occurs only for degenerate paths like a bare \"Distro.toml\" reference with no directory portion. Security-relevant relatives: traversal and symlink escapes from this root are checked afterwards and fail closed.","triggerScenarios":"Calling distro install/resolve with a manifest path such as `Distro.toml` (no directory prefix) so `Path::parent()` returns None, and the manifest references relative member archives.","commonSituations":"Scripting `--manifest Distro.toml` from a working directory where the path was reduced to a bare filename; passing a programmatically constructed PathBuf of just a file name.","solutions":["Pass the manifest with an explicit directory prefix: `./Distro.toml` instead of `Distro.toml`.","Use an absolute path to the manifest: `--manifest /path/to/distro/Distro.toml`.","cd into the manifest's directory and reference it as `./Distro.toml`.","If constructing the path in code, canonicalize it first (`path.canonicalize()`) so a parent component exists."],"exampleFix":"// before (shell)\nastrid distro install --manifest Distro.toml\n// after (shell)\nastrid distro install --manifest \"$PWD/Distro.toml\"","handlingStrategy":"validation","validationCode":"let manifest = std::path::PathBuf::from(manifest_arg);\nlet manifest = if manifest.is_relative() {\n    std::env::current_dir()?.join(manifest)\n} else { manifest };\nif manifest.parent().is_none() {\n    return Err(anyhow!(\"manifest path must include a directory component\"));\n}","typeGuard":null,"tryCatchPattern":"match resolve_local_capsule_archive(&manifest, source) {\n    Err(e) if e.to_string().contains(\"no parent directory\") => {\n        let abs = std::fs::canonicalize(\"Distro.toml\")?;\n        resolve_local_capsule_archive(&abs, source)\n    }\n    other => other,\n}","preventionTips":["Always pass manifest paths with an explicit `./` prefix or absolute path.","Canonicalize manifest paths before handing them to distro commands.","In scripts, use \"$PWD/Distro.toml\" rather than bare filenames.","Add a shell-completion/arg validation that rejects bare filenames for --manifest."],"tags":["distro","path","cli","validation"],"backgroundTag":"invalid-argument-format","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}