From 727eeb19d42850d0af0b8346677cf2af29fa410c Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Mon, 27 Oct 2025 13:05:18 -0700 Subject: [PATCH 1/2] chore(api-public): return build metadata --- Cargo.lock | 85 +++++++++++++++++++++- Cargo.toml | 3 +- engine/packages/api-public/Cargo.toml | 3 + engine/packages/api-public/build.rs | 13 +++- engine/packages/api-public/src/metadata.rs | 8 +- 5 files changed, 105 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ffd3bfd28b..712365d1e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -581,6 +581,38 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "camino" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.12", +] + [[package]] name = "cc" version = "1.2.30" @@ -2942,6 +2974,15 @@ dependencies = [ "libc", ] +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + [[package]] name = "object" version = "0.36.7" @@ -4086,6 +4127,8 @@ dependencies = [ "tower-http", "tracing", "utoipa", + "vergen", + "vergen-gitcl", ] [[package]] @@ -5073,6 +5116,10 @@ name = "semver" version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +dependencies = [ + "serde", + "serde_core", +] [[package]] name = "sentry" @@ -5195,10 +5242,11 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ + "serde_core", "serde_derive", ] @@ -5211,11 +5259,20 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -5801,7 +5858,9 @@ checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", "itoa 1.0.15", + "libc", "num-conv", + "num_threads", "powerfmt", "serde", "time-core", @@ -6544,8 +6603,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b2bf58be11fc9414104c6d3a2e464163db5ef74b12296bda593cac37b6e4777" dependencies = [ "anyhow", + "cargo_metadata", "derive_builder 0.20.2", + "regex", + "rustc_version", "rustversion", + "time", + "vergen-lib", +] + +[[package]] +name = "vergen-gitcl" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9dfc1de6eb2e08a4ddf152f1b179529638bedc0ea95e6d667c014506377aefe" +dependencies = [ + "anyhow", + "derive_builder 0.20.2", + "rustversion", + "time", + "vergen", "vergen-lib", ] diff --git a/Cargo.toml b/Cargo.toml index bb464b4edd..682e70a9dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,7 +82,8 @@ tracing = "0.1.40" tracing-core = "0.1" tracing-opentelemetry = "0.29" tracing-slog = "0.2" -vergen = "9.0.4" +vergen = { version = "9.0.4", features = ["build", "cargo", "rustc"] } +vergen-gitcl = "1.0.0" reqwest-eventsource = "0.6.0" [workspace.dependencies.sentry] diff --git a/engine/packages/api-public/Cargo.toml b/engine/packages/api-public/Cargo.toml index ad9a71d21c..88cdc25d21 100644 --- a/engine/packages/api-public/Cargo.toml +++ b/engine/packages/api-public/Cargo.toml @@ -33,4 +33,7 @@ tracing.workspace = true utoipa.workspace = true [build-dependencies] +anyhow.workspace = true fs_extra.workspace = true +vergen.workspace = true +vergen-gitcl.workspace = true diff --git a/engine/packages/api-public/build.rs b/engine/packages/api-public/build.rs index d29886f311..36cbe97b44 100644 --- a/engine/packages/api-public/build.rs +++ b/engine/packages/api-public/build.rs @@ -1,9 +1,18 @@ +use anyhow::Result; use fs_extra::dir; use std::env; use std::fs; use std::path::Path; -fn main() { +fn main() -> Result<()> { + // Configure vergen to emit build metadata + vergen::Emitter::default() + .add_instructions(&vergen::BuildBuilder::all_build()?)? + .add_instructions(&vergen::CargoBuilder::all_cargo()?)? + .add_instructions(&vergen::RustcBuilder::all_rustc()?)? + .add_instructions(&vergen_gitcl::GitclBuilder::all_git()?)? + .emit()?; + let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); let out_dir = env::var("OUT_DIR").unwrap(); let ui_dir = Path::new(&out_dir).join("ui"); @@ -39,4 +48,6 @@ fn main() { fs::write(index_html_path, index_html_content).expect("Failed to write index.html"); } + + Ok(()) } diff --git a/engine/packages/api-public/src/metadata.rs b/engine/packages/api-public/src/metadata.rs index c4a7a2cb64..07cdfd8c5d 100644 --- a/engine/packages/api-public/src/metadata.rs +++ b/engine/packages/api-public/src/metadata.rs @@ -12,6 +12,12 @@ pub async fn get_metadata(Extension(ctx): Extension) -> impl IntoRespons Json(json!({ "runtime": "engine", - "version": env!("CARGO_PKG_VERSION") + "version": env!("CARGO_PKG_VERSION"), + "git_sha": env!("VERGEN_GIT_SHA"), + "build_timestamp": env!("VERGEN_BUILD_TIMESTAMP"), + "rustc_version": env!("VERGEN_RUSTC_SEMVER"), + "rustc_host": env!("VERGEN_RUSTC_HOST_TRIPLE"), + "cargo_target": env!("VERGEN_CARGO_TARGET_TRIPLE"), + "cargo_profile": if env!("VERGEN_CARGO_DEBUG") == "true" { "debug" } else { "release" } })) } From 0c63817b1df4068e4f0815c1be5a75a410c9ed4a Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Mon, 27 Oct 2025 17:57:54 -0700 Subject: [PATCH 2/2] chore(guard): move token routing out off inner router for path-based routing --- engine/packages/guard/src/routing/mod.rs | 2 + .../guard/src/routing/pegboard_gateway.rs | 61 ++++++++++++------- 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/engine/packages/guard/src/routing/mod.rs b/engine/packages/guard/src/routing/mod.rs index 6a05134c99..be7bf98582 100644 --- a/engine/packages/guard/src/routing/mod.rs +++ b/engine/packages/guard/src/routing/mod.rs @@ -16,6 +16,8 @@ pub(crate) const X_RIVET_TOKEN: HeaderName = HeaderName::from_static("x-rivet-to pub(crate) const SEC_WEBSOCKET_PROTOCOL: HeaderName = HeaderName::from_static("sec-websocket-protocol"); pub(crate) const WS_PROTOCOL_TARGET: &str = "rivet_target."; +pub(crate) const WS_PROTOCOL_ACTOR: &str = "rivet_actor."; +pub(crate) const WS_PROTOCOL_TOKEN: &str = "rivet_token."; #[derive(Debug, Clone)] pub struct ActorPathInfo { diff --git a/engine/packages/guard/src/routing/pegboard_gateway.rs b/engine/packages/guard/src/routing/pegboard_gateway.rs index c65bbc5c8a..f8c961f34c 100644 --- a/engine/packages/guard/src/routing/pegboard_gateway.rs +++ b/engine/packages/guard/src/routing/pegboard_gateway.rs @@ -5,12 +5,11 @@ use gas::prelude::*; use hyper::header::HeaderName; use rivet_guard_core::proxy_service::{RouteConfig, RouteTarget, RoutingOutput, RoutingTimeout}; -use super::SEC_WEBSOCKET_PROTOCOL; +use super::{SEC_WEBSOCKET_PROTOCOL, WS_PROTOCOL_ACTOR, WS_PROTOCOL_TOKEN, X_RIVET_TOKEN}; use crate::{errors, shared_state::SharedState}; const ACTOR_READY_TIMEOUT: Duration = Duration::from_secs(10); pub const X_RIVET_ACTOR: HeaderName = HeaderName::from_static("x-rivet-actor"); -const WS_PROTOCOL_ACTOR: &str = "rivet_actor."; /// Route requests to actor services using path-based routing #[tracing::instrument(skip_all)] @@ -18,17 +17,15 @@ pub async fn route_request_path_based( ctx: &StandaloneCtx, shared_state: &SharedState, actor_id_str: &str, - _token: Option<&str>, + token: Option<&str>, path: &str, _headers: &hyper::HeaderMap, _is_websocket: bool, ) -> Result> { - // NOTE: Token validation implemented in EE - // Parse actor ID let actor_id = Id::parse(actor_id_str).context("invalid actor id in path")?; - route_request_inner(ctx, shared_state, actor_id, path).await + route_request_inner(ctx, shared_state, actor_id, path, token).await } /// Route requests to actor services based on headers @@ -47,28 +44,39 @@ pub async fn route_request( return Ok(None); } - // Extract actor ID from WebSocket protocol or HTTP header - let actor_id_str = if is_websocket { + // Extract actor ID and token from WebSocket protocol or HTTP headers + let (actor_id_str, token) = if is_websocket { // For WebSocket, parse the sec-websocket-protocol header - headers + let protocols_header = headers .get(SEC_WEBSOCKET_PROTOCOL) .and_then(|protocols| protocols.to_str().ok()) - .and_then(|protocols| { - // Parse protocols to find actor.{id} - protocols - .split(',') - .map(|p| p.trim()) - .find_map(|p| p.strip_prefix(WS_PROTOCOL_ACTOR)) - }) + .ok_or_else(|| { + crate::errors::MissingHeader { + header: "sec-websocket-protocol".to_string(), + } + .build() + })?; + + let protocols: Vec<&str> = protocols_header.split(',').map(|p| p.trim()).collect(); + + let actor_id = protocols + .iter() + .find_map(|p| p.strip_prefix(WS_PROTOCOL_ACTOR)) .ok_or_else(|| { crate::errors::MissingHeader { header: "`rivet_actor.*` protocol in sec-websocket-protocol".to_string(), } .build() - })? + })?; + + let token = protocols + .iter() + .find_map(|p| p.strip_prefix(WS_PROTOCOL_TOKEN)); + + (actor_id, token) } else { - // For HTTP, use the x-rivet-actor header - headers + // For HTTP, use headers + let actor_id = headers .get(X_RIVET_ACTOR) .map(|x| x.to_str()) .transpose() @@ -78,13 +86,21 @@ pub async fn route_request( header: X_RIVET_ACTOR.to_string(), } .build() - })? + })?; + + let token = headers + .get(X_RIVET_TOKEN) + .map(|x| x.to_str()) + .transpose() + .context("invalid x-rivet-token header")?; + + (actor_id, token) }; // Find actor to route to let actor_id = Id::parse(actor_id_str).context("invalid x-rivet-actor header")?; - route_request_inner(ctx, shared_state, actor_id, path).await + route_request_inner(ctx, shared_state, actor_id, path, token).await } async fn route_request_inner( @@ -92,7 +108,10 @@ async fn route_request_inner( shared_state: &SharedState, actor_id: Id, path: &str, + _token: Option<&str>, ) -> Result> { + // NOTE: Token validation implemented in EE + // Route to peer dc where the actor lives if actor_id.label() != ctx.config().dc_label() { tracing::debug!(peer_dc_label=?actor_id.label(), "re-routing actor to peer dc");