first pass of merging in warp (doesn't build)

This commit is contained in:
Ryan Ward
2026-07-01 16:08:58 -05:00
parent 2f64909469
commit 4770ac06b5
3662 changed files with 414574 additions and 89772 deletions
@@ -0,0 +1,260 @@
use std::fmt;
use cloud_objects::cloud_object::{
GenericCloudObject, GenericServerObject, GenericStringModel, JsonObjectType,
};
use cloud_objects::ids::GenericStringObjectId;
use serde::{Deserialize, Serialize};
use crate::{JsonModel, JsonSerializer};
/// Source-control provider hosting an environment's repositories.
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
pub enum CodeForge {
#[default]
#[serde(rename = "GITHUB")]
GitHub,
#[serde(rename = "GITLAB")]
GitLab,
}
impl CodeForge {
pub const fn host(self) -> &'static str {
match self {
CodeForge::GitHub => "github.com",
CodeForge::GitLab => "gitlab.com",
}
}
}
impl fmt::Display for CodeForge {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
CodeForge::GitHub => write!(f, "GitHub"),
CodeForge::GitLab => write!(f, "GitLab"),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct GithubRepo {
/// Repository owner (e.g. "warpdotdev")
pub owner: String,
/// Repository name (e.g. "warp-internal")
pub repo: String,
}
impl GithubRepo {
pub fn new(owner: String, repo: String) -> Self {
Self { owner, repo }
}
}
impl fmt::Display for GithubRepo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}/{}", self.owner, self.repo)
}
}
/// Identifies a repository and the source-control provider that hosts it.
///
/// For GitLab, `owner` contains the full, potentially nested namespace.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct SourceRepo {
/// The repository's explicit source-control provider.
///
/// When absent, this inherits the associated environment's effective forge.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub code_forge: Option<CodeForge>,
pub owner: String,
pub repo: String,
}
impl SourceRepo {
pub fn new(code_forge: CodeForge, owner: String, repo: String) -> Self {
Self {
code_forge: Some(code_forge),
owner,
repo,
}
}
pub fn with_default_code_forge(&self, code_forge: CodeForge) -> Self {
Self::new(
self.code_forge.unwrap_or(code_forge),
self.owner.clone(),
self.repo.clone(),
)
}
pub fn https_clone_url(&self) -> String {
format!(
"https://{}/{}/{}.git",
self.code_forge.unwrap_or_default().host(),
self.owner,
self.repo
)
}
}
/// Converts a legacy GitHub repository into the provider-neutral representation.
impl From<&GithubRepo> for SourceRepo {
fn from(repo: &GithubRepo) -> Self {
Self::new(CodeForge::GitHub, repo.owner.clone(), repo.repo.clone())
}
}
/// Formats the forge-relative repository path.
impl fmt::Display for SourceRepo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}/{}", self.owner, self.repo)
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum BaseImage {
DockerImage(String),
}
impl fmt::Display for BaseImage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BaseImage::DockerImage(s) => s.fmt(f),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct GcpProviderConfig {
pub project_number: String,
pub workload_identity_federation_pool_id: String,
pub workload_identity_federation_provider_id: String,
/// Service account email for impersonation. When set, the federated token
/// is exchanged for a service account access token.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub service_account_email: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct AwsProviderConfig {
pub role_arn: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)]
pub struct ProvidersConfig {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub gcp: Option<GcpProviderConfig>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub aws: Option<AwsProviderConfig>,
}
impl ProvidersConfig {
pub fn is_empty(&self) -> bool {
self.gcp.is_none() && self.aws.is_none()
}
}
/// Identifies a managed secret configured on an environment.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct EnvironmentSecretRef {
pub name: String,
}
/// An AmbientAgentEnvironment represents an environment that we would run a Warp agent in.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct AmbientAgentEnvironment {
/// Environment name
#[serde(default)]
pub name: String,
/// Optional description of the environment (max 240 characters)
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
/// Source-control provider hosting this environment's repositories.
///
/// Absent means GitHub for legacy environments.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub code_forge: Option<CodeForge>,
/// List of GitHub repositories
#[serde(default)]
pub github_repos: Vec<GithubRepo>,
/// Provider-neutral repository list.
///
/// When present, including when empty, this is authoritative over
/// `github_repos`.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub source_repos: Option<Vec<SourceRepo>>,
/// Base image specification
#[serde(flatten)]
pub base_image: BaseImage,
/// List of setup commands to run after cloning
#[serde(default)]
pub setup_commands: Vec<String>,
/// Optional cloud provider configurations for automatic auth.
#[serde(default, skip_serializing_if = "ProvidersConfig::is_empty")]
pub providers: ProvidersConfig,
/// Default set of managed secrets for runs using this environment.
/// - `None`: no environment-level secret scoping (all secrets / defer to run config)
/// - `Some([])`: no secrets by default
/// - `Some([...])`: these specific secrets are the default
#[serde(default, skip_serializing_if = "Option::is_none")]
pub secrets: Option<Vec<EnvironmentSecretRef>>,
}
impl AmbientAgentEnvironment {
pub fn new(
name: String,
description: Option<String>,
github_repos: Vec<GithubRepo>,
docker_image: String,
setup_commands: Vec<String>,
) -> Self {
Self {
name,
description,
code_forge: None,
github_repos,
source_repos: None,
base_image: BaseImage::DockerImage(docker_image),
setup_commands,
providers: ProvidersConfig::default(),
secrets: None,
}
}
/// Returns the environment's source-control provider, defaulting to GitHub
/// for legacy environments.
pub fn effective_code_forge(&self) -> CodeForge {
self.code_forge.unwrap_or_default()
}
/// Returns the authoritative provider-neutral repository list.
pub fn effective_repos(&self) -> Vec<SourceRepo> {
let code_forge = self.effective_code_forge();
match &self.source_repos {
Some(source_repos) => source_repos
.iter()
.map(|repo| repo.with_default_code_forge(code_forge))
.collect(),
None => self
.github_repos
.iter()
.map(|repo| SourceRepo::new(code_forge, repo.owner.clone(), repo.repo.clone()))
.collect(),
}
}
}
impl JsonModel for AmbientAgentEnvironment {
fn json_object_type() -> JsonObjectType {
JsonObjectType::CloudEnvironment
}
}
pub type CloudAmbientAgentEnvironment =
GenericCloudObject<GenericStringObjectId, CloudAmbientAgentEnvironmentModel>;
pub type CloudAmbientAgentEnvironmentModel =
GenericStringModel<AmbientAgentEnvironment, JsonSerializer>;
pub type ServerAmbientAgentEnvironment =
GenericServerObject<GenericStringObjectId, CloudAmbientAgentEnvironmentModel>;
#[cfg(test)]
#[path = "cloud_environment_tests.rs"]
mod tests;