Files
ngit-grasp/bb46-git-http-protocol-test-suite.md
T

779 lines
33 KiB
Markdown

# Git HTTP Smart Protocol Comprehensive Test Suite
**ID:** bb46
## Problem
Production bug discovered: git clone failed because ngit-grasp wasn't decompressing gzip-encoded request bodies that modern git clients send. This reveals a critical gap in testing - we need comprehensive git HTTP smart protocol compliance tests that catch real-world client behavior before production.
Current testing gaps:
- No tests for Content-Encoding variations (gzip, deflate, none)
- No tests across git protocol versions (v0, v1, v2)
- No tests for edge cases (partial clones, large repos, concurrent requests)
- No integration tests with real git clients
- No conformance testing against git's own http-backend behavior
## Plan
### Completed Phases
- [x] Phase 1: Research existing test suites and specifications
- Find git project's own http-backend tests
- Survey cgit, gitea, gitlab test approaches
- Identify RFC/specification compliance requirements
- Document git HTTP smart protocol edge cases
- **Output:** Research Report section in this issue
- [x] Phase 2: Design comprehensive test matrix
- Content-Encoding variations (gzip, deflate, identity, none)
- Git protocol versions (v0, v1, v2)
- Git operations (clone, fetch, push, ls-remote)
- Repository states (empty, large, many refs, shallow)
- Client configurations and versions
- Error conditions (malformed requests, timeouts, auth failures)
- **Output:** Research Report section (test matrix doc not committed)
- [x] Phase 3: Implementation strategy
- Integration test approach using TestRelay fixture
- Real git client testing framework
- Conformance test suite structure
- CI/CD integration plan
- **Output:** Architecture documented in Vision section
- [x] Phase 4: Create test implementation in grasp-audit
- Build git protocol utilities in `grasp-audit/src/git/`
- Implement priority test cases in `grasp-audit/src/specs/grasp01/`
- Add to existing grasp-audit test suite
- **Output:** `grasp-audit/src/git/client.rs`, `grasp-audit/src/specs/grasp01/git_http_protocol.rs`
- [x] Phase 5: MVP - Single test following existing pattern
- Pick minimal test requiring minimal GitClient wrapper
- Follow pattern from `git_clone.rs` and how it's called in ngit-grasp tests
- Validate architecture works end-to-end
- **Output:** Working MVP test demonstrating the pattern
- **Completed:** `grasp-audit/src/git/client.rs`, `grasp-audit/src/specs/grasp01/git_http_protocol.rs`, `tests/git_http_protocol.rs`
### Refined Implementation Plan (Post-MVP)
**MVP Status: ✅ COMPLETE**
- `GitClient` wrapper: `grasp-audit/src/git/client.rs` (238 lines)
- Test function: `grasp-audit/src/specs/grasp01/git_http_protocol.rs` (187 lines)
- Integration test: `tests/git_http_protocol.rs` using `isolated_test!` macro
- Test passes in ~1.5 seconds
**Key Learnings:**
1. Pattern works well - grasp-audit provides test functions, ngit-grasp calls them with TestRelay
2. Using real `git fetch` validates actual client behavior (not synthetic requests)
3. `OwnerStateDataPushed` fixture provides repo with git data ready for testing
4. The `isolated_test!` macro pattern is clean and reusable
### Refined Test Matrix (65 scenarios, reduced from 95)
#### P0 - Critical (15 tests)
| ID | Test | Status | Rationale |
|----|------|--------|-----------|
| P0-01 | `test_gzip_encoded_upload_pack` | ✅ DONE | Caught production bug |
| P0-02 | `test_gzip_encoded_receive_pack` | TODO | Push path validation |
| P0-03 | `test_x_gzip_encoding_variant` | TODO | Git supports "x-gzip" |
| P0-04 | `test_identity_encoding_explicit` | TODO | Explicit no-compression |
| P0-05 | `test_no_encoding_header` | TODO | No header (implicit) |
| P0-06 | `test_truncated_gzip_stream` | TODO | Error handling |
| P0-07 | `test_protocol_v2_negotiation` | TODO | Modern git default |
| P0-08 | `test_protocol_v0_fallback` | TODO | Legacy support |
| P0-09 | `test_clone_basic` | TODO | Core operation |
| P0-10 | `test_fetch_incremental` | TODO | Most common op |
| P0-11 | `test_push_basic` | TODO | Write path |
| P0-12 | `test_ls_remote` | TODO | Ref discovery |
| P0-13 | `test_404_nonexistent_repo` | TODO | Must not return 200 |
| P0-14 | `test_403_unauthorized_push` | TODO | Auth enforcement |
| P0-15 | `test_correct_content_types` | TODO | Protocol compliance |
#### P1 - Important (25 tests)
- Protocol: v1 negotiation, version header parsing
- Operations: shallow clone, partial clone, atomic push
- Repo States: empty repo, many refs (>100), large objects
- HTTP: chunked transfer, large Content-Length, keep-alive
- Errors: malformed pkt-line, invalid Content-Type, timeout
- Concurrent: parallel clones, parallel fetches
#### P2 - Nice to Have (25 tests)
- Advanced: HTTP/2, redirects, cookies
- Security: path traversal, oversized requests
- Performance: large packs, many small fetches
- Edge Cases: peeled refs, symref, capabilities
**Removed from original 95:**
- HTTP Basic auth tests (ngit-grasp uses Nostr auth)
- Half-auth scenarios (not applicable to GRASP)
- Credential helper tests (not applicable)
- Submodule tests (out of scope)
### Fixture Optimization: `GitRepoFixture`
**Problem:** Each test creates new repo (~1-2 seconds). 65 tests = 100+ seconds.
**Solution:** Shared fixture struct:
```rust
pub struct GitRepoFixture {
pub npub: String, // Owner's bech32 pubkey
pub identifier: String, // Repo d-tag
pub relay_domain: String, // HTTP endpoint
pub commit_hash: String, // Existing commit
pub clone_url: String, // Full clone URL
pub announcement: Event, // Repo announcement
pub state_event: Event, // State event
}
```
**Performance Impact:**
| Approach | Time for 65 tests |
|----------|-------------------|
| Per-test fixture | ~100 seconds |
| Shared fixture | ~15 seconds |
| Parallel + shared | ~8 seconds |
### Remaining Implementation Phases
- [ ] Phase 6: P0 Content-Encoding Tests
- `test_gzip_encoded_receive_pack` - Push with gzip
- `test_x_gzip_encoding_variant` - Alternative gzip header
- `test_identity_encoding_explicit` - Explicit identity
- `test_no_encoding_header` - No header (implicit)
- `test_truncated_gzip_stream` - Error handling
- Add `GitClient::with_encoding()` method
- [ ] Phase 7: Protocol Version Tests
- Create `grasp-audit/src/git/pkt_line.rs` module
- `test_protocol_v2_negotiation`
- `test_protocol_v0_fallback`
- `test_protocol_v1_negotiation`
- Add `GitClient::with_protocol_version()` method
- [ ] Phase 8: Core Operations Tests
- Implement `GitRepoFixture` struct
- `test_clone_basic`
- `test_fetch_incremental`
- `test_push_basic`
- `test_ls_remote`
- `test_shallow_clone`
- [ ] Phase 9: Error Handling Tests
- `test_404_nonexistent_repo`
- `test_403_unauthorized_push`
- `test_correct_content_types`
- `test_malformed_pkt_line`
- `test_empty_repo_handling`
- [ ] Phase 10: P1 Tests & Polish
- Implement shared fixture pattern with OnceCell
- Complete remaining P1 tests (20)
- Performance optimization
- Create `docs/reference/git-http-test-matrix.md`
### Infrastructure Needed
**GitClient Enhancements:**
```rust
impl GitClient {
pub fn builder(relay_domain: &str) -> GitClientBuilder;
pub fn with_protocol_version(self, version: u8) -> Self;
pub fn with_encoding(self, encoding: Option<&str>) -> Self;
pub async fn raw_request(&self, method: Method, path: &str,
body: Option<&[u8]>, headers: HeaderMap) -> Result<Response>;
}
```
**New Modules:**
| Module | Purpose |
|--------|---------|
| `grasp-audit/src/git/pkt_line.rs` | Parse pkt-line format |
| `grasp-audit/src/git/protocol.rs` | Protocol version handling |
| `grasp-audit/src/git/fixture.rs` | GitRepoFixture struct |
### Success Metrics
| Metric | Target |
|--------|--------|
| P0 tests passing | 15/15 (100%) |
| P1 tests passing | 25/25 (100%) |
| Single test time | < 2 seconds |
| Full suite time | < 2 minutes |
| CI integration | < 5 minutes |
### Definition of Done
1. All P0 tests passing
2. All P1 tests passing
3. Test matrix documented
4. Tests run in CI
5. Full suite < 2 minutes
6. grasp-audit git module reusable
## Vision
Build comprehensive git HTTP smart protocol compliance tests in grasp-audit that:
1. **Validate GRASP conformance** - Ensure all GRASP implementations fully comply with git HTTP protocol
2. **Catch real-world bugs** - Test with actual git client behavior (gzip, protocol versions, edge cases)
3. **Reusable across implementations** - Any GRASP implementation can use these tests for validation
4. **Extend existing patterns** - Build on grasp-audit's existing HTTP testing infrastructure
### Architecture
```
grasp-audit/
├── src/
│ ├── git/ # NEW: Git protocol utilities
│ │ ├── mod.rs
│ │ ├── pkt_line.rs # Pkt-line parsing
│ │ ├── protocol.rs # Protocol v2 support
│ │ └── client.rs # GitClient wrapper (uses relay_domain)
│ │
│ └── specs/grasp01/
│ ├── git_clone.rs # EXISTING: Basic clone tests
│ ├── git_protocol.rs # NEW: Protocol compliance tests
│ ├── git_fetch.rs # NEW: Fetch protocol tests
│ └── git_push.rs # NEW: Push protocol tests
│
ngit-grasp/
└── tests/
└── git_http_protocol.rs # Calls grasp-audit tests (uses TestRelay)
```
### Integration Pattern
**grasp-audit provides:**
- Protocol utilities (pkt-line parsing, protocol v2)
- Conformance test functions that accept `relay_domain` parameter
- Reusable across any GRASP implementation
**ngit-grasp provides:**
- TestRelay fixture for convenience
- Integration tests that call grasp-audit functions
- Implementation-specific tests
### MVP Approach
Start with ONE test that:
1. Requires minimal GitClient wrapper
2. Follows existing `git_clone.rs` pattern
3. Demonstrates end-to-end architecture
4. Validates the approach before building full suite
## Progress
### 2026-01-23 [Session End] - KNOWLEDGE PRESERVED & READY FOR IMPLEMENTATION
- **Session Goals Achieved:**
- ✅ Researched existing test infrastructure (grasp-audit patterns)
- ✅ Designed comprehensive test matrix (95 scenarios)
- ✅ Made critical architectural decision (tests in grasp-audit, not ngit-grasp)
- ✅ Built and validated MVP (gzip upload-pack test)
- ✅ Preserved all knowledge to work/ directory for next session
- ✅ Refined implementation plan based on MVP learnings
- **Preserved to work/:**
- `work/2026-01-23-bb46-session-summary.md` - Comprehensive session notes
- `work/2026-01-23-bb46-mvp-code.md` - Complete MVP implementation details
- `work/2026-01-23-bb46-implementation-plan.md` - Refined next steps
- All files contain: context, code, rationale, next steps
- **MVP Validation:**
- Test passes: `cargo test --test git_http_protocol test_gzip_encoded_upload_pack`
- Architecture proven: grasp-audit provides reusable conformance tests
- Pattern established: `relay_domain` parameter, follows existing fixtures
- GitClient wrapper validated: minimal, extensible, idiomatic Rust
- **Key Learnings:**
- grasp-audit ALREADY has extensive git HTTP testing infrastructure
- TestRelay is convenience (ngit-grasp), not requirement (grasp-audit uses relay_domain)
- Existing patterns (git_clone.rs, OwnerStateDataPushed) are perfect foundation
- Shell git commands already used in fixtures - no new precedent needed
- **Current Status:**
- Phase 1-3, 5: COMPLETE (Research, Design, Strategy, MVP)
- Phase 4: READY TO START (Full test suite implementation)
- No blockers - clear path forward
- **Next Steps:**
1. Review preserved knowledge in work/ directory
2. Implement remaining 94 test scenarios (prioritize P0 → P1 → P2)
3. Add pkt-line parsing utilities if needed for protocol v2 tests
4. Document test coverage in grasp-audit README
5. Update GRASP-01 spec to require git HTTP protocol compliance
- **Notes:**
- Work can resume immediately from preserved files
- All architectural decisions documented and justified
- MVP proves the approach - scaling to full suite is mechanical
- Fixture optimization opportunity: `OwnerStateDataPushed` could be parameterized for better reuse
### 2026-01-21 [Session 18:00] - MVP COMPLETE ✅
- **MVP Implementation Complete:** All three architect agents completed their work
- **Test Selection (Architect 1):**
- Selected: `test_gzip_encoded_upload_pack_request`
- Rationale: Catches production bug, minimal wrapper needed, follows existing pattern
- Uses existing `OwnerStateDataPushed` fixture
- No new GitClient wrapper needed for MVP - uses reqwest directly
- **GitClient Design (Architect 2):**
- Created minimal wrapper in `grasp-audit/src/git/client.rs`
- Methods: `get_info_refs()`, `upload_pack_gzip()`, `receive_pack_gzip()`
- Builder pattern: `GitClient::builder(relay_domain).with_gzip(true).build()`
- Uses `flate2` for gzip compression
- Follows existing grasp-audit patterns (relay_domain parameter, reqwest client)
- **Implementation (Architect 3):**
- Created: `grasp-audit/src/git/mod.rs` - Module exports
- Created: `grasp-audit/src/git/client.rs` - GitClient wrapper (200+ lines)
- Created: `grasp-audit/src/specs/grasp01/git_http_protocol.rs` - Test file
- Created: `tests/git_http_protocol.rs` - Integration test in ngit-grasp
- Modified: `grasp-audit/Cargo.toml` - Added flate2 dependency
- Modified: `grasp-audit/src/lib.rs` - Exported git module
- Modified: `grasp-audit/src/specs/grasp01/mod.rs` - Exported GitHttpProtocolTests
- **Test Verification:**
- Test passes: `cargo test --test git_http_protocol test_gzip_encoded_upload_pack`
- Validates gzip-encoded request handling (production bug scenario)
- Follows existing pattern: `isolated_test!` macro, TestRelay fixture
- **Architecture Validated:**
- grasp-audit provides test functions accepting `relay_domain` parameter
- ngit-grasp integration tests use TestRelay and call grasp-audit functions
- Pattern is reusable and extensible
- **Next:** Review MVP implementation, then expand to full test suite
### 2026-01-21 [Session 17:30]
- Updated: Issue with vision, architecture, and MVP approach
- Plan: Build MVP with single test following existing pattern
- Next: Architect to plan MVP test selection and implementation
### 2026-01-21 [Session 17:15] - REVISED DECISION
- **DECISION REVERSED:** Tests SHOULD move to grasp-audit
- User clarification: "We want other GRASP implementations to be fully compatible with the git HTTP protocol"
- Key insight: Git HTTP compliance IS part of GRASP conformance, not just implementation detail
- Architect-plan analysis revealed:
- ✅ grasp-audit ALREADY tests HTTP endpoints extensively (CORS, git clone, capabilities)
- ✅ Existing fixture system (`relay_domain` parameter) can support comprehensive git HTTP tests
- ✅ Pattern already exists: `git_clone.rs` makes direct HTTP requests via reqwest
- ✅ Shell git commands already used: `clone_repo()`, `try_push()` in fixtures
- ❌ Previous recommendation was too quick to dismiss - architectural barrier is lower than assessed
- Technical findings:
- grasp-audit's `test-ngit-relay.sh` already manages relay lifecycle
- Tests receive `relay_domain` parameter for HTTP access
- TestRelay is a **convenience**, not a **requirement**
- What's missing: pkt-line parsing, protocol v2 support, comprehensive edge cases
- Proposed architecture:
- Add `grasp-audit/src/git/` module for protocol utilities (pkt_line.rs, protocol.rs, client.rs)
- Expand existing `specs/grasp01/git_clone.rs` with protocol-level validation
- Add new test files: `git_fetch.rs`, `git_push.rs`, `git_protocol.rs`
- ngit-grasp keeps TestRelay for convenience, calls grasp-audit library functions
- Specification clarity needed:
- GRASP-01 spec should explicitly require "Git Smart HTTP protocol as defined in git-scm.com/docs/http-protocol"
- Should require protocol v2 support when client requests it
- Should specify HTTP status codes for error conditions
- Migration path:
- Phase 1: Add git protocol utilities to grasp-audit
- Phase 2: Expand existing tests with protocol-level validation
- Phase 3: ngit-grasp integration tests continue using TestRelay, call grasp-audit functions
- Next: Implement git protocol utilities in grasp-audit, migrate tests
### 2026-01-21 [Session 16:56]
- Fixed: Worktree setup to follow proper start-work conventions
- Issue: Original worktree was created with branch name `bb46` instead of `bb46-git-http-protocol-test-suite`
- Action: Removed incorrect worktree and recreated with proper naming
- Current state:
- ✅ Branch name: `bb46-git-http-protocol-test-suite` (matches issue filename without .md)
- ✅ Worktree directory: `worktrees/bb46-git-http-protocol-test-suite`
- ✅ dcdev-issues symlink: Properly configured and working
- ❌ Test files: Lost during worktree recreation (were untracked)
- Next: Test files need to be recreated from previous session's work
- `tests/git_http_protocol.rs` (18,844 bytes - 50 integration tests)
- `tests/common/git_client.rs` (15,732 bytes - Git client wrapper)
- `docs/reference/git-http-test-matrix.md` (20,169 bytes)
- `docs/explanation/git-integration-test-framework.md` (22,329 bytes)
- Note: Files were created in Session 17:30 but not committed before worktree was incorrectly set up
### 2026-01-21 [Session 16:45] - SUPERSEDED BY SESSION 17:15
- Decision: Keep tests in ngit-grasp, do NOT move to grasp-audit
- Rationale:
- grasp-audit is for GRASP compliance testing (Nostr events, black-box)
- bb46 tests are implementation-specific (HTTP protocol, git client behavior)
- grasp-audit already has sufficient git tests for GRASP-01 compliance
- bb46 tests go beyond spec requirements (protocol versions, gzip, edge cases)
- No other GRASP implementations exist yet to benefit from shared tests
- Architectural analysis:
- grasp-audit scope: Nostr-level compliance via AuditClient
- bb46 tests scope: HTTP-level implementation quality via GitClient
- Scope mismatch would require new abstraction layer and maintenance burden
- Alternative approach: Document test patterns for other implementations to adapt
- Next: Commit tests to ngit-grasp, add reference note to grasp-audit README
### 2026-01-21 [Session 16:27]
- Started work: Created worktree for issue bb46
- Moved test implementation files from root repository to worktree:
- `tests/git_http_protocol.rs` (18,844 bytes)
- `tests/common/git_client.rs` (15,732 bytes)
- `docs/reference/git-http-test-matrix.md` (20,169 bytes)
- `docs/explanation/git-integration-test-framework.md` (22,329 bytes)
- Files are now in worktree as untracked files, ready to be committed
- Next: Review files, add to git, and commit to bb46 branch
### 2026-01-21 [Session 17:30]
- Completed: Phase 3 & 4 - Implementation strategy and test framework
- Created: `docs/explanation/git-integration-test-framework.md` - Comprehensive design document
- Created: `tests/common/git_client.rs` - Git client wrapper with protocol/compression control
- Created: `tests/git_http_protocol.rs` - 50 integration tests covering:
- Protocol versions (v0, v1, v2)
- Content encoding (gzip, uncompressed)
- Git operations (clone, fetch, ls-remote, shallow clone)
- Edge cases (nonexistent repos, timeouts, concurrent clones)
- All 50 tests passing
- Framework features:
- Configurable git client wrapper (protocol version, gzip, timeout)
- Proper test isolation using TestRelay fixture
- Helper functions for repo setup with announcement + state events
- Slow tests marked with `#[ignore]` for CI optimization
### 2026-01-21 [Session 16:00]
- Completed: Phase 1 - Research on existing test suites and specifications
- Analyzed: Git project's HTTP test suite (t55*.sh files)
- Reviewed: Gitea, GitLab test approaches
- Key findings from research:
- Git's t5562-http-backend-content-length.sh is the key reference for Content-Encoding tests
- Git supports both "gzip" and "x-gzip" Content-Encoding values
- Protocol v2 is now default in modern git clients
- Git tests use real Apache httpd via lib-httpd.sh
- Documented: 8 categories of edge cases, specification references
- Output: Research Report section added to this issue
### 2026-01-21 [Session 14:30]
- Completed: Phase 2 - Comprehensive test matrix designed
- Deliverable: `docs/reference/git-http-test-matrix.md`
- Coverage: 95 test scenarios across 10 categories
- Key findings:
- Content-Encoding: 0% coverage (critical gap - caused production bug)
- Protocol Versions: 0% coverage (v2 is default in modern git)
- Git Operations: ~15% coverage (only basic clone tested)
- Error Handling: ~20% coverage (minimal edge cases)
- Prioritization: 25 P0 tests, 40 P1 tests, 30 P2 tests
- Roadmap: 4-week implementation plan with weekly milestones
- Next: Phase 3 - Implementation strategy and test infrastructure
### 2026-01-21 [Session Start]
- Created: Issue created to track comprehensive git HTTP protocol testing
- Context: Discovered gzip decompression bug in production
- Goal: Build test suite that catches real-world client issues before production
## Notes
### General
- Root cause: Modern git clients send gzip-encoded request bodies by default
- Current tests use TestRelay fixture (tests/common/relay.rs:14)
- Need to test against REAL git clients, not just synthetic requests
- Consider using git's own test suite as reference implementation
- Must cover both happy path AND edge cases
- Integration tests should run against live ngit-grasp instance
### Key Learnings from MVP (2026-01-23)
- **Architecture Proven:** grasp-audit pattern works perfectly for git HTTP tests
- Tests accept `relay_domain` parameter (implementation-agnostic)
- ngit-grasp integration tests use TestRelay for convenience
- Pattern is reusable by any GRASP implementation
- **Existing Infrastructure:** grasp-audit already has comprehensive HTTP testing
- See: `src/specs/grasp01/git_clone.rs` - Makes direct HTTP requests via reqwest
- See: `src/fixtures/relay.rs` - `OwnerStateDataPushed` sets up test repos
- See: Shell commands in fixtures - `clone_repo()`, `try_push()` already used
- **Minimal Wrapper Sufficient:** GitClient doesn't need to be complex
- Builder pattern: `GitClient::builder(relay_domain).with_gzip(true).build()`
- Methods: `get_info_refs()`, `upload_pack_gzip()`, `receive_pack_gzip()`
- Uses reqwest (already dependency), flate2 for gzip (minimal addition)
- ~200 lines for MVP - can grow incrementally as tests need more features
- **Fixture Optimization Opportunity:**
- Current: Each test scenario needs separate fixture
- Future: Could parameterize `OwnerStateDataPushed` for different repo states
- Example: `OwnerStateDataPushed::with_commits(5)` vs `::with_many_refs(2000)`
- Tradeoff: Fixture complexity vs test boilerplate
### Preserved Knowledge (2026-01-23)
- **Session Summary:** `work/2026-01-23-bb46-session-summary.md`
- Complete timeline of research → design → decision → MVP
- Rationale for architectural choices
- Links to all relevant files and discussions
- **MVP Implementation:** `work/2026-01-23-bb46-mvp-code.md`
- Full code for GitClient wrapper
- Test implementation details
- Build and test commands
- Architecture diagram
- **Implementation Plan:** `work/2026-01-23-bb46-implementation-plan.md`
- Week-by-week roadmap for remaining 94 tests
- Prioritization: P0 (gzip, protocol versions) → P1 (operations) → P2 (edge cases)
- Fixture design patterns
- CI/CD integration strategy
### Next Session Quick Start
**START HERE:** `work/bb46-next-steps.md` - Read this first for complete action plan and roadmap
**Then review the proposed plan:**
1. `work/bb46-detailed-test-plan.md` - Review the 65-test matrix and priorities
2. `work/bb46-fixture-optimization.md` - Review proposed GitRepoFixture design
3. `work/bb46-architecture.md` - Understand the architecture and patterns
**Then review the MVP implementation:**
1. `grasp-audit/src/git/client.rs` - GitClient wrapper (238 lines)
2. `grasp-audit/src/specs/grasp01/git_http_protocol.rs` - Test pattern to replicate (187 lines)
3. `tests/git_http_protocol.rs` - Integration test example
**Reference materials:**
1. `work/bb46-test-reference-libraries.md` - Git's test suite, specs, edge cases
## Research Report (Phase 1)
### 1. Git Project's Own Test Suite
**Key Test Files (in git/t/):**
| File | Purpose |
|------|---------|
| `t5551-http-fetch-smart.sh` | Core smart HTTP fetch tests |
| `t5541-http-push-smart.sh` | Smart HTTP push tests |
| `t5555-http-smart-common.sh` | Protocol version tests (v0, v1, v2) |
| `t5560-http-backend-noserver.sh` | HTTP backend without server (unit-like) |
| `t5561-http-backend.sh` | Full HTTP backend integration |
| `t5562-http-backend-content-length.sh` | **CRITICAL: Content-Length and gzip tests** |
| `t5539-fetch-http-shallow.sh` | Shallow clone over HTTP |
| `t5559-http-fetch-smart-http2.sh` | HTTP/2 protocol tests |
| `t556x_common` | Shared test helpers |
| `lib-httpd.sh` | Apache httpd test infrastructure |
**What Git Tests:**
- Reference discovery (info/refs?service=git-upload-pack)
- Smart service responses (git-upload-pack, git-receive-pack)
- Content-Type validation (`application/x-git-upload-pack-advertisement`)
- Protocol version negotiation (v0, v1, v2 via Git-Protocol header)
- Authentication (Basic auth, credential helpers)
- Redirects (301, 302)
- Chunked transfer encoding
- Large fetch-pack requests
- Cookie handling
- Error conditions (invalid Content-Type, server errors)
### 2. Content-Encoding Handling (Critical!)
**From git's http-backend.c:**
```c
const char *encoding = getenv("HTTP_CONTENT_ENCODING");
if (encoding && (!strcmp(encoding, "gzip") || !strcmp(encoding, "x-gzip")))
gzipped_request = 1;
```
**From t5562-http-backend-content-length.sh:**
```bash
# Tests gzip-encoded request bodies
test_expect_success GZIP 'fetch gzipped' '
test_env HTTP_CONTENT_ENCODING="gzip" test_http_env upload fetch_body.gz &&
verify_http_result "200 OK"
'
test_expect_success GZIP 'push gzipped' '
test_env HTTP_CONTENT_ENCODING="gzip" test_http_env receive push_body.gz &&
verify_http_result "200 OK"
'
```
**MUST TEST:**
- `Content-Encoding: gzip` - Most common, git client default
- `Content-Encoding: x-gzip` - Alternative gzip identifier
- `Content-Encoding: identity` - Explicit no encoding
- No Content-Encoding header - Implicit identity
- Truncated gzip streams (error handling)
- Empty gzip bodies (error handling)
### 3. Protocol Versions
**Version 0 (Legacy):**
- No Git-Protocol header
- Capabilities in first ref line after NUL byte
- `symref=HEAD:refs/heads/main` in capability line
**Version 1:**
- `Git-Protocol: version=1` header
- Response starts with `version 1` pkt-line
- Same capability format as v0
**Version 2:**
- `Git-Protocol: version=2` header
- Response starts with `version 2` pkt-line
- Capabilities as separate lines (agent, ls-refs, fetch, etc.)
- Stateless by default
- Commands: ls-refs, fetch, server-option, object-info
**From t5555-http-smart-common.sh:**
```bash
test_expect_success 'git upload-pack --advertise-refs: v2' '
cat >expect <<-EOF &&
version 2
agent=FAKE
ls-refs=unborn
fetch=shallow wait-for-done
server-option
object-format=$(test_oid algo)
0000
EOF
GIT_PROTOCOL=version=2 git upload-pack --advertise-refs . >out
'
```
### 4. HTTP Protocol Specification Requirements
**From git-scm.com/docs/http-protocol:**
**Reference Discovery:**
- GET `$GIT_URL/info/refs?service=git-upload-pack`
- Response Content-Type: `application/x-git-upload-pack-advertisement`
- Response must start with `# service=git-upload-pack` pkt-line
- Must include capability declarations on first ref
**Smart Service (upload-pack):**
- POST `$GIT_URL/git-upload-pack`
- Request Content-Type: `application/x-git-upload-pack-request`
- Response Content-Type: `application/x-git-upload-pack-result`
- Cache-Control: no-cache, max-age=0, must-revalidate
**Smart Service (receive-pack):**
- POST `$GIT_URL/git-receive-pack`
- Request Content-Type: `application/x-git-receive-pack-request`
- Response Content-Type: `application/x-git-receive-pack-result`
**Error Handling:**
- 403 Forbidden for disabled services
- 404 Not Found for missing repositories
- Must NOT return 200 OK for non-existent repos
### 5. Edge Cases That MUST Be Tested
**Content-Encoding:**
1. Gzip-encoded POST bodies (clone, fetch, push)
2. x-gzip encoding variant
3. Truncated gzip streams
4. Empty gzip bodies
5. Mixed encoding (gzip request, identity response)
**Protocol Negotiation:**
1. Client requests v2, server supports v2
2. Client requests v2, server only supports v0 (fallback)
3. Client requests v1
4. No version specified (default to v0)
**Repository States:**
1. Empty repository (no refs)
2. Repository with many refs (>2000 tags test in git)
3. Shallow repository
4. Repository with large objects
5. Repository with submodules
**Operations:**
1. Clone (full)
2. Clone (shallow with --depth)
3. Clone (partial with --filter)
4. Fetch (incremental)
5. Fetch (shallow-since, shallow-exclude)
6. Push (standard)
7. Push (atomic)
8. Push (chunked encoding for large packs)
9. ls-remote
**HTTP Edge Cases:**
1. Chunked Transfer-Encoding
2. Large Content-Length values
3. CONTENT_LENGTH overflow (ssize_t boundary)
4. Empty CONTENT_LENGTH
5. HTTP/1.0 vs HTTP/1.1
6. HTTP/2 (if supported)
7. Keep-alive connections
8. Redirects (301, 302)
9. Path traversal attempts (security)
**Authentication:**
1. No auth (public repo)
2. Basic auth required
3. Auth only for push
4. Auth only for objects (half-auth)
5. Invalid credentials
6. Expired credentials
### 6. Other Implementation Approaches
**Gitea:**
- Uses real git client integration tests
- Tests HTTP clone/push with actual git commands
- Tests LFS integration
- Tests SSH and HTTP in parallel
**GitLab:**
- Extensive RSpec tests for git HTTP
- Tests authentication edge cases
- Tests project path variations (.git suffix handling)
- Tests blocked users, expired passwords
- Tests namespace/project creation via push
### 7. Recommendations for Test Approach
**Priority 1 - Critical (Would have caught our bug):**
1. Content-Encoding: gzip for POST bodies
2. Content-Encoding: x-gzip variant
3. Truncated/malformed gzip handling
**Priority 2 - Protocol Compliance:**
1. Protocol version negotiation (v0, v1, v2)
2. Correct Content-Type headers
3. Correct pkt-line format
4. Capability advertisement
**Priority 3 - Operations:**
1. Clone (basic)
2. Clone (shallow)
3. Fetch (incremental)
4. Push (basic)
5. ls-remote
**Priority 4 - Edge Cases:**
1. Empty repository
2. Large repository (many refs)
3. Chunked encoding
4. HTTP/2 (if applicable)
**Test Infrastructure:**
- Use real git client (not mocked requests)
- Test with multiple git versions if possible
- Use TestRelay fixture for isolation
- Consider adapting git's t5562 test approach
### 8. Specification References
| Document | URL |
|----------|-----|
| HTTP Protocol | https://git-scm.com/docs/http-protocol |
| Pack Protocol | https://git-scm.com/docs/pack-protocol |
| Protocol v2 | https://git-scm.com/docs/protocol-v2 |
| Git Test Suite | https://github.com/git/git/tree/master/t |
| RFC 2616 (HTTP/1.1) | https://www.ietf.org/rfc/rfc2616.txt |
| RFC 1952 (GZIP) | https://www.ietf.org/rfc/rfc1952.txt |
### 9. Key Gotchas from Other Implementations
1. **Git's gzip handling:** Uses `HTTP_CONTENT_ENCODING` env var, supports both "gzip" and "x-gzip"
2. **Protocol fallback:** Client may request v2 but server can respond with v0 - client must handle gracefully
3. **Half-auth:** Some servers require auth only for objects, not refs - complex to test
4. **Path normalization:** Must handle `/repo.git` vs `/repo` vs `/repo.git/` consistently
5. **Chunked encoding:** Large pushes use chunked encoding when http.postbuffer is small
6. **Empty repos:** Must handle repos with no refs (capabilities^{} line)
7. **Peeled refs:** Annotated tags must show both tag and peeled object
8. **Symref:** HEAD symref must be communicated in capabilities
### 2026-01-23 [Session 10:00] - Plan Refinement
- **Reviewed:** MVP implementation in bb46 worktree
- **Validated:** Test passes (`cargo test --test git_http_protocol` ~1.5s)
- **Refined:** Test matrix reduced from 95 to 65 scenarios
- Removed: HTTP Basic auth, half-auth, credential helpers, submodules (not applicable to GRASP)
- Kept: All content-encoding, protocol version, core operations, error handling tests
- **Designed:** `GitRepoFixture` struct for fixture optimization
- Estimated performance improvement: 100s → 15s for full suite
- **Created:** Detailed implementation phases 6-10
- Phase 6: P0 Content-Encoding tests
- Phase 7: Protocol version tests (requires pkt-line parser)
- Phase 8: Core operations tests (requires GitRepoFixture)
- Phase 9: Error handling tests
- Phase 10: P1 tests and polish
- **Defined:** Success metrics and definition of done
- **Next:** Merge MVP to main, then implement Phase 6