auths_sdk/workflows/
artifact.rs1use auths_core::ports::network::{NetworkError, RateLimitInfo, RegistryClient};
4use auths_verifier::core::ResourceId;
5use serde::Deserialize;
6use thiserror::Error;
7
8use crate::ports::artifact::{ArtifactDigest, ArtifactError, ArtifactSource};
9
10pub struct ArtifactPublishConfig {
17 pub attestation: serde_json::Value,
19 pub package_name: Option<String>,
21 pub registry_url: String,
23}
24
25#[derive(Debug, Deserialize)]
27pub struct ArtifactPublishResult {
28 pub attestation_rid: ResourceId,
30 pub package_name: Option<String>,
32 pub signer_did: String,
34 #[serde(skip)]
36 pub rate_limit: Option<RateLimitInfo>,
37}
38
39#[derive(Debug, Error)]
41pub enum ArtifactPublishError {
42 #[error("artifact attestation already published (duplicate RID)")]
44 DuplicateAttestation,
45 #[error("signature verification failed at registry: {0}")]
47 VerificationFailed(String),
48 #[error("registry error ({status}): {body}")]
50 RegistryError {
51 status: u16,
53 body: String,
55 },
56 #[error("network error: {0}")]
58 Network(#[from] NetworkError),
59 #[error("failed to serialize publish request: {0}")]
61 Serialize(String),
62 #[error("failed to deserialize registry response: {0}")]
64 Deserialize(String),
65}
66
67pub async fn publish_artifact<R: RegistryClient>(
79 config: &ArtifactPublishConfig,
80 registry: &R,
81) -> Result<ArtifactPublishResult, ArtifactPublishError> {
82 let mut body = serde_json::json!({ "attestation": config.attestation });
83 if let Some(ref name) = config.package_name {
84 body["package_name"] = serde_json::Value::String(name.clone());
85 }
86 let json_bytes =
87 serde_json::to_vec(&body).map_err(|e| ArtifactPublishError::Serialize(e.to_string()))?;
88
89 let response = registry
90 .post_json(&config.registry_url, "v1/artifacts", &json_bytes)
91 .await?;
92
93 match response.status {
94 201 => {
95 let mut result: ArtifactPublishResult = serde_json::from_slice(&response.body)
96 .map_err(|e| ArtifactPublishError::Deserialize(e.to_string()))?;
97 result.rate_limit = response.rate_limit;
98 Ok(result)
99 }
100 409 => Err(ArtifactPublishError::DuplicateAttestation),
101 422 => {
102 let body = String::from_utf8_lossy(&response.body).into_owned();
103 Err(ArtifactPublishError::VerificationFailed(body))
104 }
105 status => {
106 let body = String::from_utf8_lossy(&response.body).into_owned();
107 Err(ArtifactPublishError::RegistryError { status, body })
108 }
109 }
110}
111
112pub fn compute_digest(source: &dyn ArtifactSource) -> Result<ArtifactDigest, ArtifactError> {
123 source.digest()
124}
125
126pub async fn verify_artifact<R: RegistryClient>(
142 config: &ArtifactVerifyConfig,
143 registry: &R,
144) -> Result<ArtifactVerifyResult, ArtifactPublishError> {
145 let body = serde_json::json!({
146 "attestation": config.attestation_json,
147 "issuer_key": config.signer_did,
148 });
149 let json_bytes =
150 serde_json::to_vec(&body).map_err(|e| ArtifactPublishError::Serialize(e.to_string()))?;
151
152 let response = registry
153 .post_json(&config.registry_url, "v1/verify", &json_bytes)
154 .await?;
155
156 match response.status {
157 200 => {
158 let result: ArtifactVerifyResult = serde_json::from_slice(&response.body)
159 .map_err(|e| ArtifactPublishError::Deserialize(e.to_string()))?;
160 Ok(result)
161 }
162 status => {
163 let body = String::from_utf8_lossy(&response.body).into_owned();
164 Err(ArtifactPublishError::RegistryError { status, body })
165 }
166 }
167}
168
169pub struct ArtifactVerifyConfig {
171 pub attestation_json: String,
173 pub signer_did: String,
175 pub registry_url: String,
177}
178
179#[derive(Debug, Deserialize)]
181pub struct ArtifactVerifyResult {
182 pub valid: bool,
184 pub signer_did: Option<String>,
186}