astrid-runtime/astrid · error

workspace capsule component path is unsafe

Error message

workspace capsule component path is unsafe ({}): {error}

What it means

Wraps `resolve_file` failing for one declared capsule component: the component's path, joined to the capsule-relative directory, cannot be resolved safely inside the workspace (missing file, symlink escape, or redirect). The manifest-declared path plus its display string are included for diagnosis.

Solutions

  1. Fix the component path in the capsule manifest so it stays relative and inside the capsule directory
  2. Restore or recreate the missing/renamed component file at the declared path
  3. Replace any symlinked component with a real file inside the capsule tree
  4. Reinstall the capsule from a trusted archive matching the manifest

Example fix

// before (manifest.toml)
[[component]]
path = "../../shared/lib.wasm"
// after
[[component]]
path = "components/lib.wasm"
Defensive patterns

Strategy: validation

Validate before calling

let p = capsule_relative.join(&component.path);
if component.path.is_absolute() || p.components().any(|c| matches!(c, std::path::Component::ParentDir)) {
    return Err(format!("unsafe component path: {}", component.path.display()));
}

Type guard

fn is_safe_relative(p: &Path) -> bool {
    !p.is_absolute()
        && p.components().all(|c| matches!(c, std::path::Component::Normal(_)))
}

Prevention

When it happens

Trigger: Iterating manifest components and calling resolve_file(capsule_relative.join(&component.path)) during workspace capsule verification; fails for the component whose path escapes the capsule root or does not resolve.

Common situations: Manifest lists a component with '../' or absolute path; component file was deleted or renamed; component is a symlink pointing outside the capsule; manifest was authored against a different capsule layout version.

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 astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/83d5d4df697dded2. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-kernel/src/lib.rs:1471

    fn verify_workspace_component_paths(
        &self,
        dir: &Path,
        manifest: &astrid_capsule_types::manifest::CapsuleManifest,
    ) -> anyhow::Result<()> {
        let Ok(capsule_relative) = dir.strip_prefix(self.workspace_selection.state_dir()) else {
            return Ok(());
        };
        for component in &manifest.components {
            if component.path.is_absolute() {
                anyhow::bail!(
                    "workspace capsule component must be relative: {}",
                    component.path.display()
                );
            }
            self.workspace_selection
                .resolve_file(capsule_relative.join(&component.path))
                .map_err(|error| {
                    anyhow::anyhow!(
                        "workspace capsule component path is unsafe ({}): {error}",
                        component.path.display()
                    )
                })?;
        }
        Ok(())
    }

    /// Verify an installed capsule against the authority source selected by
    /// this runtime. Native daemon loads use the packed System catalog; the
    /// unbound compatibility path retains its POSIX executable check.
    #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
    fn verify_installed_authority_for_runtime(
        &self,
        dir: &Path,
        manifest: &astrid_capsule_types::manifest::CapsuleManifest,
    ) -> anyhow::Result<()> {
        if let Some(store) = self.principal_store.as_ref() {

View on GitHub (pinned to affd8760f4)