{"record":{"id":"335455fa30cd38b5","repo":"astrid-runtime/astrid","slug":"local-capsule-source-source-requires-a-local-a","errorCode":null,"errorMessage":"local capsule source {source:?} requires a local authenticated Distro.toml; remote manifests cannot resolve relative members","messagePattern":"local capsule source (.+?) requires a local authenticated Distro\\.toml; remote manifests cannot resolve relative members","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/distro/local_source.rs","lineNumber":49,"sourceCode":"        )\n    })?;\n    Ok(current_dir.join(manifest_path))\n}\n\n/// Resolve a local `.capsule` member against the authenticated manifest.\n///\n/// `Ok(None)` means the source belongs to the caller's remote resolver.\n/// 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    {","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/distro/local_source.rs#L31-L67","documentation":"resolve_local_capsule_archive only handles local capsule sources when a local, authenticated Distro.toml manifest path is supplied. If the source is local but manifest_path is None (e.g. the manifest came from a remote registry), relative member paths cannot be anchored anywhere, so the function fails closed instead of guessing a root directory.","triggerScenarios":"A Distro.toml fetched from a remote source references a local capsule `source = \"...\"` entry; resolve_local_capsule_archive is invoked without a manifest path while is_local_capsule_source(source) is true.","commonSituations":"Sealing/publishing a manifest that mixes remote registry entries with local relative capsule paths; running against a fetched manifest outside its project directory.","solutions":["Use the local authenticated Distro.toml (pass its path so relative members can be resolved)","Replace the local capsule source with a registry-published reference in remote manifests","Restructure the manifest so remote entries and local capsule members are not mixed"],"exampleFix":"// before\nresolve_local_capsule_archive(source, None)?;\n// after\nresolve_local_capsule_archive(source, Some(&local_distro_toml_path))?;","handlingStrategy":"validation","validationCode":"if is_local_capsule_source(source) && manifest_path.is_none() {\n    anyhow::bail!(\"local capsule source requires a local Distro.toml path\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always supply the local authenticated Distro.toml path when resolving local capsule sources","Keep remote manifests free of local relative capsule references","Resolve sources only after loading the manifest from disk"],"tags":["manifest","capsule","path-resolution"],"backgroundTag":"missing-required-argument","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}