Skip to main content
KeyOS API Reference

app_manager/
error.rs

1// SPDX-FileCopyrightText: 2025 Foundation Devices, Inc. <hello@foundation.xyz>
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#[derive(
5    Debug,
6    Clone,
7    Copy,
8    thiserror::Error,
9    rkyv::Archive,
10    rkyv::Serialize,
11    rkyv::Deserialize,
12    num_derive::FromPrimitive,
13    num_derive::ToPrimitive,
14)]
15pub enum AppManagerError {
16    #[error("Unknown AppId")]
17    UnknownAppId = 0,
18
19    #[error("Verification Failed")]
20    VerificationFailed = 1,
21
22    #[error("Internal Error")]
23    InternalError = 2,
24
25    #[error("No Certificate")]
26    NoCertificate = 3,
27
28    #[error("Publisher Certificate Expired")]
29    PublisherCertificateExpired = 4,
30
31    #[error("Publisher Certificate Not Active Yet")]
32    PublisherCertificateNotYetActive = 5,
33
34    #[error("KeyOS Version Too Old")]
35    KeyOsVersionTooOld = 6,
36
37    #[error("Running KeyOS Version Unavailable")]
38    RunningKeyOsVersionUnavailable = 7,
39}
40
41#[derive(Debug, Clone, PartialEq, Eq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
42pub enum VerificationError {
43    Unverified,
44    MissingCosign2Header,
45    InternalError,
46}
47
48/// A manifest is well-formed but cannot run on the current KeyOS release.
49#[derive(
50    Debug, Clone, PartialEq, Eq, thiserror::Error, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize,
51)]
52pub enum CompatibilityError {
53    #[error("app requires KeyOS {minimum}, but this device is running {current}")]
54    KeyOsVersionTooOld { minimum: String, current: String },
55    #[error("the running KeyOS version is unavailable")]
56    RunningKeyOsVersionUnavailable,
57}
58
59#[derive(Debug, Clone, PartialEq, Eq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
60pub enum LaunchError {
61    UnknownAppId,
62    Verification(VerificationError),
63    NameRegistration,
64    NoCertificate,
65    PublisherCertificateExpired,
66    PublisherCertificateNotYetActive,
67    Compatibility(CompatibilityError),
68    OutOfMemory,
69    InternalError,
70}
71
72impl From<xous::Error> for LaunchError {
73    fn from(value: xous::Error) -> Self {
74        match value {
75            xous::Error::OutOfMemory => LaunchError::OutOfMemory,
76            _ => LaunchError::InternalError,
77        }
78    }
79}
80
81impl From<std::str::Utf8Error> for LaunchError {
82    fn from(_: std::str::Utf8Error) -> Self { LaunchError::InternalError }
83}
84
85impl From<LaunchError> for AppManagerError {
86    fn from(value: LaunchError) -> Self {
87        match value {
88            LaunchError::UnknownAppId => AppManagerError::UnknownAppId,
89            LaunchError::Verification(_) => AppManagerError::VerificationFailed,
90            LaunchError::NoCertificate => AppManagerError::NoCertificate,
91            LaunchError::PublisherCertificateExpired => AppManagerError::PublisherCertificateExpired,
92            LaunchError::PublisherCertificateNotYetActive => {
93                AppManagerError::PublisherCertificateNotYetActive
94            }
95            LaunchError::Compatibility(CompatibilityError::KeyOsVersionTooOld { .. }) => {
96                AppManagerError::KeyOsVersionTooOld
97            }
98            LaunchError::Compatibility(CompatibilityError::RunningKeyOsVersionUnavailable) => {
99                AppManagerError::RunningKeyOsVersionUnavailable
100            }
101            _ => AppManagerError::InternalError,
102        }
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109
110    #[test]
111    fn unavailable_running_version_remains_a_compatibility_error() {
112        assert!(matches!(
113            AppManagerError::from(LaunchError::Compatibility(
114                CompatibilityError::RunningKeyOsVersionUnavailable
115            )),
116            AppManagerError::RunningKeyOsVersionUnavailable
117        ));
118    }
119}
120
121#[cfg(not(keyos))]
122impl From<std::io::Error> for LaunchError {
123    fn from(_value: std::io::Error) -> Self { LaunchError::InternalError }
124}
125
126#[cfg(not(keyos))]
127impl From<serde_json::Error> for LaunchError {
128    fn from(_value: serde_json::Error) -> Self { LaunchError::InternalError }
129}