Skip to content

Commit f6868b5

Browse files
committed
refactor: remove obsolete code
1 parent b521033 commit f6868b5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+2115
-2997
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ unicode-width = "0.2"
139139
validator = { version = "0.20", features = ["derive"] }
140140

141141
# Caching
142-
moka = { version = "0.12", features = ["sync"] }
142+
moka = { version = "0.12", features = ["future", "sync"] }
143143

144144
# NTP client
145145
rsntp = { version = "4", default-features = false, features = ["chrono", "async"] }

crates/api/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ chrono = { workspace = true }
2929
ed25519-dalek = { workspace = true }
3030
jsonwebtoken = { workspace = true }
3131
metrics-exporter-prometheus = { workspace = true }
32+
moka = { workspace = true }
3233
pem = { workspace = true }
3334
rand = { workspace = true }
3435
serde = { workspace = true }

crates/api/src/audit.rs

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 27 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
//! Audit log handlers.
22
//!
33
//! Audit logs are managed by Ledger's event system. The `list_audit_logs`
4-
//! handler serves paginated events for an organization, while `create_audit_log`
5-
//! is an internal endpoint for ingesting Control-originated events.
4+
//! handler serves paginated events for an organization. Event ingestion
5+
//! is handled directly by Ledger.
66
7-
use std::collections::HashMap;
7+
use std::{collections::HashMap, time::Instant};
88

99
use axum::{
1010
Extension, Json,
1111
extract::{Path, Query, State},
12-
http::StatusCode,
1312
};
14-
use inferadb_control_core::service;
13+
use inferadb_control_core::SdkResultExt;
1514
use inferadb_control_types::Error as CoreError;
16-
use inferadb_ledger_sdk::{EventFilter, EventOutcome, OrganizationSlug, SdkIngestEventEntry};
15+
use inferadb_ledger_sdk::{EventFilter, EventOutcome, OrganizationSlug};
1716
use serde::{Deserialize, Serialize};
1817

