mirror of
https://github.com/openai/codex.git
synced 2026-08-23 13:09:46 +00:00
Support workload identity in remote exec-server auth (#38610)
## Why Remote exec-server registry requests need to refresh managed credentials before sending a request. Static auth-header resolution cannot perform the asynchronous token exchange required by workload identity. ## What changed - Add asynchronous auth-header resolution to `AuthProvider`, with the existing static-header behavior as the default. - Resolve fresh managed credentials for each remote environment registry request while preserving the expected account and workspace identity. - Load the cloud configuration bundle during remote exec-server startup when workload identity is selected. ## Testing - Update the managed-auth and environment-registry auth tests to exercise asynchronous header resolution. GitOrigin-RevId: 5d60f1127467aaacdb5d1a8f3d92278bc4bf2e29
This commit is contained in:
@@ -129,18 +129,20 @@ impl EnvironmentRegistryClient {
|
||||
environment_id: &str,
|
||||
executor_public_key: &NoiseChannelPublicKey,
|
||||
) -> Result<EnvironmentRegistryRegistrationResponse, ExecServerError> {
|
||||
let url = endpoint_url(
|
||||
&self.base_url,
|
||||
&format!("/cloud/environment/{environment_id}/register"),
|
||||
);
|
||||
let body = EnvironmentRegistryRegistrationRequest {
|
||||
security_profile: NOISE_RELAY_SECURITY_PROFILE.to_string(),
|
||||
executor_public_key: executor_public_key.clone(),
|
||||
};
|
||||
let response = self
|
||||
.http
|
||||
.post(endpoint_url(
|
||||
&self.base_url,
|
||||
&format!("/cloud/environment/{environment_id}/register"),
|
||||
))
|
||||
.headers(self.auth_provider.to_auth_headers())
|
||||
.post(url)
|
||||
.headers(self.resolve_auth_headers().await?)
|
||||
.headers(current_trace_context_headers())
|
||||
.json(&EnvironmentRegistryRegistrationRequest {
|
||||
security_profile: NOISE_RELAY_SECURITY_PROFILE.to_string(),
|
||||
executor_public_key: executor_public_key.clone(),
|
||||
})
|
||||
.json(&body)
|
||||
.send()
|
||||
.await?;
|
||||
let response: EnvironmentRegistryRegistrationResponse =
|
||||
@@ -185,15 +187,17 @@ impl EnvironmentRegistryClient {
|
||||
environment_id: &str,
|
||||
harness_public_key: NoiseChannelPublicKey,
|
||||
) -> Result<NoiseRendezvousConnectBundle, ExecServerError> {
|
||||
let url = endpoint_url(
|
||||
&self.base_url,
|
||||
&format!("/cloud/environment/{environment_id}/connect"),
|
||||
);
|
||||
let body = EnvironmentRegistryConnectRequest { harness_public_key };
|
||||
let response = self
|
||||
.http
|
||||
.post(endpoint_url(
|
||||
&self.base_url,
|
||||
&format!("/cloud/environment/{environment_id}/connect"),
|
||||
))
|
||||
.headers(self.auth_provider.to_auth_headers())
|
||||
.post(url)
|
||||
.headers(self.resolve_auth_headers().await?)
|
||||
.headers(current_trace_context_headers())
|
||||
.json(&EnvironmentRegistryConnectRequest { harness_public_key })
|
||||
.json(&body)
|
||||
.timeout(self.connect_timeout)
|
||||
.send()
|
||||
.await?;
|
||||
@@ -227,6 +231,17 @@ impl EnvironmentRegistryClient {
|
||||
})
|
||||
}
|
||||
|
||||
async fn resolve_auth_headers(&self) -> Result<HeaderMap, ExecServerError> {
|
||||
self.auth_provider
|
||||
.resolve_auth_headers()
|
||||
.await
|
||||
.map_err(|error| {
|
||||
ExecServerError::EnvironmentRegistryAuth(format!(
|
||||
"failed to resolve environment registry authentication: {error}"
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
async fn parse_json_response<R>(&self, response: HttpResponse) -> Result<R, ExecServerError>
|
||||
where
|
||||
R: for<'de> Deserialize<'de>,
|
||||
@@ -275,20 +290,22 @@ impl HarnessKeyValidator for RegistryHarnessKeyValidator {
|
||||
authorization: &str,
|
||||
) -> Result<(), ExecServerError> {
|
||||
let environment_id = &self.environment_id;
|
||||
let url = endpoint_url(
|
||||
&self.client.base_url,
|
||||
&format!("/cloud/environment/{environment_id}/validate"),
|
||||
);
|
||||
let body = EnvironmentRegistryHarnessKeyValidationRequest {
|
||||
executor_registration_id: self.executor_registration_id.clone(),
|
||||
harness_public_key: harness_public_key.clone(),
|
||||
harness_key_authorization: authorization.to_string(),
|
||||
};
|
||||
let response = self
|
||||
.client
|
||||
.http
|
||||
.post(endpoint_url(
|
||||
&self.client.base_url,
|
||||
&format!("/cloud/environment/{environment_id}/validate"),
|
||||
))
|
||||
.headers(self.client.auth_provider.to_auth_headers())
|
||||
.post(url)
|
||||
.headers(self.client.resolve_auth_headers().await?)
|
||||
.headers(current_trace_context_headers())
|
||||
.json(&EnvironmentRegistryHarnessKeyValidationRequest {
|
||||
executor_registration_id: self.executor_registration_id.clone(),
|
||||
harness_public_key: harness_public_key.clone(),
|
||||
harness_key_authorization: authorization.to_string(),
|
||||
})
|
||||
.json(&body)
|
||||
.send()
|
||||
.await?;
|
||||
let status = response.status();
|
||||
@@ -791,15 +808,21 @@ mod tests {
|
||||
struct StaticRegistryAuthProvider;
|
||||
|
||||
impl AuthProvider for StaticRegistryAuthProvider {
|
||||
fn add_auth_headers(&self, headers: &mut HeaderMap) {
|
||||
let _ = headers.insert(
|
||||
http::header::AUTHORIZATION,
|
||||
HeaderValue::from_static("Bearer registry-token"),
|
||||
);
|
||||
let _ = headers.insert(
|
||||
"ChatGPT-Account-ID",
|
||||
HeaderValue::from_static("workspace-123"),
|
||||
);
|
||||
fn add_auth_headers(&self, _headers: &mut HeaderMap) {}
|
||||
|
||||
fn resolve_auth_headers(&self) -> codex_api::AuthHeadersFuture<'_> {
|
||||
Box::pin(async {
|
||||
let mut headers = HeaderMap::new();
|
||||
let _ = headers.insert(
|
||||
http::header::AUTHORIZATION,
|
||||
HeaderValue::from_static("Bearer registry-token"),
|
||||
);
|
||||
let _ = headers.insert(
|
||||
"ChatGPT-Account-ID",
|
||||
HeaderValue::from_static("workspace-123"),
|
||||
);
|
||||
Ok(headers)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user