Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a2b6771
chore: Remove old tracing stubs
St4NNi May 15, 2026
fdac7f4
feat: Added distributed tracing to create group request
St4NNi May 15, 2026
9c3ab6d
chore: Replaced info with trace and additional tracing events
lfbrehm May 18, 2026
dba3162
feat: Added additional tracing spans for create_group debug
St4NNi May 18, 2026
4e2cd45
fix: Clippy fmt
St4NNi May 18, 2026
978b0d8
chore: Add debug logging for replication
das-Abroxas May 18, 2026
e64a7bc
feat: Add tracing
St4NNi May 18, 2026
f37d537
feat: Timeouts including storage timeouts
St4NNi May 18, 2026
ba71866
fix: bound peer-controlled stream frames
St4NNi May 19, 2026
c96c02a
fix: avoid holding blob connection map during transfers
St4NNi May 19, 2026
8a9f65d
fix: stop receive side when closing streams
St4NNi May 19, 2026
daa8a78
fix: log corrupt DHT storage entries
St4NNi May 19, 2026
6a53d1b
refactor: pool reusable quic connections
St4NNi May 19, 2026
2e3539c
fix: harden quic endpoint and stream handling
St4NNi May 19, 2026
2996673
fix: reduce metadata frame size limit
St4NNi May 19, 2026
776efdc
chore: Clippy fixes
St4NNi May 19, 2026
2d3fcaf
fix: Recursion issue in suboperation
St4NNi May 19, 2026
f4bd13f
refactor: introduce blob head and hash path primitives
das-Abroxas May 22, 2026
6d0b70b
refactor: centralize blob permission path construction
das-Abroxas May 22, 2026
a800dca
refactor: migrate s3 object state to blob keyspaces
das-Abroxas May 22, 2026
0577ae0
feat: persist reference objects as blob versions
das-Abroxas May 22, 2026
2d19e76
feat: replicate reference-backed blob versions on demand
das-Abroxas May 22, 2026
61f82ab
feat: add doctor support for blob keyspaces
das-Abroxas May 22, 2026
5903d90
chore: clippy fixes and fmt
das-Abroxas May 22, 2026
eae140c
feat: add multipart completion deduplication against existing objects
das-Abroxas May 28, 2026
f5b7eeb
fix: increase scan limits in delete bucket/object
das-Abroxas May 28, 2026
99e5928
feat: add missing S3 related keyspaces to aruna-doctor explorer
das-Abroxas May 28, 2026
c361a29
feat: extend granular path-based permission handling for S3 credentials
das-Abroxas May 28, 2026
366e934
chore: cargo clippy fixes and cargo fmt
das-Abroxas May 28, 2026
74733c1
feat: add scoped authorization tests for S3 credentials restrictions
das-Abroxas May 28, 2026
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
71 changes: 10 additions & 61 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 10 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,15 @@ opendal = { version = "0.56", features = [
"services-http",
"services-webdav",
] }
opentelemetry = "0.31.0"
opentelemetry-otlp = { version = "0.31.1", features = ["grpc-tonic"] }
opentelemetry_sdk = { version = "0.31.0", features = ["rt-tokio"] }
opentelemetry = { version = "0.31.0", default-features = false, features = ["trace"] }
opentelemetry-otlp = { version = "0.31.1", default-features = false, features = [
"trace",
"grpc-tonic",
] }
opentelemetry_sdk = { version = "0.31.0", default-features = false, features = [
"trace",
"rt-tokio",
] }
oxrdf = "0.3"
parking_lot = { version = "0.12.5", features = ["deadlock_detection"] }
postcard = { version = "1.1.3", features = ["alloc"] }
Expand All @@ -110,7 +116,7 @@ thiserror = "2.0.18"
tokio = { version = "1.52.1", features = ["full", "tracing"] }
tokio-util = "0.7.18"
tracing = "0.1.44"
tracing-opentelemetry = "0.32.1"
tracing-opentelemetry = { version = "0.32.1", default-features = false }
tracing-subscriber = { version = "0.3.23", features = [
"env-filter",
"time",
Expand Down
56 changes: 52 additions & 4 deletions api/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use crate::error::{OidcError, ServerError, ServerResult, TokenError};
use crate::server_state::ServerState;
use crate::telemetry::record_auth_context;
use aruna_core::errors::ConversionError;
use aruna_core::structs::{AuthContext, OidcProviderConfig, Permission, RealmId, TokenClaims};
use aruna_core::structs::{
AuthContext, OidcProviderConfig, Permission, RealmId, TokenClaims, blob_object_permission_path,
};
use aruna_operations::check_permissions::{CheckPermissionsConfig, CheckPermissionsOperation};
use aruna_operations::driver::drive;
use axum::extract::Request;
Expand Down Expand Up @@ -484,16 +486,21 @@ pub(crate) fn bucket_blob_permission_path(
bucket: &str,
key: &str,
) -> String {
format!(
"/{}/g/{group_id}/data/{}/{bucket}/{key}",
blob_object_permission_path(
state.get_realm_id(),
group_id,
state.get_node_id(),
bucket,
key,
)
}

#[cfg(test)]
mod test {
use crate::auth::{OIDC_PROVIDER_METADATA_CACHE_TTL_SECS, OidcValidator, extract_auth_context};
use crate::auth::{
OIDC_PROVIDER_METADATA_CACHE_TTL_SECS, OidcValidator, bucket_blob_permission_path,
extract_auth_context,
};
use crate::server::ServerState;
use aruna_core::UserId;
use aruna_core::effects::{Effect, StorageEffect};
Expand Down Expand Up @@ -531,6 +538,47 @@ mod test {
use tokio::sync::RwLock;
use ulid::Ulid;

#[tokio::test]
async fn bucket_blob_permission_path_matches_canonical_blob_object_path() {
let storage_dir = tempfile::tempdir().unwrap();
let storage_handle =
storage::FjallStorage::open(storage_dir.path().to_str().unwrap()).unwrap();
let realm_id = RealmId::from_bytes(
*ed25519_dalek::SigningKey::from_bytes(&[7u8; 32])
.verifying_key()
.as_bytes(),
);
let node_id = iroh::SecretKey::generate().public();
let state = ServerState::new(
Arc::new(DriverContext {
storage_handle,
net_handle: None,
blob_handle: None,
automerge_handle: None,
metadata_handle: None,
task_handle: None,
}),
realm_id,
node_id,
NodeCapabilities::local_node(realm_id).unwrap(),
false,
None,
)
.await;

let group_id = Ulid::from_bytes([9u8; 16]);
assert_eq!(
bucket_blob_permission_path(&state, group_id, "bucket", "nested/file.txt"),
aruna_core::structs::blob_object_permission_path(
realm_id,
group_id,
node_id,
"bucket",
"nested/file.txt",
)
);
}

#[derive(Clone)]
struct OidcTestServerState {
issuer: String,
Expand Down
39 changes: 26 additions & 13 deletions api/src/routes/blobs.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use crate::error::{ErrorResponse, ServerError, ServerResult};
use crate::server_state::ServerState;
use aruna_core::NodeId;
use aruna_core::structs::{AuthContext, Permission};
use aruna_core::structs::{
AuthContext, Permission, blob_bucket_permission_path, blob_object_permission_path,
};
use aruna_operations::check_permissions::{CheckPermissionsConfig, CheckPermissionsOperation};
use aruna_operations::driver::drive;
use aruna_operations::replication::protocol::ReplicationMode;
Expand All @@ -16,7 +18,7 @@ use axum::{Extension, Json, Router};
use serde::{Deserialize, Serialize};
use std::str::FromStr;
use std::sync::Arc;
use tracing::{Instrument, info, warn};
use tracing::{Instrument, debug, info, warn};
use utoipa::{OpenApi, ToSchema};

#[derive(OpenApi)]
Expand Down Expand Up @@ -87,17 +89,21 @@ pub async fn replicate_blob(
Ok(None) => return Err(ServerError::NotFound),
};

let mut permission_path = format!(
"/{}/g/{}/data/{}/{}",
state.get_realm_id(),
bucket_info.group_id,
state.get_node_id(),
request.bucket
);
if let Some(path) = request.path.as_deref() {
permission_path.push('/');
permission_path.push_str(path);
}
let permission_path = match request.path.as_deref() {
Some(path) => blob_object_permission_path(
state.get_realm_id(),
bucket_info.group_id,
state.get_node_id(),
&request.bucket,
path,
),
None => blob_bucket_permission_path(
state.get_realm_id(),
bucket_info.group_id,
state.get_node_id(),
&request.bucket,
),
};

let allowed = drive(
CheckPermissionsOperation::new(CheckPermissionsConfig {
Expand Down Expand Up @@ -166,6 +172,13 @@ pub async fn replicate_blob(

tokio::spawn(
async move {
debug!(
bucket = %bucket,
path = ?path,
version_id = ?version_id,
target_node = %target_node_id,
"Starting on-demand replication task"
);
match drive(ReplicateScopeOperation::new(input), &ctx).await {
Ok(Some(Ok(result))) if result.failed == 0 => {
info!(bucket,
Expand Down
Loading
Loading