Files
dsh-web/internal/api/admission_routes_test.go
T

116 lines
4.2 KiB
Go

package api
import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestAdmissionEvidenceUTF8Limit(t *testing.T) {
id := "sha256:" + strings.Repeat("d", 64)
a, sid := runtimeTestAPI(t, func(w http.ResponseWriter, r *http.Request) { writeImageInspect(w, id, "0.2.0-rc.2") })
seedVerifiedImage(t, a, id, "0.2.0-rc.2")
if _, err := a.s.DB.Exec("UPDATE users SET admin=1"); err != nil {
t.Fatal(err)
}
for _, tc := range []struct {
name, evidence string
want int
}{
{"ascii boundary", strings.Repeat("a", 4096), 200},
{"ascii over", strings.Repeat("a", 4097), 400},
{"Chinese regression", strings.Repeat("中", 1400), 400},
{"Chinese below", strings.Repeat("中", 1365), 200},
{"Chinese boundary", strings.Repeat("中", 1365) + "a", 200},
{"Chinese over", strings.Repeat("中", 1365) + "ab", 400},
{"emoji boundary", strings.Repeat("😀", 1024), 200},
{"emoji over", strings.Repeat("😀", 1024) + "a", 400},
{"two byte boundary", strings.Repeat("é", 2048), 200},
{"raw whitespace counts", " " + strings.Repeat("a", 4096), 400},
} {
t.Run(tc.name, func(t *testing.T) {
body, err := json.Marshal(map[string]string{"image_id": id, "state": "compatible", "evidence": tc.evidence})
if err != nil {
t.Fatal(err)
}
w := httptest.NewRecorder()
a.imageAdmission(w, runtimeRequest("POST", "/api/images/admission", string(body), sid))
if w.Code != tc.want {
t.Fatal(w.Code, w.Body.String())
}
if tc.want == 400 && !strings.Contains(w.Body.String(), "4096 UTF-8 bytes") {
t.Fatal(w.Body.String())
}
if tc.want == 200 {
var evidence string
if err := a.s.DB.QueryRow("SELECT evidence FROM image_admissions WHERE image_id=?", id).Scan(&evidence); err != nil || evidence != tc.evidence {
t.Fatal(evidence, err)
}
}
})
}
}
func TestAdmissionRoutesEnforceAuthorization(t *testing.T) {
id := "sha256:" + strings.Repeat("d", 64)
a, sid := runtimeTestAPI(t, func(w http.ResponseWriter, r *http.Request) { writeImageInspect(w, id, "0.2.0-rc.2") })
seedVerifiedImage(t, a, id, "0.2.0-rc.2")
_, csrf, err := a.s.SessionUser(sid)
if err != nil {
t.Fatal(err)
}
body := fmt.Sprintf(`{"image_id":%q,"state":"compatible","evidence":"isolated validation reference"}`, id)
request := func(method, path, payload string, auth, token bool) *httptest.ResponseRecorder {
session := ""
if auth {
session = sid
}
r := runtimeRequest(method, path, payload, session)
r.Header.Set("Origin", "http://panel.test")
if token {
r.Header.Set("X-CSRF-Token", csrf)
}
w := httptest.NewRecorder()
a.Handler().ServeHTTP(w, r)
return w
}
for _, path := range []string{"/api/latest", "/api/compatibility", "/api/intents", "/api/intents/old"} {
if w := request("GET", path, "", true, false); w.Code != 404 {
t.Fatal(path, w.Code, w.Body.String())
}
}
if w := request("POST", "/api/images/admission", body, true, true); w.Code != 403 {
t.Fatal("nonadmin admission", w.Code, w.Body.String())
}
if w := request("POST", "/api/builds", `{"version":"9.8.7","experimental":true}`, true, true); w.Code != 405 {
t.Fatal("nonadmin experiment", w.Code, w.Body.String())
}
if _, err = a.s.DB.Exec("UPDATE users SET admin=1 WHERE id='owner'"); err != nil {
t.Fatal(err)
}
if w := request("POST", "/api/images/admission", body, true, false); w.Code != 403 {
t.Fatal("missing CSRF", w.Code, w.Body.String())
}
if w := request("POST", "/api/images/admission", body, true, true); w.Code != 200 {
t.Fatal("admin admission", w.Code, w.Body.String())
}
for _, payload := range []string{
body + "{}",
body + strings.Repeat(" ", 8192),
fmt.Sprintf(`{"image_id":%q,"state":"compatible","evidence":" "}`, id),
fmt.Sprintf(`{"image_id":%q,"state":"available","evidence":"invalid state"}`, id),
fmt.Sprintf(`{"image_id":%q,"state":"compatible","evidence":"test","dockerfile":"not allowed"}`, id),
} {
if w := request("POST", "/api/images/admission", payload, true, true); w.Code != 400 {
t.Fatal(w.Code, w.Body.String())
}
}
var count int
if err = a.s.DB.QueryRow("SELECT count(*) FROM audit WHERE action='image.admission'").Scan(&count); err != nil || count != 1 {
t.Fatal(count, err)
}
}