#[non_exhaustive]pub enum ToolsetInstallError {
Show 30 variants
Io {
detail: String,
},
PackageTooLarge {
cap: usize,
},
HashMismatch,
SignatureInvalid,
UntrustedPublisher {
publisher_key_redacted: String,
},
TrustSetEmpty,
TrustSetMalformed {
detail: String,
},
InvalidVersion {
detail: String,
},
InvalidShasum {
detail: String,
},
InvalidPackageName {
detail: String,
},
ArchivePathTraversal {
entry_name: String,
},
ArchiveEntryNameInvalid {
detail: String,
},
ArchiveDisallowedEntryType,
ArchiveDuplicateEntry {
entry_name: String,
},
ArchiveTooManyEntries {
cap: usize,
},
ArchiveEntryTooLarge {
cap: usize,
},
ArchiveTooLarge {
cap: usize,
},
ArchiveTrailingData,
ArchiveBadTopLevel {
detail: String,
},
ToolsetFormat(ToolsetFormatError),
IdentityMismatch {
field: &'static str,
extracted: String,
expected: String,
},
AlreadyInstalled {
package: String,
installed_version: String,
},
VersionDowngrade {
new_version: String,
installed_version: String,
},
NotInstalled {
package: String,
},
PinRecordMalformed {
detail: String,
},
ToolsetsRootInvalid {
detail: String,
},
AttestationRequired {
package: String,
},
AttestationInvalid {
detail: &'static str,
},
AuditorUntrusted {
auditor_key_redacted: String,
},
AttestationFieldMismatch {
field: &'static str,
},
}Expand description
Typed closed-set error for toolset install and uninstall operations.
§Variant overview
| Variant | Trigger |
|---|---|
Io | OS-level I/O failure (file open, read, write, rename, remove). |
PackageTooLarge | Package bytes exceed crate::MAX_PACKAGE_BYTES. |
HashMismatch | SHA-256 of package bytes ≠ signed shasum. |
SignatureInvalid | ed25519 publisher signature fails verify_strict. |
UntrustedPublisher | Signer public key not in the publisher trust set. |
TrustSetEmpty | Trust-set file is absent or contains no entries (publisher or auditor). |
TrustSetMalformed | Trust-set file contains a malformed or duplicate entry. |
InvalidVersion | Version string fails SemVer parse or length cap. |
InvalidShasum | signed_shasum argument is not exactly 64 lowercase hex chars. |
InvalidPackageName | Package name fails the [a-z0-9-] validation rule. |
ArchivePathTraversal | Archive entry path escapes the package root. |
ArchiveEntryNameInvalid | Archive entry name contains NUL, control bytes, non-UTF-8, or non-ASCII. |
ArchiveDisallowedEntryType | Archive entry is a symlink, hardlink, device, FIFO, or other disallowed type. |
ArchiveDuplicateEntry | Two archive entries normalise to the same ASCII-lowercase key. |
ArchiveTooManyEntries | Archive entry count exceeds the cap. |
ArchiveEntryTooLarge | A single entry’s decompressed size exceeds the per-entry cap. |
ArchiveTooLarge | Total decompressed output exceeds the cap. |
ArchiveTrailingData | Gzip stream contains trailing data after the first member (multi-member or garbage rejected). |
ArchiveBadTopLevel | Archive does not contain exactly one top-level directory named after the package. |
ToolsetFormat | TOOLSET.md parse/validation failed (wraps ToolsetFormatError). |
IdentityMismatch | Extracted TOOLSET.md name ≠ signed package name. Version is bound by signature. |
AlreadyInstalled | Toolset is already installed and --force was not supplied. |
VersionDowngrade | --force reinstall would downgrade the version; requires --allow-downgrade. |
NotInstalled | Uninstall requested for a toolset that is not installed. |
PinRecordMalformed | Stored pin record is invalid (bad name, escaping path, or symlink target) during uninstall. |
ToolsetsRootInvalid | The toolsets root directory itself is a symlink leaf (install-time check). |
AttestationRequired | Toolset declares a key-touching capability but no attestation was supplied and override_attestation is false. |
AttestationInvalid | Attestation signature fails verify_strict, or auditor_pubkey is not a valid ed25519 point. |
AuditorUntrusted | Auditor public key is not in the auditor trust set. |
AttestationFieldMismatch | An attestation field (package/version/shasum/capabilities) does not match the verified install values. |
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
Io
OS-level I/O error.
The detail string is sanitised (length-capped at 256 chars,
control/ANSI stripped) to prevent log-injection.
PackageTooLarge
Package bytes exceed the maximum allowed size.
The size limit prevents OOM on untrusted sources; reading is aborted as soon as the limit is reached.
HashMismatch
SHA-256 of the package bytes does not match the signed shasum.
This indicates either data corruption or a tampered package.
SignatureInvalid
ed25519 signature failed verify_strict.
The signature was well-formed but cryptographically invalid for the signed payload and claimed publisher key.
UntrustedPublisher
The signer public key is not present in the trust set.
The publisher key is redacted to first-5-last-5 in Display output.
TrustSetEmpty
Trust-set file is absent or contains no entries.
An empty trust set means no toolset can be installed (fail-closed).
TrustSetMalformed
Trust-set file contains a malformed or duplicate entry.
The entire file is rejected on any single bad entry (ALL-OR-NOTHING parse contract).
InvalidVersion
Version string fails SemVer parse or exceeds the length cap.
For package-name failures see ToolsetInstallError::InvalidPackageName.
For shasum format failures see ToolsetInstallError::InvalidShasum.
InvalidShasum
Shasum argument fails format validation.
The signed_shasum argument must be exactly 64 lowercase hexadecimal
characters ([0-9a-f]). Uppercase hex digits, wrong length, or
non-hex characters all trigger this variant before any hash comparison
or signature verification.
InvalidPackageName
Package name fails the [a-z0-9-] validation rule.
A package name must be non-empty, ≤ 64 characters, contain only lowercase ASCII letters, digits, and hyphens, and must not start, end, or contain consecutive hyphens.
ArchivePathTraversal
Archive entry path escapes the package root.
Triggered by .. components, absolute paths, drive prefixes, or
root-only paths.
ArchiveEntryNameInvalid
Archive entry name contains NUL, control bytes, or non-UTF-8 bytes.
Entry names are validated before any path comparison.
ArchiveDisallowedEntryType
Archive entry is a disallowed type (symlink, hardlink, device, FIFO, etc.).
Type check is performed FIRST, before any path or body read.
ArchiveDuplicateEntry
Two archive entries normalise to the same ASCII-lowercase key.
Rejected to prevent APFS/HFS+ case-folding attacks. ASCII-lowercase collision detection is used; full Unicode NFC+case-fold is not yet implemented.
ArchiveTooManyEntries
Archive entry count exceeds the configured cap.
ArchiveEntryTooLarge
A single entry’s decompressed size exceeds the per-entry cap.
ArchiveTooLarge
Total decompressed output exceeds the cap.
ArchiveTrailingData
Gzip stream contains trailing data after the first member.
Any non-zero byte after the first gzip footer is rejected — whether it forms a second gzip member (multi-member concatenation) or is arbitrary garbage. Only tar end-of-archive zero padding is tolerated.
ArchiveBadTopLevel
Archive top-level shape is invalid.
A valid package must contain exactly one top-level directory whose name equals the package name.
ToolsetFormat(ToolsetFormatError)
TOOLSET.md parse or validation failed.
Wraps ToolsetFormatError; the staging directory is rolled back on
this error.
IdentityMismatch
Extracted TOOLSET.md name does not match the signed package name.
Version identity is established by the SIGNATURE BINDING — the signed
tuple includes the version string, so a package cannot be relabeled to
a different version without invalidating the signature. Only the name
field is content-cross-checked here because TOOLSET.md carries a name
but no version field.
The field is always "name" in current code; "version" is reserved
for a future format revision that adds a version field to TOOLSET.md.
Fields
AlreadyInstalled
Toolset is already installed and --force was not supplied.
Fields
VersionDowngrade
--force reinstall would downgrade the installed version.
Downgrade (installing an older version over a newer one) is refused by
default; pass --allow-downgrade to override.
Fields
NotInstalled
Uninstall was requested for a toolset that is not installed.
PinRecordMalformed
The stored pin record is invalid.
Triggered during uninstall when the pin record’s package name fails
validation or the reconstructed path escapes the toolsets root or resolves
to a symlink. NOT used for install-time toolsets-root checks; see
ToolsetInstallError::ToolsetsRootInvalid for those.
ToolsetsRootInvalid
The toolsets root directory is invalid at install time.
Triggered when the toolsets root directory leaf is a symlink
(no-follow discipline). Distinct from
ToolsetInstallError::PinRecordMalformed which covers uninstall
pin-record issues.
AttestationRequired
Toolset declares a key-touching capability but no attestation was supplied
and override_attestation is false.
A key-touching toolset (e.g. sign-payment) MUST be accompanied by a
valid auditor attestation when override_attestation is false.
Absent attestation → install is refused before any artefact is written.
AttestationInvalid
Attestation signature is cryptographically invalid.
Covers both cases opaquely:
auditor_pubkeyis not a valid compressed ed25519 point.- ed25519
verify_strictfails for the attestation signature over the canonical preimage.
The error is intentionally opaque — no key bytes, no signature bytes, no oracle for an attacker to distinguish the two cases.
Fields
AuditorUntrusted
Auditor public key is not in the auditor trust set.
The auditor key carried in the attestation is not present in
<toolsets_dir>/auditor-trust.txt. Note that the auditor trust set is
DISTINCT from the publisher trust set (trust.txt) — placing a key in
trust.txt does NOT implicitly grant auditor status.
The auditor key is redacted to first-5-last-5 in Display.
AttestationFieldMismatch
An attestation field does not match the verified install values.
One of package, version, shasum, or capabilities in the
ToolsetAttestation struct does not equal the value from the verified
install context. This prevents cross-package / version / capability
replay attacks.
The field is a closed set of &'static str values —
"package" / "version" / "shasum" / "capabilities" — so no
attacker-controlled string reaches the error.
Implementations§
Source§impl ToolsetInstallError
impl ToolsetInstallError
Sourcepub fn from_io(err: Error) -> Self
pub fn from_io(err: Error) -> Self
Constructs an ToolsetInstallError::Io from a std::io::Error.
The error’s Display string is sanitised (length-capped at 256 chars,
control/ANSI stripped) to prevent log-injection.
§Examples
use stellar_agent_toolsets_install::error::ToolsetInstallError;
let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
let err = ToolsetInstallError::from_io(io_err);
assert!(matches!(err, ToolsetInstallError::Io { .. }));Trait Implementations§
Source§impl Debug for ToolsetInstallError
impl Debug for ToolsetInstallError
Source§impl Display for ToolsetInstallError
impl Display for ToolsetInstallError
Source§impl Error for ToolsetInstallError
impl Error for ToolsetInstallError
Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()
Source§impl From<ToolsetFormatError> for ToolsetInstallError
impl From<ToolsetFormatError> for ToolsetInstallError
Source§fn from(source: ToolsetFormatError) -> Self
fn from(source: ToolsetFormatError) -> Self
Auto Trait Implementations§
impl Freeze for ToolsetInstallError
impl RefUnwindSafe for ToolsetInstallError
impl Send for ToolsetInstallError
impl Sync for ToolsetInstallError
impl Unpin for ToolsetInstallError
impl UnsafeUnpin for ToolsetInstallError
impl UnwindSafe for ToolsetInstallError
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> Paint for Twhere
T: ?Sized,
impl<T> Paint for Twhere
T: ?Sized,
Source§fn fg(&self, value: Color) -> Painted<&T>
fn fg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the foreground set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like red() and
green(), which have the same functionality but are
pithier.
§Example
Set foreground color to white using fg():
use yansi::{Paint, Color};
painted.fg(Color::White);Set foreground color to white using white().
use yansi::Paint;
painted.white();Source§fn bright_black(&self) -> Painted<&T>
fn bright_black(&self) -> Painted<&T>
Source§fn bright_red(&self) -> Painted<&T>
fn bright_red(&self) -> Painted<&T>
Source§fn bright_green(&self) -> Painted<&T>
fn bright_green(&self) -> Painted<&T>
Source§fn bright_yellow(&self) -> Painted<&T>
fn bright_yellow(&self) -> Painted<&T>
Source§fn bright_blue(&self) -> Painted<&T>
fn bright_blue(&self) -> Painted<&T>
Source§fn bright_magenta(&self) -> Painted<&T>
fn bright_magenta(&self) -> Painted<&T>
Source§fn bright_cyan(&self) -> Painted<&T>
fn bright_cyan(&self) -> Painted<&T>
Source§fn bright_white(&self) -> Painted<&T>
fn bright_white(&self) -> Painted<&T>
Source§fn bg(&self, value: Color) -> Painted<&T>
fn bg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the background set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like on_red() and
on_green(), which have the same functionality but
are pithier.
§Example
Set background color to red using fg():
use yansi::{Paint, Color};
painted.bg(Color::Red);Set background color to red using on_red().
use yansi::Paint;
painted.on_red();Source§fn on_primary(&self) -> Painted<&T>
fn on_primary(&self) -> Painted<&T>
Source§fn on_magenta(&self) -> Painted<&T>
fn on_magenta(&self) -> Painted<&T>
Source§fn on_bright_black(&self) -> Painted<&T>
fn on_bright_black(&self) -> Painted<&T>
Source§fn on_bright_red(&self) -> Painted<&T>
fn on_bright_red(&self) -> Painted<&T>
Source§fn on_bright_green(&self) -> Painted<&T>
fn on_bright_green(&self) -> Painted<&T>
Source§fn on_bright_yellow(&self) -> Painted<&T>
fn on_bright_yellow(&self) -> Painted<&T>
Source§fn on_bright_blue(&self) -> Painted<&T>
fn on_bright_blue(&self) -> Painted<&T>
Source§fn on_bright_magenta(&self) -> Painted<&T>
fn on_bright_magenta(&self) -> Painted<&T>
Source§fn on_bright_cyan(&self) -> Painted<&T>
fn on_bright_cyan(&self) -> Painted<&T>
Source§fn on_bright_white(&self) -> Painted<&T>
fn on_bright_white(&self) -> Painted<&T>
Source§fn attr(&self, value: Attribute) -> Painted<&T>
fn attr(&self, value: Attribute) -> Painted<&T>
Enables the styling Attribute value.
This method should be used rarely. Instead, prefer to use
attribute-specific builder methods like bold() and
underline(), which have the same functionality
but are pithier.
§Example
Make text bold using attr():
use yansi::{Paint, Attribute};
painted.attr(Attribute::Bold);Make text bold using using bold().
use yansi::Paint;
painted.bold();Source§fn rapid_blink(&self) -> Painted<&T>
fn rapid_blink(&self) -> Painted<&T>
Source§fn quirk(&self, value: Quirk) -> Painted<&T>
fn quirk(&self, value: Quirk) -> Painted<&T>
Enables the yansi Quirk value.
This method should be used rarely. Instead, prefer to use quirk-specific
builder methods like mask() and
wrap(), which have the same functionality but are
pithier.
§Example
Enable wrapping using .quirk():
use yansi::{Paint, Quirk};
painted.quirk(Quirk::Wrap);Enable wrapping using wrap().
use yansi::Paint;
painted.wrap();Source§fn clear(&self) -> Painted<&T>
👎Deprecated since 1.0.1: renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
fn clear(&self) -> Painted<&T>
renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
Source§fn whenever(&self, value: Condition) -> Painted<&T>
fn whenever(&self, value: Condition) -> Painted<&T>
Conditionally enable styling based on whether the Condition value
applies. Replaces any previous condition.
See the crate level docs for more details.
§Example
Enable styling painted only when both stdout and stderr are TTYs:
use yansi::{Paint, Condition};
painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);