everruns_core/connection_services.rs
1//! Neutral contracts for provider credentials and user connections.
2
3use crate::error::Result;
4use crate::typed_id::SessionId;
5use async_trait::async_trait;
6use uuid::Uuid;
7
8/// Provider credentials resolved for tool-side API clients.
9#[derive(Debug, Clone)]
10pub struct ProviderCredentials {
11 pub api_key: String,
12 pub base_url: Option<String>,
13}
14
15#[async_trait]
16pub trait ProviderCredentialStore: Send + Sync {
17 /// Resolve default credentials for a provider type (for example `openai`).
18 ///
19 /// Implementations may apply environment fallbacks internally, but tools
20 /// should never read provider env vars directly.
21 async fn get_default_provider_credentials(
22 &self,
23 provider_type: &str,
24 ) -> Result<Option<ProviderCredentials>>;
25}
26
27/// Resolves user connection tokens (e.g. GitHub) lazily at tool execution time.
28///
29/// Instead of eagerly injecting tokens at session creation, tools call this
30/// resolver when they need a token. If the user hasn't connected, returns None.
31#[async_trait]
32pub trait UserConnectionResolver: Send + Sync {
33 /// Get a decrypted connection token for the given provider.
34 /// Returns None if the user has no connection for this provider.
35 async fn get_connection_token(
36 &self,
37 session_id: SessionId,
38 provider: &str,
39 ) -> Result<Option<String>>;
40
41 /// Resolve the user ID of the connection used for a session/provider pair.
42 ///
43 /// This is used by leased resources to bind cleanup to the same provider
44 /// identity that created the remote resource.
45 async fn get_connection_user(
46 &self,
47 _session_id: SessionId,
48 _provider: &str,
49 ) -> Result<Option<Uuid>> {
50 Ok(None)
51 }
52
53 /// Resolve a provider token for a specific user.
54 ///
55 /// Cleanup workers use this to avoid "first org member wins" behavior when
56 /// cleaning resources created by a specific provider connection owner.
57 async fn get_connection_token_for_user(
58 &self,
59 _user_id: Uuid,
60 _provider: &str,
61 ) -> Result<Option<String>> {
62 Ok(None)
63 }
64
65 /// Get provider-specific metadata stored alongside the connection.
66 /// Returns None if no metadata is stored or no connection exists.
67 async fn get_connection_metadata(
68 &self,
69 _session_id: SessionId,
70 _provider: &str,
71 ) -> Result<Option<serde_json::Value>> {
72 Ok(None)
73 }
74}