• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

maxlambrecht / rust-spiffe / 20588937519

30 Dec 2025 04:32AM UTC coverage: 66.13% (-4.0%) from 70.134%
20588937519

push

github

web-flow
Production refactor: Workload API + X509Source hardening, observability, and API polish (#214)

* refactor(spiffe): production hardening, observability, and API polish

Signed-off-by: Max Lambrecht <maxlambrecht@gmail.com>

* Refactor x509_source module

Signed-off-by: Max Lambrecht <maxlambrecht@gmail.com>

* Change spiffe rust-version to 1.85

Signed-off-by: Max Lambrecht <maxlambrecht@gmail.com>

* Exercise 'tracing' feature in builds

Signed-off-by: Max Lambrecht <maxlambrecht@gmail.com>

---------

Signed-off-by: Max Lambrecht <maxlambrecht@gmail.com>

1218 of 1843 new or added lines in 16 files covered. (66.09%)

401 existing lines in 8 files now uncovered.

2915 of 4408 relevant lines covered (66.13%)

89.45 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/spiffe/src/workload_api/error.rs
1
//! Error types for Workload API operations.
2

3
use thiserror::Error;
4

5
use crate::endpoint::EndpointError;
6
use crate::{JwtBundleError, JwtSvidError, SpiffeIdError, X509BundleError, X509SvidError};
7

8
#[cfg(feature = "transport")]
9
use crate::transport::TransportError;
10

11
/// Errors produced by Workload API operations.
12
#[derive(Debug, Error)]
13
#[non_exhaustive]
14
pub enum WorkloadApiError {
15
    /// `SPIFFE_ENDPOINT_SOCKET` is not set.
16
    #[error("missing SPIFFE endpoint socket path (SPIFFE_ENDPOINT_SOCKET)")]
17
    MissingEndpointSocket,
18

19
    /// The Workload API returned an empty response.
20
    ///
21
    /// This error can occur when:
22
    /// - The gRPC stream ends unexpectedly
23
    /// - No SVIDs are available for the requested identity
24
    /// - The Workload API is misconfigured or the workload is not registered
25
    ///
26
    /// **Common causes:**
27
    /// - Workload selectors don't match
28
    /// - SPIRE agent is not running
29
    /// - Network connectivity issues
30
    #[error("empty Workload API response")]
31
    EmptyResponse,
32

33
    /// Failed to parse the Workload API endpoint string.
34
    #[error("invalid workload api endpoint: {0}")]
35
    Endpoint(#[from] EndpointError),
36

37
    /// The Workload API denied issuing an identity for this workload (e.g. selectors do not match).
38
    ///
39
    /// This error occurs when the SPIRE agent cannot match the workload to any
40
    /// registration entry based on the workload's selectors.
41
    #[error("no identity issued")]
42
    NoIdentityIssued,
43

44
    /// The Workload API denied the request for other permission reasons.
45
    #[error("permission denied: {0}")]
46
    PermissionDenied(String),
47

48
    /// No JWT-SVID found with the requested hint.
49
    #[error("no JWT-SVID found with hint: {0}")]
50
    HintNotFound(String),
51

52
    /// Errors returned by the underlying transport.
53
    #[cfg(feature = "transport")]
54
    #[error(transparent)]
55
    Transport(#[from] TransportError),
56

57
    /// Failed to parse an X.509 SVID from the Workload API response.
58
    #[error("failed to parse X.509 SVID: {0}")]
59
    X509Svid(#[from] X509SvidError),
60

61
    /// Failed to parse a JWT-SVID from the Workload API response.
62
    #[error("failed to parse JWT-SVID: {0}")]
63
    JwtSvid(#[from] JwtSvidError),
64

65
    /// Failed to parse an X.509 bundle from the Workload API response.
66
    #[error("failed to parse X.509 bundle: {0}")]
67
    X509Bundle(#[from] X509BundleError),
68

69
    /// Failed to parse a JWT bundle from the Workload API response.
70
    #[error("failed to parse JWT bundle: {0}")]
71
    JwtBundle(#[from] JwtBundleError),
72

73
    /// Failed to parse a SPIFFE identifier from the Workload API response.
74
    #[error("failed to parse SPIFFE ID: {0}")]
75
    SpiffeId(#[from] SpiffeIdError),
76
}
77

78
#[cfg(feature = "transport")]
79
impl From<tonic::Status> for WorkloadApiError {
NEW
80
    fn from(status: tonic::Status) -> Self {
×
81
        use tonic::Code;
82

NEW
83
        if status.code() == Code::PermissionDenied {
×
NEW
84
            let msg = status.message();
×
85

NEW
86
            if msg.contains("no identity issued") {
×
NEW
87
                return Self::NoIdentityIssued;
×
NEW
88
            }
×
89

NEW
90
            return Self::PermissionDenied(msg.to_owned());
×
NEW
91
        }
×
92

NEW
93
        Self::Transport(TransportError::Status(status))
×
NEW
94
    }
×
95
}
96

97
#[cfg(feature = "transport")]
98
impl From<tonic::transport::Error> for WorkloadApiError {
NEW
99
    fn from(e: tonic::transport::Error) -> Self {
×
NEW
100
        Self::Transport(TransportError::Tonic(e))
×
NEW
101
    }
×
102
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc