Files
AetherForge/agent/client/file_ops_common_test.go
AetherForge 7b2d41cda8
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Expand P2 test coverage: mining chain, spread lanes, path forge, WS/beacon, E2E onion, file handling
2026-06-07 04:58:55 -07:00

184 lines
4.6 KiB
Go

package client
import (
"encoding/base64"
"fmt"
"os"
"path/filepath"
"strings"
"testing"
)
func TestContainsPathTraversal(t *testing.T) {
cases := []struct {
path string
want bool
}{
{"", false},
{"/home/user/docs", false},
{"C:\\Users\\alice", false},
{"~/Downloads", false},
{"../etc/passwd", true},
{"/home/user/../../etc", true},
{"foo/../bar", true},
}
for _, tc := range cases {
if got := containsPathTraversal(tc.path); got != tc.want {
t.Errorf("containsPathTraversal(%q) = %v, want %v", tc.path, got, tc.want)
}
}
}
func TestResolveListDirPathRejectsTraversal(t *testing.T) {
_, err := resolveListDirPath("../outside")
if err == nil {
t.Fatal("expected traversal error")
}
}
func TestResolveListDirPathEmptyUsesHome(t *testing.T) {
home, err := os.UserHomeDir()
if err != nil {
t.Skip("no home dir")
}
for _, input := range []string{"", "~", "@home"} {
got, err := resolveListDirPath(input)
if err != nil {
t.Fatalf("resolveListDirPath(%q): %v", input, err)
}
if got != filepath.Clean(home) {
t.Fatalf("resolveListDirPath(%q) = %q, want %q", input, got, home)
}
}
}
func TestIsBlockedDeletePath(t *testing.T) {
if !isBlockedDeletePath(`C:\Windows\System32\kernel32.dll`) {
t.Fatal("expected Windows system path blocked")
}
if !isBlockedDeletePath(`/usr/bin/bash`) {
t.Fatal("expected /usr blocked")
}
home, err := os.UserHomeDir()
if err != nil {
t.Skip("no home")
}
if !isBlockedDeletePath(home) {
t.Fatal("expected home root blocked")
}
tmp := filepath.Join(home, "test_delete_guard.txt")
if isBlockedDeletePath(tmp) {
t.Fatalf("expected user file path allowed: %s", tmp)
}
}
func TestReadFileCommandRejectsOversize(t *testing.T) {
dir := t.TempDir()
big := filepath.Join(dir, "huge.bin")
if err := os.WriteFile(big, make([]byte, maxReadFileBytes+1), 0o644); err != nil {
t.Fatal(err)
}
c := newTestClient(t)
var gotOK bool
var gotMsg string
c.commandResultHook = func(_ string, success bool, message string) {
gotOK = success
gotMsg = message
}
c.handleCommand("read_file", 0, "", big, "", "")
if gotOK {
t.Fatal("oversize read_file should fail")
}
if !strings.Contains(gotMsg, "file too large") {
t.Fatalf("message=%q", gotMsg)
}
}
func TestReadFileCommandAcceptsWithinCap(t *testing.T) {
dir := t.TempDir()
small := filepath.Join(dir, "small.txt")
want := "config-value"
if err := os.WriteFile(small, []byte(want), 0o644); err != nil {
t.Fatal(err)
}
c := newTestClient(t)
var gotOK bool
var gotMsg string
c.commandResultHook = func(_ string, success bool, message string) {
gotOK = success
gotMsg = message
}
c.handleCommand("read_file", 0, "", small, "", "")
if !gotOK || gotMsg != want {
t.Fatalf("ok=%v msg=%q want %q", gotOK, gotMsg, want)
}
}
func TestAgentConfigFileUploadReadRoundTrip(t *testing.T) {
dir := t.TempDir()
cfgPath := filepath.Join(dir, "agent-config.json")
payload := `{"server_url":"http://127.0.0.1:8989","worker_name":"test-node"}`
encoded := base64.StdEncoding.EncodeToString([]byte(payload))
c := newTestClient(t)
uploadDone := make(chan struct{})
c.commandResultHook = func(action string, success bool, message string) {
if action == "upload" {
if !success {
t.Fatalf("upload failed: %s", message)
}
close(uploadDone)
}
}
c.handleCommand("upload", 0, "", cfgPath, encoded, "")
<-uploadDone
readDone := make(chan struct{})
var readBody string
c.commandResultHook = func(action string, success bool, message string) {
if action == "read_file" {
if !success {
t.Fatalf("read_file failed: %s", message)
}
readBody = message
close(readDone)
}
}
c.handleCommand("read_file", 0, "", cfgPath, "", "")
<-readDone
if readBody != payload {
t.Fatalf("round-trip mismatch:\nwant %q\ngot %q", payload, readBody)
}
}
func TestReadFileCommandRejectsTraversal(t *testing.T) {
c := newTestClient(t)
var gotMsg string
c.commandResultHook = func(_ string, success bool, message string) {
if !success {
gotMsg = message
}
}
c.handleCommand("read_file", 0, "", "../../etc/passwd", "", "")
if !strings.Contains(gotMsg, "path traversal") {
t.Fatalf("message=%q", gotMsg)
}
}
func TestReadDirectoryEntriesCapsCount(t *testing.T) {
dir := t.TempDir()
for i := 0; i < maxListDirEntries+10; i++ {
name := filepath.Join(dir, fmt.Sprintf("file_%d.txt", i))
if err := os.WriteFile(name, []byte("x"), 0o644); err != nil {
t.Fatal(err)
}
}
entries, err := readDirectoryEntries(dir)
if err != nil {
t.Fatal(err)
}
if len(entries) != maxListDirEntries {
t.Fatalf("entries len = %d, want cap %d", len(entries), maxListDirEntries)
}
}