astrid-runtime/astrid · error
authenticated macOS lifecycle tool is redirected or not regu
Error message
authenticated macOS lifecycle tool is redirected or not regular: {name} What it means
prepare_macos_update_assets copies the macOS FSKit lifecycle scripts (manage-macos-fskit.sh, validate-macos-fskit.sh) out of the verified update archive. Before copying, each must be a regular file and not a symlink. This error fires when one of these lifecycle tools is missing its expected form, blocking a potentially redirected file from being executed later with elevated privileges.
Source
Thrown at crates/astrid-cli/src/commands/self_update/mod.rs:412
if !target.contains("-apple-darwin") {
return Ok(());
}
let app = extract_dir.join("AstridFS.app");
let app_metadata = std::fs::symlink_metadata(&app)
.with_context(|| format!("authenticated macOS release is missing {}", app.display()))?;
anyhow::ensure!(
app_metadata.is_dir() && !app_metadata.file_type().is_symlink(),
"authenticated AstridFS.app is redirected or not a directory"
);
for name in ["manage-macos-fskit.sh", "validate-macos-fskit.sh"] {
let source = extract_dir.join("macos").join(name);
let metadata = std::fs::symlink_metadata(&source).with_context(|| {
format!(
"authenticated macOS release is missing {}",
source.display()
)
})?;
anyhow::ensure!(
metadata.is_file() && !metadata.file_type().is_symlink(),
"authenticated macOS lifecycle tool is redirected or not regular: {name}"
);
std::fs::copy(&source, extract_dir.join(name))?;
}
Ok(())
}
fn restore_managed_set(
install_dir: &Path,
names: &[&str],
previously_present: &[bool],
) -> anyhow::Result<()> {
let rollback = tempfile::tempdir_in(install_dir)?;
let mut staged = Vec::new();
for (name, present) in names.iter().zip(previously_present) {
if *present {
let temporary = rollback.path().join(name);
std::fs::copy(install_dir.join(format!("{name}.bak")), &temporary)?;View on GitHub (pinned to affd8760f4)
Solutions
- Re-download the official signed release and retry the update
- List archive contents (tar -tvf) and verify macos/*.sh are regular files
- Fix the release packaging to emit real regular-file scripts
- Clear the partially-extracted directory and re-run the update
Defensive patterns
Strategy: validation
Validate before calling
fn is_regular_file(p: &Path) -> bool {
std::fs::symlink_metadata(p).map(|m| m.is_file() && !m.file_type().is_symlink()).unwrap_or(false)
}
for name in ["manage-macos-fskit.sh", "validate-macos-fskit.sh"] {
assert!(is_regular_file(&extract_dir.join("macos").join(name)), "{name} must be a regular file");
} Type guard
fn is_regular_file(p: &Path) -> bool {
std::fs::symlink_metadata(p)
.map(|m| m.is_file() && !m.file_type().is_symlink())
.unwrap_or(false)
} Prevention
- Verify macos/*.sh entries are regular files in every release build
- Refuse to run lifecycle scripts via symlinked paths
- Only extract archives from the authenticated channel
- Clean stale extractions before retrying an update
When it happens
Trigger: apply_authenticated_update handling a -apple-darwin archive where extract_dir/macos/manage-macos-fskit.sh or validate-macos-fskit.sh is a symlink, a directory, or otherwise not a regular file per symlink_metadata.
Common situations: Tampered or third-party repackaged release archives; packaging pipelines that replaced scripts with symlinks; extraction tooling that rewrote entries as links.
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.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- authenticated AstridFS.app is redirected or not a directory
- capsule archive contains a link or special file {name}
- durable capsule archive contains a link or special file
- malicious shuttle detected: links are not allowed ('{}')
- leftover capsule authority receipt is not a regular file: {}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/8873ebd5f577373f.
Report an issue: GitHub.