spiral-sdk 0.1.7

Rust SDK for Spiral resource and table APIs
Documentation
//! Scandal bindings from the storage bindings that Spiral's storage service issues.

use crate::api::tables::{StorageAccess, StorageBinding as IssuedBinding, VendedCredential};
use crate::scandal::{GcsSession, S3Session, ScandalError, StorageBinding, StorageCredential};

impl StorageBinding {
    /// The scandal binding of `root` that storage's `binding` authorizes: an SPFS capability, or
    /// a provider session vended for the binding's provider root. When `root`, the root that a
    /// Table's object references name, differs from the binding's, it becomes the alias.
    pub fn from_storage(root: String, binding: IssuedBinding) -> Result<Self, ScandalError> {
        match binding.access {
            StorageAccess::Signed(access) => Ok(Self {
                root_alias: (root != binding.root_uri).then_some(binding.root_uri),
                root_uri: root,
                credential: Some(StorageCredential(access.token.0)),
            }),
            StorageAccess::Vended(access) => match access.credential {
                VendedCredential::AwsSession(credential) => {
                    let session = S3Session {
                        access_key_id: credential.access_key_id,
                        secret_access_key: credential.secret_access_key.0,
                        session_token: credential.session_token.0,
                        region: credential.region,
                        endpoint: credential.endpoint,
                        expires_at_micros: credential.expires_at_micros.0,
                    };
                    Ok(vended(root, binding.root_uri, session_json(&session)?))
                }
                VendedCredential::GcsAccessToken(credential) => {
                    let session = GcsSession {
                        access_token: credential.access_token.0,
                        expires_at_micros: credential.expires_at_micros.0,
                    };
                    Ok(vended(root, binding.root_uri, session_json(&session)?))
                }
                _ => Err(unsupported(&root)),
            },
            StorageAccess::Unknown { .. } => Err(unsupported(&root)),
        }
    }

    /// The scandal binding of a resource's whole storage, which `spiral://` addresses name
    /// relative to its root.
    pub fn for_resource(binding: IssuedBinding) -> Result<Self, ScandalError> {
        Self::from_storage(binding.root_uri.clone(), binding)
    }
}

/// Scandal storage at the vended `provider_root`, under the session `credential`, aliased by
/// `root` when that differs.
fn vended(root: String, provider_root: String, credential: String) -> StorageBinding {
    let root_alias = (root != provider_root).then_some(root);
    StorageBinding {
        root_uri: provider_root,
        root_alias,
        credential: Some(StorageCredential(credential)),
    }
}

fn session_json(session: &impl serde::Serialize) -> Result<String, ScandalError> {
    serde_json::to_string(session).map_err(|error| ScandalError::Internal {
        message: error.to_string(),
    })
}

fn unsupported(root: &str) -> ScandalError {
    ScandalError::InvalidArgument {
        message: format!("storage at {root} is neither signed by SPFS nor in object storage"),
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    use crate::api::tables::{
        GcsAccessToken, HuggingFaceToken, SecretToken, StorageMode, VendedAccess,
    };

    fn vended_binding(credential: VendedCredential) -> IssuedBinding {
        IssuedBinding {
            root_uri: "gs://acme/lake/tables/t1/".to_owned(),
            mode: StorageMode::ReadOnly,
            expires_at: 0.into(),
            access: StorageAccess::Vended(VendedAccess { credential }),
        }
    }

    /// A vended binding reaches scandal at its provider root with its session as the
    /// credential, aliased by the table's recorded root when that differs, and a credential that
    /// opens no object store is refused.
    #[test]
    fn a_vended_binding_carries_its_session_to_scandal() {
        let root = "gs://acme/lake/tables/t1/".to_owned();
        let gcs = || {
            vended_binding(VendedCredential::GcsAccessToken(GcsAccessToken {
                access_token: SecretToken("ya29.vended".into()),
                expires_at_micros: 7.into(),
            }))
        };
        let binding = StorageBinding::from_storage(root.clone(), gcs()).unwrap();
        assert_eq!(binding.root_uri, root);
        assert_eq!(binding.root_alias, None);
        let session: GcsSession = serde_json::from_str(binding.credential().unwrap()).unwrap();
        assert_eq!(session.access_token, "ya29.vended");
        assert_eq!(session.expires_at_micros, 7);

        let aliased =
            StorageBinding::from_storage("spfsu://4b44-alias/".to_owned(), gcs()).unwrap();
        assert_eq!(aliased.root_uri, root);
        assert_eq!(aliased.root_alias.as_deref(), Some("spfsu://4b44-alias/"));

        let refused = StorageBinding::from_storage(
            root,
            vended_binding(VendedCredential::HuggingFaceToken(HuggingFaceToken {
                token: SecretToken("hf".into()),
                expires_at_micros: 7.into(),
                endpoint: "https://huggingface.co".to_owned(),
            })),
        );
        assert!(refused.is_err());
    }
}