1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
//! Typed errors for `arc package` (AP2.1-10).
use std::fmt;
use std::path::PathBuf;
/// A failure during production artifact packaging. Preserved (not collapsed
/// to `String`) so the operator sees which step failed and why (AGENTS.md
/// §18). No secret content is ever carried by these variants — paths and
/// step names only.
#[derive(Debug)]
pub(crate) enum PackageError {
/// Copying a file or directory into the bundle failed.
Copy {
what: &'static str,
from: PathBuf,
source: std::io::Error,
},
/// Reading a file failed.
Read {
path: PathBuf,
source: std::io::Error,
},
/// Writing a bundle artifact (manifest, checksums, sbom, license) failed.
Write {
path: PathBuf,
source: std::io::Error,
},
/// A required bundle input was missing (e.g. the release binary).
Missing { what: &'static str, path: PathBuf },
/// Serializing an artifact (manifest JSON, SPDX SBOM JSON) failed.
Serialize {
what: &'static str,
source: serde_json::Error,
},
/// Parsing a TOML file (`Cargo.lock`, the framework `Cargo.toml`) for
/// the SBOM / framework version failed. Distinct from `Serialize`
/// (which is JSON) so the operator sees the right parser failed
/// (AGENTS.md §18).
Toml {
what: &'static str,
source: toml::de::Error,
},
/// A bundle path that would have leaked a secret / dev source / private
/// file was detected and refused (defense in depth; the copy step also
/// filters proactively).
Forbidden { what: &'static str, path: PathBuf },
/// Walking the bundle tree failed.
Walk {
root: PathBuf,
source: std::io::Error,
},
}
impl fmt::Display for PackageError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Copy { what, from, source } => {
write!(f, "cannot copy {what} from {}: {source}", from.display())
}
Self::Read { path, source } => {
write!(f, "cannot read {}: {source}", path.display())
}
Self::Write { path, source } => {
write!(f, "cannot write {}: {source}", path.display())
}
Self::Missing { what, path } => {
write!(
f,
"missing {what} at {} (run `arc build` first)",
path.display()
)
}
Self::Serialize { what, source } => {
write!(f, "cannot serialize {what}: {source}")
}
Self::Toml { what, source } => {
write!(f, "cannot parse {what}: {source}")
}
Self::Forbidden { what, path } => {
write!(
f,
"refusing to package forbidden {what} at {}",
path.display()
)
}
Self::Walk { root, source } => {
write!(f, "cannot walk bundle root {}: {source}", root.display())
}
}
}
}
impl std::error::Error for PackageError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Copy { source, .. }
| Self::Read { source, .. }
| Self::Write { source, .. }
| Self::Walk { source, .. } => Some(source),
Self::Serialize { source, .. } => Some(source),
Self::Toml { source, .. } => Some(source),
Self::Missing { .. } | Self::Forbidden { .. } => None,
}
}
}