Skip to content
This repository was archived by the owner on Apr 1, 2026. It is now read-only.

Commit 9413921

Browse files
aharvardcraigwalkeruk
authored andcommitted
feat: self-signed HTTPS for goosed server (aaif-goose#7126)
1 parent 21559a5 commit 9413921

File tree

17 files changed

+579
-99
lines changed

17 files changed

+579
-99
lines changed

Cargo.lock

Lines changed: 60 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/goose-server/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,13 @@ rand = "0.9.2"
4747
hex = "0.4.3"
4848
socket2 = "0.6.1"
4949
fs2 = { workspace = true }
50-
rustls = { version = "0.23", features = ["ring"] }
50+
rustls = { version = "0.23", features = ["aws_lc_rs"] }
5151
uuid = { workspace = true }
5252
once_cell = { workspace = true }
5353
dirs = { workspace = true }
54+
rcgen = "0.13"
55+
axum-server = { version = "0.8.0", features = ["tls-rustls"] }
56+
aws-lc-rs = "1.16.0"
5457

5558
[target.'cfg(windows)'.dependencies]
5659
winreg = { version = "0.55.0" }

crates/goose-server/src/auth.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub async fn check_token(
1313
if request.uri().path() == "/status"
1414
|| request.uri().path() == "/mcp-ui-proxy"
1515
|| request.uri().path() == "/mcp-app-proxy"
16+
|| request.uri().path() == "/mcp-app-guest"
1617
{
1718
return Ok(next.run(request).await);
1819
}

crates/goose-server/src/commands/agent.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ use crate::configuration;
22
use crate::state;
33
use anyhow::Result;
44
use axum::middleware;
5+
use axum_server::Handle;
56
use goose_server::auth::check_token;
7+
use goose_server::tls::self_signed_config;
68
use tower_http::cors::{Any, CorsLayer};
79
use tracing::info;
810

9-
// Graceful shutdown signal
1011
#[cfg(unix)]
1112
async fn shutdown_signal() {
1213
use tokio::signal::unix::{signal, SignalKind};
@@ -53,8 +54,17 @@ pub async fn run() -> Result<()> {
5354
))
5455
.layer(cors);
5556

56-
let listener = tokio::net::TcpListener::bind(settings.socket_addr()).await?;
57-
info!("listening on {}", listener.local_addr()?);
57+
let addr = settings.socket_addr();
58+
let tls_setup = self_signed_config().await?;
59+
60+
let handle = Handle::new();
61+
let shutdown_handle = handle.clone();
62+
tokio::spawn(async move {
63+
shutdown_signal().await;
64+
shutdown_handle.graceful_shutdown(None);
65+
});
66+
67+
info!("listening on https://{}", addr);
5868

5969
let tunnel_manager = app_state.tunnel_manager.clone();
6070
tokio::spawn(async move {
@@ -66,8 +76,9 @@ pub async fn run() -> Result<()> {
6676
gateway_manager.check_auto_start().await;
6777
});
6878

69-
axum::serve(listener, app)
70-
.with_graceful_shutdown(shutdown_signal())
79+
axum_server::bind_rustls(addr, tls_setup.config)
80+
.handle(handle)
81+
.serve(app.into_make_service())
7182
.await?;
7283

7384
if goose::otel::otlp::is_otlp_initialized() {

crates/goose-server/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pub mod error;
44
pub mod openapi;
55
pub mod routes;
66
pub mod state;
7+
pub mod tls;
78
pub mod tunnel;
89

910
// Re-export commonly used items

crates/goose-server/src/routes/agent.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,16 @@ async fn update_working_dir(
848848
Ok(StatusCode::OK)
849849
}
850850

851+
async fn ensure_extensions_loaded(state: &AppState, session_id: &str) {
852+
if let Some(_results) = state.take_extension_loading_task(session_id).await {
853+
tracing::debug!(
854+
"Awaited background extension loading for session {} before serving request",
855+
session_id
856+
);
857+
state.remove_extension_loading_task(session_id).await;
858+
}
859+
}
860+
851861
#[utoipa::path(
852862
post,
853863
path = "/agent/read_resource",
@@ -866,6 +876,8 @@ async fn read_resource(
866876
) -> Result<Json<ReadResourceResponse>, StatusCode> {
867877
use rmcp::model::ResourceContents;
868878

879+
ensure_extensions_loaded(&state, &payload.session_id).await;
880+
869881
let agent = state
870882
.get_agent_for_route(payload.session_id.clone())
871883
.await?;
@@ -879,7 +891,16 @@ async fn read_resource(
879891
CancellationToken::default(),
880892
)
881893
.await
882-
.map_err(|_e| StatusCode::INTERNAL_SERVER_ERROR)?;
894+
.map_err(|e| {
895+
tracing::error!(
896+
"read_resource failed for session={}, uri={}, extension={}: {:?}",
897+
payload.session_id,
898+
payload.uri,
899+
payload.extension_name,
900+
e
901+
);
902+
StatusCode::INTERNAL_SERVER_ERROR
903+
})?;
883904

884905
let content = read_result
885906
.contents
@@ -936,6 +957,8 @@ async fn call_tool(
936957
State(state): State<Arc<AppState>>,
937958
Json(payload): Json<CallToolRequest>,
938959
) -> Result<Json<CallToolResponse>, StatusCode> {
960+
ensure_extensions_loaded(&state, &payload.session_id).await;
961+
939962
let agent = state
940963
.get_agent_for_route(payload.session_id.clone())
941964
.await?;

0 commit comments

Comments
 (0)