{"record":{"id":"edb9dbc68d8b8b9e","repo":"unicity-aos/aos-ce","slug":"temporary-product-manifest-path-must-be-a-regular-file","errorCode":null,"errorMessage":"temporary product manifest path must be a regular file","messagePattern":"temporary product manifest path must be a regular file","errorType":"validation","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"crates/unicity-aos-bootstrap/src/lib.rs","lineNumber":214,"sourceCode":"            Ok(metadata) if metadata.file_type().is_symlink() || !metadata.is_file() => {\n                return Err(io::Error::new(\n                    io::ErrorKind::InvalidInput,\n                    \"product manifest path must be a regular file\",\n                ));\n            }\n            Ok(_) if fs::read(&path)?.as_slice() == manifest.as_bytes() => return Ok(path),\n            Ok(_) => {}\n            Err(error) if error.kind() == io::ErrorKind::NotFound => {}\n            Err(error) => return Err(error),\n        }\n        self.ensure_layout()?;\n        create_private_dir(&self.root.join(\"distributions\"))?;\n        let parent = path.parent().expect(\"manifest path has a parent\");\n        create_private_dir(parent)?;\n        let temporary = path.with_extension(\"toml.tmp\");\n        if let Ok(metadata) = fs::symlink_metadata(&temporary) {\n            if metadata.file_type().is_symlink() || !metadata.is_file() {\n                return Err(io::Error::new(\n                    io::ErrorKind::InvalidInput,\n                    \"temporary product manifest path must be a regular file\",\n                ));\n            }\n            fs::remove_file(&temporary)?;\n        }\n        fs::write(&temporary, manifest)?;\n        set_private_file_permissions(&temporary)?;\n        fs::rename(&temporary, &path)?;\n        Ok(path)\n    }\n\n    /// Initialize the trusted CE system fleet before the runtime performs its\n    /// daemon-backed grant preflight.\n    ///\n    /// A completely fresh Astrid home has no capsule capable of accepting CLI\n    /// connections. Astrid installs through the daemon in bounded batches.\n    /// Resume partial batches after the kernel's rate-limit window, leaving","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/unicity-aos/aos-ce/blob/f6f22024fb1e8d122f28a1b4a9f75aee448ae839/crates/unicity-aos-bootstrap/src/lib.rs#L196-L232","documentation":"During ensure_unicity_ce_manifest, the temporary file path <manifest>.toml.tmp is checked with symlink_metadata before writing; if it exists as a symlink or non-regular file the function returns InvalidInput \"temporary product manifest path must be a regular file\". A normal leftover regular temp file is simply removed; only dangerous non-regular entries are refused, guarding against symlink attacks on the temp path.","triggerScenarios":"Calling ensure_unicity_ce_manifest when <manifest>.toml.tmp exists in the distributions directory as a symlink, directory, fifo, or other non-regular file.","commonSituations":"A previous crashed/aborted write left a temp entry that something replaced with a symlink; a malicious actor pre-planted a symlink at the predictable .tmp path; manual cleanup accidentally created a directory there.","solutions":["Inspect `ls -la <manifest>.toml.tmp` and remove the offending symlink/special file, then retry.","Clear the distributions directory of stale temp files after abnormal terminations.","Run the process under a dedicated user so a hostile local user cannot plant entries in the private directory."],"exampleFix":"// before (shell, failing state)\nls -la $ROOT/distributions/product.toml.tmp  # lrwxrwxrwx -> /etc/shadow\n// after\nrm -f $ROOT/distributions/product.toml.tmp && retry ensure_unicity_ce_manifest","handlingStrategy":"validation","validationCode":"fn tmp_path_is_safe(tmp: &Path) -> Result<(), String> {\n    if let Ok(m) = std::fs::symlink_metadata(tmp) {\n        if m.file_type().is_symlink() || !m.is_file() {\n            return Err(format!(\"{:?} is a symlink or special file; delete it before writing\", tmp));\n        }\n    }\n    Ok(())\n}","typeGuard":"fn tmp_is_absent_or_regular(path: &Path) -> bool {\n    match std::fs::symlink_metadata(path) {\n        Ok(m) => m.is_file() && !m.file_type().is_symlink(),\n        Err(_) => true, // absent is fine\n    }\n}","tryCatchPattern":"if let Err(e) = runtime.ensure_unicity_ce_manifest() {\n    if e.to_string().contains(\"temporary product manifest\") {\n        let _ = std::fs::remove_file(manifest_path.with_extension(\"toml.tmp\"));\n        // retry once\n    } else { return Err(e.into()); }\n}","preventionTips":["Clean up stale .tmp files after crashes or abnormal termination of the daemon.","Run under a dedicated user with a private runtime directory so hostile local users cannot plant symlinks at predictable temp paths.","Avoid hand-editing files inside the distributions directory while the daemon runs."],"tags":["symlink","security","filesystem","temp-file","rust"],"backgroundTag":"symlink-detected","analyzedSha":"f6f22024fb1e8d122f28a1b4a9f75aee448ae839","analyzedAt":"2026-09-13T03:04:44.565Z","contentChangedAt":"2026-09-13T03:04:44.565Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}