This repository has no description
1package repo
2
3import (
4 "net/http"
5 "net/http/httptest"
6 "net/url"
7 "strings"
8 "testing"
9
10 "github.com/go-chi/chi/v5"
11 "tangled.org/core/appview/config"
12 "tangled.org/core/appview/models"
13 "tangled.org/core/gitutil"
14)
15
16const (
17 testRepoDid = "did:plc:limpet"
18 testRepoOwner = "did:plc:boltless"
19 testRepoRkey = "3kzabcdefghij"
20 testRepoPath = "/boltless.dev/squid"
21)
22
23func TestParseArchiveRequest(t *testing.T) {
24 var (
25 got gitutil.ArchiveParams
26 gotErr error
27 )
28 router := chi.NewRouter()
29 router.Get("/{user}/{repo}"+archiveRoute, func(w http.ResponseWriter, r *http.Request) {
30 got, gotErr = parseArchiveRequest(r)
31 })
32
33 resolvedParams := gitutil.ArchiveParams{
34 Rev: "6f1d3a2b4c5d6e7f8091a2b3c4d5e6f708192a3b",
35 Format: gitutil.ArchiveZip,
36 Prefix: gitutil.ArchivePrefix("").OrDefault("squid", "refs/heads/feat/uni"),
37 }
38 rp := &Repo{config: &config.Config{Core: config.CoreConfig{Dev: true, AppviewHost: "tangled.org"}}}
39 immutable, err := url.Parse(rp.immutableArchiveURL(
40 &models.Repo{Did: testRepoOwner, Rkey: testRepoRkey, Name: "squid", RepoDid: testRepoDid},
41 resolvedParams,
42 ))
43 if err != nil {
44 t.Fatalf("the immutable URL must parse: %v", err)
45 }
46
47 windows := "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
48 targz, zip := gitutil.ArchiveTarGz, gitutil.ArchiveZip
49 cases := []struct {
50 name string
51 path string
52 userAgent string
53 want gitutil.ArchiveParams
54 wantErr bool
55 }{
56 {"short ref", testRepoPath + "/archive/v1.0.0?format=tar.gz", "", gitutil.ArchiveParams{Rev: "v1.0.0", Format: targz}, false},
57 {"full ref unescaped", testRepoPath + "/archive/refs/tags/v1.0.0?prefix=did:plc:boltless", "", gitutil.ArchiveParams{Rev: "refs/tags/v1.0.0", Format: targz, Prefix: "did:plc:boltless"}, false},
58 {"full ref escaped", testRepoPath + "/archive/refs%2Ftags%2Fv1.0.0?prefix=did:plc:boltless", "", gitutil.ArchiveParams{Rev: "refs/tags/v1.0.0", Format: targz, Prefix: "did:plc:boltless"}, false},
59 {"format from suffix", testRepoPath + "/archive/refs/tags/v1.0.0.zip", "", gitutil.ArchiveParams{Rev: "refs/tags/v1.0.0", Format: zip}, false},
60 {"unknown format query with a zip suffix", testRepoPath + "/archive/refs/tags/v1.0.0.zip?format=tar.xz", "", gitutil.ArchiveParams{Rev: "refs/tags/v1.0.0", Format: zip}, false},
61 {"zip for a windows user agent", testRepoPath + "/archive/main?format=tar.xz", windows, gitutil.ArchiveParams{Rev: "main", Format: zip}, false},
62 {"percent in the ref itself", testRepoPath + "/archive/refs/tags/a%252Fb", "", gitutil.ArchiveParams{Rev: "refs/tags/a%2Fb", Format: targz}, false},
63 {"prefix wrapped in slashes", testRepoPath + "/archive/main?prefix=/kelp/", "", gitutil.ArchiveParams{Rev: "main", Format: targz, Prefix: "kelp"}, false},
64 {"traversal escaped", testRepoPath + "/archive/..%2F..%2Fetc", "", gitutil.ArchiveParams{Rev: "../../etc", Format: targz}, false},
65 {"parse deletes a ref query", testRepoPath + "/archive/main?ref=other", "", gitutil.ArchiveParams{Rev: "main", Format: targz}, false},
66 {"our own immutable URL", immutable.RequestURI(), "", resolvedParams, false},
67
68 {"empty ref", testRepoPath + "/archive/", "", gitutil.ArchiveParams{}, true},
69 {"escaped space", testRepoPath + "/archive/refs/tags/a%20b", "", gitutil.ArchiveParams{}, true},
70 {"ref that git would read as an option", testRepoPath + "/archive/--output=%2Ftmp%2Fevil", "", gitutil.ArchiveParams{}, true},
71 }
72
73 for _, tc := range cases {
74 t.Run(tc.name, func(t *testing.T) {
75 got, gotErr = gitutil.ArchiveParams{}, nil
76 path := tc.path
77 if rest, isRepoDid := strings.CutPrefix(path, "/"+testRepoDid); isRepoDid {
78 path = "/" + testRepoOwner + "/" + testRepoRkey + rest
79 }
80
81 req := httptest.NewRequest(http.MethodGet, path, nil)
82 req.Header.Set("User-Agent", tc.userAgent)
83 rec := httptest.NewRecorder()
84 router.ServeHTTP(rec, req)
85
86 if rec.Code != http.StatusOK {
87 t.Fatalf("%s: status = %d, want the archive route to match", path, rec.Code)
88 }
89 if got != tc.want || (gotErr != nil) != tc.wantErr {
90 t.Errorf("params = %+v with err %v, want %+v and rejected = %v", got, gotErr, tc.want, tc.wantErr)
91 }
92 })
93 }
94}