diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2026-02-03 14:50:22 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2026-02-03 15:18:23 +0000 |
| commit | 874a8abe1d076cfafd9baf919ec23d7d58200698 (patch) | |
| tree | dce0d0d36bddc496ff32f8555a8790d8dc7be7e4 /src/git | |
| parent | 9fd4350c57bbe986ebf65bf3ea4c996572e81884 (diff) | |
| parent | 92a9a3bfe0bc522e8ae411991a366a3a6310d525 (diff) | |
Merge relay.ngit.dev migration: bug fixes and migration tooling
This merge includes critical bug fixes and comprehensive migration tooling
developed during the relay.ngit.dev migration effort.
Bug Fixes:
- Fix git protocol error handling to return HTTP 200 with ERR pkt-line
- Fix naughty list false positives and DNS failure identification
- Fix database query filters in load_existing_events (remove .since())
- Fix OID fetch tracking to distinguish 0 OIDs from successful fetches
- Fix purgatory event source tracking for filtered expiry logging
- Implement OID retry logic for 'not our ref' errors
Migration Tools & Documentation:
- Complete 5-phase migration analysis pipeline with orchestration script
- Phase 1: Event fetching from source relay
- Phase 2: Git sync verification
- Phase 3: Categorization and relay comparison
- Phase 4: Log extraction (parse failures, purgatory expiry)
- Phase 5: Action classification for migration decisions
- Comprehensive migration guide with lessons learned
- Troubleshooting guide for permission and corruption issues
Configuration:
- Add NGIT_LOG_LEVEL configuration option
- Update git throttle limits to 60/minute
- Improve logging throughout for better observability
Diffstat (limited to 'src/git')
| -rw-r--r-- | src/git/handlers.rs | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/src/git/handlers.rs b/src/git/handlers.rs index 017eee4..e3a6ad4 100644 --- a/src/git/handlers.rs +++ b/src/git/handlers.rs | |||
| @@ -99,6 +99,42 @@ pub async fn handle_info_refs( | |||
| 99 | .unwrap()) | 99 | .unwrap()) |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | /// Build an HTTP 200 OK response with an ERR pkt-line for git protocol errors. | ||
| 103 | /// | ||
| 104 | /// Per the git smart HTTP protocol spec, protocol-level errors (like "not our ref") | ||
| 105 | /// should be returned as HTTP 200 OK with the error message in pkt-line format: | ||
| 106 | /// `PKT-LINE("ERR" SP explanation-text)` | ||
| 107 | /// | ||
| 108 | /// This allows git clients to properly parse and display the error message. | ||
| 109 | fn build_git_protocol_error_response( | ||
| 110 | service: GitService, | ||
| 111 | error_message: &str, | ||
| 112 | ) -> Response<Full<Bytes>> { | ||
| 113 | // Format: "ERR <message>\n" | ||
| 114 | let err_content = format!("ERR {}\n", error_message.trim()); | ||
| 115 | let err_pktline = PktLine::data(err_content.as_bytes()).encode(); | ||
| 116 | |||
| 117 | Response::builder() | ||
| 118 | .status(StatusCode::OK) | ||
| 119 | .header("content-type", service.result_content_type()) | ||
| 120 | .header("cache-control", "no-cache") | ||
| 121 | .body(Full::new(Bytes::from(err_pktline))) | ||
| 122 | .unwrap() | ||
| 123 | } | ||
| 124 | |||
| 125 | /// Check if a git process failure is a protocol error (vs transport error). | ||
| 126 | /// | ||
| 127 | /// Protocol errors are communicated via stderr when git exits with code 128. | ||
| 128 | /// These should be returned to the client as HTTP 200 with ERR pkt-line. | ||
| 129 | /// | ||
| 130 | /// Transport errors (process spawn failures, I/O errors, signals) should | ||
| 131 | /// remain as HTTP 500 errors. | ||
| 132 | fn is_git_protocol_error(exit_code: Option<i32>, stderr: &[u8]) -> bool { | ||
| 133 | // Git uses exit code 128 for protocol/usage errors | ||
| 134 | // If there's stderr content, it's a protocol error message | ||
| 135 | exit_code == Some(128) && !stderr.is_empty() | ||
| 136 | } | ||
| 137 | |||
| 102 | /// Handle POST /git-upload-pack (clone/fetch) | 138 | /// Handle POST /git-upload-pack (clone/fetch) |
| 103 | pub async fn handle_upload_pack( | 139 | pub async fn handle_upload_pack( |
| 104 | repo_path: PathBuf, | 140 | repo_path: PathBuf, |
| @@ -150,6 +186,21 @@ pub async fn handle_upload_pack( | |||
| 150 | 186 | ||
| 151 | if !status.success() { | 187 | if !status.success() { |
| 152 | let stderr_str = String::from_utf8_lossy(&stderr_output); | 188 | let stderr_str = String::from_utf8_lossy(&stderr_output); |
| 189 | |||
| 190 | // Check if this is a git protocol error (exit code 128 with stderr) | ||
| 191 | // Protocol errors should be returned as HTTP 200 with ERR pkt-line | ||
| 192 | if is_git_protocol_error(status.code(), &stderr_output) { | ||
| 193 | warn!( | ||
| 194 | "Git upload-pack protocol error (returning ERR pkt-line): {}", | ||
| 195 | stderr_str | ||
| 196 | ); | ||
| 197 | return Ok(build_git_protocol_error_response( | ||
| 198 | GitService::UploadPack, | ||
| 199 | &stderr_str, | ||
| 200 | )); | ||
| 201 | } | ||
| 202 | |||
| 203 | // Transport errors (spawn failures, signals, etc.) remain as HTTP 500 | ||
| 153 | error!("Git upload-pack failed: {}", stderr_str); | 204 | error!("Git upload-pack failed: {}", stderr_str); |
| 154 | return Err(GitError::GitFailed(status.code())); | 205 | return Err(GitError::GitFailed(status.code())); |
| 155 | } | 206 | } |
| @@ -277,6 +328,21 @@ pub async fn handle_receive_pack( | |||
| 277 | 328 | ||
| 278 | if !status.success() { | 329 | if !status.success() { |
| 279 | let stderr_str = String::from_utf8_lossy(&stderr_output); | 330 | let stderr_str = String::from_utf8_lossy(&stderr_output); |
| 331 | |||
| 332 | // Check if this is a git protocol error (exit code 128 with stderr) | ||
| 333 | // Protocol errors should be returned as HTTP 200 with ERR pkt-line | ||
| 334 | if is_git_protocol_error(status.code(), &stderr_output) { | ||
| 335 | warn!( | ||
| 336 | "Git receive-pack protocol error (returning ERR pkt-line): {}", | ||
| 337 | stderr_str | ||
| 338 | ); | ||
| 339 | return Ok(build_git_protocol_error_response( | ||
| 340 | GitService::ReceivePack, | ||
| 341 | &stderr_str, | ||
| 342 | )); | ||
| 343 | } | ||
| 344 | |||
| 345 | // Transport errors (spawn failures, signals, etc.) remain as HTTP 500 | ||
| 280 | error!("Git receive-pack failed: {}", stderr_str); | 346 | error!("Git receive-pack failed: {}", stderr_str); |
| 281 | return Err(GitError::GitFailed(status.code())); | 347 | return Err(GitError::GitFailed(status.code())); |
| 282 | } | 348 | } |