Skip to content

fix(forge): serve extensionless Git HTTP URLs - #319

Merged
tonibergholm merged 2 commits into
mainfrom
fix/forge-extensionless-git
Oct 25, 2026
Merged

tonibergholm merged 2 commits into
mainfrom
fix/forge-extensionless-git

Conversation

@tonibergholm-codento

@tonibergholm-codento tonibergholm-codento commented Oct 25, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

- git clone http://host/owner/repo → 404
+ both repository URL forms use the same Git transport

Accept the optional .git suffix for whitelisted Git requests. Normalize both forms before repository authorization and CGI construction, while keeping REST paths on the API router. Extend the real-Git round trip to clone and push through both forms and check the same missing/private repository refusals.

Closes #318.

Also stop the maintenance test's GC thread before propagating a writer-thread failure. Its prior unwind order could leave CI running indefinitely and hide the actual writer failure.

Evidence

  • Before: the real-Git round trip failed on the extensionless clone with repository ... not found. A repeated container probe cloned the .git URL successfully and returned exit 128 for the same private repository without it.
    After: 25 Git transport tests and 137 library tests pass; formatting, affected-crate Clippy and diff checks pass.

  • Full recorded conformance replay: 24/24 scenarios pass, 0 failed exchanges (4 web exchanges excluded). The rebuilt pinned-toolchain container also passes the original clone probe through both URL forms.

  • Maintenance regression suite: 18/18 pass; affected-crate Clippy, formatting and diff checks pass.

Merge Danger

Door: two-way

Blast Radius: transport

Request classification changes. Tests cover private-repository refusals and REST fallthrough; the existing authorization and CGI owners handle both URL forms.

Summary by CodeRabbit

  • New Features
    • Git repository URLs now work with or without the .git suffix for clone and push operations. Both URL forms access the same repository and follow the same authorization rules.
  • Bug Fixes
    • API paths are handled separately from Git requests, preventing API endpoints from being interpreted as repositories.
    • Requests to missing repositories return the same 404 response whether or not the URL includes .git.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review 🔄 Running since 2026-10-25T13:58:45.700342Z 9d053be Manual request
🔒 Security Review ✅ Completed 2026-10-25T14:02:28.131829Z 9d053be Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: c9b28973-d16c-41dc-a720-1d0c7f6f9f69
Commits

Reviewing files that changed from the base of the PR and between dd563f2 and 9d053be.

Files selected for processing: 1
  • crates/forge/tests/e2e_maintenance.rs

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Walkthrough

The transport parser now accepts whitelisted Git paths with or without .git and routes /api/ paths as non-Git. Tests cover cloning and pushing with both URL forms and missing-repository responses. The maintenance test now joins its pass thread before unwrapping writer results.

Changes: Git transport URL handling

Layer / File(s) Summary
Suffix-aware transport routing
crates/forge/src/transport.rs, docs/superpowers/specs/2026-10-22-p38-forge-design.md
The parser accepts whitelisted Git sub-paths with or without .git and returns NotGit for /api/ paths. The route specification describes both URL forms using the same repository resolution, authorization, and CGI path.
URL-form integration tests
crates/forge/tests/e2e_git.rs
The round-trip test clones and pushes with both URL forms. Missing-repository checks cover upload-pack and receive-pack requests with both forms.

Maintenance writer-test shutdown

Layer / File(s) Summary
Writer and maintenance thread join order
crates/forge/tests/e2e_maintenance.rs
The test collects writer join results, stops and joins the maintenance-pass thread, then unwraps the writer results.

Priority: Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant GitClient
  participant TransportParser
  participant RepositoryAuthorization
  participant GitCGI
  GitClient->>TransportParser: Request repository path with or without .git
  TransportParser->>RepositoryAuthorization: Pass whitelisted Git path
  RepositoryAuthorization->>GitCGI: Use the same repository and CGI path
Loading

Possibly related issues

  • git-agentic/src-control#318: The issue reports extensionless clone requests returning 404; this change adds extensionless Git-path parsing and end-to-end coverage.

Possibly related PRs

  • git-agentic/src-control#304: It introduced the Smart-HTTP transport parser that this change updates for extensionless repository paths.
  • git-agentic/src-control#311: It added the maintenance runner and writer-exclusion test that this change updates to join threads in a different order.
Merge Risk: Minimal · up to 9d053

