auth: enforce workspace worker credentials over ticket REST
This commit is contained in:
@@ -12,7 +12,7 @@ use crate::auth::{
|
||||
};
|
||||
use crate::catalog::{
|
||||
ConfigBundleRef, CreateWorkerRequest, WorkerDetail, WorkerLifecycleAck, WorkerSummary,
|
||||
WorkingDirectoryRequest, WorkingDirectoryStatus,
|
||||
WorkingDirectoryRequest, WorkingDirectoryStatus, WorkspaceApiRef,
|
||||
};
|
||||
use crate::config_bundle::{ConfigBundle, ConfigBundleAvailability, ConfigBundleSummary};
|
||||
use crate::error::RuntimeError;
|
||||
@@ -193,6 +193,10 @@ fn runtime_http_router_with_optional_auth(
|
||||
)
|
||||
.route("/v1/workers/{worker_id}/input", post(send_worker_input))
|
||||
.route("/v1/workers/{worker_id}/restore", post(restore_worker))
|
||||
.route(
|
||||
"/v1/workers/{worker_id}/workspace-api",
|
||||
post(replace_worker_workspace_api),
|
||||
)
|
||||
.route(
|
||||
"/v1/workers/{worker_id}/completions",
|
||||
post(worker_completions),
|
||||
@@ -282,6 +286,12 @@ pub struct RuntimeHttpWorkerResponse {
|
||||
pub worker: WorkerDetail,
|
||||
}
|
||||
|
||||
/// Replace the Workspace API binding for an existing Worker.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct RuntimeHttpWorkerWorkspaceApiRequest {
|
||||
pub workspace_api: WorkspaceApiRef,
|
||||
}
|
||||
|
||||
/// Worker delete response.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct RuntimeHttpWorkerDeleteResponse {
|
||||
@@ -509,6 +519,28 @@ async fn create_worker(
|
||||
Ok(Json(RuntimeHttpWorkerResponse { worker }))
|
||||
}
|
||||
|
||||
async fn replace_worker_workspace_api(
|
||||
State(state): State<RuntimeHttpState>,
|
||||
auth: Option<Extension<RuntimeAuthContext>>,
|
||||
Path(worker_id): Path<String>,
|
||||
body: Result<Json<RuntimeHttpWorkerWorkspaceApiRequest>, JsonRejection>,
|
||||
) -> RestResult<RuntimeHttpWorkerResponse> {
|
||||
let Json(request) = body.map_err(RuntimeHttpRestError::json_rejection)?;
|
||||
let worker_ref = worker_ref_for(&state.runtime, worker_id)?;
|
||||
let worker = match auth_workspace_scope(&state, auth.as_ref())? {
|
||||
Some(scope) => state.runtime.replace_worker_workspace_api_scoped(
|
||||
&scope,
|
||||
&worker_ref,
|
||||
request.workspace_api,
|
||||
),
|
||||
None => state
|
||||
.runtime
|
||||
.replace_worker_workspace_api(&worker_ref, request.workspace_api),
|
||||
}
|
||||
.map_err(RuntimeHttpRestError::runtime)?;
|
||||
Ok(Json(RuntimeHttpWorkerResponse { worker }))
|
||||
}
|
||||
|
||||
async fn restore_worker(
|
||||
State(state): State<RuntimeHttpState>,
|
||||
auth: Option<Extension<RuntimeAuthContext>>,
|
||||
@@ -960,6 +992,9 @@ fn required_runtime_permission(method: &Method, path: &str) -> Option<&'static s
|
||||
if path.starts_with("/v1/config-bundles") || path.starts_with("/v1/working-directories") {
|
||||
return Some("workers:create");
|
||||
}
|
||||
if path.ends_with("/workspace-api") {
|
||||
return Some("workers:create");
|
||||
}
|
||||
if path.ends_with("/input") || path.ends_with("/restore") {
|
||||
return Some("workers:input");
|
||||
}
|
||||
@@ -1484,6 +1519,17 @@ mod tests {
|
||||
)
|
||||
}
|
||||
|
||||
fn replace_workspace_access_token(
|
||||
&self,
|
||||
_handle: &WorkerExecutionHandle,
|
||||
_access_token: String,
|
||||
) -> WorkerExecutionResult {
|
||||
WorkerExecutionResult::accepted(
|
||||
WorkerExecutionOperation::ReplaceWorkspaceAccessToken,
|
||||
WorkerExecutionRunState::Idle,
|
||||
)
|
||||
}
|
||||
|
||||
fn stop_worker(&self, _handle: &WorkerExecutionHandle) -> WorkerExecutionResult {
|
||||
WorkerExecutionResult::accepted(
|
||||
WorkerExecutionOperation::Stop,
|
||||
@@ -1575,6 +1621,23 @@ mod tests {
|
||||
created.worker.worker_id
|
||||
);
|
||||
|
||||
let response = authed_json_request(
|
||||
app.clone(),
|
||||
Method::POST,
|
||||
&format!("/v1/workers/{}/workspace-api", created.worker.worker_id),
|
||||
token,
|
||||
&RuntimeHttpWorkerWorkspaceApiRequest {
|
||||
workspace_api: WorkspaceApiRef {
|
||||
workspace_id: "local".to_string(),
|
||||
base_url: "http://127.0.0.1:8787".to_string(),
|
||||
runtime_id: None,
|
||||
access_token: Some("workspace-access-token".to_string()),
|
||||
},
|
||||
},
|
||||
)
|
||||
.await;
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
|
||||
let input = WorkerInput::user("hello from backend");
|
||||
let response = authed_json_request(
|
||||
app.clone(),
|
||||
|
||||
Reference in New Issue
Block a user