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}