72 lines
2.0 KiB
Go
72 lines
2.0 KiB
Go
package oplog_test
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"proxyctl/internal/app"
|
|
"proxyctl/internal/oplog"
|
|
)
|
|
|
|
func TestLoggerRejectsSymlinkedStateAncestor(t *testing.T) {
|
|
root := t.TempDir()
|
|
victim := filepath.Join(root, "victim")
|
|
if err := os.Mkdir(victim, 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.Symlink(victim, filepath.Join(root, "state")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
logger := oplog.New(filepath.Join(root, "state", "proxyctl", "operations.log"), 1024, 1)
|
|
if err := logger.Write(app.LogEntry{Operation: "reset", Result: "failure"}); err == nil {
|
|
t.Fatal("logger followed a symlinked state ancestor")
|
|
}
|
|
entries, err := os.ReadDir(victim)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(entries) != 0 {
|
|
t.Fatalf("victim changed: %v", entries)
|
|
}
|
|
}
|
|
|
|
func TestLoggerRotatesAtBoundAndNeverStoresAuthenticatedURL(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "state", "proxyctl.log")
|
|
logger := oplog.New(path, 180, 2)
|
|
for i := 0; i < 20; i++ {
|
|
err := logger.Write(app.LogEntry{Time: time.Unix(int64(i), 0), Operation: "reset", Target: "fake", Result: "failure", Detail: "request http://alice:secret@proxy.example:8080/private failed"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
for _, candidate := range []string{path, path + ".1", path + ".2"} {
|
|
data, err := os.ReadFile(candidate)
|
|
if os.IsNotExist(err) {
|
|
continue
|
|
}
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(data) > 180 {
|
|
t.Errorf("%s has %d bytes, max 180", filepath.Base(candidate), len(data))
|
|
}
|
|
text := string(data)
|
|
if strings.Contains(text, "secret") || strings.Contains(text, "proxy.example:8080/private") {
|
|
t.Errorf("log leaked authenticated URL: %q", text)
|
|
}
|
|
if !strings.Contains(text, "operation=reset") || !strings.Contains(text, "target=fake") || !strings.Contains(text, "result=failure") {
|
|
t.Errorf("log lacks operation fields: %q", text)
|
|
}
|
|
}
|
|
matches, err := filepath.Glob(path + "*")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(matches) > 3 {
|
|
t.Fatalf("retained %d logs, want at most 3: %v", len(matches), matches)
|
|
}
|
|
}
|