Initial public release of Warp.

Repo-Sync-Origin: warpdotdev/warp-internal@12af1d983b
This commit is contained in:
David Stern
2026-04-28 08:43:33 -05:00
commit 0dbd3d567a
4982 changed files with 1431549 additions and 0 deletions
+19
View File
@@ -0,0 +1,19 @@
[package]
name = "warp_isolation_platform"
description = "Utilities for running Warp within an isolated sandbox, such as a Docker container or Github Actions"
version = "0.1.0"
authors.workspace = true
publish.workspace = true
license.workspace = true
edition = "2024"
[dependencies]
anyhow.workspace = true
base64.workspace = true
chrono.workspace = true
log.workspace = true
serde.workspace = true
serde_json.workspace = true
thiserror.workspace = true
command.workspace = true
warp_core.workspace = true
+10
View File
@@ -0,0 +1,10 @@
/// The Docker engine creates this file at the root of every container.
const DOCKER_ENV_FILE: &str = "/.dockerenv";
/// Detect whether we are running inside a Docker container.
///
/// The Docker runtime places a `/.dockerenv` marker file in the root filesystem of
/// every container it creates. This is the standard heuristic used to detect Docker.
pub fn is_in_docker() -> bool {
std::fs::exists(DOCKER_ENV_FILE).unwrap_or(false)
}
@@ -0,0 +1,11 @@
use std::time::Duration;
use crate::{IsolationPlatformError, WorkloadToken};
/// Issue a Docker sandbox workload token.
/// Docker sandbox tokens do not have an expiration time.
pub async fn issue_workload_token(
_duration: Option<Duration>,
) -> Result<WorkloadToken, IsolationPlatformError> {
crate::read_generic_workload_token()
}
@@ -0,0 +1,6 @@
/// Detect whether we are running inside a Kubernetes pod.
///
/// The kubelet unconditionally injects `KUBERNETES_SERVICE_HOST` into every pod.
pub fn is_in_kubernetes() -> bool {
std::env::var("KUBERNETES_SERVICE_HOST").is_ok_and(|v| !v.is_empty())
}
+187
View File
@@ -0,0 +1,187 @@
use std::{io, process::ExitStatus, sync::OnceLock, time::Duration};
use chrono::{DateTime, Utc};
use serde::Serialize;
use warp_core::channel::{Channel, ChannelState};
#[cfg(not(target_family = "wasm"))]
mod docker;
#[cfg(not(target_family = "wasm"))]
mod docker_sandbox;
#[cfg(not(target_family = "wasm"))]
mod kubernetes;
#[cfg(not(target_family = "wasm"))]
mod namespace;
/// Environment variable set by the server to identify the isolation platform.
/// The value should match one of the `IsolationPlatformType` variants in snake_case.
#[cfg(not(target_family = "wasm"))]
const WARP_ISOLATION_PLATFORM_ENV: &str = "WARP_ISOLATION_PLATFORM";
/// Environment variable containing the generic Warp-managed workload token that we use
/// for isolation platforms that don't issue their own tokens.
#[cfg(not(target_family = "wasm"))]
const WARP_WORKLOAD_TOKEN_ENV: &str = "WARP_WORKLOAD_TOKEN";
/// A kind of isolation platform. For our usage, isolation platforms are different ways where Warp
/// can be sandboxed, such as VMs, containers, or cloud hosts. This may also include weaker forms
/// of sandboxing such as Git worktrees.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum IsolationPlatformType {
/// Warp is running within a Docker container. Note that this does *not* mean this is a Warp-hosted
/// Docker Sandboxes environment. Instead, it's likely a self-hosted agent.
#[cfg(not(target_family = "wasm"))]
Docker,
/// Warp is running within a Docker Sandbox, likely as a Warp-hosted agent.
#[cfg(not(target_family = "wasm"))]
DockerSandbox,
/// Warp is running within a Kubernetes pod, likely as a self-hosted agent.
#[cfg(not(target_family = "wasm"))]
Kubernetes,
/// Warp is running within a Namespace instance, likely as a Warp-hosted agent.
#[cfg(not(target_family = "wasm"))]
Namespace,
}
/// A workload identity token issued by the isolation platform.
#[derive(Debug, Clone)]
pub struct WorkloadToken {
/// The token string.
pub token: String,
/// The expiration time of the token. On some platforms, workload tokens do not expire.
pub expires_at: Option<DateTime<Utc>>,
}
/// Detect the current isolation platform, if any.
///
/// Results are memoized for the lifetime of the process.
pub fn detect() -> Option<IsolationPlatformType> {
static DETECTED_PLATFORM: OnceLock<Option<IsolationPlatformType>> = OnceLock::new();
*DETECTED_PLATFORM.get_or_init(|| {
// This never applies to integration tests.
if ChannelState::channel() == Channel::Integration {
return None;
}
// Use a closure so we can early-return.
#[allow(clippy::redundant_closure_call)]
let platform = (|| {
// If the server explicitly told us which platform we're on, trust it.
// This takes priority over all heuristic-based detection.
#[cfg(not(target_family = "wasm"))]
if let Some(platform) = platform_from_env() {
return Some(platform);
}
#[cfg(not(target_family = "wasm"))]
if namespace::is_in_namespace_instance() {
return Some(IsolationPlatformType::Namespace);
}
#[cfg(not(target_family = "wasm"))]
if kubernetes::is_in_kubernetes() {
return Some(IsolationPlatformType::Kubernetes);
}
#[cfg(not(target_family = "wasm"))]
if docker::is_in_docker() {
return Some(IsolationPlatformType::Docker);
}
None
})();
match platform {
Some(platform) => {
log::debug!("Detected isolation platform: {:?}", platform);
}
None => {
log::info!("No isolation platform detected");
}
}
platform
})
}
/// Issue a workload identity token for the current isolation platform.
///
/// This will fail if no isolation platform is detected and no platform-agnostic workload token
/// is available.
#[cfg_attr(target_family = "wasm", allow(unused_variables))]
pub async fn issue_workload_token(
duration: Option<Duration>,
) -> Result<WorkloadToken, IsolationPlatformError> {
match detect() {
#[cfg(not(target_family = "wasm"))]
Some(IsolationPlatformType::DockerSandbox) => {
docker_sandbox::issue_workload_token(duration).await
}
#[cfg(not(target_family = "wasm"))]
Some(IsolationPlatformType::Namespace) => namespace::issue_workload_token(duration).await,
#[cfg(not(target_family = "wasm"))]
// Check for a platform-agnostic workload token if there's no
// isolation platform or if the detected platform doesn't have
// its own workload token mechanism.
_ => read_generic_workload_token()
.inspect_err(|err| log::debug!("No platform-agnostic workload token: {err}"))
.map_err(|_| IsolationPlatformError::NoIsolationPlatformDetected),
#[cfg(target_family = "wasm")]
_ => Err(IsolationPlatformError::NoIsolationPlatformDetected),
}
}
/// Read a platform-agnostic workload token from the `WARP_WORKLOAD_TOKEN` environment variable.
/// Returns a `WorkloadToken` with no expiration, or an error if the variable is missing/empty.
#[cfg(not(target_family = "wasm"))]
fn read_generic_workload_token() -> Result<WorkloadToken, IsolationPlatformError> {
let token = std::env::var(WARP_WORKLOAD_TOKEN_ENV)
.map_err(|_| IsolationPlatformError::GenericWorkloadTokenMissing)?;
if token.is_empty() {
return Err(IsolationPlatformError::GenericWorkloadTokenMissing);
}
Ok(WorkloadToken {
token,
expires_at: None,
})
}
/// Parse the `WARP_ISOLATION_PLATFORM` environment variable into a platform type.
#[cfg(not(target_family = "wasm"))]
fn platform_from_env() -> Option<IsolationPlatformType> {
let value = std::env::var(WARP_ISOLATION_PLATFORM_ENV).ok()?;
match value.as_str() {
"docker" => Some(IsolationPlatformType::Docker),
"docker_sandbox" => Some(IsolationPlatformType::DockerSandbox),
"kubernetes" => Some(IsolationPlatformType::Kubernetes),
"namespace" => Some(IsolationPlatformType::Namespace),
other => {
log::warn!("Unknown {WARP_ISOLATION_PLATFORM_ENV} value: {other}");
None
}
}
}
#[derive(Debug, thiserror::Error)]
pub enum IsolationPlatformError {
#[error("No isolation platform detected")]
NoIsolationPlatformDetected,
#[error("Workload token is missing or empty")]
GenericWorkloadTokenMissing,
#[error("Required command {command} is unavailable")]
CommandUnavailable {
command: String,
#[source]
source: io::Error,
},
#[error("Command `{command}` exited with non-zero status: {status}")]
CommandFailed { command: String, status: ExitStatus },
#[error(transparent)]
Other(#[from] anyhow::Error),
}
+105
View File
@@ -0,0 +1,105 @@
use std::{env, fs, time::Duration};
use base64::prelude::{BASE64_URL_SAFE_NO_PAD, Engine as _};
use chrono::{DateTime, Utc};
use command::r#async::Command;
use warp_core::channel::ChannelState;
use crate::{IsolationPlatformError, WorkloadToken};
/// Detect whether or not we are running in a Namespace instance.
pub fn is_in_namespace_instance() -> bool {
// For Namespace, match their CLI's logic for detecting a token:
// https://github.com/namespacelabs/integrations/blob/08d0acd17ce05f8486ec8da329066dd6a12572a0/auth/token.go#L116-L131
env::var("NSC_TOKEN_FILE").is_ok() || fs::exists("/var/run/nsc/token.json").is_ok_and(|v| v)
}
/// Issue a Namespace workload identity token.
pub async fn issue_workload_token(
duration: Option<Duration>,
) -> Result<WorkloadToken, IsolationPlatformError> {
let mut nsc_command = Command::new("nsc");
nsc_command
.arg("auth")
.arg("issue-id-token")
.arg("--audience")
.arg(&*ChannelState::workload_audience_url())
.arg("--output")
.arg("json");
if let Some(duration) = duration {
nsc_command
.arg("--duration")
.arg(format!("{}ns", duration.as_nanos()));
}
let output =
nsc_command
.output()
.await
.map_err(|err| IsolationPlatformError::CommandUnavailable {
command: "nsc".to_owned(),
source: err,
})?;
if !output.status.success() {
log::warn!(
"`nsc` command failed with status {}: {}",
output.status,
String::from_utf8_lossy(&output.stderr)
);
return Err(IsolationPlatformError::CommandFailed {
command: "nsc".to_owned(),
status: output.status,
});
}
/// JSON output from `nsc auth issue-id-token`.
#[derive(serde::Deserialize)]
struct NscTokenOutput {
id_token: String,
}
let token_output = serde_json::from_slice::<NscTokenOutput>(&output.stdout)
.map_err(|_| anyhow::anyhow!("Unexpected output from `nsc auth issue-id-token`"))?;
// Namespace ID tokens are JWTs.
let expires_at = parse_jwt_expiration(&token_output.id_token)?;
Ok(WorkloadToken {
token: token_output.id_token,
expires_at: Some(expires_at),
})
}
/// Parse the expiration time from a JWT token.
///
/// JWTs have three base64url-encoded parts separated by dots: header.payload.signature.
/// The payload contains an `exp` claim with the Unix timestamp of expiration.
fn parse_jwt_expiration(token: &str) -> Result<DateTime<Utc>, IsolationPlatformError> {
let parts: Vec<&str> = token.split('.').collect();
if parts.len() != 3 {
return Err(
anyhow::anyhow!("Invalid JWT format: expected 3 parts, got {}", parts.len()).into(),
);
}
let payload_bytes = BASE64_URL_SAFE_NO_PAD
.decode(parts[1])
.map_err(|e| anyhow::anyhow!("Failed to decode JWT payload: {e}"))?;
#[derive(serde::Deserialize)]
struct JwtPayload {
exp: i64,
}
let payload: JwtPayload = serde_json::from_slice(&payload_bytes)
.map_err(|e| anyhow::anyhow!("Failed to parse JWT payload: {e}"))?;
DateTime::from_timestamp(payload.exp, 0)
.ok_or_else(|| anyhow::anyhow!("Invalid exp timestamp in JWT: {}", payload.exp).into())
}
#[cfg(test)]
#[path = "namespace_tests.rs"]
mod tests;
@@ -0,0 +1,51 @@
use base64::prelude::{BASE64_URL_SAFE_NO_PAD, Engine as _};
use chrono::{TimeZone, Utc};
use super::parse_jwt_expiration;
/// Helper to create a JWT token string for testing.
fn make_jwt(payload_json: &str) -> String {
let header = BASE64_URL_SAFE_NO_PAD.encode(r#"{"alg":"HS256","typ":"JWT"}"#);
let payload = BASE64_URL_SAFE_NO_PAD.encode(payload_json);
let signature = BASE64_URL_SAFE_NO_PAD.encode("fake_signature");
format!("{header}.{payload}.{signature}")
}
#[test]
fn test_parse_jwt_expiration_valid() {
// Unix timestamp for 2024-01-15 12:00:00 UTC.
let exp_timestamp: i64 = 1705320000;
let token = make_jwt(&format!(r#"{{"exp":{exp_timestamp},"sub":"user123"}}"#));
let result = parse_jwt_expiration(&token).unwrap();
let expected = Utc.timestamp_opt(exp_timestamp, 0).unwrap();
assert_eq!(result, expected);
}
#[test]
fn test_parse_jwt_expiration_invalid_format_too_few_parts() {
let token = "header.payload";
assert!(parse_jwt_expiration(token).is_err());
}
#[test]
fn test_parse_jwt_expiration_invalid_format_too_many_parts() {
let token = "a.b.c.d";
assert!(parse_jwt_expiration(token).is_err());
}
#[test]
fn test_parse_jwt_expiration_invalid_json() {
let header = BASE64_URL_SAFE_NO_PAD.encode(r#"{"alg":"HS256"}"#);
let payload = BASE64_URL_SAFE_NO_PAD.encode("not valid json");
let token = format!("{header}.{payload}.signature");
assert!(parse_jwt_expiration(&token).is_err());
}
#[test]
fn test_parse_jwt_expiration_missing_exp_field() {
let token = make_jwt(r#"{"sub":"user123","iat":1234567890}"#);
assert!(parse_jwt_expiration(token.as_str()).is_err());
}