Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,424 changes: 693 additions & 731 deletions Cargo.lock

Large diffs are not rendered by default.

20 changes: 10 additions & 10 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
[package]
name = "openbridge"
name = "bridge"
version = "0.1.0"
edition = "2024"

[[bin]]
name = "openbridge"
name = "bridge"
path = "./src/main.rs"

[workspace]
Expand Down Expand Up @@ -33,11 +33,11 @@ time = { version = "0.3.36", features = ["serde"] }
parking_lot = "~0.12"
num-bigint = "~0.4"
# Web deps
actix-web = { version = "~4.11", features = ["rustls-0_23", "cookies"] }
actix-web = { version = "~4.12", features = ["rustls-0_23", "cookies"] }
actix-web-httpauth = "0.8"
actix-files = "0.6.6"
tera = { version = "1.20.0", features= ["builtins"] }
reqwest = { version = "0.12", features = ["stream", "json"] }
reqwest = { version = "0.13", features = ["stream", "json"] }
url = "2.5.0"
toml = "0.9.0"
urlencoding = "2.1.3"
Expand All @@ -62,24 +62,24 @@ regex = "~1.12"
# Error handling
thiserror = "2"
# DB
mongodb = "=3.3"
redis = { version = "0.32", features = ["tokio-comp", "num-bigint"] }
mongodb = "=3.5"
redis = { version = "=1.0.2", features = ["tokio-comp", "num-bigint"] }
#macro
utils = { path = "utils" }
# Kubernetes
kube = { version = "~2.0", features = ["runtime", "derive"], optional = true }
k8s-openapi = { version = "0.26", features = ["latest"], optional = true }
kube = { version = "~3.0", features = ["runtime", "derive"], optional = true }
k8s-openapi = { version = "0.27", features = ["latest"], optional = true }
schemars = { version = "1.0", optional = true }
either = { version = "1.13.0", optional = true }
# memory allocator
mimalloc = "~0.1"
# security
base64 = "~0.22.1"
rand = "~0.9"
uuid = { version = "~1.18", features = ["v4"] }
uuid = { version = "~1.19", features = ["v4"] }

[dev-dependencies]
jsonwebkey = { version = "~0.3", features = ["jwt-convert"] }
jsonwebkey = { version = "~0.4", features = ["jwt-convert"] }

[workspace.dependencies]
quote = "1.0"
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ WORKDIR /app

RUN apt update -y && apt install openssl -y && apt install ca-certificates

COPY --from=builder /app/target/release/openbridge .
COPY --from=builder /app/target/release/bridge .
COPY ./certs ./certs
COPY ./config ./config
COPY ./templates ./templates
Expand All @@ -59,4 +59,4 @@ USER 1001
EXPOSE 8080
EXPOSE 8000

CMD ["./openbridge"]
CMD ["./bridge"]
4 changes: 4 additions & 0 deletions config/services_sample.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
readiness = "/get"
check = true
mcp = false
description = "Postman echo server for testing purposes"

[services.postman-mcp]
url = "https://postman-echo.com"
readiness = "/get"
check = true
mcp = true
description = "Postman echo server for mcp testing purposes"

# Not a service with a readiness check, see services.rs for more details
[services.notebook]
Expand Down Expand Up @@ -39,9 +41,11 @@
readiness = "/"
check = true
show = true
description = "Example.com for testing purposes"

