mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-05-06 16:57:29 +08:00
Harden gateway auth and file boundaries
This commit is contained in:
93
pkg/api/server_skills_test.go
Normal file
93
pkg/api/server_skills_test.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestImportSkillArchiveFromMultipartSucceedsForSmallArchive(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var archive bytes.Buffer
|
||||
zw := zip.NewWriter(&archive)
|
||||
entry, err := zw.Create("demo/SKILL.md")
|
||||
if err != nil {
|
||||
t.Fatalf("create entry: %v", err)
|
||||
}
|
||||
if _, err := entry.Write([]byte("# Demo\n")); err != nil {
|
||||
t.Fatalf("write entry: %v", err)
|
||||
}
|
||||
if err := zw.Close(); err != nil {
|
||||
t.Fatalf("close zip: %v", err)
|
||||
}
|
||||
|
||||
req := multipartRequest(t, "demo.zip", archive.Bytes())
|
||||
skillsDir := t.TempDir()
|
||||
imported, err := importSkillArchiveFromMultipart(req, skillsDir)
|
||||
if err != nil {
|
||||
t.Fatalf("import archive: %v", err)
|
||||
}
|
||||
if len(imported) != 1 || imported[0] != "demo" {
|
||||
t.Fatalf("unexpected imported skills: %+v", imported)
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(skillsDir, "demo", "SKILL.md")); err != nil {
|
||||
t.Fatalf("expected imported SKILL.md: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractArchiveRejectsOversizedExpandedEntry(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var archive bytes.Buffer
|
||||
zw := zip.NewWriter(&archive)
|
||||
entry, err := zw.Create("demo/SKILL.md")
|
||||
if err != nil {
|
||||
t.Fatalf("create entry: %v", err)
|
||||
}
|
||||
if _, err := entry.Write(bytes.Repeat([]byte("a"), int(skillArchiveMaxSingleFile+1))); err != nil {
|
||||
t.Fatalf("write entry: %v", err)
|
||||
}
|
||||
if err := zw.Close(); err != nil {
|
||||
t.Fatalf("close zip: %v", err)
|
||||
}
|
||||
|
||||
archivePath := filepath.Join(t.TempDir(), "demo.zip")
|
||||
if err := os.WriteFile(archivePath, archive.Bytes(), 0o644); err != nil {
|
||||
t.Fatalf("write archive: %v", err)
|
||||
}
|
||||
err = extractArchive(archivePath, t.TempDir(), &archiveExtractLimits{
|
||||
maxFiles: skillArchiveMaxFiles,
|
||||
maxSingleFile: skillArchiveMaxSingleFile,
|
||||
maxExpanded: skillArchiveMaxExpanded,
|
||||
})
|
||||
if err == nil || !strings.Contains(err.Error(), "size limit") {
|
||||
t.Fatalf("expected size limit error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func multipartRequest(t *testing.T, filename string, body []byte) *http.Request {
|
||||
t.Helper()
|
||||
var form bytes.Buffer
|
||||
mw := multipart.NewWriter(&form)
|
||||
part, err := mw.CreateFormFile("file", filename)
|
||||
if err != nil {
|
||||
t.Fatalf("create form file: %v", err)
|
||||
}
|
||||
if _, err := part.Write(body); err != nil {
|
||||
t.Fatalf("write form file: %v", err)
|
||||
}
|
||||
if err := mw.Close(); err != nil {
|
||||
t.Fatalf("close multipart writer: %v", err)
|
||||
}
|
||||
req := httptest.NewRequest("POST", "/api/skills", &form)
|
||||
req.Header.Set("Content-Type", mw.FormDataContentType())
|
||||
req.ContentLength = int64(form.Len())
|
||||
return req
|
||||
}
|
||||
Reference in New Issue
Block a user