engine/hmr_test.go
Rama main · réplica de lectura del repositorio original.
package engine
import (
"net/http/httptest"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
)
// Path components of ".." must not escape the server root (CWE-22).
func TestHMRUpdateHandlerRejectsTraversal(t *testing.T) {
root := t.TempDir()
ac := &Config{serverDirOrFilename: root}
req := httptest.NewRequest("GET", hmrUpdatePrefix+"../../etc/passwd", nil)
w := httptest.NewRecorder()
ac.HMRUpdateHandler(w, req)
if w.Code != 403 {
t.Errorf("Expected 403 for traversal attempt, got %d", w.Code)
}
}
// A symlink in the server root pointing outside it must not be served.
func TestHMRUpdateHandlerRejectsSymlinkEscape(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Symlink creation typically requires elevated privileges on Windows")
}
outside := t.TempDir()
secretPath := filepath.Join(outside, "secret.js")
if err := os.WriteFile(secretPath, []byte("export const secret = 42;\n"), 0o600); err != nil {
t.Fatalf("Failed writing secret file: %s", err)
}
root := t.TempDir()
linkPath := filepath.Join(root, "leak.js")
if err := os.Symlink(secretPath, linkPath); err != nil {
t.Fatalf("Failed creating symlink: %s", err)
}
ac := &Config{serverDirOrFilename: root}
req := httptest.NewRequest("GET", hmrUpdatePrefix+"leak.js", nil)
w := httptest.NewRecorder()
ac.HMRUpdateHandler(w, req)
if w.Code != 403 {
t.Errorf("Expected 403 for symlink escape, got %d (body: %s)", w.Code, w.Body.String())
}
}
// A request with no path after the HMR prefix must return 400.
func TestHMRUpdateHandlerMissingPath(t *testing.T) {
ac := &Config{serverDirOrFilename: t.TempDir()}
req := httptest.NewRequest("GET", hmrUpdatePrefix, nil)
w := httptest.NewRecorder()
ac.HMRUpdateHandler(w, req)
if w.Code != 400 {
t.Errorf("Expected 400 for missing path, got %d", w.Code)
}
}
// An absolute path supplied by the client must be refused.
func TestHMRUpdateHandlerRejectsAbsolutePath(t *testing.T) {
ac := &Config{serverDirOrFilename: t.TempDir()}
req := httptest.NewRequest("GET", hmrUpdatePrefix+"/etc/passwd", nil)
w := httptest.NewRecorder()
ac.HMRUpdateHandler(w, req)
if w.Code != 403 {
t.Errorf("Expected 403 for absolute path, got %d", w.Code)
}
}
// Files that can not be hot-swapped must not be readable through this endpoint.
func TestHMRUpdateHandlerRejectsNonScriptFiles(t *testing.T) {
root := t.TempDir()
ac := &Config{serverDirOrFilename: root}
for _, filename := range []string{".env", "secret.lua", "notes.txt"} {
if err := os.WriteFile(filepath.Join(root, filename), []byte("SECRET=1"), 0o644); err != nil {
t.Fatal(err)
}
req := httptest.NewRequest("GET", hmrUpdatePrefix+filename, nil)
w := httptest.NewRecorder()
ac.HMRUpdateHandler(w, req)
if w.Code != 403 {
t.Errorf("Expected 403 for %s, got %d", filename, w.Code)
}
if strings.Contains(w.Body.String(), "SECRET") {
t.Errorf("The contents of %s were served", filename)
}
}
}