Skip to main content

alien_core/bindings/
artifact_registry.rs

1//! Service-type based artifact registry binding definitions
2
3use super::BindingValue;
4use serde::{Deserialize, Serialize};
5
6/// AWS ECR (Elastic Container Registry) binding configuration
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
8#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
9#[serde(rename_all = "camelCase")]
10pub struct EcrArtifactRegistryBinding {
11    /// Repository prefix for this registry (used to construct ECR repository names)
12    pub repository_prefix: BindingValue<String>,
13    /// Optional namespace for sandbox images served by regional ECR pull-through caches.
14    /// Configure cache rules before enabling this; workers keep using `repositoryPrefix`.
15    #[serde(default, skip_serializing_if = "Option::is_none")]
16    pub sandbox_repository_prefix: Option<BindingValue<String>>,
17    /// ARN of the IAM role for pull permissions (optional — omit for single-account)
18    #[serde(default, skip_serializing_if = "Option::is_none")]
19    pub pull_role_arn: Option<BindingValue<String>>,
20    /// ARN of the IAM role for push+pull permissions (optional — omit for single-account)
21    #[serde(default, skip_serializing_if = "Option::is_none")]
22    pub push_role_arn: Option<BindingValue<String>>,
23}
24
25/// Azure Container Registry binding configuration
26#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
27#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
28#[serde(rename_all = "camelCase")]
29pub struct AcrArtifactRegistryBinding {
30    /// Registry name (e.g., "myregistry") - endpoint is derived from this
31    pub registry_name: BindingValue<String>,
32    /// Resource group name where the registry is located
33    pub resource_group_name: BindingValue<String>,
34    /// Repository prefix for this registry (used for proxy routing)
35    #[serde(default, skip_serializing_if = "Option::is_none")]
36    pub repository_prefix: Option<BindingValue<String>>,
37}
38
39/// Google Artifact Registry binding configuration
40#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
41#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
42#[serde(rename_all = "camelCase")]
43pub struct GarArtifactRegistryBinding {
44    /// Repository name in the Artifact Registry (e.g., "alien-test").
45    /// Used as the default when cross-account access methods are called
46    /// without a specific repo name.
47    pub repository_name: BindingValue<String>,
48    /// Optional service account email for pull permissions (omit for single-project)
49    #[serde(default, skip_serializing_if = "Option::is_none")]
50    pub pull_service_account_email: Option<BindingValue<String>>,
51    /// Optional service account email for push+pull permissions (omit for single-project)
52    #[serde(default, skip_serializing_if = "Option::is_none")]
53    pub push_service_account_email: Option<BindingValue<String>>,
54}
55
56/// Local container registry binding configuration.
57///
58/// The local registry runs on localhost only and does not require authentication.
59/// Security boundary is the OS process isolation on the customer's machine.
60/// External image access is secured by the manager's registry proxy (deployment tokens).
61#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
62#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
63#[serde(rename_all = "camelCase")]
64pub struct LocalArtifactRegistryBinding {
65    /// The registry URL endpoint (e.g., "localhost:5000")
66    pub registry_url: BindingValue<String>,
67    /// Optional base directory for registry data
68    pub data_dir: BindingValue<Option<String>>,
69}
70
71/// Service-type based artifact registry binding that supports multiple registry providers
72#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
73#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
74#[serde(tag = "service", rename_all = "lowercase")]
75pub enum ArtifactRegistryBinding {
76    /// AWS ECR (Elastic Container Registry)
77    Ecr(EcrArtifactRegistryBinding),
78    /// Azure Container Registry
79    Acr(AcrArtifactRegistryBinding),
80    /// Google Artifact Registry
81    Gar(GarArtifactRegistryBinding),
82    /// Local container registry
83    Local(LocalArtifactRegistryBinding),
84}
85
86impl ArtifactRegistryBinding {
87    /// Creates an ECR artifact registry binding
88    pub fn ecr(
89        repository_prefix: impl Into<BindingValue<String>>,
90        pull_role_arn: Option<impl Into<BindingValue<String>>>,
91        push_role_arn: Option<impl Into<BindingValue<String>>>,
92    ) -> Self {
93        Self::Ecr(EcrArtifactRegistryBinding {
94            sandbox_repository_prefix: None,
95            repository_prefix: repository_prefix.into(),
96            pull_role_arn: pull_role_arn.map(|v| v.into()),
97            push_role_arn: push_role_arn.map(|v| v.into()),
98        })
99    }
100
101    /// Creates an ACR artifact registry binding
102    pub fn acr(
103        registry_name: impl Into<BindingValue<String>>,
104        resource_group_name: impl Into<BindingValue<String>>,
105    ) -> Self {
106        Self::Acr(AcrArtifactRegistryBinding {
107            registry_name: registry_name.into(),
108            resource_group_name: resource_group_name.into(),
109            repository_prefix: None,
110        })
111    }
112
113    /// Creates a GAR artifact registry binding
114    pub fn gar(
115        repository_name: impl Into<BindingValue<String>>,
116        pull_service_account_email: Option<impl Into<BindingValue<String>>>,
117        push_service_account_email: Option<impl Into<BindingValue<String>>>,
118    ) -> Self {
119        Self::Gar(GarArtifactRegistryBinding {
120            repository_name: repository_name.into(),
121            pull_service_account_email: pull_service_account_email.map(|v| v.into()),
122            push_service_account_email: push_service_account_email.map(|v| v.into()),
123        })
124    }
125
126    /// Creates a local artifact registry binding
127    pub fn local(
128        registry_url: impl Into<BindingValue<String>>,
129        data_dir: impl Into<BindingValue<Option<String>>>,
130    ) -> Self {
131        Self::Local(LocalArtifactRegistryBinding {
132            registry_url: registry_url.into(),
133            data_dir: data_dir.into(),
134        })
135    }
136}