No concrete merge-blocking defect was identified in the changed behavior.

Security architecture risk: Minimal · up to 9d053

The additional URL form uses the same repository permissions and resource limits as the existing form. No material security regression was found in the reviewed change.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The reachability expansion adds URL aliases for existing repository operations, not a new repository-selection authority. Within the inspected application flow, callers remain limited to live repositories they can access; receive-pack additionally requires repository-write scope and write permission.

Trust Boundaries and Controls

  • observed — Both URL forms retain decoded-name validation and the exact Git subpath whitelist. Token validation, method checks, service selection, scopes, repository visibility, and permissions run before child creation. The child receives a cleared, reconstructed environment, a repository-ID-based PATH_INFO, and REMOTE_USER only after write authorization.

Resilience and Maintainability Implications

  • inferred — Using both aliases concurrently does not create separate admission or lifecycle namespaces: those controls use the resolved repository ID. The shared execution path retains live-state rechecking, disk reservations, startup-failure handling, cancellation, timeout supervision, and child cleanup. No alias-specific mutation or recovery transition was identified.
Pre-merge checks: Passed 3 · Failed 2

Failed Failed checks: 2 warnings

Check name Status Explanation Resolution
Out of Scope Changes check Warning Changes in transport.rs, e2e_git.rs, and the design document (docs/superpowers/specs/2026-10-22-p38-forge-design.md) connect directly to #318. The change in `crates/forge/tests/e2e_maintenance.r… Remove the crates/forge/tests/e2e_maintenance.rs change from this pull request. Move it to its own pull request, with its own linked issue or a clear rationale for the CI fix. Keep the transport, e2e_git, and design-document changes in th…
Docstring Coverage Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 3 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 3 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: Forge now serves Git HTTP URLs without the .git suffix.
Linked Issues check Passed [#318] Requires extensionless and .git Git URLs to reach the same authorization and Git backend. Requires REST routing and private-repository refusals to stay unchanged. Whole-PR diff (merge base to…
Full details: Linked Issues check

Explanation

[#318] Requires extensionless and .git Git URLs to reach the same authorization and Git backend. Requires REST routing and private-repository refusals to stay unchanged. Whole-PR diff (merge base to head) of crates/forge/src/transport.rs shows: (1) parse returns NotGit for any path starting with /api/, so REST paths stay on the API router; (2) the .git suffix is optional when the remainder matches a whitelisted Git sub-path (sub_of(rest) returns Some); (3) both forms build the same GitPath { owner, repo, sub }, so the existing authorization and CGI code receives identical data; (4) a path without suffix and with an unrecognized sub-path returns NotGit. The whole-PR diff of crates/forge/tests/e2e_git.rs clones and pushes through both URL forms in push_then_clone_round_trips. It also checks that missing and private repositories return the same 404 body (Repository not found) for both forms, for upload-pack and receive-pack. Residual note: an owner literally named api now routes to REST for /api/<repo>.git/... paths. The issue asks to preserve REST routing, so this is consistent with the requirement. Test execution results were not independently re-run; the assessment relies on the source diff and the test code.

Full details: Out of Scope Changes check

Explanation

Changes in transport.rs, e2e_git.rs, and the design document (docs/superpowers/specs/2026-10-22-p38-forge-design.md) connect directly to #318. The change in crates/forge/tests/e2e_maintenance.rs (passes_beside_writers_lose_nothing) does not. It reorders writer-thread join results and the maintenance-pass thread join so that writer panics are unwrapped after the GC thread stops. It does not touch Git URL parsing, authorization, or CGI construction. The PR description also presents it as a separate fix ("Also stop the maintenance test's GC thread...") with a separate CI rationale. No linked issue covers this CI hang or the writer-failure propagation, and the PR objectives mention it only as a commit message summary. Demonstrated: the change is unrelated to the linked issue objective.

Resolution

Remove the crates/forge/tests/e2e_maintenance.rs change from this pull request. Move it to its own pull request, with its own linked issue or a clear rationale for the CI fix. Keep the transport, e2e_git, and design-document changes in this pull request.

Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@tonibergholm-codento

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 9d053be3c7

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@tonibergholm
tonibergholm merged commit a44dd0a into main Oct 25, 2026
11 checks passed
@tonibergholm
tonibergholm deleted the fix/forge-extensionless-git branch October 25, 2026 19:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

forge: clone URLs without .git return 404

2 participants