refactor(bare): enhance security and performance optimizations
- Remove unnecessary sorting in advertise_refs for deterministic output - Add path traversal detection and validation in bare_dir construction - Implement symlink resolution checks to prevent security vulnerabilities - Refactor cache system with CRC validation and improved metrics - Integrate repo-specific cache invalidation using indexed keys - Add comprehensive unit tests for commit operations and diff functionality - Move configuration constants to centralized config module - Optimize string operations in disk cache random value generation - Enhance license detection algorithm with cleaner matching logic - Streamline argument processing in various git operations - Update dependencies including crc32fast and flate2 for performance - Add signal handling capability to tokio runtime configuration
This commit is contained in:
+71
-15
@@ -65,6 +65,12 @@ struct MetricsInner {
|
||||
cache_hit_by_namespace: DashMap<String, AtomicU64>,
|
||||
/// Counter: cache misses by namespace
|
||||
cache_miss_by_namespace: DashMap<String, AtomicU64>,
|
||||
/// Histogram: cache value size in bytes
|
||||
cache_value_size_buckets: DashMap<String, AtomicU64>,
|
||||
/// Counter: rate-limit rejections by repository
|
||||
rate_limit_reject_count: DashMap<String, AtomicU64>,
|
||||
/// Counter: rate-limit acquires by repository
|
||||
rate_limit_acquire_count: DashMap<String, AtomicU64>,
|
||||
}
|
||||
|
||||
static METRICS: OnceLock<Arc<MetricsInner>> = OnceLock::new();
|
||||
@@ -99,6 +105,9 @@ fn metrics() -> &'static Arc<MetricsInner> {
|
||||
cache_eviction_count: DashMap::new(),
|
||||
cache_hit_by_namespace: DashMap::new(),
|
||||
cache_miss_by_namespace: DashMap::new(),
|
||||
cache_value_size_buckets: DashMap::new(),
|
||||
rate_limit_reject_count: DashMap::new(),
|
||||
rate_limit_acquire_count: DashMap::new(),
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -144,7 +153,6 @@ pub fn record_request(method: &str, status_code: &str, duration: Duration) {
|
||||
let m = metrics();
|
||||
let duration_ms = duration.as_millis() as u64;
|
||||
|
||||
// Request count
|
||||
let key = format!("{method}:{status_code}");
|
||||
m.request_count
|
||||
.entry(key)
|
||||
@@ -152,10 +160,8 @@ pub fn record_request(method: &str, status_code: &str, duration: Duration) {
|
||||
.value()
|
||||
.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
// Duration histogram
|
||||
record_duration_bucket(&m.duration_buckets, method, duration_ms);
|
||||
|
||||
// Slow request detection
|
||||
let threshold = m.slow_request_threshold_ms.load(Ordering::Relaxed);
|
||||
if threshold > 0 && duration_ms >= threshold {
|
||||
m.slow_request_count
|
||||
@@ -270,6 +276,46 @@ pub fn record_hook_execution(hook_type: &str, result: &str, duration: Duration)
|
||||
record_duration_bucket(&m.hook_duration_buckets, hook_type, duration_ms);
|
||||
}
|
||||
|
||||
/// Record cache value size distribution (in bytes).
|
||||
pub fn record_cache_value_size(namespace: &str, size: usize) {
|
||||
let m = metrics();
|
||||
record_size_bucket(&m.cache_value_size_buckets, namespace, size as u64);
|
||||
}
|
||||
|
||||
/// Record a rate-limit rejection event.
|
||||
pub fn record_rate_limit_reject(repo: &str) {
|
||||
let m = metrics();
|
||||
m.rate_limit_reject_count
|
||||
.entry(repo.to_string())
|
||||
.or_insert_with(|| AtomicU64::new(0))
|
||||
.value()
|
||||
.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// Record a rate-limit acquire event.
|
||||
pub fn record_rate_limit_acquire(repo: &str) {
|
||||
let m = metrics();
|
||||
m.rate_limit_acquire_count
|
||||
.entry(repo.to_string())
|
||||
.or_insert_with(|| AtomicU64::new(0))
|
||||
.value()
|
||||
.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// Record size distribution buckets (log2-based: 1KB, 4KB, 16KB, ..., 1GB).
|
||||
fn record_size_bucket(map: &DashMap<String, AtomicU64>, label: &str, size: u64) {
|
||||
let buckets = [1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216, 67108864, 268435456, 1073741824];
|
||||
for &bound in &buckets {
|
||||
let key = format!("{label}:le_{bound}");
|
||||
if size <= bound {
|
||||
map.entry(key)
|
||||
.or_insert_with(|| AtomicU64::new(0))
|
||||
.value()
|
||||
.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Escape a string for use as a Prometheus label value.
|
||||
/// Replaces `\` → `\\`, `"` → `\"`, `\n` → `\n` per the Prometheus spec.
|
||||
fn prom_escape(value: &str) -> String {
|
||||
@@ -349,7 +395,6 @@ pub fn render_metrics() -> String {
|
||||
out.push_str("# TYPE gitks_repository_count gauge\n");
|
||||
out.push_str(&format!("gitks_repository_count {repos}\n\n"));
|
||||
|
||||
// gRPC requests
|
||||
render_counter_map(
|
||||
&mut out,
|
||||
"gitks_requests_total",
|
||||
@@ -358,7 +403,6 @@ pub fn render_metrics() -> String {
|
||||
&["method", "status"],
|
||||
);
|
||||
|
||||
// gRPC duration
|
||||
render_histogram(
|
||||
&mut out,
|
||||
"gitks_request_duration_milliseconds",
|
||||
@@ -366,7 +410,6 @@ pub fn render_metrics() -> String {
|
||||
&m.duration_buckets,
|
||||
);
|
||||
|
||||
// Slow requests
|
||||
render_counter_map(
|
||||
&mut out,
|
||||
"gitks_slow_requests_total",
|
||||
@@ -375,7 +418,6 @@ pub fn render_metrics() -> String {
|
||||
&["method"],
|
||||
);
|
||||
|
||||
// Cache
|
||||
let hits = m.cache_hits.load(Ordering::Relaxed);
|
||||
let misses = m.cache_misses.load(Ordering::Relaxed);
|
||||
out.push_str("# HELP gitks_cache_hits_total Cache hit count\n");
|
||||
@@ -385,7 +427,6 @@ pub fn render_metrics() -> String {
|
||||
out.push_str("# TYPE gitks_cache_misses_total counter\n");
|
||||
out.push_str(&format!("gitks_cache_misses_total {misses}\n\n"));
|
||||
|
||||
// Errors
|
||||
render_counter_map(
|
||||
&mut out,
|
||||
"gitks_errors_total",
|
||||
@@ -394,7 +435,6 @@ pub fn render_metrics() -> String {
|
||||
&["kind"],
|
||||
);
|
||||
|
||||
// Git subprocess
|
||||
render_counter_map(
|
||||
&mut out,
|
||||
"gitks_git_cmd_total",
|
||||
@@ -409,7 +449,6 @@ pub fn render_metrics() -> String {
|
||||
&m.git_cmd_duration_buckets,
|
||||
);
|
||||
|
||||
// Cache operations
|
||||
render_counter_map(
|
||||
&mut out,
|
||||
"gitks_cache_ops_total",
|
||||
@@ -424,7 +463,6 @@ pub fn render_metrics() -> String {
|
||||
&m.cache_op_duration_buckets,
|
||||
);
|
||||
|
||||
// Cache evictions by cause and namespace
|
||||
render_counter_map(
|
||||
&mut out,
|
||||
"gitks_cache_evictions_total",
|
||||
@@ -433,7 +471,6 @@ pub fn render_metrics() -> String {
|
||||
&["cause", "namespace"],
|
||||
);
|
||||
|
||||
// Per-namespace cache hits
|
||||
render_counter_map(
|
||||
&mut out,
|
||||
"gitks_cache_hits_by_namespace_total",
|
||||
@@ -442,7 +479,6 @@ pub fn render_metrics() -> String {
|
||||
&["namespace"],
|
||||
);
|
||||
|
||||
// Per-namespace cache misses
|
||||
render_counter_map(
|
||||
&mut out,
|
||||
"gitks_cache_misses_by_namespace_total",
|
||||
@@ -451,7 +487,6 @@ pub fn render_metrics() -> String {
|
||||
&["namespace"],
|
||||
);
|
||||
|
||||
// Hook execution
|
||||
render_counter_map(
|
||||
&mut out,
|
||||
"gitks_hook_executions_total",
|
||||
@@ -466,6 +501,28 @@ pub fn render_metrics() -> String {
|
||||
&m.hook_duration_buckets,
|
||||
);
|
||||
|
||||
render_histogram(
|
||||
&mut out,
|
||||
"gitks_cache_value_size_bytes",
|
||||
"Cache value size distribution in bytes",
|
||||
&m.cache_value_size_buckets,
|
||||
);
|
||||
|
||||
render_counter_map(
|
||||
&mut out,
|
||||
"gitks_rate_limit_rejects_total",
|
||||
"Rate-limit rejections by repository",
|
||||
&m.rate_limit_reject_count,
|
||||
&["repo"],
|
||||
);
|
||||
render_counter_map(
|
||||
&mut out,
|
||||
"gitks_rate_limit_acquires_total",
|
||||
"Rate-limit acquires by repository",
|
||||
&m.rate_limit_acquire_count,
|
||||
&["repo"],
|
||||
);
|
||||
|
||||
out
|
||||
}
|
||||
|
||||
@@ -688,7 +745,6 @@ impl RequestMetrics {
|
||||
let duration_ms = duration.as_millis() as u64;
|
||||
record_request(self.method, status, duration);
|
||||
|
||||
// Slow request warning
|
||||
let threshold = metrics().slow_request_threshold_ms.load(Ordering::Relaxed);
|
||||
if threshold > 0 && duration_ms >= threshold {
|
||||
tracing::warn!(
|
||||
|
||||
Reference in New Issue
Block a user