8f472a0443
- Integrate etcd-client for distributed coordination and leader election - Add remote client macros with proper formatting for all services - Implement RequestMetrics for tracking RPC performance and errors - Add rate limiting mechanism across all service endpoints - Create ElectionRequest and ElectionResult message types for leader election - Add role management with primary/replica switching capabilities - Implement health checker with automatic failover detection - Add repository count metrics for cluster monitoring - Update Cargo.toml with etcd-client and dashmap dependencies - Modify RepoEntry to include read_only flag for replica handling - Implement should_accept_election logic to prevent duplicate elections - Add RoleChangedEvent handling for cluster role updates
85 lines
2.2 KiB
Rust
85 lines
2.2 KiB
Rust
//! Hook content sanitization.
|
|
//!
|
|
//! Validates custom hook scripts to prevent dangerous commands.
|
|
|
|
use crate::error::{GitError, GitResult};
|
|
|
|
/// Commands/patterns that are never allowed in custom hook scripts.
|
|
const FORBIDDEN_PATTERNS: &[&str] = &[
|
|
"rm -rf",
|
|
"rm -r /",
|
|
"chmod 777",
|
|
"chmod 666",
|
|
"mkfs",
|
|
"dd if=",
|
|
":(){ :|:& };:", // fork bomb
|
|
"> /dev/sda",
|
|
"curl -o /",
|
|
"wget -O /",
|
|
"/etc/passwd",
|
|
"/etc/shadow",
|
|
"shutdown",
|
|
"reboot",
|
|
"init 0",
|
|
"init 6",
|
|
"poweroff",
|
|
"halt",
|
|
];
|
|
|
|
/// Maximum hook script size (64KB).
|
|
const MAX_HOOK_SIZE: usize = 65536;
|
|
|
|
/// Validate a custom hook script content for safety.
|
|
pub fn validate_hook_content(content: &str) -> GitResult<()> {
|
|
if content.is_empty() {
|
|
return Err(GitError::InvalidArgument(
|
|
"hook content cannot be empty".into(),
|
|
));
|
|
}
|
|
if content.len() > MAX_HOOK_SIZE {
|
|
return Err(GitError::InvalidArgument(format!(
|
|
"hook content too large (max {} bytes): {} bytes",
|
|
MAX_HOOK_SIZE,
|
|
content.len()
|
|
)));
|
|
}
|
|
let content_lower = content.to_lowercase();
|
|
for pattern in FORBIDDEN_PATTERNS {
|
|
if content_lower.contains(pattern) {
|
|
return Err(GitError::InvalidArgument(format!(
|
|
"hook content contains forbidden pattern: '{pattern}'"
|
|
)));
|
|
}
|
|
}
|
|
if content.contains('\0') {
|
|
return Err(GitError::InvalidArgument(
|
|
"hook content cannot contain null bytes".into(),
|
|
));
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// Validate a hook name (must be a recognized git hook name).
|
|
pub fn validate_hook_name(name: &str) -> GitResult<()> {
|
|
const VALID_HOOK_NAMES: &[&str] = &[
|
|
"pre-receive",
|
|
"update",
|
|
"post-receive",
|
|
"pre-applypatch",
|
|
"applypatch-msg",
|
|
"post-applypatch",
|
|
"pre-commit",
|
|
"prepare-commit-msg",
|
|
"commit-msg",
|
|
"post-commit",
|
|
"pre-auto-gc",
|
|
];
|
|
if !VALID_HOOK_NAMES.contains(&name) {
|
|
return Err(GitError::InvalidArgument(format!(
|
|
"invalid hook name: '{name}'. Must be one of: {}",
|
|
VALID_HOOK_NAMES.join(", ")
|
|
)));
|
|
}
|
|
Ok(())
|
|
}
|