18+
use super::common::require_ledger;
1919
use crate::{
2020
handlers::auth::{AppState, Result},
2121
middleware::UserClaims,
@@ -26,8 +26,8 @@ use crate::{
2626
/// Query parameters for listing audit logs.
2727
#[derive(Debug, Deserialize)]
2828
pub struct ListAuditLogsQuery {
29-
/// Maximum entries per page (1..=1000, default 100).
30-
pub limit: Option<u32>,
29+
/// Number of items per page (default 50, max 100).
30+
pub page_size: Option<u32>,
3131
/// Opaque cursor for the next page.
3232
pub page_token: Option<String>,
3333
/// Filter by event type prefix (e.g., `"ledger.vault"`).
@@ -61,42 +61,8 @@ pub struct ListAuditLogsResponse {
6161
pub total_estimate: Option<u64>,
6262
}
6363

64-
/// Request body for creating an audit log entry (internal endpoint).
65-
#[derive(Debug, Deserialize)]
66-
pub struct CreateAuditLogRequest {
67-
/// Organization slug (external identifier).
68-
pub organization: u64,
69-
/// Hierarchical dot-separated event type (e.g., `"control.user.created"`).
70-
pub event_type: String,
71-
/// Who performed the action.
72-
pub principal: String,
73-
/// Outcome: `"success"`, `"failed"`, or `"denied"`.
74-
#[serde(default = "default_outcome")]
75-
pub outcome: String,
76-
/// Action-specific key-value context.
77-
#[serde(default)]
78-
pub details: HashMap<String, String>,
79-
}
80-
81-
fn default_outcome() -> String {
82-
"success".to_string()
83-
}
84-
85-
/// Response from creating an audit log entry.
86-
#[derive(Debug, Serialize)]
87-
pub struct CreateAuditLogResponse {
88-
pub accepted_count: u32,
89-
pub rejected_count: u32,
90-
}
91-
9264
// ── Helpers ─────────────────────────────────────────────────────────
9365

94-
fn require_ledger(
95-
state: &AppState,
96-
) -> std::result::Result<&inferadb_ledger_sdk::LedgerClient, CoreError> {
97-
state.ledger.as_deref().ok_or_else(|| CoreError::internal("Ledger client not configured"))
98-
}
99-
10066
fn format_outcome(outcome: &inferadb_ledger_sdk::EventOutcome) -> String {
10167
match outcome {
10268
EventOutcome::Success => "success".to_string(),
@@ -148,45 +114,41 @@ fn build_event_filter(query: &ListAuditLogsQuery) -> std::result::Result<EventFi
148114
Ok(filter)
149115
}
150116

151-
fn parse_request_outcome(
152-
outcome: &str,
153-
details: &HashMap<String, String>,
154-
) -> std::result::Result<EventOutcome, CoreError> {
155-
match outcome {
156-
"success" => Ok(EventOutcome::Success),
157-
"failed" => Ok(EventOutcome::Failed {
158-
code: details.get("error_code").cloned().unwrap_or_default(),
159-
detail: details.get("error_detail").cloned().unwrap_or_default(),
160-
}),
161-
"denied" => Ok(EventOutcome::Denied {
162-
reason: details.get("denial_reason").cloned().unwrap_or_default(),
163-
}),
164-
_ => Err(CoreError::validation(format!(
165-
"invalid outcome '{outcome}': expected 'success', 'failed', or 'denied'"
166-
))),
167-
}
168-
}
169-
170117
// ── Handlers ────────────────────────────────────────────────────────
171118

172119
/// List audit logs for an organization.
173120
///
174121
/// GET /control/v1/organizations/{org}/audit-logs
175122
pub async fn list_audit_logs(
176123
State(state): State<AppState>,
177-
Extension(_claims): Extension<UserClaims>,
124+
Extension(claims): Extension<UserClaims>,
178125
Path(org): Path<u64>,
179126
Query(query): Query<ListAuditLogsQuery>,
180127
) -> Result<Json<ListAuditLogsResponse>> {
181128
let ledger = require_ledger(&state)?;
182129
let organization = OrganizationSlug::new(org);
183130

131+
// Verify the caller is a member of this organization.
132+
let start = Instant::now();
133+
ledger
134+
.get_organization(organization, claims.user_slug)
135+
.await
136+
.map_sdk_err_instrumented("get_organization", start)?;
137+
184138
let page = if let Some(ref page_token) = query.page_token {
185-
service::audit::list_events_next(ledger, organization, page_token).await?
139+
let start = Instant::now();
140+
ledger
141+
.list_events_next(organization, page_token)
142+
.await
143+
.map_sdk_err_instrumented("list_events_next", start)?
186144
} else {
187145
let filter = build_event_filter(&query)?;
188-
let limit = query.limit.unwrap_or(100).clamp(1, 1000);
189-
service::audit::list_events(ledger, organization, filter, limit).await?
146+
let limit = query.page_size.unwrap_or(50).clamp(1, 100);
147+
let start = Instant::now();
148+
ledger
149+
.list_events(organization, filter, limit)
150+
.await
151+
.map_sdk_err_instrumented("list_events", start)?
190152
};
191153

192154
let entries = page.entries.into_iter().map(sdk_entry_to_response).collect();
@@ -197,28 +159,3 @@ pub async fn list_audit_logs(
197159
total_estimate: page.total_estimate,
198160
}))
199161
}
200-
201-
/// Record an audit log event (internal endpoint).
202-
///
203-
/// POST /internal/audit
204-
pub async fn create_audit_log(
205-
State(state): State<AppState>,
206-
Json(req): Json<CreateAuditLogRequest>,
207-
) -> Result<(StatusCode, Json<CreateAuditLogResponse>)> {
208-
let ledger = require_ledger(&state)?;
209-
let organization = OrganizationSlug::new(req.organization);
210-
let outcome = parse_request_outcome(&req.outcome, &req.details)?;
211-
212-
let event =
213-
SdkIngestEventEntry::new(&req.event_type, &req.principal, outcome).details(req.details);
214-
215-
let result = service::audit::ingest_events(ledger, organization, vec![event]).await?;
216-
217-
Ok((
218-
StatusCode::CREATED,
219-
Json(CreateAuditLogResponse {
220-
accepted_count: result.accepted_count,
221-
rejected_count: result.rejected_count,
222-
}),
223-
))
224-
}

crates/api/src/handlers/auth.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ pub struct AppState {
2424
#[builder(default = std::time::SystemTime::now())]
2525
pub start_time: std::time::SystemTime,
2626
pub email_service: Option<Arc<inferadb_control_core::EmailService>>,
27-
pub control_identity: Option<Arc<inferadb_control_types::ControlIdentity>>,
2827
#[builder(default)]
2928
pub rate_limits: crate::middleware::RateLimitConfig,
3029
/// Ledger SDK client for direct service calls.
@@ -33,9 +32,15 @@ pub struct AppState {
3332
pub blinding_key: Option<Arc<inferadb_ledger_types::EmailBlindingKey>>,
3433
/// WebAuthn instance for passkey ceremony validation.
3534
pub webauthn: Option<Arc<webauthn_rs::Webauthn>>,
36-
/// In-memory challenge store for WebAuthn begin/finish ceremonies.
35+
/// Stateless challenge store for WebAuthn begin/finish ceremonies.
3736
#[builder(default)]
3837
pub challenge_store: inferadb_control_core::webauthn::ChallengeStore,
38+
/// Application-level rate limiter for auth endpoints.
39+
#[builder(default = Arc::new(inferadb_control_core::in_memory_rate_limiter()))]
40+
pub rate_limiter: Arc<inferadb_control_core::InMemoryRateLimiter>,
41+
/// JWKS cache for local JWT validation on read routes.
42+
#[builder(default)]
43+
pub jwks_cache: crate::middleware::JwksCache,
3944
}
4045

4146
impl AppState {

crates/api/src/handlers/auth_v2.rs

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
//! Ledger's token service. These coexist with the old auth handlers
55
//! during migration.
66
7+
use std::time::Instant;
8+
79
use axum::{Json, extract::State};
810
use axum_extra::extract::cookie::{Cookie, CookieJar, SameSite};
911
use inferadb_control_const::auth::{ACCESS_TOKEN_COOKIE_NAME, REFRESH_TOKEN_COOKIE_NAME};
10-
use inferadb_control_core::service;
12+
use inferadb_control_core::SdkResultExt;
1113
use inferadb_control_types::Error as CoreError;
1214
use serde::{Deserialize, Serialize};
1315
use time;
@@ -57,12 +59,21 @@ pub fn set_token_cookies(
5759
jar: CookieJar,
5860
token_pair: &inferadb_ledger_sdk::token::TokenPair,
5961
) -> CookieJar {
62+
// Derive access cookie max-age from token expiry when available,
63+
// falling back to the default constant.
64+
let access_max_age_secs = token_pair
65+
.access_expires_at
66+
.and_then(|expires_at| {
67+
expires_at.duration_since(std::time::SystemTime::now()).ok().map(|d| d.as_secs() as i64)
68+
})
69+
.unwrap_or(ACCESS_COOKIE_MAX_AGE_SECS);
70+
6071
let access_cookie = Cookie::build((ACCESS_TOKEN_COOKIE_NAME, token_pair.access_token.clone()))
6172
.path("/")
6273
.http_only(true)
6374
.secure(true)
6475
.same_site(SameSite::Lax)
65-
.max_age(time::Duration::seconds(ACCESS_COOKIE_MAX_AGE_SECS))
76+
.max_age(time::Duration::seconds(access_max_age_secs))
6677
.build();
6778

6879
let refresh_cookie =
@@ -94,16 +105,22 @@ pub async fn refresh(
94105
jar: CookieJar,
95106
Json(body): Json<RefreshTokenRequest>,
96107
) -> Result<(CookieJar, Json<TokenPairResponse>), ApiError> {
97-
let ledger =
98-
state.ledger.as_ref().ok_or_else(|| CoreError::internal("Ledger client not configured"))?;
108+
let ledger = state
109+
.ledger
110+
.as_deref()
111+
.ok_or_else(|| CoreError::internal("Ledger client not configured"))?;
99112

100113
// Extract refresh token from body or cookie
101114
let refresh_token = body
102115
.refresh_token
103116
.or_else(|| jar.get(REFRESH_TOKEN_COOKIE_NAME).map(|c| c.value().to_string()))
104117
.ok_or_else(|| CoreError::auth("no refresh token provided"))?;
105118

106-
let token_pair = service::session::refresh_token(ledger, &refresh_token).await?;
119+
let start = Instant::now();
120+
let token_pair = ledger
121+
.refresh_token(&refresh_token)
122+
.await
123+
.map_sdk_err_instrumented("refresh_token", start)?;
107124

108125
let response = TokenPairResponse {
109126
access_token: token_pair.access_token.clone(),
@@ -122,15 +139,22 @@ pub async fn logout(
122139
State(state): State<AppState>,
123140
jar: CookieJar,
124141
) -> Result<(CookieJar, Json<LogoutResponse>), ApiError> {
125-
let ledger =
126-
state.ledger.as_ref().ok_or_else(|| CoreError::internal("Ledger client not configured"))?;
142+
let ledger = state
143+
.ledger
144+
.as_deref()
145+
.ok_or_else(|| CoreError::internal("Ledger client not configured"))?;
127146

128147
// Try to revoke the refresh token if present
129148
if let Some(cookie) = jar.get(REFRESH_TOKEN_COOKIE_NAME) {
130149
let refresh_token = cookie.value();
131150
if !refresh_token.is_empty() {
132151
// Best-effort revocation — don't fail the logout if revocation fails
133-
if let Err(e) = service::session::revoke_token(ledger, refresh_token).await {
152+
let start = Instant::now();
153+
if let Err(e) = ledger
154+
.revoke_token(refresh_token)
155+
.await
156+
.map_sdk_err_instrumented("revoke_token", start)
157+
{
134158
tracing::warn!(error = %e, "Failed to revoke refresh token during logout");
135159
}
136160
}
@@ -148,11 +172,16 @@ pub async fn revoke_all(
148172
axum::Extension(claims): axum::Extension<UserClaims>,
149173
jar: CookieJar,
150174
) -> Result<(CookieJar, Json<RevokeAllResponse>), ApiError> {
151-
let ledger =
152-
state.ledger.as_ref().ok_or_else(|| CoreError::internal("Ledger client not configured"))?;
153-
154-
let revoked_count =
155-
service::session::revoke_all_user_sessions(ledger, claims.user_slug).await?;
175+
let ledger = state
176+
.ledger
177+
.as_deref()
178+
.ok_or_else(|| CoreError::internal("Ledger client not configured"))?;
179+
180+
let start = Instant::now();
181+
let revoked_count = ledger
182+
.revoke_all_user_sessions(claims.user_slug)
183+
.await
184+
.map_sdk_err_instrumented("revoke_all_user_sessions", start)?;
156185

157186
let jar = clear_token_cookies(jar);
158187
Ok((jar, Json(RevokeAllResponse { revoked_count })))

0 commit comments

Comments
 (0)