Skip to content

GitHub connector: gateway drops Location on 302 responses, making archive endpoints unusable #227

Open

Description

@dantevisser

Summary

Requests proxied through a GitHub connector lose the Location header on 302 responses. GitHub's repository-archive endpoints (/tarball, /zipball) always redirect to codeload.github.com, so through the gateway they return a bodyless 302 with nothing to follow, and the archive can never be retrieved.

Reproduction

From inside a Sprite authorised for a GitHub connector whose access policy allows the path:

curl -sS -D - -o /dev/null \
  "https://api.sprites.dev/v1/gateway/github/<conn_id>/repos/<owner>/<repo>/tarball/<ref>"

Response headers:

HTTP/2 302
date: Wed, 19 Aug 2026 07:18:02 GMT
content-length: 0
vary: accept-encoding
cache-control: max-age=0, private, must-revalidate
x-ratelimit-remaining: 4860
content-type: text/html;charset=utf-8; charset=utf-8
server: Fly/d778e1ff4 (2026-08-17)
via: 2 fly.io
fly-request-id: 01M0CE4P4JB2SPJ4T4V6BVHHR7-sin

There is no Location. curl -L consequently follows nothing and writes a zero-byte file, exiting 0.

The same connector against a non-redirecting endpoint works as expected:

curl -sS "https://api.sprites.dev/v1/gateway/github/<conn_id>/repos/<owner>/<repo>/contents/Gemfile"
{"name":"Gemfile","path":"Gemfile","sha":"...","size":3571, ...}

Expected

GitHub's Location (a pre-signed codeload.github.com URL) is passed through so clients can follow the redirect.

Impact

/tarball, /zipball and any other redirecting GitHub endpoint are unreachable through a connector. A connector is not a git transport either, so there is currently no way to get a private repository's source into a Sprite using one. The only redirect-free alternative is fetching blobs individually through /contents, which for a ~3,900-file repository is close to the entire hourly rate limit for a single clone.

Possibly related

Accept: application/vnd.github.raw on a /contents/ request through the gateway returns 406 Not Acceptable. The identical request without that header succeeds and returns JSON, which suggests request headers are not forwarded to the provider.

Environment

sprite CLI 2026-08-14, default base image (Ubuntu 26.04), OAuth GitHub connector with repo scope.

Activity

  1. dantevisser commented on Aug 20, 2026

    @dantevisser
    Author

    as a follow up I've tested this on a custom API connector as well and get a different issue. I'm pasting the AI summary verbatim as I think it more accurately describes it than I can

    Title: Gateway 406s requests whose Accept omits a recognised type, blocking git clone through a custom_api connector

    A custom_api connector pointed at https://github.com/ gets most of the way to a working git clone — then fails on one header.

    The ref advertisement works: GET .../<owner>/<repo>.git/info/refs?service=git-upload-pack returns 200 with application/x-git-upload-pack-advertisement, 300 KB, correct pkt-line framing. Git sends Accept: */* on that one.

    The pack POST 406s, because git sends Accept: application/x-git-upload-pack-result. Varying only the headers on that POST:

    Accept Content-Type result
    application/x-git-upload-pack-result application/x-git-upload-pack-request 406
    application/x-git-upload-pack-result application/octet-stream 406
    */* application/x-git-upload-pack-request 200
    (unset) application/x-git-upload-pack-request 200
    application/x-git-upload-pack-result, */* application/x-git-upload-pack-request 200

    Content-Type is irrelevant — only the Accept value decides it, and adding */* to the list makes the identical request succeed. So this isn't about carrying non-JSON bodies; the gateway does that fine.

    Same check breaks the built-in GitHub connector for GitHub's own media types (Accept: application/vnd.github.diff and .patch on a PR, .raw on /contents/): 200 direct to api.github.com, 406 through the gateway.

    Workarounds: none client-side. Git offers no way to replace its own Accept, and appending a second one via http.extraHeader produces two Accept headers, after which the gateway returns no response at all rather than merging them per RFC 9110 §5.3. The only route left is running your own credential-injecting proxy outside the Sprite, which defeats the purpose of a connector.

    Suggested fix: drop the Accept check, or allowlist the git smart-HTTP types (application/x-git-upload-pack-request/-result, application/x-git-receive-pack-request/-result) and the provider media types. Merging duplicate Accept headers would also restore the client-side workaround.

    Worth fixing because it's the last thing standing between a custom_api connector and credential-free git clone of a private repo into a Sprite — auth injection, path/query forwarding and non-JSON bodies already work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions