systemprompt_loader/bundle/
error.rs1use std::path::PathBuf;
11
12use thiserror::Error;
13
14#[derive(Debug, Error)]
15pub enum VerifyFailure {
16 #[error("archive digest is {actual}, profile pins {expected}")]
17 DigestMismatch { expected: String, actual: String },
18
19 #[error("manifest signature does not verify against any pinned key")]
20 BadSignature,
21
22 #[error("manifest is signed by unpinned key {key_id}")]
23 UnknownKey { key_id: String },
24
25 #[error("checksum mismatch for {path}")]
26 FileChecksum { path: String },
27
28 #[error("recomputed content hash does not match the manifest")]
29 ContentHash,
30
31 #[error("bundle requires core {required}, this build is {actual}")]
32 RequiresCore { required: String, actual: String },
33
34 #[error("bundle claims non-marketplace directory {dir}")]
35 NotMarketplaceOnly { dir: String },
36
37 #[error("bundle is unsigned but the profile pins ed25519 keys")]
38 MissingSignature,
39
40 #[error("unsupported signature algorithm {alg}")]
41 UnsupportedAlgorithm { alg: String },
42
43 #[error("bundle declares format {format}, this build reads {supported}")]
44 UnsupportedFormat { format: u32, supported: u32 },
45
46 #[error("extracted tree has {count} file(s) not listed in the manifest")]
47 UnexpectedFiles { count: usize },
48
49 #[error("bundle is missing bundle.json")]
50 MissingManifest,
51}
52
53#[derive(Debug, Error)]
54pub enum BundleError {
55 #[error("source {source_name}: fetch failed: {detail}")]
56 Fetch { source_name: String, detail: String },
57
58 #[error("source {source_name}: registry rejected the credentials")]
59 Auth { source_name: String },
60
61 #[error("verification failed: {0}")]
62 Verify(#[from] VerifyFailure),
63
64 #[error("extract failed at {path}: {detail}")]
65 Extract { path: PathBuf, detail: String },
66
67 #[error("io error: {0}")]
68 Io(#[from] std::io::Error),
69
70 #[error("policy: {detail}")]
71 Policy { detail: String },
72
73 #[error("{kind} {id} is claimed by both {first} and {second}")]
74 Ownership {
75 id: String,
76 kind: String,
77 first: String,
78 second: String,
79 },
80
81 #[error("no cached bundle for source {name} and no usable fallback")]
82 SourceMissing { name: String },
83
84 #[error("bundle exceeds the {bytes} byte limit")]
85 TooLarge { bytes: u64 },
86}
87
88pub type BundleResult<T> = Result<T, BundleError>;
89
90impl BundleError {
91 #[must_use]
92 pub fn fetch(source_name: &str, detail: impl std::fmt::Display) -> Self {
93 Self::Fetch {
94 source_name: source_name.to_owned(),
95 detail: detail.to_string(),
96 }
97 }
98
99 #[must_use]
100 pub fn policy(detail: impl std::fmt::Display) -> Self {
101 Self::Policy {
102 detail: detail.to_string(),
103 }
104 }
105
106 #[must_use]
107 pub fn extract(path: impl Into<PathBuf>, detail: impl std::fmt::Display) -> Self {
108 Self::Extract {
109 path: path.into(),
110 detail: detail.to_string(),
111 }
112 }
113}