diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2026-01-10 02:14:01 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2026-01-10 02:15:22 +0000 |
| commit | 1b6b669b9b82d1f81b887a32055f19c53d3bb8bf (patch) | |
| tree | 3ce1785757cb3f16dfa30d74557042973d3bf53f /src/purgatory/sync/context.rs | |
| parent | 730f430c906c6c2d43ea8f2e5fc3b408a3de128b (diff) | |
Add naughty list for git remotes with persistent SSL/DNS errors
Implement domain-level naughty list tracking for git remotes, reusing the
existing NaughtyListTracker from relay sync. This prevents repeated attempts
to fetch from git domains with persistent infrastructure issues (SSL/TLS
certificate errors, DNS failures).
Changes:
- Updated NaughtyListTracker to track both relay URLs and git domains
- Added git_naughty_list field to RealSyncContext for error classification
- Modified fetch_oids() to classify git fetch errors and record naughty domains
- Updated sync_identifier_next_url() to filter out naughty domains during URL selection
- Added git_naughty_list parameter to ThrottleManager for domain queue processing
- Threaded naughty list through start_sync_loop and all sync functions
- Updated all tests to pass naughty list parameter
The naughty list uses 12-hour expiration (configurable) to allow domains to
recover from infrastructure issues. First occurrence logs WARN, repeats log DEBUG.
Diffstat (limited to 'src/purgatory/sync/context.rs')
| -rw-r--r-- | src/purgatory/sync/context.rs | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/src/purgatory/sync/context.rs b/src/purgatory/sync/context.rs index e61de01..3c2c683 100644 --- a/src/purgatory/sync/context.rs +++ b/src/purgatory/sync/context.rs | |||
| @@ -187,6 +187,9 @@ use tracing::debug; | |||
| 187 | use crate::nostr::builder::SharedDatabase; | 187 | use crate::nostr::builder::SharedDatabase; |
| 188 | use crate::nostr::events::RepositoryState; | 188 | use crate::nostr::events::RepositoryState; |
| 189 | use crate::purgatory::Purgatory; | 189 | use crate::purgatory::Purgatory; |
| 190 | use crate::sync::naughty_list::NaughtyListTracker; | ||
| 191 | |||
| 192 | use super::functions::extract_domain; | ||
| 190 | 193 | ||
| 191 | /// Real implementation of `SyncContext` that connects to actual systems. | 194 | /// Real implementation of `SyncContext` that connects to actual systems. |
| 192 | /// | 195 | /// |
| @@ -210,6 +213,9 @@ pub struct RealSyncContext { | |||
| 210 | 213 | ||
| 211 | /// Local relay for notifying WebSocket subscribers | 214 | /// Local relay for notifying WebSocket subscribers |
| 212 | local_relay: Option<LocalRelay>, | 215 | local_relay: Option<LocalRelay>, |
| 216 | |||
| 217 | /// Naughty list tracker for git remote domains with persistent errors | ||
| 218 | git_naughty_list: Arc<NaughtyListTracker>, | ||
| 213 | } | 219 | } |
| 214 | 220 | ||
| 215 | impl RealSyncContext { | 221 | impl RealSyncContext { |
| @@ -221,12 +227,14 @@ impl RealSyncContext { | |||
| 221 | /// * `git_data_path` - Base path for git repositories | 227 | /// * `git_data_path` - Base path for git repositories |
| 222 | /// * `our_domain` - Our domain to exclude from clone URLs | 228 | /// * `our_domain` - Our domain to exclude from clone URLs |
| 223 | /// * `local_relay` - Local relay for WebSocket notifications | 229 | /// * `local_relay` - Local relay for WebSocket notifications |
| 230 | /// * `git_naughty_list` - Naughty list tracker for git remote domains | ||
| 224 | pub fn new( | 231 | pub fn new( |
| 225 | purgatory: Arc<Purgatory>, | 232 | purgatory: Arc<Purgatory>, |
| 226 | database: SharedDatabase, | 233 | database: SharedDatabase, |
| 227 | git_data_path: PathBuf, | 234 | git_data_path: PathBuf, |
| 228 | our_domain: Option<String>, | 235 | our_domain: Option<String>, |
| 229 | local_relay: Option<LocalRelay>, | 236 | local_relay: Option<LocalRelay>, |
| 237 | git_naughty_list: Arc<NaughtyListTracker>, | ||
| 230 | ) -> Self { | 238 | ) -> Self { |
| 231 | Self { | 239 | Self { |
| 232 | purgatory, | 240 | purgatory, |
| @@ -234,8 +242,14 @@ impl RealSyncContext { | |||
| 234 | git_data_path, | 242 | git_data_path, |
| 235 | our_domain_value: our_domain, | 243 | our_domain_value: our_domain, |
| 236 | local_relay, | 244 | local_relay, |
| 245 | git_naughty_list, | ||
| 237 | } | 246 | } |
| 238 | } | 247 | } |
| 248 | |||
| 249 | /// Get reference to the git naughty list tracker | ||
| 250 | pub fn git_naughty_list(&self) -> &Arc<NaughtyListTracker> { | ||
| 251 | &self.git_naughty_list | ||
| 252 | } | ||
| 239 | } | 253 | } |
| 240 | 254 | ||
| 241 | #[async_trait] | 255 | #[async_trait] |
| @@ -344,6 +358,7 @@ impl SyncContext for RealSyncContext { | |||
| 344 | let repo_path = repo_path.to_path_buf(); | 358 | let repo_path = repo_path.to_path_buf(); |
| 345 | let url = url.to_string(); | 359 | let url = url.to_string(); |
| 346 | let missing_oids: Vec<String> = missing.into_iter().cloned().collect(); | 360 | let missing_oids: Vec<String> = missing.into_iter().cloned().collect(); |
| 361 | let naughty_list = self.git_naughty_list.clone(); | ||
| 347 | 362 | ||
| 348 | tokio::task::spawn_blocking(move || -> Result<Vec<String>> { | 363 | tokio::task::spawn_blocking(move || -> Result<Vec<String>> { |
| 349 | // git fetch <remote> <sha1> <sha2> ... - fetch all OIDs in one command | 364 | // git fetch <remote> <sha1> <sha2> ... - fetch all OIDs in one command |
| @@ -370,6 +385,29 @@ impl SyncContext for RealSyncContext { | |||
| 370 | } | 385 | } |
| 371 | Ok(result) => { | 386 | Ok(result) => { |
| 372 | let stderr = String::from_utf8_lossy(&result.stderr); | 387 | let stderr = String::from_utf8_lossy(&result.stderr); |
| 388 | |||
| 389 | // Extract domain and classify error for naughty list | ||
| 390 | if let Some(domain) = extract_domain(&url) { | ||
| 391 | if let Some(category) = NaughtyListTracker::classify_error(&stderr) { | ||
| 392 | let is_new = naughty_list.record(&domain, category, stderr.to_string()); | ||
| 393 | |||
| 394 | if is_new { | ||
| 395 | tracing::warn!( | ||
| 396 | domain = %domain, | ||
| 397 | category = %category, | ||
| 398 | error = %stderr, | ||
| 399 | "Git remote domain added to naughty list" | ||
| 400 | ); | ||
| 401 | } else { | ||
| 402 | debug!( | ||
| 403 | domain = %domain, | ||
| 404 | category = %category, | ||
| 405 | "Git remote domain still on naughty list" | ||
| 406 | ); | ||
| 407 | } | ||
| 408 | } | ||
| 409 | } | ||
| 410 | |||
| 373 | Err(anyhow::anyhow!("git fetch failed: {}", stderr)) | 411 | Err(anyhow::anyhow!("git fetch failed: {}", stderr)) |
| 374 | } | 412 | } |
| 375 | Err(e) => Err(anyhow::anyhow!("git fetch command error: {}", e)), | 413 | Err(e) => Err(anyhow::anyhow!("git fetch command error: {}", e)), |