package web
import (
"context"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"craftdesign.group/quarry/internal/ops"
)
type newRepoIn struct {
Name string `json:"name" validate:"max=64"`
Create bool `json:"create"`
}
// The pages run ops in process, past the API router, so a token limited
// to repositories must meet its forge-scope refusal in the ops layer: a
// new-repository form posted on such a token creates nothing, even when
// the name it asks for is the token's own repository.
func TestALimitedTokenCannotCreateARepositoryFromAPage(t *testing.T) {
r := ops.NewRegistry()
created := ""
if err := ops.Register(r, ops.Op[newRepoIn, struct {
Name string `json:"name"`
}]{
Name: "repo.add", Kind: ops.Command, Auth: ops.Token, Route: "POST /api/v1/repos", Doc: "test double",
Run: func(_ context.Context, in newRepoIn) (struct {
Name string `json:"name"`
}, error) {
created = in.Name
return struct {
Name string `json:"name"`
}{in.Name}, nil
},
}); err != nil {
t.Fatal(err)
}
h := HandlerWith(r, nil, nil, []Option{WithSessions(fakeSessions{user: "jan", roles: map[string]ops.Auth{"": ops.Token}})})
post := func(limited bool) int {
req := httptest.NewRequest("POST", "/new", strings.NewReader(url.Values{"name": {"vault"}}.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.AddCookie(&http.Cookie{Name: sessionCookie, Value: "good"})
req = req.WithContext(ops.WithToken(req.Context(), ops.TokenAuth{ID: "T",
Caps: func(string) ops.Caps { return nil }, Limited: limited}))
w := httptest.NewRecorder()
h.ServeHTTP(w, req)
return w.Code
}
if code := post(true); created != "" || code == http.StatusSeeOther {
t.Errorf("FAIL: a [vault]-limited token created %q from the page (%d)", created, code)
} else {
t.Logf("ok: the page's repo.add refuses a limited token (%d)", code)
}
if post(false); created != "vault" {
t.Errorf("FAIL: the form does not work at all, so the refusal above proves nothing")
}
}