[resources.reddit]
url = "https://www.reddit.com"
readiness = "/"
check = true
show = false
description = "Reddit.com for testing purposes. This is a much longer text description. Blah blah blah blah. Also this resource should not show up in the side menu."
4 changes: 2 additions & 2 deletions doc/architecture.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[← Back](../#OpenBridge)
[← Back](../#Bridge)

# Architecture

Expand All @@ -7,7 +7,7 @@

<br>

### Technology powering OpenBridge
### Technology powering Bridge

- Front-end:
- HTMX
Expand Down
14 changes: 11 additions & 3 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,21 @@ watch-tailwind:
tailwindcss -i ./static/css/input.css -o ./static/css/output.css --minify --watch

watch-rust:
bacon run-long --features "notebook lifecycle"
bacon run-long --features "full"

watch-backend:
bacon . --features "notebook lifecycle"
bacon . --features "full"

watch:
bacon --features "notebook lifecycle"
bacon --features "full"

# -- Local Dev Networking --
start-port-forward:
sudo iptables -t nat -A OUTPUT -p tcp -d 127.255.255.254 --dport 443 -j DNAT --to-destination 127.255.255.254:8080
check-port-forward:
sudo iptables -t nat -L OUTPUT -n -v
stop-port-forward:
sudo iptables -t nat -D OUTPUT -p tcp -d 127.255.255.254 --dport 443 -j DNAT --to-destination 127.255.255.254:8080

# --- Certificates ---
certs:
Expand Down
4 changes: 2 additions & 2 deletions src/auth/openid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ pub fn get_openid_provider(provider: OpenIDProvider) -> Result<&'static OpenID>

pub struct OpenID {
client: OIDC,
reqwest_client: reqwest::Client,
reqwest_client: openidconnect::reqwest::Client,
}

pub static OPENID_W3: OnceLock<OpenID> = OnceLock::new();
Expand All @@ -110,7 +110,7 @@ impl OpenID {
.get(table_name)
.ok_or_else(|| BridgeError::TomlLookupError)?;

let reqwest_client = reqwest::Client::new();
let reqwest_client = openidconnect::reqwest::Client::new();

let provider_metadata = core::CoreProviderMetadata::discover_async(
IssuerUrl::new(oidc.url.to_owned())?,
Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::io::Result;

use mimalloc::MiMalloc;

use openbridge::web::start_server;
use bridge::web::start_server;

#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
Expand Down
2 changes: 1 addition & 1 deletion src/web/bridge_middleware/maintenance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ where
&& let Some(rg) = MAINTENANCE_WINDOWS.try_read()
&& *rg
{
// OpenBridge under maintenance
// Bridge under maintenance
return Box::pin(async move {
Ok(req.into_response(
HttpResponse::Found()
Expand Down
16 changes: 11 additions & 5 deletions src/web/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const LIFECYCLE_TIME: Duration = Duration::from_secs(3600);
#[cfg(all(feature = "notebook", feature = "lifecycle"))]
const SIGTERM_FREQ: Duration = Duration::from_secs(5);

/// Starts the OpenBridge server either with or without TLS. If with TLS, please ensure you have the
/// Starts the Bridge server either with or without TLS. If with TLS, please ensure you have the
/// appropriate certs in the `certs` directory.
///
/// # Example
Expand Down Expand Up @@ -118,7 +118,7 @@ pub async fn start_server(with_tls: bool) -> Result<()> {
let server = HttpServer::new(move || {
let tera_data = Data::new(templating::start_template_eng());
let mut context = Context::new();
context.insert("application", "OpenBridge");
context.insert("application", "Bridge");
context.insert("application_version", "v0.1.0");
context.insert("app_name", &CONFIG.app_name);
context.insert("company", &CONFIG.company);
Expand Down Expand Up @@ -180,13 +180,19 @@ pub async fn start_server(with_tls: bool) -> Result<()> {
})
});

let ip_addr = if cfg!(debug_assertions) {
"127.255.255.254"
} else {
"0.0.0.0"
};

if with_tls {
// Application level https redirect, but only in release mode
let redirect_handle = if cfg!(not(debug_assertions)) {
Some(tokio::spawn(
HttpServer::new(move || App::new().wrap(HttpRedirect))
.workers(1)
.bind(("0.0.0.0", 8000))?
.bind((ip_addr, 8000))?
.run(),
))
} else {
Expand All @@ -195,7 +201,7 @@ pub async fn start_server(with_tls: bool) -> Result<()> {

server
.bind_rustls_0_23(
("0.0.0.0", 8080),
(ip_addr, 8080),
tls::load_certs("certs/fullchain.cer", "certs/open.accelerate.science.key"),
)?
.run()
Expand All @@ -205,7 +211,7 @@ pub async fn start_server(with_tls: bool) -> Result<()> {
handler.await??;
}
} else {
server.bind(("0.0.0.0", 8080))?.run().await?;
server.bind((ip_addr, 8080))?.run().await?;
}

// shutdown signal
Expand Down
31 changes: 25 additions & 6 deletions src/web/route/portal/group_admin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,23 @@ use tera::{Context, Tera};
use tracing::instrument;

use crate::{
auth::COOKIE_NAME, config::CONFIG, db::{
auth::COOKIE_NAME,
config::CONFIG,
db::{
Database,
models::{
AdminTab, AdminTabs, BridgeCookie, GROUP, Group, ModifyUser, NotebookStatusCookie,
OWUICookie, USER, User, UserGroupMod, UserPortalRep, UserType,
},
mongo::DB,
}, errors::{BridgeError, Result}, web::{
},
errors::{BridgeError, Result},
web::{
bridge_middleware::{HTMX_ERROR_RES, Htmx},
helper::{self, bson},
route::portal::helper::check_admin,
route::portal::{helper::check_admin, user_htmx::Subscription},
services::CATALOG,
}
},
};

#[cfg(feature = "notebook")]
Expand Down Expand Up @@ -86,7 +90,22 @@ pub(super) async fn group(
let subscriptions: Result<Group> = db.find(doc! {"name": group_name}, GROUP).await;
let (subs, group_created_at, group_updated_at, group_last_updated) = match subscriptions {
Ok(g) => (
g.subscriptions,
{
let mut sub_details: Vec<Subscription> = Vec::new();

g.subscriptions.iter().for_each(|name| {
if let Some(sub) = CATALOG.get_all().get(name.as_str()) {
sub_details.push(Subscription {
name: name.to_owned(),
kind: sub.0,
kind_designation: if sub.1 { "mcp" } else { "inference" },
description: sub.2,
});
}
});

sub_details
},
g.created_at.to_string(),
g.updated_at.to_string(),
g.last_updated_by.to_string(),
Expand Down Expand Up @@ -118,7 +137,7 @@ pub(super) async fn group(

// add notebook tab if user has a notebook subscription
#[cfg(feature = "notebook")]
let nb_cookies = notebook_bookkeeping(&user, nsc, &mut bridge_cookie, &mut ctx, subs).await?;
let nb_cookies = notebook_bookkeeping(&user, nsc, &mut bridge_cookie, &mut ctx, &subs).await?;

#[cfg(feature = "notebook")]
if let Some(ref conf) = bridge_cookie.config {
Expand Down
17 changes: 8 additions & 9 deletions src/web/route/portal/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ use crate::{
#[cfg(feature = "notebook")]
use k8s_openapi::api::core::v1::Pod;

#[cfg(feature = "notebook")]
use super::user_htmx::Subscription;

#[allow(dead_code)]
#[allow(unused_variables)]
pub(super) fn portal_hygienic_group(gc: &BridgeCookie, doc: &dyn Any) -> Result<bool> {
Expand Down Expand Up @@ -84,22 +87,18 @@ where
#[cfg(feature = "notebook")]
/// This is a helper function that takes care of the notebook setup for all users
/// Is the user does not have access to notebooks, None is returned
pub(super) async fn notebook_bookkeeping<'c, C>(
pub(super) async fn notebook_bookkeeping<'c>(
user: &User,
nsc: Option<ReqData<NotebookStatusCookie>>,
bc: &mut BridgeCookie,
ctx: &mut Context,
subscription: Vec<C>,
) -> Result<Option<[Cookie<'c>; 2]>>
where
C: Deref<Target = str>,
{
subscription: &Vec<Subscription<'c>>,
) -> Result<Option<[Cookie<'c>; 2]>> {
// Check is user is allowed to access the notebook
if subscription
.iter()
.map(Deref::deref)
.collect::<Vec<&str>>()
.contains(&NOTEBOOK_SUB_NAME)
.map(|v| &v.name)
.any(|name| name == NOTEBOOK_SUB_NAME)
{
// For notwbook UI component
let mut user_notebook = Into::<UserNotebook>::into(user);
Expand Down
1 change: 0 additions & 1 deletion src/web/route/portal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ use crate::{

mod group_admin;
mod helper;
mod profile_htmx;
mod system_admin;
mod token;
mod user;
Expand Down
40 changes: 0 additions & 40 deletions src/web/route/portal/profile_htmx.rs

This file was deleted.

4 changes: 2 additions & 2 deletions src/web/route/portal/system_admin/htmx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use tera::Tera;
use crate::errors::Result;

pub struct GroupContent {
pub items: Vec<String>,
pub items: Vec<&'static str>,
}

pub(super) static VIEW_GROUP: &str = "components/group_view.html";
Expand All @@ -16,7 +16,7 @@ impl GroupContent {
Self { items: Vec::new() }
}

pub fn add(&mut self, item: String) {
pub fn add(&mut self, item: &'static str) {
self.items.push(item);
}

Expand Down
Loading