Skip to main content

nexo_ext_installer/
extract_error.rs

1//! Error variants returned by [`crate::extract::extract_verified_tarball`].
2
3use std::path::PathBuf;
4
5/// Errors surfaced by the tarball extraction pipeline.
6#[derive(Debug, thiserror::Error)]
7pub enum ExtractError {
8    /// IO read/write/rename/remove against the local filesystem failed.
9    #[error("extract io error: {0}")]
10    Io(String),
11
12    /// Tarball file size exceeds the configured `max_tarball_bytes`.
13    #[error("tarball at `{path}` is {actual} bytes, exceeds limit {limit}")]
14    TarballTooLarge {
15        /// Path of the offending tarball.
16        path: PathBuf,
17        /// Actual size in bytes.
18        actual: u64,
19        /// Configured limit.
20        limit: u64,
21    },
22
23    /// Number of entries (files + dirs) exceeds the configured `max_entries`.
24    #[error("tarball entry count exceeds limit {limit}")]
25    TooManyEntries {
26        /// Configured limit.
27        limit: u64,
28    },
29
30    /// One entry's header-declared size exceeds `max_entry_bytes`.
31    #[error("entry `{path}` size {actual} exceeds per-entry limit {limit}")]
32    EntryTooLarge {
33        /// Entry path inside the tarball.
34        path: String,
35        /// Header-declared size.
36        actual: u64,
37        /// Per-entry limit.
38        limit: u64,
39    },
40
41    /// Sum of all entry sizes exceeds `max_extracted_bytes`.
42    #[error("total extracted size exceeds limit {limit}")]
43    ExtractedTooLarge {
44        /// Configured limit.
45        limit: u64,
46    },
47
48    /// Entry path was absolute, contained `..`, was Windows-prefixed, or
49    /// included NUL bytes.
50    #[error("entry path `{path}` rejected: {reason}")]
51    UnsafePath {
52        /// Offending entry path as it appeared in the tarball.
53        path: String,
54        /// Why the path was rejected.
55        reason: &'static str,
56    },
57
58    /// Entry type was not in the allowed set (regular file or directory).
59    #[error("entry `{path}` rejected: type `{kind}` not allowed")]
60    DisallowedEntryType {
61        /// Entry path as it appeared in the tarball.
62        path: String,
63        /// Disallowed entry kind label (e.g. `"symlink"`, `"hardlink"`).
64        kind: &'static str,
65    },
66
67    /// Manifest extracted from the tarball does not match the manifest the
68    /// resolver advertised. The mismatch implies tarball/registry tampering
69    /// or a publish convention violation; staging is cleaned up.
70    #[error(
71        "extracted manifest mismatch: expected id={expected_id}@{expected_version}, \
72         got id={got_id}@{got_version}"
73    )]
74    ManifestMismatch {
75        /// Expected plugin id (from the resolver).
76        expected_id: String,
77        /// Expected plugin version (from the resolver).
78        expected_version: semver::Version,
79        /// Plugin id observed in the tarball's `nexo-plugin.toml`.
80        got_id: String,
81        /// Plugin version observed in the tarball's `nexo-plugin.toml`.
82        got_version: semver::Version,
83    },
84
85    /// Manifest file at the given path could not be parsed as a valid
86    /// `PluginManifest`.
87    #[error("extracted manifest at `{path}` invalid: {reason}")]
88    ManifestInvalid {
89        /// Path on disk where the manifest was expected.
90        path: PathBuf,
91        /// Parse failure reason.
92        reason: String,
93    },
94
95    /// `bin/<plugin_id>` was not present after extraction. Indicates a
96    /// publish convention violation upstream.
97    #[error("expected binary at `{path}` not found after extract")]
98    BinaryMissing {
99        /// Path on disk where the binary was expected.
100        path: PathBuf,
101    },
102
103    /// `tokio::task::spawn_blocking` join failure (panic in the sync extract
104    /// task, or runtime shutdown mid-extract).
105    #[error("extract task panicked: {0}")]
106    JoinError(String),
107}